diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile
index 9973c599..ec22b073 100644
--- a/.devcontainer/Dockerfile
+++ b/.devcontainer/Dockerfile
@@ -22,6 +22,9 @@ RUN rm -rf /var/lib/apt/lists/* && \
vim \
netcat-openbsd \
socat \
+ bubblewrap \
+ iptables \
+ ipset \
chromium && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
index 61edaa29..166f25c0 100644
--- a/.devcontainer/devcontainer.json
+++ b/.devcontainer/devcontainer.json
@@ -8,6 +8,9 @@
"${localWorkspaceFolderBasename}"
],
"workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",
+ "mounts": [
+ "source=claude-code-config-${devcontainerId},target=/root/.claude,type=volume"
+ ],
"customizations": {
"vscode": {
"extensions": [
diff --git a/README.md b/README.md
index d81db38a..a991e7cd 100644
--- a/README.md
+++ b/README.md
@@ -44,6 +44,7 @@ curl -fsSL https://raw.githubusercontent.com/maxritter/pilot-shell/main/install.
**Pilot Shell is different.** Every component solves a real problem:
- **`/spec`** — plans, implements, and verifies features end-to-end with TDD
+- **`/fix`** — bugfix workflow with TDD; bails out when complexity exceeds the standard fix lane
- **`/prd`** — brainstorm ideas into clear requirements through with optional deep research
- **Quality hooks** — enforce linting, formatting, type checking, and tests as quality gates
- **Context engineering** — preserves decisions and knowledge across sessions
@@ -107,6 +108,8 @@ curl -fsSL https://raw.githubusercontent.com/maxritter/pilot-shell/main/uninstal
Pilot Shell works inside Dev Containers. Copy the [`.devcontainer`](https://github.com/maxritter/pilot-shell/tree/main/.devcontainer) folder from this repository into your project, adapt it to your needs (base image, extensions, dependencies), and run the installer inside the container. The installer auto-detects the container environment and skips system-level dependencies like Homebrew.
+For tighter isolation when working with untrusted code, combine the dev container with Claude Code's [`/sandbox`](https://code.claude.com/docs/en/sandboxing) — `bubblewrap`, `socat`, `iptables`, and `ipset` are pre-installed in the Dockerfile so it works out of the box on Linux. See Anthropic's [development containers](https://code.claude.com/docs/en/devcontainer) and [sandboxing](https://code.claude.com/docs/en/sandboxing) docs for hardening patterns (egress allowlist, managed settings, persistent volumes).
+
@@ -130,16 +133,14 @@ Pilot Shell works inside Dev Containers. Copy the [`.devcontainer`](https://gith
Just chat — no plan, no approval gate. [Quick mode](https://pilot-shell.com/docs/workflows/quick-mode) is the default: quality hooks and TDD enforcement still apply, best for small tasks and exploration. For anything that needs a plan, use `/spec` — not Claude Code's built-in plan mode.
-### /spec — Spec-Driven Development
-
-**[`/spec`](https://pilot-shell.com/docs/workflows/spec) replaces Claude Code's built-in plan mode** (Shift+Tab). It provides a complete planning workflow with TDD, verification, and code review — use `/spec` instead of plan mode for all planned work.
+### /spec — Spec-Driven Development (features)
-Features, bug fixes, refactoring — describe it and `/spec` handles the rest. Auto-detects whether it's a feature or a bugfix and adapts the workflow. Specs are saved to `docs/plans/` and visible in the Console's **Specification** tab.
+**[`/spec`](https://pilot-shell.com/docs/workflows/spec) replaces Claude Code's built-in plan mode** (Shift+Tab) for new features, refactoring, and architectural work. It provides a complete planning workflow with TDD, verification, and code review.
```bash
pilot
-> /spec "Add user authentication with OAuth and JWT tokens" # → feature mode
-> /spec "Fix the crash when deleting nodes with two children" # → bugfix mode (auto-detected)
+> /spec "Add user authentication with OAuth and JWT tokens"
+> /spec "Migrate the REST API to GraphQL"
```
```
@@ -163,18 +164,177 @@ Full exploration workflow for new functionality, refactoring, or architectural c
+### /fix — Bugfix Workflow
+
+**[`/fix`](https://pilot-shell.com/docs/workflows/fix) is the bugfix command.** Investigate the bug, write the failing test, fix at the root cause, single-pass audit, done. No plan file, no approval mid-flow, no separate verify phase.
+
+```bash
+pilot
+> /fix "annotation persistence drops fields between save and reload"
+> /fix "off-by-one in pagination at boundary"
+> /fix "wrong default for max_retries"
+```
+
+```text
+Investigate → RED → Fix → Audit → Quality Gate → Done
+```
+
+If investigation reveals the bug is multi-component or architectural, `/fix` stops cleanly and tells you to re-invoke with `/spec`. `/fix` is always quick; `/spec` is the full workflow.
+
+
+How /fix works
+
+For local bugs. Single file, obvious-once-traced root cause. No plan file, no approval mid-flow, no separate verify phase. TDD still enforced — bugfixes without a failing test don't ship.
+
+- **Investigate:** Reproduce the bug → trace to root cause at `file:line` with `codegraph_context` + targeted reads → state confidence (High/Medium required to proceed). For UI / async / race bugs, add temporary `SPEC-DEBUG:`-marked logs at component boundaries before tracing.
+- **RED:** Write the failing test via an existing public entry point → run, must fail with the documented symptom.
+- **Fix:** Minimal change at the root cause. Symptom patches are forbidden. Reproducing test must pass, then the targeted test module. Diff sanity check (root-cause file in diff, no unplanned files, < 20 lines, symptom-patching grep) catches issues with the fix itself.
+- **Verify End-to-End:** The primary correctness signal. Run the actual program with the original input (Claude Code Chrome → Chrome DevTools MCP → playwright-cli → agent-browser for UI; CLI / API / REPL / job trigger for non-UI) and capture concrete evidence. A passing unit test alone is never accepted as proof.
+- **Quality Gate:** Lint + types + build + full anti-regression suite, once.
+- **Bail-out:** If investigation reveals the bug is multi-component, architectural, needs defense-in-depth at multiple layers, or two fix attempts have failed, `/fix` stops cleanly and tells you to re-invoke with `/spec`. It does not silently switch lanes.
+
+
+
-Bugfix Mode
+How /spec handles bugs
+
+When you type `/spec ""`, the full bugfix workflow runs — for bugs that warrant a written plan, approval, code review, and the full verify ceremony.
+
+- **Behavior Contract:** every plan pins down `Given / When / Currently / Expected / Anti-regression` — the invariant the fix must produce and the behavior it must not break
+- **Three uniform tasks** (always, regardless of bug size): Write Reproducing Test (RED) → Implement Fix at Root Cause → Quality Gate
+- **Verify audit:** always-on `cp`+`trap` revert-test (proves the reproducing test would genuinely fail without the fix — rules out retroactive rubber-stamp tests) + root-cause-at-source audit (flags symptom patches and caller-side workarounds) + original-symptom re-check — no sub-agents, tests carry the proof
+- **Iteration cap at 3:** after three failed verify cycles, the workflow stops and asks if the bug is architectural rather than letting you loop forever
+
+
+
+### /prd — Brainstorm Ideas Into Product Requirements Documents
+
+[`/prd`](https://pilot-shell.com/docs/workflows/prd) is the brainstorming surface for ideas that aren't specs yet — vague problem statements and fuzzy shapes. It pitches directions, pressure-tests them with you, and converges on a PRD you can hand to `/spec`. PRDs are saved to `docs/prd/` and visible in the Console's **Requirements** tab.
+
+```bash
+pilot
+> /prd "Add real-time notifications for team updates"
+> /prd "We need better onboarding — users drop off after signup"
+```
+
+
+What /prd Does
+
+**When to use `/prd` over `/spec`:** `/prd` is for **what** and **why**; `/spec` is for **how**. Reach for `/prd` first when you only have a problem statement, want to riff across multiple directions, or need scope boundaries defined before someone starts building.
-Investigation-first workflow for targeted fixes. Finds the root cause before touching any code.
+**Flow:** two modes, picked automatically from how fuzzy the idea is:
-**Investigate:** Reproduces the bug → traces backward through the call chain to find the **root cause** at a specific `file:line` → compares against working code patterns → states the fix with confidence level. If 3+ hypotheses fail, escalates as an architectural problem.
+1. **Ideate** — free-form prose, Claude pitches 3-5 directions, you react (only runs when the idea is vague)
+2. **Clarify → Converge → Write** — structured multiple-choice questions once the shape is known, then the PRD is written
-**Test-Before-Fix:** Writes a regression test that FAILS on current code → implements the minimal fix at the root cause → verifies all tests pass. Defense-in-depth validation at multiple layers when the bug involves data flowing through shared code paths.
+**Research tiers** (picked at the start):
-**Verify:** Lightweight verification — regression test confirmation → full test suite → lint + type check → quality checks. No review sub-agents — the regression test proves the fix works, the full suite proves nothing else broke.
+| Tier | Behavior |
+|------|----------|
+| **Quick** | Skip research |
+| **Standard** | Web search for competitors, prior art, best practices |
+| **Deep** | Parallel research agents for comprehensive findings |
-**Why this matters:** Root cause investigation prevents "fix one thing, break another." The regression test locks in the fix. No formal notation overhead — just trace, test, fix, verify.
+The final PRD covers problem statement, core user flows, scope boundaries, and technical context — then offers to hand off directly to `/spec` for implementation.
+
+
+
+### /setup-rules — Generate Modular Rules
+
+[`/setup-rules`](https://pilot-shell.com/docs/workflows/setup-rules) explores your codebase, discovers conventions, generates modular rules and documents MCP servers. Run once initially, then anytime your project changes significantly.
+
+```bash
+pilot
+> /setup-rules
+```
+
+
+What /setup-rules Does
+
+12 phases that read your codebase and produce comprehensive AI context:
+
+0. **Reference** — load best practices for rule structure, path-scoping, and quality standards
+1. **Read existing rules** — inventory all `.claude/rules/` files, detect structure and path-scoping. Also detects `CLAUDE.md` and `AGENTS.md` (the cross-framework agent context file used by Codex, Cursor, etc.)
+2. **Migrate unscoped assets** — prefix with project slug for better sharing
+3. **Quality audit** — check rules against best practices (size, specificity, stale references, conflicts)
+4. **Explore codebase** — semantic search with Probe CLI, structural analysis with CodeGraph
+5. **Compare patterns** — discovered vs documented conventions
+6. **Sync project rule** — update `{slug}-project.md` with current tech stack, structure, commands. Migrates `CLAUDE.md` / `AGENTS.md` content into modular rules
+7. **Sync MCP docs** — smoke-test user MCP servers, document working tools
+8. **Discover new rules** — find undocumented patterns worth capturing
+9. **Cross-check** — validate all references, ensure consistency across generated files
+10. **Sync AGENTS.md** — if `AGENTS.md` already exists, offer to re-export the updated rules into it so non-Claude agents see the same context. Always asks first, never creates the file if absent, preserves user-authored sections
+11. **Summary** — report all changes made
+
+**For monorepos:** Organizes rules in nested subdirectories by product and team, with `paths` frontmatter to scope rules to specific file types. Generates a `README.md` documenting the structure.
+
+
+
+### /create-skill — Reusable Skill Creator
+
+[`/create-skill`](https://pilot-shell.com/docs/workflows/create-skill) builds a reusable skill from any topic — explores the codebase and creates it interactively with you. If no topic is given, evaluates the current session for extractable knowledge.
+
+```bash
+pilot
+> /create-skill "Automate the review and triaging of our PR Bot comments"
+```
+
+
+What /create-skill Does
+
+6 phases that turn domain knowledge into a reusable skill:
+
+1. **Reference** — load use case categories, complexity spectrum, file structure template, description formula, security restrictions
+2. **Understand** — explore the codebase for relevant patterns, ask clarifying questions, or evaluate the current session for extractable knowledge
+3. **Check existing** — search project and global skills to avoid duplicates
+4. **Create** — write to `.claude/skills/` (project) or `~/.claude/skills/` (global), apply portability and determinism checklists
+5. **Quality gates** — structure checklist (SKILL.md naming, frontmatter fields), content checklist (error handling, examples, exclusions), triggering test (should/shouldn't trigger), iteration signals
+6. **Test & iterate** — run test prompts with sub-agents, evaluate results, optimize description triggering
+
+**Use case categories:**
+
+| Category | Best For |
+| ----------------------------- | -------------------------------------------------------------------------- |
+| **Document & Asset Creation** | Consistent reports, designs, code with embedded style guides and templates |
+| **Workflow Automation** | Multi-step processes with validation gates and iterative refinement |
+| **MCP Enhancement** | Workflow guidance on top of MCP tool access, multi-MCP coordination |
+
+**Skill structure:** Each skill is a folder with a `SKILL.md` file (case-sensitive), optional `scripts/`, `references/`, and `assets/` directories. The YAML frontmatter description determines when Claude loads the skill — it must include what the skill does, when to use it, and specific trigger phrases. Progressive disclosure keeps context lean: frontmatter loads always (~100 tokens), SKILL.md loads on activation, linked files load on demand.
+
+
+
+### /benchmark — Measure Rule & Skill Impact
+
+[`/benchmark`](https://pilot-shell.com/docs/workflows/benchmark) runs your prompts with and without the target, grades outputs against falsifiable assertions, and shows a structured report you can absorb in 30 seconds — labeled verdict, quadrant breakdown, and only the divergent assertions in the drill-down. Finishes with a concrete improvement plan so you know exactly what to change next.
+
+```bash
+pilot
+> /benchmark pilot/skills/create-skill
+> /benchmark pilot/rules/testing.md
+```
+
+
+What /benchmark Does
+
+Six phases turn a rule or skill into a before/after comparison with an actionable plan:
+
+1. **Intake** — pick up an existing `benchmarks//evals.json` or author one
+2. **Target discovery** — classify as `skill` or `rules`
+3. **Author evals** — draft 3 falsifiable assertions; falsifiability gate ensures baseline actually fails
+4. **Execute** — run both configs in isolated sandboxes; grader subagent scores every assertion
+5. **Present findings** — three layers, scannable top-to-bottom:
+
+ | Layer | Content |
+ |---|---|
+ | **Verdict** | One labeled sentence with a recommended next step. Delta bands: 🟢 Strong (≥ +0.50) / 🟢 Moderate (+0.20) / 🟡 Weak (+0.05) / ⚪ Indistinguishable (±0.05) / 🔴 Regression (< −0.05) |
+ | **Quadrant breakdown** | Counts each assertion as Signal (✓/✗) / Baseline (✓/✓) / Unreachable (✗/✗) / Regression (✗/✓). The dominant quadrant drives the plan |
+ | **Per-eval drill-down** | Only divergent assertions get a row; matching ones fold into header counts so the report stays under one screen |
+
+6. **Improvement plan** — ≤ 5 ranked proposals in a uniform format (`[TARGET]` or `[EVALS]` tag, location, current quote, replacement, "Lever" line). You pick: apply target edits, iterate on evals, both, or save the plan and stop. Re-runs land in a fresh `runs//` so iteration deltas stay legible.
+
+**Isolation:** each run gets its own sandbox directory; a globally-installed copy of the target in `~/.claude/` is auto-hidden for the duration and restored afterward (with on-disk recovery manifest covering SIGKILL / power loss / segfault). Conditional-loading frontmatter (`path:` / `paths:`) is stripped from the copy installed into the `with` sandbox so the target loads unconditionally for every prompt — without that, rules scoped to e.g. `paths: ["**/*.py"]` would stay dormant in both configs and the delta would collapse to 0.00. The source file is never modified.
+
+**Key flags:** `--runs N` (default 1), `--configs with,without`, `--workers N`, `--model`, `--no-isolate-global`, `--restore-hidden`.
@@ -412,137 +572,6 @@ Pilot Bot defines scheduled jobs, automates recurring tasks, and monitor system
-### /prd — Brainstorm Ideas Into Product Requirements Documents
-
-[`/prd`](https://pilot-shell.com/docs/workflows/prd) is the brainstorming surface for ideas that aren't specs yet — vague problem statements and fuzzy shapes. It pitches directions, pressure-tests them with you, and converges on a PRD you can hand to `/spec`. PRDs are saved to `docs/prd/` and visible in the Console's **Requirements** tab.
-
-```bash
-pilot
-> /prd "Add real-time notifications for team updates"
-> /prd "We need better onboarding — users drop off after signup"
-```
-
-
-What /prd Does
-
-**When to use `/prd` over `/spec`:** `/prd` is for **what** and **why**; `/spec` is for **how**. Reach for `/prd` first when you only have a problem statement, want to riff across multiple directions, or need scope boundaries defined before someone starts building.
-
-**Flow:** two modes, picked automatically from how fuzzy the idea is:
-
-1. **Ideate** — free-form prose, Claude pitches 3-5 directions, you react (only runs when the idea is vague)
-2. **Clarify → Converge → Write** — structured multiple-choice questions once the shape is known, then the PRD is written
-
-**Research tiers** (picked at the start):
-
-| Tier | Behavior |
-|------|----------|
-| **Quick** | Skip research |
-| **Standard** | Web search for competitors, prior art, best practices |
-| **Deep** | Parallel research agents for comprehensive findings |
-
-The final PRD covers problem statement, core user flows, scope boundaries, and technical context — then offers to hand off directly to `/spec` for implementation.
-
-
-
-### /setup-rules — Generate Modular Rules
-
-[`/setup-rules`](https://pilot-shell.com/docs/workflows/setup-rules) explores your codebase, discovers conventions, generates modular rules and documents MCP servers. Run once initially, then anytime your project changes significantly.
-
-```bash
-pilot
-> /setup-rules
-```
-
-
-What /setup-rules Does
-
-12 phases that read your codebase and produce comprehensive AI context:
-
-0. **Reference** — load best practices for rule structure, path-scoping, and quality standards
-1. **Read existing rules** — inventory all `.claude/rules/` files, detect structure and path-scoping. Also detects `CLAUDE.md` and `AGENTS.md` (the cross-framework agent context file used by Codex, Cursor, etc.)
-2. **Migrate unscoped assets** — prefix with project slug for better sharing
-3. **Quality audit** — check rules against best practices (size, specificity, stale references, conflicts)
-4. **Explore codebase** — semantic search with Probe CLI, structural analysis with CodeGraph
-5. **Compare patterns** — discovered vs documented conventions
-6. **Sync project rule** — update `{slug}-project.md` with current tech stack, structure, commands. Migrates `CLAUDE.md` / `AGENTS.md` content into modular rules
-7. **Sync MCP docs** — smoke-test user MCP servers, document working tools
-8. **Discover new rules** — find undocumented patterns worth capturing
-9. **Cross-check** — validate all references, ensure consistency across generated files
-10. **Sync AGENTS.md** — if `AGENTS.md` already exists, offer to re-export the updated rules into it so non-Claude agents see the same context. Always asks first, never creates the file if absent, preserves user-authored sections
-11. **Summary** — report all changes made
-
-**For monorepos:** Organizes rules in nested subdirectories by product and team, with `paths` frontmatter to scope rules to specific file types. Generates a `README.md` documenting the structure.
-
-
-
-### /create-skill — Reusable Skill Creator
-
-[`/create-skill`](https://pilot-shell.com/docs/workflows/create-skill) builds a reusable skill from any topic — explores the codebase and creates it interactively with you. If no topic is given, evaluates the current session for extractable knowledge.
-
-```bash
-pilot
-> /create-skill "Automate the review and triaging of our PR Bot comments"
-```
-
-
-What /create-skill Does
-
-6 phases that turn domain knowledge into a reusable skill:
-
-1. **Reference** — load use case categories, complexity spectrum, file structure template, description formula, security restrictions
-2. **Understand** — explore the codebase for relevant patterns, ask clarifying questions, or evaluate the current session for extractable knowledge
-3. **Check existing** — search project and global skills to avoid duplicates
-4. **Create** — write to `.claude/skills/` (project) or `~/.claude/skills/` (global), apply portability and determinism checklists
-5. **Quality gates** — structure checklist (SKILL.md naming, frontmatter fields), content checklist (error handling, examples, exclusions), triggering test (should/shouldn't trigger), iteration signals
-6. **Test & iterate** — run test prompts with sub-agents, evaluate results, optimize description triggering
-
-**Use case categories:**
-
-| Category | Best For |
-| ----------------------------- | -------------------------------------------------------------------------- |
-| **Document & Asset Creation** | Consistent reports, designs, code with embedded style guides and templates |
-| **Workflow Automation** | Multi-step processes with validation gates and iterative refinement |
-| **MCP Enhancement** | Workflow guidance on top of MCP tool access, multi-MCP coordination |
-
-**Skill structure:** Each skill is a folder with a `SKILL.md` file (case-sensitive), optional `scripts/`, `references/`, and `assets/` directories. The YAML frontmatter description determines when Claude loads the skill — it must include what the skill does, when to use it, and specific trigger phrases. Progressive disclosure keeps context lean: frontmatter loads always (~100 tokens), SKILL.md loads on activation, linked files load on demand.
-
-
-
-### /benchmark — Measure Rule & Skill Impact
-
-[`/benchmark`](https://pilot-shell.com/docs/workflows/benchmark) runs your prompts with and without the target, grades outputs against falsifiable assertions, and shows a structured report you can absorb in 30 seconds — labeled verdict, quadrant breakdown, and only the divergent assertions in the drill-down. Finishes with a concrete improvement plan so you know exactly what to change next.
-
-```bash
-pilot
-> /benchmark pilot/skills/create-skill
-> /benchmark pilot/rules/testing.md
-```
-
-
-What /benchmark Does
-
-Six phases turn a rule or skill into a before/after comparison with an actionable plan:
-
-1. **Intake** — pick up an existing `benchmarks//evals.json` or author one
-2. **Target discovery** — classify as `skill` or `rules`
-3. **Author evals** — draft 3 falsifiable assertions; falsifiability gate ensures baseline actually fails
-4. **Execute** — run both configs in isolated sandboxes; grader subagent scores every assertion
-5. **Present findings** — three layers, scannable top-to-bottom:
-
- | Layer | Content |
- |---|---|
- | **Verdict** | One labeled sentence with a recommended next step. Delta bands: 🟢 Strong (≥ +0.50) / 🟢 Moderate (+0.20) / 🟡 Weak (+0.05) / ⚪ Indistinguishable (±0.05) / 🔴 Regression (< −0.05) |
- | **Quadrant breakdown** | Counts each assertion as Signal (✓/✗) / Baseline (✓/✓) / Unreachable (✗/✗) / Regression (✗/✓). The dominant quadrant drives the plan |
- | **Per-eval drill-down** | Only divergent assertions get a row; matching ones fold into header counts so the report stays under one screen |
-
-6. **Improvement plan** — ≤ 5 ranked proposals in a uniform format (`[TARGET]` or `[EVALS]` tag, location, current quote, replacement, "Lever" line). You pick: apply target edits, iterate on evals, both, or save the plan and stop. Re-runs land in a fresh `runs//` so iteration deltas stay legible.
-
-**Isolation:** each run gets its own sandbox directory; a globally-installed copy of the target in `~/.claude/` is auto-hidden for the duration and restored afterward (with on-disk recovery manifest covering SIGKILL / power loss / segfault). Conditional-loading frontmatter (`path:` / `paths:`) is stripped from the copy installed into the `with` sandbox so the target loads unconditionally for every prompt — without that, rules scoped to e.g. `paths: ["**/*.py"]` would stay dormant in both configs and the delta would collapse to 0.00. The source file is never modified.
-
-**Key flags:** `--runs N` (default 1), `--configs with,without`, `--workers N`, `--model`, `--no-isolate-global`, `--restore-hidden`.
-
-
-
### Claude CLI Flag Passthrough
All Claude Code CLI flags work directly with `pilot` — current and future. Pilot forwards any flag it doesn't recognize to the Claude CLI automatically.
@@ -719,6 +748,8 @@ On **Team**, every developer runs `pilot customize install ` once and st
Yes. Copy the `.devcontainer` folder from this repository into your project, adapt it to your needs (base image, extensions, dependencies), and install Pilot Shell inside the container. Everything works the same — hooks, rules, MCP servers, persistent memory, and the Console dashboard all run inside the container. This is a great option for teams that want a consistent, reproducible development environment.
+For tighter isolation when working with untrusted code, layer Claude Code's [`/sandbox`](https://code.claude.com/docs/en/sandboxing) on top — the Dockerfile pre-installs `bubblewrap`, `socat`, `iptables`, and `ipset` so it works out of the box. See Anthropic's [development containers](https://code.claude.com/docs/en/devcontainer) and [sandboxing](https://code.claude.com/docs/en/sandboxing) docs for the hardening patterns.
+
diff --git a/console/package.json b/console/package.json
index 54e54bc9..d3f78dbf 100644
--- a/console/package.json
+++ b/console/package.json
@@ -35,8 +35,12 @@
"devDependencies": {
"@git-diff-view/file": "^0.1.1",
"@git-diff-view/react": "^0.1.1",
+ "@happy-dom/global-registrator": "^20.9.0",
"@iconify/react": "^6.0.2",
"@tailwindcss/vite": "^4.1.18",
+ "@testing-library/dom": "^10.4.1",
+ "@testing-library/react": "^16.3.2",
+ "@testing-library/user-event": "^14.6.1",
"@types/bun": "^1.3.8",
"@types/cookie-parser": "^1.4.10",
"@types/cors": "^2.8.19",
diff --git a/console/src/ui/viewer/hooks/useSettings.ts b/console/src/ui/viewer/hooks/useSettings.ts
index d8889ef0..536bed4c 100644
Binary files a/console/src/ui/viewer/hooks/useSettings.ts and b/console/src/ui/viewer/hooks/useSettings.ts differ
diff --git a/console/src/ui/viewer/views/Settings/index.tsx b/console/src/ui/viewer/views/Settings/index.tsx
index 7e9ae3fb..9d72bc15 100644
Binary files a/console/src/ui/viewer/views/Settings/index.tsx and b/console/src/ui/viewer/views/Settings/index.tsx differ
diff --git a/console/src/ui/viewer/views/Spec/annotation/PlanAnnotator.tsx b/console/src/ui/viewer/views/Spec/annotation/PlanAnnotator.tsx
index 38872022..6ee5ac4a 100644
Binary files a/console/src/ui/viewer/views/Spec/annotation/PlanAnnotator.tsx and b/console/src/ui/viewer/views/Spec/annotation/PlanAnnotator.tsx differ
diff --git a/console/src/ui/viewer/views/Spec/annotation/useAnnotation.ts b/console/src/ui/viewer/views/Spec/annotation/useAnnotation.ts
index d2c4d872..3a929d6a 100644
Binary files a/console/src/ui/viewer/views/Spec/annotation/useAnnotation.ts and b/console/src/ui/viewer/views/Spec/annotation/useAnnotation.ts differ
diff --git a/console/src/ui/viewer/views/Spec/index.tsx b/console/src/ui/viewer/views/Spec/index.tsx
index 6a8c6071..3bfdf91a 100644
Binary files a/console/src/ui/viewer/views/Spec/index.tsx and b/console/src/ui/viewer/views/Spec/index.tsx differ
diff --git a/console/src/ui/viewer/views/Spec/parsePlanContent.ts b/console/src/ui/viewer/views/Spec/parsePlanContent.ts
new file mode 100644
index 00000000..37c56e5a
Binary files /dev/null and b/console/src/ui/viewer/views/Spec/parsePlanContent.ts differ
diff --git a/console/tests/annotation/plan-annotator-persistence.test.tsx b/console/tests/annotation/plan-annotator-persistence.test.tsx
new file mode 100644
index 00000000..f66f6cfc
Binary files /dev/null and b/console/tests/annotation/plan-annotator-persistence.test.tsx differ
diff --git a/console/tests/ui/spec-section-rendering.test.ts b/console/tests/ui/spec-section-rendering.test.ts
new file mode 100644
index 00000000..180c518f
Binary files /dev/null and b/console/tests/ui/spec-section-rendering.test.ts differ
diff --git a/console/tsconfig.json b/console/tsconfig.json
index a9add684..3a52a1ca 100644
--- a/console/tsconfig.json
+++ b/console/tsconfig.json
@@ -25,7 +25,8 @@
"include": [
"src/**/*.ts",
"src/**/*.tsx",
- "tests/**/*.ts"
+ "tests/**/*.ts",
+ "tests/**/*.tsx"
],
"exclude": [
"node_modules",
diff --git a/docs/docusaurus/docs/getting-started/installation.md b/docs/docusaurus/docs/getting-started/installation.md
index ff12ea73..a6a994a4 100644
--- a/docs/docusaurus/docs/getting-started/installation.md
+++ b/docs/docusaurus/docs/getting-started/installation.md
@@ -49,6 +49,13 @@ When enabled, Codex provides an independent adversarial review during `/spec` pl
Pilot Shell works inside Dev Containers. Copy the `.devcontainer` folder from the [Pilot Shell repository](https://github.com/maxritter/pilot-shell/tree/main/.devcontainer) into your project, adapt it to your needs (base image, extensions, dependencies), and run the installer inside the container. The installer auto-detects the container environment and skips system-level dependencies like Homebrew.
+For tighter isolation when working with untrusted code, layer Claude Code's [`/sandbox`](https://code.claude.com/docs/en/sandboxing) on top — `bubblewrap`, `socat`, `iptables`, and `ipset` are pre-installed in the Dockerfile so it works out of the box on Linux.
+
+### Further reading
+
+- [Claude Code · Development containers](https://code.claude.com/docs/en/devcontainer) — Anthropic's reference container, persistent volumes, organization policy, network egress, the `--dangerously-skip-permissions` flag.
+- [Claude Code · Sandboxing](https://code.claude.com/docs/en/sandboxing) — Seatbelt (macOS) and bubblewrap (Linux/WSL2), `/sandbox` modes, `allowedDomains`, filesystem allow/deny rules, security limitations.
+
## Install Specific Version
```bash
diff --git a/docs/docusaurus/docs/workflows/fix.md b/docs/docusaurus/docs/workflows/fix.md
new file mode 100644
index 00000000..0f802d8c
--- /dev/null
+++ b/docs/docusaurus/docs/workflows/fix.md
@@ -0,0 +1,106 @@
+---
+sidebar_position: 5
+title: /fix
+description: Bugfix workflow — investigate, RED test, fix, verify end-to-end, done.
+---
+
+# /fix
+
+Bugfix workflow with TDD. Investigates the bug, writes a failing test, fixes at the root cause, **verifies end-to-end against the running program**, finishes. No plan file, no approval mid-flow, no separate verify phase.
+
+Use `/fix` for bugs. Use [`/spec`](/docs/workflows/spec) for features and architectural changes — including bugfixes that warrant a full plan with approval and code review.
+
+```bash
+$ pilot
+> /fix "annotation persistence drops fields between save and reload"
+> /fix "off-by-one in pagination at boundary"
+> /fix "wrong default for max_retries"
+```
+
+`/fix` is **always quick**. If investigation reveals the bug is multi-component, architectural, or otherwise larger than a quick fix, `/fix` stops cleanly and tells you to re-invoke with `/spec`. It does not silently switch lanes.
+
+## Workflow
+
+```text
+Investigate → RED → Fix → Verify End-to-End → Quality Gate → Done
+```
+
+### Investigate
+
+Trace the bug to `file:lineN — function() does X but should do Y` with **High** or **Medium** confidence. For UI / async / race / timing bugs that don't surface from a static read, add temporary `SPEC-DEBUG:`-marked logs at component boundaries before tracing. Low confidence bails out.
+
+### RED — Write the Reproducing Test
+
+Encode `Currently → Expected` via an existing public entry point. Run it; it must **fail** with an error matching the symptom. A test that passes against buggy code doesn't encode the bug.
+
+### Fix at the Root Cause
+
+Minimal change at the root cause. Symptom patches (`try/except` hiding the bug, swallowed returns, silently normalised inputs) are forbidden. Re-run the reproducing test → must pass. Run the targeted test module(s).
+
+A diff sanity check follows: root-cause file IS in the diff, no unplanned files, < 20 lines typically. A grep over the diff catches symptom-patching and leftover `print` / `console.log` / `SPEC-DEBUG:` markers — every match must be justified or reverted.
+
+### Verify End-to-End
+
+The primary correctness signal. Run the actual program with the original input and observe the symptom is gone — a passing unit test alone is never accepted. This step is mandatory.
+
+| Bug surface | Tool | Evidence |
+| --- | --- | --- |
+| **UI / web** | 4-tier browser stack: **Claude Code Chrome** → **Chrome DevTools MCP** → **playwright-cli** → **agent-browser** | Page state, element values |
+| **CLI** | The exact command the user ran | Stdout, exit code |
+| **HTTP API** | `curl` / HTTP client with the user's body | Status code, response field |
+| **Library / SDK / function** | `python -c '…'`, `node -e '…'`, REPL, scratch script | Returned value |
+| **Background job** | Trigger manually with the failing input | Logs |
+
+The completion report must include concrete evidence — bare assertions ("looks fixed", "tests pass") are insufficient. If the symptom persists, the unit test is at the wrong layer: move the assertion up to the user's actual entry point and re-run RED → Fix → Verify End-to-End.
+
+### Quality Gate
+
+Lint + types + build (when applicable), then the full anti-regression suite, once. If a far-from-the-fix test breaks, the bug has unintended cross-coupling — bail out to `/spec`.
+
+### Finalise
+
+Worktree mode: bundle test + fix into one `fix:` commit. Approval gate fires only if **Plan Approval** is enabled. The completion report includes a mandatory **E2E** line documenting what was actually run.
+
+## When to bail out — use `/spec` instead
+
+`/fix` stops and tells you to re-invoke with `/spec` when:
+
+- Bug spans 3+ files or 2+ components.
+- Root cause is architectural, not a single line.
+- Fix needs defense-in-depth at multiple layers.
+- Confidence stays Low — root cause can't be pinned to file:line.
+- Two failed fix attempts.
+- Fix has non-trivial UI implications that warrant a recorded Verification Scenario.
+
+The full lane (`/spec`) adds: Behavior Contract, three-task structure, plan file with approval gate, Console annotation cycle, `cp`+`trap` revert-test proof in verify, iteration cap at 3.
+
+## Common issues
+
+| Symptom | What it means | What to do |
+| --- | --- | --- |
+| Can't reproduce | Description too vague or environment-dependent | Ask for exact steps, env, stack trace. Don't write a speculative fix. |
+| Test passes without the fix | Test doesn't encode the bug | Tighten the assertion or pick a more specific input. |
+| Fix breaks far-away tests | Cross-coupling beyond the quick lane | Bail out. Re-invoke with `/spec`. |
+| Reproducing test green but user still hits the bug | Test sits below the user's layer | Move the assertion up and re-run RED → Fix → Verify End-to-End. |
+| Two failed fix attempts | Architectural problem, not a fix problem | Bail out. The pattern needs reconsidering, not another patch. |
+
+## Configurable Toggles
+
+`/fix` honours the same Console Settings as `/spec`:
+
+| Toggle | Default | Effect when disabled |
+| --- | --- | --- |
+| **Ask Questions** | On | Investigation skips clarifying questions and uses defaults. |
+| **Plan Approval** | On | The end-of-flow approval gate is skipped. |
+
+When both are off, `/fix` runs end-to-end with no user interaction. Worktree isolation is not honoured — use `/spec` if you want a worktree.
+
+## When to use `/spec` vs `/fix`
+
+| Use `/fix` | Use `/spec` |
+| --- | --- |
+| Something is broken | Building new functionality |
+| You want a fix without ceremony | Architecture or design decision matters |
+| You want it done now | Work warrants a written plan + approval |
+
+`/fix` handles the full range — from typos to multi-step debugging. It bails out and points to `/spec` only when complexity is truly architectural (multiple components, defense-in-depth at multiple layers, repeated failed attempts).
diff --git a/docs/docusaurus/docs/workflows/spec.md b/docs/docusaurus/docs/workflows/spec.md
index 064785b8..3bf9b7db 100644
--- a/docs/docusaurus/docs/workflows/spec.md
+++ b/docs/docusaurus/docs/workflows/spec.md
@@ -8,15 +8,14 @@ description: Plan, implement, and verify complex features with full automation u
Plan, implement, and verify complex features with full automation using Spec-Driven Development.
-**Replaces Claude Code's built-in plan mode (Shift+Tab).** Best for complex features, refactoring tasks, or any work where you want to review a plan before implementation begins. The structured workflow prevents scope creep and ensures every task is tested and verified before being marked complete.
+**Replaces Claude Code's built-in plan mode (Shift+Tab).** Best for new features, refactoring, architectural changes — work where a plan and a design discussion add value before code. The structured workflow prevents scope creep and ensures every task is tested and verified before being marked complete.
-> **Tip:** For vague ideas or unclear requirements, use [`/prd`](/docs/workflows/prd) first to brainstorm back-and-forth and produce a PRD, then hand off to `/spec`.
+For bugfixes, use [`/fix`](/docs/workflows/fix). For vague ideas, use [`/prd`](/docs/workflows/prd) first to produce a PRD, then hand off to `/spec`.
```bash
$ pilot
> /spec "Add user authentication with OAuth and JWT tokens"
> /spec "Migrate the REST API to GraphQL"
-> /spec "Fix the crash when deleting nodes with two children" # bugfix auto-detected
```
## Workflow
@@ -38,18 +37,9 @@ Full exploration workflow for new functionality, refactoring, or any work where
- Full plan with scope, risks, and Definition of Done
- Unified verification agent (optional, configurable in Console Settings)
-### Bugfix Spec (auto-detected)
+### Bugfixes
-Investigation-first flow for targeted fixes. Finds the root cause before touching any code, then enforces a uniform three-task structure so every bugfix follows the same process — no freewheeling.
-
-- **Root cause tracing:** backward through the call chain to `file:line`, with CodeGraph caller/callee analysis
-- **Pattern analysis:** compare broken vs working code paths
-- **Behavior Contract:** every plan pins down `Given / When / Currently / Expected / Anti-regression` — the invariant the fix must produce and the behavior it must not break
-- **Three uniform tasks** (always, regardless of bug size):
- 1. **Write Reproducing Test (RED)** — must FAIL before any fix code exists
- 2. **Implement Fix at Root Cause** — reproducing test passes, full suite passes
- 3. **Quality Gate** — lint, type check, build, full suite green after any auto-fixes
-- **Verify audit:** authoritative full suite + always-on revert-test (proves the reproducing test would genuinely fail without the fix — rules out retroactive rubber-stamp tests) + root-cause-at-source audit (flags symptom patches and caller-side workarounds) + anti-regression spot-check — no sub-agents, tests carry the proof
+For a bugfix workflow without a plan file, use [`/fix`](/docs/workflows/fix). When the user types `/spec` with a bug description, the full bugfix workflow runs — root-cause investigation, three-task structure (RED test → fix → quality gate), Behavior Contract audit, revert-test proof in verify, iteration cap at 3.
## Three Phases
@@ -66,7 +56,7 @@ Investigation-first flow for targeted fixes. Finds the root cause before touchin
- Isolated git worktree, new branch from default, or current branch (your choice)
- Strict TDD for each task: RED → GREEN → REFACTOR
- Quality hooks auto-lint, format, and type-check every edit
-- Full test suite after each task to catch regressions early
+- Full test suite runs at the **Quality Gate** task (end), not after every task — running it per-fix-task is the single biggest token sink in bundled bugfix plans, so the targeted test module is used between fixes and the authoritative full-suite run happens once
### Verify Phase
@@ -100,6 +90,8 @@ When all three are disabled, `/spec` runs end-to-end without any user interactio
Both reviewers run in a separate context window and don't consume the main session's context budget. Optional **Codex adversarial reviewers** (off by default) provide an independent second opinion using OpenAI Codex.
+**Codex runs at most once per `/spec` invocation.** Plan iterations (annotation feedback, verify re-runs, fixing prior findings) reuse the result of the first Codex review instead of re-launching — a sentinel file in the session directory enforces this. The bugfix planning phase no longer runs Codex at all; adversarial review is most valuable on real code, not on a plan.
+
## Branch Strategy (Optional)
When starting a `/spec` task, you're asked how you want to work:
@@ -111,3 +103,5 @@ When starting a `/spec` task, you're asked how you want to work:
| **New branch from default** | Fetches origin, creates `feat/` (or `fix/` for bugfixes) from `origin/main`, and checks it out. Best when your current branch isn't clean but you don't want full worktree isolation. |
Disable the **Worktree Support** toggle in Console Settings to skip this question entirely — `/spec` will always use the current branch.
+
+For bugfixes, use [`/fix`](/docs/workflows/fix) — the worktree question is asked here in `/spec` because that's where it applies.
diff --git a/docs/docusaurus/sidebars.ts b/docs/docusaurus/sidebars.ts
index 60467827..5429aedf 100644
--- a/docs/docusaurus/sidebars.ts
+++ b/docs/docusaurus/sidebars.ts
@@ -22,6 +22,7 @@ const sidebars: SidebarsConfig = {
"workflows/create-skill",
"workflows/prd",
"workflows/spec",
+ "workflows/fix",
"workflows/benchmark",
"workflows/quick-mode",
],
diff --git a/docs/site/src/components/HeroSection.tsx b/docs/site/src/components/HeroSection.tsx
index 77bd8e5e..267e5d8a 100644
--- a/docs/site/src/components/HeroSection.tsx
+++ b/docs/site/src/components/HeroSection.tsx
@@ -1,6 +1,5 @@
import { GithubIcon, BookOpen } from "lucide-react";
import { Button } from "@/components/ui/button";
-import { Badge } from "@/components/ui/badge";
import Logo from "@/components/Logo";
const HeroSection = () => {
@@ -26,73 +25,6 @@ const HeroSection = () => {
- {/* Feature highlights */}
-
-
-
- Spec-Driven
-
-
- Plan → Build → Verify
-
-
-
-
-
- TDD
-
-
- Test-First
-
-
-
-
-
- Memory
-
-
- Persistent Context
-
-
-
-
-
- Overlays
-
-
- Modify Defaults
-
-
-
-
-
- Hooks
-
-
- Quality Gates
-
-
-
-
- {/* Feature badges */}
-
-
- Worktree Support
-
-
- MCP Servers
-
-
- LSP Servers
-
-
- Semantic Search
-
-
- Pilot Bot
-
-
-
{/* CTA Buttons */}
{
/spec
{" "}
- features & bugfixes{" → "}
+ features{" → "}
+
+ /fix
+ {" "}
+ bugfixes{" → "}
/create-skill
{" "}
diff --git a/docs/site/src/components/WhatsInside.tsx b/docs/site/src/components/WhatsInside.tsx
index 78acc8a5..c36c7cfa 100644
--- a/docs/site/src/components/WhatsInside.tsx
+++ b/docs/site/src/components/WhatsInside.tsx
@@ -25,7 +25,7 @@ const insideItems: InsideItem[] = [
title: "Spec-Driven Development",
description: "Replaces plan mode",
summary:
- "/spec plans features and bugfixes, gets your approval, implements each task with TDD, then verifies with automated code review. Loops back if any check fails.",
+ "/spec plans features end-to-end with TDD — explore, plan, approve, implement, verify. /fix runs the bugfix workflow with the same TDD discipline. Both honour your approval and review toggles.",
href: "/docs/workflows/spec",
},
{
@@ -33,7 +33,7 @@ const insideItems: InsideItem[] = [
title: "Context Engineering",
description: "Keep your context window lean",
summary:
- "Curated rules for best practices, TDD, debugging, and verification. Language- and architecture-specific standards cover Python, TypeScript, Go, frontend, and backend. Concise and modular \u2014 only what\u2019s relevant loads into context.",
+ "Curated rules for best practices, TDD, debugging, and verification. Language- and architecture-specific standards for Python, TypeScript, Go, frontend, and backend \u2014 modular, only what\u2019s relevant loads.",
href: "/docs/features/context-optimization",
},
{
@@ -41,7 +41,7 @@ const insideItems: InsideItem[] = [
title: "Quality Hooks & Testing",
description: "Deterministic checks on every edit",
summary:
- "15 hooks across 7 lifecycle events. Auto-lint, format, and type-check every file edit. TDD enforcer warns when implementation is written without a failing test.",
+ "15 hooks across 7 lifecycle events. Auto-lint, format, and type-check every file edit. The TDD enforcer warns when implementation lands without a failing test in place first.",
href: "/docs/features/hooks",
},
{
@@ -49,7 +49,7 @@ const insideItems: InsideItem[] = [
title: "MCP & LSP Servers",
description: "Pre-configured, zero setup",
summary:
- "Six MCP servers (docs, search, memory, code graphs) plus Python, TypeScript, and Go language servers \u2014 all auto-installed. Real-time diagnostics and type intelligence on every edit.",
+ "Six MCP servers ship pre-configured: docs, web search, persistent memory, code graphs. Python, TypeScript, and Go language servers auto-install for real-time diagnostics on every edit.",
href: "/docs/features/mcp-servers",
},
{
@@ -57,7 +57,7 @@ const insideItems: InsideItem[] = [
title: "Semantic Search",
description: "Find code by intent, not keywords",
summary:
- "Search your codebase by intent, not just keywords. AST-aware extraction pulls exactly what\u2019s needed. Call graph tracing maps blast radius before you change anything. Sub-300ms.",
+ "Search the codebase by intent, not keywords. AST-aware extraction pulls exactly what\u2019s needed. Call-graph tracing maps blast radius before you change anything. Sub-300ms results.",
href: "/docs/features/open-source-tools",
},
{
@@ -65,7 +65,7 @@ const insideItems: InsideItem[] = [
title: "Cost Optimization",
description: "Right model, right task, visible spend",
summary:
- "Smart model routing: Opus for planning, Sonnet for implementation. CLI proxy saves 60\u201390% on tool output tokens. Usage tracking in Console shows daily cost and trends.",
+ "Smart model routing \u2014 Opus for planning and verification, Sonnet for implementation. CLI proxy saves 60\u201390% on tool-output tokens. Console tracks daily cost and trends over time.",
href: "/docs/features/model-routing",
},
{
@@ -73,7 +73,7 @@ const insideItems: InsideItem[] = [
title: "Extensions & Sharing",
description: "Skills, rules, commands, agents",
summary:
- "Create custom skills and rules with built-in generators. Share across machines via git, across teams via project repos. Seven extension types at four scopes \u2014 managed in Console.",
+ "Create custom skills and rules with built-in generators. Share across machines via git, across teams via project repos. Seven extension types at four scopes, managed in the Console UI.",
href: "/docs/features/extensions",
},
{
@@ -81,7 +81,7 @@ const insideItems: InsideItem[] = [
title: "Customization",
description: "Modify what Pilot auto-installs",
summary:
- "Tweak the built-in /spec workflow, adjust rules, add hooks and agents, change the configured MCP and LSP servers, override auto-applied Claude settings. Ship as a git repo for your team or a local directory for personal use. Upstream drift detected automatically.",
+ "Tweak the built-in /spec workflow, adjust rules, add hooks and agents, swap MCP/LSP servers, override Claude settings. Ship as a team git repo or a local dir. Upstream drift detected automatically.",
href: "/docs/features/customization",
},
];
diff --git a/docs/site/src/components/WorkflowSteps.tsx b/docs/site/src/components/WorkflowSteps.tsx
index 96fd6eb8..0c34e67c 100644
--- a/docs/site/src/components/WorkflowSteps.tsx
+++ b/docs/site/src/components/WorkflowSteps.tsx
@@ -8,6 +8,8 @@ import {
Brain,
Lightbulb,
Gauge,
+ Bug,
+ ArrowRight,
} from "lucide-react";
import { useInView } from "@/hooks/use-in-view";
@@ -49,9 +51,13 @@ const WorkflowSteps = () => {
className={`grid md:grid-cols-3 gap-6 mb-12 ${modesInView ? "animate-fade-in-up" : "opacity-0"}`}
>
{/* Requirements Mode */}
-
+
-
+
@@ -66,17 +72,23 @@ const WorkflowSteps = () => {
-
- Back-and-forth brainstorming for vague ideas: Claude pitches
- directions, pressure-tests them, and converges on a PRD — then
- hands off to /spec.
+
+ Back-and-forth brainstorming for vague ideas. Claude pitches directions, pressure-tests them, and converges on a PRD that hands off cleanly to /spec.
-
+
+
{/* Spec-Driven Mode */}
-
+
-
+
@@ -91,34 +103,45 @@ const WorkflowSteps = () => {
-
- Creates a plan, gets your approval, implements with TDD, verifies
- completion. Best for anything that touches multiple files or needs
- careful planning.
+
+ Creates a plan, gets your approval, implements each task with TDD, verifies completion. Best for features and anything multi-file that needs careful planning.
-
+
+
- {/* Quick Mode */}
-
{/* Spec-Driven Workflow Diagram */}
@@ -198,7 +221,7 @@ const WorkflowSteps = () => {
All Commands
-
+
Spec-Driven Development — plan, approve, implement, verify.
- Features and bug fixes. Auto-detects bugfix intent.
+ For features, refactoring, and architectural changes.
+
+
+
+
+
+ /fix
+
+
+ Bugfix workflow — investigate, write a failing test, fix at the
+ root cause, audit end-to-end. Bails out for complex bugs.
list[bool]:
"""Download multiple files in parallel using ThreadPoolExecutor.
Returns a list of booleans indicating success/failure for each file,
in the same order as the input lists.
+
+ After the parallel pass, any files that still failed get one more
+ sequential retry with a cool-down — handles burst-related CDN 502s
+ that don't recover within a single file's retry budget.
"""
if len(file_infos) != len(dest_paths):
raise ValueError("file_infos and dest_paths must have the same length")
@@ -216,6 +226,12 @@ def download_files_parallel(
except Exception:
results[index] = False
+ failed_indices = [i for i, ok in enumerate(results) if not ok]
+ if failed_indices:
+ time.sleep(5.0)
+ for i in failed_indices:
+ results[i] = download_file(file_infos[i], dest_paths[i], config)
+
return [r if r is not None else False for r in results]
diff --git a/installer/steps/finalize.py b/installer/steps/finalize.py
index 47f99fcd..8f008916 100644
--- a/installer/steps/finalize.py
+++ b/installer/steps/finalize.py
@@ -110,10 +110,12 @@ def _display_success(self, ctx: InstallContext) -> None:
)
workflows: list[tuple[str, str]] = [
+ ("/spec", "Plan, implement & verify features end-to-end with TDD"),
+ ("/fix", "Investigate, RED test, fix, audit — bugfix workflow"),
+ ("/prd", "Brainstorm ideas into PRDs with optional research before /spec"),
("/setup-rules", "Create modular and concise rules for your project codebase"),
("/create-skill", "Create well-structured reusable skills for your workflows"),
- ("/prd", "Brainstorm ideas into PRDs with optional research before /spec"),
- ("/spec", "Plan, implement & verify features and bug fixes (replaces CC plan mode)"),
+ ("/benchmark", "Quantitative before/after evals for rules, skills, and workflows"),
]
ui.next_steps(
diff --git a/installer/tests/unit/steps/test_finalize.py b/installer/tests/unit/steps/test_finalize.py
index 2f0e4fc4..ebf82211 100644
--- a/installer/tests/unit/steps/test_finalize.py
+++ b/installer/tests/unit/steps/test_finalize.py
@@ -182,35 +182,6 @@ def test_run_displays_success_message(self):
mock_next_steps.assert_called()
- def test_prd_appears_before_spec_in_next_steps(self):
- """/prd entry appears before /spec in the next steps panel."""
- from installer.context import InstallContext
- from installer.steps.finalize import FinalizeStep
- from installer.ui import Console
-
- step = FinalizeStep()
- with tempfile.TemporaryDirectory() as tmpdir:
- project_dir = Path(tmpdir)
- (project_dir / ".claude").mkdir()
-
- console = Console(non_interactive=True)
- ctx = InstallContext(
- project_dir=project_dir,
- ui=console,
- )
-
- with patch.object(console, "next_steps") as mock_next_steps:
- step.run(ctx)
-
- sections = mock_next_steps.call_args[0][0]
- # Flatten all items across sections
- labels = [item[0] for _, items in sections for item in items]
- assert "/prd" in labels
- assert "/spec" in labels
- prd_idx = labels.index("/prd")
- spec_idx = labels.index("/spec")
- assert prd_idx < spec_idx
-
def test_next_steps_has_two_sections(self):
"""Next steps panel has Getting Started and Workflows sections."""
from installer.context import InstallContext
@@ -234,6 +205,10 @@ def test_next_steps_has_two_sections(self):
sections = mock_next_steps.call_args[0][0]
section_titles = [title for title, _ in sections]
assert section_titles == ["Getting Started", "Workflows"]
- # Each section has 4 items
- for _, items in sections:
- assert len(items) == 4
+ # Getting Started has 4 items, Workflows has 6 (incl. /fix and /benchmark)
+ expected_lengths = {"Getting Started": 4, "Workflows": 6}
+ for title, items in sections:
+ assert len(items) == expected_lengths[title]
+ workflow_labels = [label for label, _ in dict(sections)["Workflows"]]
+ assert "/fix" in workflow_labels
+ assert "/benchmark" in workflow_labels
diff --git a/installer/tests/unit/test_downloads.py b/installer/tests/unit/test_downloads.py
index 31fe1d54..ba9845f0 100644
--- a/installer/tests/unit/test_downloads.py
+++ b/installer/tests/unit/test_downloads.py
@@ -408,6 +408,79 @@ def test_download_files_parallel_mismatched_lengths_raises(self):
config,
)
+ def test_download_files_parallel_sequential_retry_recovers_failed_files(self, monkeypatch):
+ """After the parallel pass, files that failed get one sequential retry — and may succeed there."""
+ from unittest.mock import patch
+
+ from installer import downloads
+ from installer.downloads import (
+ DownloadConfig,
+ FileInfo,
+ download_files_parallel,
+ )
+
+ # Skip the 5-second cool-down between parallel and sequential pass.
+ monkeypatch.setattr(downloads.time, "sleep", lambda _seconds: None)
+
+ config = DownloadConfig(
+ repo_url="https://github.com/test/repo",
+ repo_branch="main",
+ local_mode=True,
+ local_repo_dir=Path("/tmp"),
+ )
+
+ # download_file is called once per file in parallel pass, then once more
+ # per failed file in the sequential retry pass. Use a per-path call counter
+ # so file-A fails in parallel and succeeds on retry, while file-B always succeeds.
+ call_counts: dict[str, int] = {}
+
+ def fake_download_file(file_info, _dest_path, _config):
+ call_counts[file_info.path] = call_counts.get(file_info.path, 0) + 1
+ if file_info.path == "flaky.txt":
+ # Fail on first (parallel) call, succeed on retry.
+ return call_counts[file_info.path] >= 2
+ return True
+
+ with patch("installer.downloads.download_file", side_effect=fake_download_file):
+ results = download_files_parallel(
+ [FileInfo(path="flaky.txt"), FileInfo(path="ok.txt")],
+ [Path("/tmp/flaky.txt"), Path("/tmp/ok.txt")],
+ config,
+ )
+
+ assert results == [True, True]
+ assert call_counts["flaky.txt"] == 2 # parallel + sequential retry
+ assert call_counts["ok.txt"] == 1 # parallel only — no retry needed
+
+ def test_download_files_parallel_sequential_retry_still_fails(self, monkeypatch):
+ """If the sequential retry pass also fails, the file's result is False."""
+ from unittest.mock import patch
+
+ from installer import downloads
+ from installer.downloads import (
+ DownloadConfig,
+ FileInfo,
+ download_files_parallel,
+ )
+
+ monkeypatch.setattr(downloads.time, "sleep", lambda _seconds: None)
+
+ config = DownloadConfig(
+ repo_url="https://github.com/test/repo",
+ repo_branch="main",
+ local_mode=True,
+ local_repo_dir=Path("/tmp"),
+ )
+
+ with patch("installer.downloads.download_file", return_value=False):
+ results = download_files_parallel(
+ [FileInfo(path="always-fails.txt")],
+ [Path("/tmp/always-fails.txt")],
+ config,
+ )
+
+ assert results == [False]
+
class TestTreeJsonFallback:
"""Test tree.json release asset fallback for get_repo_files."""
diff --git a/launcher/banner.py b/launcher/banner.py
index e6f8d506..809ae709 100644
Binary files a/launcher/banner.py and b/launcher/banner.py differ
diff --git a/launcher/codegraph.py b/launcher/codegraph.py
index 630e5f04..7b63775d 100644
Binary files a/launcher/codegraph.py and b/launcher/codegraph.py differ
diff --git a/launcher/model_config.py b/launcher/model_config.py
index 81a6020a..dac369f5 100644
Binary files a/launcher/model_config.py and b/launcher/model_config.py differ
diff --git a/launcher/tests/unit/test_banner.py b/launcher/tests/unit/test_banner.py
index 36945677..ef1021cd 100644
Binary files a/launcher/tests/unit/test_banner.py and b/launcher/tests/unit/test_banner.py differ
diff --git a/launcher/tests/unit/test_codegraph.py b/launcher/tests/unit/test_codegraph.py
index 92bcbe14..c45b29ff 100644
Binary files a/launcher/tests/unit/test_codegraph.py and b/launcher/tests/unit/test_codegraph.py differ
diff --git a/launcher/tests/unit/test_model_config.py b/launcher/tests/unit/test_model_config.py
index acc4cd74..b3e89896 100644
Binary files a/launcher/tests/unit/test_model_config.py and b/launcher/tests/unit/test_model_config.py differ
diff --git a/pilot/.mcp.json b/pilot/.mcp.json
index c4423eaa..82a2b5d9 100644
--- a/pilot/.mcp.json
+++ b/pilot/.mcp.json
@@ -2,20 +2,24 @@
"mcpServers": {
"context7": {
"command": "npx",
+ "alwaysLoad": true,
"args": ["-y", "@upstash/context7-mcp"]
},
"codegraph": {
"type": "stdio",
"command": "codegraph",
+ "alwaysLoad": true,
"args": ["serve", "--mcp"]
},
"mem-search": {
"type": "stdio",
"command": "sh",
+ "alwaysLoad": true,
"args": ["-c", "bun run ~/.claude/pilot/scripts/mcp-server.cjs"]
},
"web-search": {
"command": "npx",
+ "alwaysLoad": true,
"args": ["-y", "open-websearch"],
"env": {
"MODE": "stdio",
@@ -25,10 +29,12 @@
},
"grep-mcp": {
"type": "http",
+ "alwaysLoad": true,
"url": "https://mcp.grep.app"
},
"web-fetch": {
"command": "npx",
+ "alwaysLoad": true,
"args": ["-y", "fetcher-mcp"]
}
}
diff --git a/pilot/hooks/hooks.json b/pilot/hooks/hooks.json
index 22a43389..6aa5c159 100644
--- a/pilot/hooks/hooks.json
+++ b/pilot/hooks/hooks.json
@@ -61,7 +61,7 @@
],
"PreToolUse": [
{
- "matcher": "Bash|WebSearch|WebFetch|Grep|Agent|EnterPlanMode|ExitPlanMode",
+ "matcher": "Bash|WebSearch|WebFetch|Grep|Glob|Agent|EnterPlanMode|ExitPlanMode",
"hooks": [
{
"type": "command",
diff --git a/pilot/hooks/tests/test_spec_stop_guard.py b/pilot/hooks/tests/test_spec_stop_guard.py
index 69a0e5ca..13e4c41f 100644
--- a/pilot/hooks/tests/test_spec_stop_guard.py
+++ b/pilot/hooks/tests/test_spec_stop_guard.py
@@ -16,7 +16,6 @@
from unittest.mock import patch
import pytest
-
from spec_stop_guard import main
HOOK_PATH = Path(__file__).resolve().parent.parent / "spec_stop_guard.py"
diff --git a/pilot/hooks/tests/test_tool_redirect.py b/pilot/hooks/tests/test_tool_redirect.py
index 82264521..315823a2 100644
--- a/pilot/hooks/tests/test_tool_redirect.py
+++ b/pilot/hooks/tests/test_tool_redirect.py
@@ -518,7 +518,7 @@ def test_blocks_git_dash_c_push_force(self):
def test_blocks_bash_wrapped_force_push(self):
"""`bash -c '...'` wrapping does not bypass — pattern matches the substring."""
- code, output = self._bash("bash -c \"git push --force origin main\"")
+ code, output = self._bash('bash -c "git push --force origin main"')
assert code == 2
assert _is_denied(output)
@@ -698,3 +698,335 @@ def test_passes_dryrun_segment_alone(self):
"""`git push --dry-run origin main` in a single segment still passes."""
code, _ = self._bash("git push --dry-run origin main")
assert code == 0
+
+
+# ---------------------------------------------------------------------------
+# Search-nudge classifier tests (added 2026-04-29 for codegraph-probe-enforcement)
+# ---------------------------------------------------------------------------
+
+
+def _has_nudge(output: str) -> bool:
+ """Check whether the hook stdout contains an additionalContext nudge."""
+ if not output.strip():
+ return False
+ try:
+ data = json.loads(output.strip())
+ except (json.JSONDecodeError, ValueError):
+ return False
+ hook_output = data.get("hookSpecificOutput", {})
+ return bool(hook_output.get("additionalContext"))
+
+
+def _nudge_text(output: str) -> str:
+ """Extract additionalContext string (or empty)."""
+ try:
+ data = json.loads(output.strip())
+ except (json.JSONDecodeError, ValueError):
+ return ""
+ return data.get("hookSpecificOutput", {}).get("additionalContext", "")
+
+
+import pytest # noqa: E402 — added at end-of-file to avoid touching original imports
+
+
+@pytest.fixture
+def fresh_throttle(tmp_path, monkeypatch):
+ """Redirect the throttle sentinel to a per-test file so each test starts fresh.
+
+ The implementation exposes `_throttle_sentinel_path()` returning the sentinel
+ Path; tests monkeypatch it to point at tmp_path.
+ """
+ import tool_redirect as tr
+
+ sentinel = tmp_path / "search_nudge_sent.json"
+ monkeypatch.setattr(tr, "_throttle_sentinel_path", lambda: sentinel)
+ return sentinel
+
+
+@pytest.mark.usefixtures("fresh_throttle")
+class TestSearchNudgeBashGrep:
+ """Bash(grep ...) recursive search → nudge."""
+
+ def test_nudges_grep_short_recursive(self):
+ code, output = _run_with_input("Bash", {"command": "grep -rn 'foo' ./src"})
+ assert code == 0
+ assert _has_nudge(output)
+ text = _nudge_text(output)
+ assert "codegraph_search" in text or "codegraph" in text
+ assert "probe search" in text or "probe" in text
+
+ def test_nudges_grep_capital_R(self):
+ code, output = _run_with_input("Bash", {"command": "grep -R pattern ."})
+ assert code == 0
+ assert _has_nudge(output)
+
+ def test_nudges_grep_long_recursive(self):
+ code, output = _run_with_input("Bash", {"command": "grep --recursive 'x' ."})
+ assert code == 0
+ assert _has_nudge(output)
+
+ def test_nudges_grep_recursive_listfiles(self):
+ code, output = _run_with_input("Bash", {"command": "grep -rl pattern ."})
+ assert code == 0
+ assert _has_nudge(output)
+
+ def test_nudges_grep_with_include(self):
+ code, output = _run_with_input("Bash", {"command": "grep --include='*.py' -r pattern ."})
+ assert code == 0
+ assert _has_nudge(output)
+
+ def test_nudges_grep_with_time_prefix(self):
+ code, output = _run_with_input("Bash", {"command": "time grep -r foo ."})
+ assert code == 0
+ assert _has_nudge(output)
+
+ def test_nudges_grep_with_sudo_prefix(self):
+ code, output = _run_with_input("Bash", {"command": "sudo grep -r foo ."})
+ assert code == 0
+ assert _has_nudge(output)
+
+ def test_nudges_grep_with_nice_prefix(self):
+ code, output = _run_with_input("Bash", {"command": "nice grep -r foo ."})
+ assert code == 0
+ assert _has_nudge(output)
+
+ def test_nudges_compound_segment(self):
+ code, output = _run_with_input("Bash", {"command": "cd src && grep -r foo ."})
+ assert code == 0
+ assert _has_nudge(output)
+
+
+@pytest.mark.usefixtures("fresh_throttle")
+class TestSearchNudgeBashRg:
+ def test_nudges_rg_default_recursive(self):
+ code, output = _run_with_input("Bash", {"command": "rg 'pattern' ."})
+ assert code == 0
+ assert _has_nudge(output)
+
+ def test_nudges_rg_no_path(self):
+ code, output = _run_with_input("Bash", {"command": "rg pattern"})
+ assert code == 0
+ assert _has_nudge(output)
+
+ def test_nudges_rg_files_mode(self):
+ code, output = _run_with_input("Bash", {"command": "rg --files"})
+ assert code == 0
+ assert _has_nudge(output)
+ assert "codegraph_files" in _nudge_text(output)
+
+
+@pytest.mark.usefixtures("fresh_throttle")
+class TestSearchNudgeBashFind:
+ def test_nudges_find_with_name(self):
+ code, output = _run_with_input("Bash", {"command": "find . -name '*.py'"})
+ assert code == 0
+ assert _has_nudge(output)
+ assert "codegraph_files" in _nudge_text(output)
+
+ def test_nudges_find_with_iname(self):
+ code, output = _run_with_input("Bash", {"command": "find . -iname '*.PY'"})
+ assert code == 0
+ assert _has_nudge(output)
+
+ def test_nudges_find_with_type_only(self):
+ code, output = _run_with_input("Bash", {"command": "find . -type f"})
+ assert code == 0
+ assert _has_nudge(output)
+
+ def test_nudges_find_with_type_and_delete(self):
+ code, output = _run_with_input("Bash", {"command": "find . -type f -delete"})
+ assert code == 0
+ assert _has_nudge(output)
+
+ def test_nudges_find_subdir_with_name(self):
+ code, output = _run_with_input("Bash", {"command": "find ./src -name '*.ts'"})
+ assert code == 0
+ assert _has_nudge(output)
+
+
+@pytest.mark.usefixtures("fresh_throttle")
+class TestSearchNudgeBashFdAg:
+ def test_nudges_fd_with_pattern(self):
+ code, output = _run_with_input("Bash", {"command": "fd config"})
+ assert code == 0
+ assert _has_nudge(output)
+
+ def test_nudges_fd_no_args(self):
+ code, output = _run_with_input("Bash", {"command": "fd"})
+ assert code == 0
+ assert _has_nudge(output)
+
+ def test_nudges_ag_basic(self):
+ code, output = _run_with_input("Bash", {"command": "ag 'TODO'"})
+ assert code == 0
+ assert _has_nudge(output)
+
+
+@pytest.mark.usefixtures("fresh_throttle")
+class TestSearchNudgeBuiltinTools:
+ """Built-in Grep / Glob tools."""
+
+ def test_nudges_grep_tool_call(self):
+ code, output = _run_with_input("Grep", {"pattern": "foo", "path": "./src"})
+ assert code == 0
+ assert _has_nudge(output)
+ text = _nudge_text(output)
+ assert "codegraph_search" in text
+
+ def test_nudges_grep_no_path(self):
+ code, output = _run_with_input("Grep", {"pattern": "foo"})
+ assert code == 0
+ assert _has_nudge(output)
+
+ def test_nudges_glob_tool_call(self):
+ code, output = _run_with_input("Glob", {"pattern": "**/*.py"})
+ assert code == 0
+ assert _has_nudge(output)
+ assert "codegraph_files" in _nudge_text(output)
+
+
+@pytest.mark.usefixtures("fresh_throttle")
+class TestSearchNudgeNegatives:
+ """Cases that must NOT produce a nudge."""
+
+ def test_no_nudge_grep_single_file(self):
+ code, output = _run_with_input("Bash", {"command": "grep ERROR /var/log/app.log"})
+ assert code == 0
+ assert not _has_nudge(output)
+
+ def test_no_nudge_grep_n_single_file(self):
+ code, output = _run_with_input("Bash", {"command": "grep -n pattern src/file.py"})
+ assert code == 0
+ assert not _has_nudge(output)
+
+ def test_no_nudge_rg_single_file(self):
+ code, output = _run_with_input("Bash", {"command": "rg pattern src/main.ts"})
+ assert code == 0
+ assert not _has_nudge(output)
+
+ def test_no_nudge_git_grep(self):
+ code, output = _run_with_input("Bash", {"command": "git grep 'foo'"})
+ assert code == 0
+ assert not _has_nudge(output)
+
+ def test_no_nudge_git_grep_with_args(self):
+ code, output = _run_with_input("Bash", {"command": "git grep -n pattern -- '*.py'"})
+ assert code == 0
+ assert not _has_nudge(output)
+
+ def test_no_nudge_curl_pipe_grep(self):
+ code, output = _run_with_input("Bash", {"command": "curl https://example.com | grep error"})
+ assert code == 0
+ assert not _has_nudge(output)
+
+ def test_no_nudge_cat_pipe_grep(self):
+ code, output = _run_with_input("Bash", {"command": "cat foo.log | grep WARN"})
+ assert code == 0
+ assert not _has_nudge(output)
+
+ def test_no_nudge_echo_pipe_grep(self):
+ code, output = _run_with_input("Bash", {"command": "echo $PATH | grep node"})
+ assert code == 0
+ assert not _has_nudge(output)
+
+ def test_no_nudge_xargs_grep(self):
+ # Composed command via xargs — pipeline filtering, lean conservative.
+ code, output = _run_with_input("Bash", {"command": "ls *.py | xargs grep foo"})
+ assert code == 0
+ assert not _has_nudge(output)
+
+ def test_no_nudge_npm_install(self):
+ code, output = _run_with_input("Bash", {"command": "npm install"})
+ assert code == 0
+ assert not _has_nudge(output)
+
+ def test_no_nudge_uv_pytest(self):
+ code, output = _run_with_input("Bash", {"command": "uv run pytest -q"})
+ assert code == 0
+ assert not _has_nudge(output)
+
+ def test_no_nudge_ls_grep_filter(self):
+ code, output = _run_with_input("Bash", {"command": "ls -la | grep '\\.py$'"})
+ assert code == 0
+ assert not _has_nudge(output)
+
+
+class TestSearchNudgeThrottle:
+ @pytest.mark.usefixtures("fresh_throttle")
+ def test_throttle_grep_only_first_call_nudges(self):
+ code1, out1 = _run_with_input("Grep", {"pattern": "foo"})
+ assert code1 == 0
+ assert _has_nudge(out1)
+ code2, out2 = _run_with_input("Grep", {"pattern": "bar"})
+ assert code2 == 0
+ assert not _has_nudge(out2)
+
+ @pytest.mark.usefixtures("fresh_throttle")
+ def test_throttle_separate_categories(self):
+ _, out1 = _run_with_input("Bash", {"command": "grep -r foo ."})
+ assert _has_nudge(out1)
+ # Different category — must still nudge
+ _, out2 = _run_with_input("Bash", {"command": "rg pattern ."})
+ assert _has_nudge(out2)
+
+ @pytest.mark.usefixtures("fresh_throttle")
+ def test_throttle_glob_separate_from_grep(self):
+ _, out1 = _run_with_input("Grep", {"pattern": "foo"})
+ assert _has_nudge(out1)
+ _, out2 = _run_with_input("Glob", {"pattern": "**/*.py"})
+ assert _has_nudge(out2)
+
+ def test_throttle_corrupt_sentinel_file(self, fresh_throttle):
+ # Pre-write malformed JSON; throttle should treat as never-sent.
+ fresh_throttle.parent.mkdir(parents=True, exist_ok=True)
+ fresh_throttle.write_text("not json {{{")
+ code, output = _run_with_input("Grep", {"pattern": "foo"})
+ assert code == 0
+ assert _has_nudge(output)
+
+ @pytest.mark.usefixtures("fresh_throttle")
+ def test_throttle_no_session_id(self, monkeypatch):
+ monkeypatch.delenv("PILOT_SESSION_ID", raising=False)
+ code, output = _run_with_input("Grep", {"pattern": "foo"})
+ assert code == 0
+ # With sentinel monkeypatched the env var isn't even read, but ensure no crash.
+ assert _has_nudge(output)
+
+
+@pytest.mark.usefixtures("fresh_throttle")
+class TestSearchNudgeSafety:
+ """Hook never denies, never crashes on bad input, preserves existing deny logic."""
+
+ def test_search_nudge_never_denies_on_bash_grep(self):
+ code, output = _run_with_input("Bash", {"command": "grep -r foo ."})
+ assert code == 0
+ try:
+ data = json.loads(output.strip())
+ assert data.get("permissionDecision") != "deny"
+ except (json.JSONDecodeError, ValueError):
+ pass # additionalContext payload is fine
+
+ def test_search_nudge_never_denies_on_grep_tool(self):
+ code, output = _run_with_input("Grep", {"pattern": "foo"})
+ assert code == 0
+ assert not _is_denied(output)
+
+ def test_search_nudge_never_denies_on_glob_tool(self):
+ code, output = _run_with_input("Glob", {"pattern": "**/*.py"})
+ assert code == 0
+ assert not _is_denied(output)
+
+ def test_existing_dangerous_git_still_denies(self):
+ code, output = _run_with_input("Bash", {"command": "git push --force origin main"})
+ assert code == 2
+ assert _is_denied(output)
+
+ def test_existing_websearch_still_denies(self):
+ code, output = _run_with_input("WebSearch", {"query": "x"})
+ assert code == 2
+ assert _is_denied(output)
+
+ def test_existing_explore_agent_still_denies(self):
+ code, output = _run_with_input("Agent", {"subagent_type": "Explore", "prompt": "find files"})
+ assert code == 2
+ assert _is_denied(output)
diff --git a/pilot/hooks/tool_redirect.py b/pilot/hooks/tool_redirect.py
index 5a5fc6c0..cf802cf6 100755
--- a/pilot/hooks/tool_redirect.py
+++ b/pilot/hooks/tool_redirect.py
@@ -6,18 +6,23 @@
Explore and Plan agents are hard-blocked (both by subagent_type AND description).
Research-pattern agents (description starts with "Research") are blocked,
unless the subagent_type is in SILENT_AGENT_TYPES.
-All other Agent calls pass through silently.
+
+Also nudges (non-deny) on recursive code-search Bash commands (grep -r, rg, find,
+fd, ag), built-in Grep, and built-in Glob — pointing at codegraph_search /
+codegraph_files / probe search. Throttled per-(category, session) so the
+reminder stays salient.
"""
from __future__ import annotations
import json
+import os
import re
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent))
-from _lib.util import pre_tool_use_deny
+from _lib.util import pre_tool_use_context, pre_tool_use_deny
BLOCKS: dict[str, dict[str, str]] = {
"WebSearch": {
@@ -80,7 +85,6 @@
),
}
-# Agent sub-agent types that pass through without any warning
SILENT_AGENT_TYPES: set[str] = {
"pilot:spec-review",
"pilot:changes-review",
@@ -88,50 +92,237 @@
"web-search-agent",
}
-# Agent sub-agent types that are hard-blocked
BLOCKED_AGENT_TYPES: set[str] = set(BLOCKED_AGENT_REASONS)
-# Patterns in Agent description that indicate research or exploration (case-insensitive)
RESEARCH_PATTERN: re.Pattern[str] = re.compile(r"^research\b", re.IGNORECASE)
EXPLORE_PATTERN: re.Pattern[str] = re.compile(r"\bexplore\b", re.IGNORECASE)
-# Strip leading `git -C ` and `git -c ` global options before pattern matching.
GIT_GLOBAL_OPTS_RE: re.Pattern[str] = re.compile(r"\bgit\s+(?:-[Cc]\s+\S+\s+)+")
-# Split a Bash command into independent shell segments at command separators.
SHELL_SEGMENT_SEP_RE: re.Pattern[str] = re.compile(r"(?:&&|\|\||;|\n)")
-# Truly irreversible git variants. Plain `git push` and `git commit` are NOT here —
-# pilot's social rule already requires explicit user authorization for those, and
-# hard-denying them would break daily workflow without adding safety.
DANGEROUS_GIT_PATTERNS: list[tuple[re.Pattern[str], str]] = [
- # Force pushes (short and long forms; -f and --force-with-lease=[)
(re.compile(r"\bgit\s+push\b[^\n|;&]*\s(?:--force(?:-with-lease)?(?:=\S+)?|-f)\b"), "git push --force"),
(re.compile(r"\bgit\s+push\b[^\n|;&]*--mirror\b"), "git push --mirror"),
- # Remote branch delete: colon-syntax (`git push origin :branch`) and long-form (`git push --delete`)
(re.compile(r"\bgit\s+push\s+\S+\s+:[^\s]"), "git push ] :"),
(re.compile(r"\bgit\s+push\b[^\n|;&]*--delete\b"), "git push --delete"),
(re.compile(r"\bgit\s+reset\s+--hard\b"), "git reset --hard"),
- # Force clean: short forms (-f, -fd) and long form (--force)
(re.compile(r"\bgit\s+clean\b[^\n|;&]*\s-[a-zA-Z]*f"), "git clean -f"),
(re.compile(r"\bgit\s+clean\b[^\n|;&]*--force\b"), "git clean --force"),
- # Force-delete branch: short (-D) and long (--delete --force in any order)
(re.compile(r"\bgit\s+branch\b[^\n|;&]*\s-D\b"), "git branch -D"),
(re.compile(r"\bgit\s+branch\b[^\n|;&]*--delete\b[^\n|;&]*(?:--force|-f)\b"), "git branch --delete --force"),
(re.compile(r"\bgit\s+branch\b[^\n|;&]*(?:--force|-f)\b[^\n|;&]*--delete\b"), "git branch --force --delete"),
- # Discard all unstaged
(re.compile(r"\bgit\s+checkout\s+\.(?:\s|$)"), "git checkout ."),
- # Discard files via `[[] -- ]` — any revision before `--` is destructive
(re.compile(r"\bgit\s+checkout\s+(?:\S+\s+)?--\s+\S"), "git checkout -- "),
- # Restore: working-tree forms. Default git restore (no --staged) writes the working tree.
(re.compile(r"\bgit\s+restore\s+(?!--staged\b)\."), "git restore ."),
- # `git restore` with --source= ending in `.` — broad-pathspec, working-tree destructive.
(re.compile(r"\bgit\s+restore\b[^\n|;&]*--source(?:=|\s+)\S+[^\n|;&]*\s\.(?:\s|$)"), "git restore --source ."),
- # `git restore --worktree` (with or without --staged) ending in broad pathspec
(re.compile(r"\bgit\s+restore\b[^\n|;&]*--worktree\b[^\n|;&]*\s\.(?:\s|$)"), "git restore --worktree ."),
]
+_LEADING_PREFIX_RE: re.Pattern[str] = re.compile(
+ r"^\s*(?:time|nice(?:\s+-n\s+\d+)?|sudo(?:\s+-\w+)?|env(?:\s+\S+=\S+)*)\s+"
+)
+
+_PIPELINE_FILTER_FIRST_TOKENS: set[str] = {
+ "cat",
+ "echo",
+ "printf",
+ "tail",
+ "head",
+ "awk",
+ "sed",
+ "tr",
+ "sort",
+ "uniq",
+ "ls",
+ "curl",
+ "wget",
+ "xargs",
+}
+
+_GREP_RECURSIVE_FLAG_RE: re.Pattern[str] = re.compile(r"(?:^|\s)(?:-[a-zA-Z]*[rR][a-zA-Z]*|--recursive|--include)\b")
+
+
+def _is_single_file_path(token: str) -> bool:
+ """True if token looks like a single-file path (extension after last slash, no glob)."""
+ if not token or token.startswith("-"):
+ return False
+ if "*" in token or "?" in token:
+ return False
+ last = token.rsplit("/", 1)[-1]
+ if "." not in last or last in {".", ".."}:
+ return False
+ name, _, ext = last.rpartition(".")
+ if not name or not ext:
+ return False
+ return ext.replace("_", "").isalnum()
+
+
+def _rg_targets_single_file(segment: str) -> bool:
+ """True if rg invocation has a single-file path as its last positional arg."""
+ tokens = segment.split()
+ for token in reversed(tokens[1:]):
+ if token.startswith("-"):
+ continue
+ return _is_single_file_path(token)
+ return False
+
+
+def _classify_segment(segment: str, first_token: str) -> str | None:
+ """Classify a single shell segment as a recursive search command, or None."""
+ if first_token == "grep":
+ rest = segment[len(first_token) :]
+ if _GREP_RECURSIVE_FLAG_RE.search(rest):
+ return "grep"
+ return None
+ if first_token == "rg":
+ if _rg_targets_single_file(segment):
+ return None
+ return "rg"
+ if first_token == "find":
+ return "find"
+ if first_token == "fd":
+ return "fd"
+ if first_token == "ag":
+ return "ag"
+ return None
+
+
+def classify_search_command(cmd: str) -> str | None:
+ """Return search category (grep/rg/find/fd/ag) for the first matching shell segment, else None.
+
+ Splits on `;`, `&&`, `||`, `|`, newline. Skips segments whose first token is a pipeline
+ filter (cat, curl, xargs, etc.) or `git` (git grep is allowed).
+ """
+ for raw_segment in SHELL_SEGMENT_SEP_RE.split(cmd):
+ segment = _LEADING_PREFIX_RE.sub("", raw_segment.strip())
+ if not segment:
+ continue
+ first_token = segment.split(maxsplit=1)[0]
+ if not first_token or first_token == "git" or first_token in _PIPELINE_FILTER_FIRST_TOKENS:
+ continue
+ category = _classify_segment(segment, first_token)
+ if category:
+ return category
+ return None
+
+
+_NUDGE_BASH_GREP = (
+ "Recursive grep on the project. For symbol search by name, codegraph_search is faster "
+ "(returns structured matches by file). For find-by-intent, probe search 'query' ./ "
+ "--max-results 5 --max-tokens 2000 ranks results by relevance. If you need exact text "
+ "in known files, proceed."
+)
+_NUDGE_BASH_RG = (
+ "Recursive ripgrep. For symbol search use codegraph_search; for project file structure "
+ "use codegraph_files; for intent-based code search use probe search 'query' ./ "
+ "--max-results 5 --max-tokens 2000. If you need exact text/regex on the filesystem, proceed."
+)
+_NUDGE_BASH_FIND = (
+ "Project file enumeration. codegraph_files returns the indexed file tree faster and "
+ "with metadata. If you need a filesystem-level operation (e.g., -delete, -exec), proceed."
+)
+_NUDGE_BASH_FD = (
+ "Project file discovery. codegraph_files returns the indexed file tree faster. "
+ "Proceed if you specifically need fd's filesystem behavior."
+)
+_NUDGE_BASH_AG = (
+ "Silver searcher. codegraph_search (by symbol) and probe search (by intent) are faster "
+ "on indexed projects. Proceed if you need exact text in arbitrary filesystem paths."
+)
+_NUDGE_BUILTIN_GREP = (
+ "Built-in Grep is valid for exact text/regex and as a completeness check after "
+ "codegraph_callers. For symbol search by name, codegraph_search is faster. For "
+ "intent-based code search, probe search 'query' ./ --max-results 5 --max-tokens 2000 "
+ "ranks by relevance."
+)
+_NUDGE_BUILTIN_GLOB = (
+ "Built-in Glob lists files by pattern. For project file structure, codegraph_files "
+ "returns the indexed tree faster (with language and symbol metadata). Proceed if you "
+ "need exact-pattern matching."
+)
+
+_BASH_NUDGE_BY_CATEGORY: dict[str, str] = {
+ "grep": _NUDGE_BASH_GREP,
+ "rg": _NUDGE_BASH_RG,
+ "find": _NUDGE_BASH_FIND,
+ "fd": _NUDGE_BASH_FD,
+ "ag": _NUDGE_BASH_AG,
+}
+
+
+def _throttle_sentinel_path() -> Path:
+ """Return path to per-session search-nudge sentinel file.
+
+ Tests monkeypatch this to redirect to a tmp_path.
+ """
+ session_id = os.environ.get("PILOT_SESSION_ID", "").strip() or "default"
+ return Path.home() / ".pilot" / "sessions" / session_id / "search_nudge_sent.json"
+
+
+def _nudge_already_sent(key: str) -> bool:
+ """Best-effort check whether a nudge was already sent for this session+key."""
+ try:
+ path = _throttle_sentinel_path()
+ if not path.exists():
+ return False
+ data = json.loads(path.read_text())
+ except (OSError, json.JSONDecodeError, ValueError):
+ return False
+ if not isinstance(data, dict):
+ return False
+ sent = data.get("sent")
+ return isinstance(sent, list) and key in sent
+
+
+def _mark_nudge_sent(key: str) -> None:
+ """Record that a nudge for this key was sent. Best-effort, never raises."""
+ try:
+ path = _throttle_sentinel_path()
+ path.parent.mkdir(parents=True, exist_ok=True)
+ sent: list[str] = []
+ if path.exists():
+ try:
+ data = json.loads(path.read_text())
+ if isinstance(data, dict) and isinstance(data.get("sent"), list):
+ sent = list(data["sent"])
+ except (json.JSONDecodeError, ValueError, OSError):
+ sent = []
+ if key not in sent:
+ sent.append(key)
+ path.write_text(json.dumps({"sent": sent}))
+ except OSError:
+ pass
+
+
+def _bash_search_nudge(command: str) -> str | None:
+ """Return Bash search-nudge text if applicable and not throttled, else None."""
+ category = classify_search_command(command)
+ if category is None:
+ return None
+ key = f"Bash:{category}"
+ if _nudge_already_sent(key):
+ return None
+ _mark_nudge_sent(key)
+ return _BASH_NUDGE_BY_CATEGORY.get(category)
+
+
+def _builtin_tool_nudge(tool_name: str) -> str | None:
+ """Return nudge for built-in Grep/Glob if not throttled, else None."""
+ if tool_name == "Grep":
+ if _nudge_already_sent("Grep"):
+ return None
+ _mark_nudge_sent("Grep")
+ return _NUDGE_BUILTIN_GREP
+ if tool_name == "Glob":
+ if _nudge_already_sent("Glob"):
+ return None
+ _mark_nudge_sent("Glob")
+ return _NUDGE_BUILTIN_GLOB
+ return None
+
+
def _normalize_git_command(command: str) -> str:
"""Strip leading `git -C ` / `git -c ` global options so patterns can match the subcommand.
@@ -157,7 +348,7 @@ def _check_dangerous_git(command: str) -> tuple[str, str] | None:
if not segment:
continue
if "--dry-run" in segment:
- continue # this segment is a read-only preview
+ continue
normalized = _normalize_git_command(segment)
for pattern, name in DANGEROUS_GIT_PATTERNS:
if pattern.search(normalized):
@@ -180,7 +371,6 @@ def run_tool_redirect() -> int:
tool_name = hook_data.get("tool_name", "")
- # Agent: silent pass for /spec reviewers, block Explore/Plan/research, warn others
if tool_name == "Agent":
tool_input = hook_data.get("tool_input", {})
subagent_type = tool_input.get("subagent_type", "")
@@ -205,7 +395,6 @@ def run_tool_redirect() -> int:
return 2
return 0
- # Bash: dangerous git pattern check (denies on match; otherwise falls through to BLOCKS check)
if tool_name == "Bash":
command = hook_data.get("tool_input", {}).get("command", "")
match = _check_dangerous_git(command)
@@ -214,8 +403,17 @@ def run_tool_redirect() -> int:
sys.stderr.write(f"\033[0;31m[Pilot] Dangerous git blocked: {pattern_name}\033[0m\n")
print(pre_tool_use_deny(reason))
return 2
+ nudge = _bash_search_nudge(command)
+ if nudge:
+ print(pre_tool_use_context(nudge))
+ return 0
+
+ if tool_name in {"Grep", "Glob"}:
+ nudge = _builtin_tool_nudge(tool_name)
+ if nudge:
+ print(pre_tool_use_context(nudge))
+ return 0
- # WebSearch/WebFetch: hard block
if tool_name in BLOCKS:
info = BLOCKS[tool_name]
reason = f"{info['message']}\n-> {info['alternative']}\nExample: {info['example']}"
diff --git a/pilot/rules/development-practices.md b/pilot/rules/development-practices.md
index 58e64200..2b9ffe9c 100644
--- a/pilot/rules/development-practices.md
+++ b/pilot/rules/development-practices.md
@@ -2,44 +2,37 @@
### Codebase Exploration — CodeGraph + Probe
-**⛔ STOP: Are you about to use Grep or Glob? Use CodeGraph or Probe FIRST.**
+**CodeGraph and Probe are the primary code-search tools.** Grep and Glob are *verifiers* — use them only for exact-text completeness checks AFTER CodeGraph, or for known-file/known-string lookups. Never start a code-search task with Grep/Glob.
-Grep and Glob are last-resort tools for exact text/regex patterns only. For everything else, CodeGraph and Probe are faster, more accurate, and return structural context that Grep cannot.
-
-**⛔ NEVER pass `projectPath` to CodeGraph tools when searching the current project.** Omit it — the MCP server already defaults to the right project. Passing it explicitly causes "not initialized" errors even when CodeGraph is working.
+**⛔ NEVER pass `projectPath` to CodeGraph tools when searching the current project.** Omit it — the MCP server defaults to the right project. Passing it explicitly causes "not initialized" errors.
#### CodeGraph-First Workflow
-**Every task starts with CodeGraph.** This is not optional — it's the single highest-value habit for efficient codebase work.
-
```
1. codegraph_context(task="") → Orient: entry points + related symbols
2. codegraph_search(query="") → Find specific symbols by name
-3. codegraph_explore(query="") → Deep dive: full source code sections in ONE call
+3. codegraph_explore(query="") → Deep dive: full source code in ONE call
4. codegraph_callers/callees(symbol="") → Trace call flow before modifying
5. codegraph_impact(symbol="") → Blast radius before committing to a change
```
-**`codegraph_explore` is the most powerful tool** — one call returns full source code sections from all relevant files, grouped by file. It replaces dozens of Read/Grep calls. Use specific symbol names (from `codegraph_search`), not natural language. Budget: follow the limit in the tool description (scales by project size).
+`codegraph_context` is the FIRST action for every task — it returns entry points, related symbols, and code context. For conceptual queries that don't map to symbol names, supplement with `probe search`.
-**`codegraph_context` is the FIRST action for every task** — it returns entry points, related symbols, and code context. Works best when the task maps to actual code symbols (e.g., "license verification" finds auth.py). For conceptual/workflow queries that don't map to symbol names, supplement with Probe `probe search`.
+`codegraph_explore` is the most powerful tool — one call returns full source code from all relevant files, grouped by file. It replaces dozens of Read/Grep calls. Pass specific symbol names (from `codegraph_search`), NOT natural language. Follow the call budget in the tool description.
-**`codegraph_callers` is essential but verify with Grep** — it finds most callers via the code graph but can miss some (especially indirect or dynamically-resolved calls). After running `codegraph_callers`, also `Grep` for the symbol name to catch anything the graph missed. Trust the graph for structure, verify with text search for completeness.
+**Verify with Grep, don't replace.** After `codegraph_callers` returns its set, a `Grep` for the symbol name is a *completeness check* for indirect/dynamic callers the graph may miss — not the primary search.
#### Mandatory Checkpoints
-| Before you... | ⛔ STOP and use |
+| Before you... | ⛔ Use |
|------|------|
-| **Start any new task** | `codegraph_context(task=)` to orient — ALWAYS FIRST |
-| **Deeply understand a feature** | `codegraph_search` to find symbols → `codegraph_explore` with those symbol names |
-| **Search for a function/class/symbol** | `codegraph_search` (NOT Grep) |
-| **Modify a function** | `codegraph_callers` + `codegraph_callees` THEN `Grep` for the symbol name (graph may miss some callers) |
-| **Plan a change** | `codegraph_impact` to check blast radius |
-| **Explore file structure** | `codegraph_files` (NOT Glob/ls) |
-| **Understand a feature by intent** | Probe `probe search "how does auth work"` |
-| **Extract code by symbol** | Probe `probe extract src/auth.ts#login` |
-| **Match AST patterns** | Probe `probe query "async function $NAME($$$)"` |
-| **Search exact text/regex** | Grep/Glob (the ONLY valid use case for these) |
+| **Start any new task** | `codegraph_context(task=)` — ALWAYS FIRST |
+| **Find a symbol by name** | `codegraph_search` (NOT Grep) |
+| **Modify a function** | `codegraph_callers` + `codegraph_callees`, then `Grep` as completeness check |
+| **Plan a change** | `codegraph_impact` for blast radius |
+| **Explore by intent** | `probe search "query" ./ --max-results 5 --max-tokens 2000` |
+
+Grep/Glob are valid for: (1) verifying CodeGraph completeness on a specific symbol name, (2) exact text/regex in a known file. They are NOT valid as the first move on a code-search task.
### Change Discipline
@@ -57,7 +50,7 @@ Grep and Glob are last-resort tools for exact text/regex patterns only. For ever
**File Size:** Aim for production files under 800 lines. Over 1000 lines is a signal to consider splitting — but only when it's the focus of the current task, not as a side-refactor. Test files exempt.
-**⛔ Dependency Check:** Before modifying any function, you MUST run `codegraph_callers` and `codegraph_callees` for the call graph, THEN `Grep` for the symbol name to catch callers the graph may miss (especially indirect or dynamic calls). CodeGraph gives you structure; Grep gives you completeness. Use both. Update all affected call sites.
+**⛔ Dependency Check:** Before modifying any function, run `codegraph_callers` and `codegraph_callees` for the call graph, then `Grep` the symbol name as a completeness check (catches indirect/dynamic callers the graph may miss). CodeGraph gives structure; Grep gives completeness verification — not a primary search.
**Self-Correction:** Fix obvious mistakes (syntax errors, typos, missing imports) in code you are actively writing. Do not auto-fix errors in code the user edited — report them and let the user decide.
diff --git a/pilot/rules/mcp-servers.md b/pilot/rules/mcp-servers.md
index 148d9e51..be750d33 100644
--- a/pilot/rules/mcp-servers.md
+++ b/pilot/rules/mcp-servers.md
@@ -137,12 +137,10 @@ Options: `waitUntil` (load/domcontentloaded/networkidle), `returnHtml`, `waitFor
### CodeGraph — Code Knowledge Graph
-**Purpose:** Semantic code knowledge graph for symbol search, call tracing, impact analysis, and code context retrieval.
+**Purpose:** Semantic code knowledge graph for symbol search, call tracing, impact analysis, and code context retrieval. **The primary code-search tool** — replaces Grep/Glob for any structural query.
**Complements Probe CLI:** Probe finds code by intent ("how does auth work?"). CodeGraph finds by structure ("who calls this?", "what's affected by changing this?").
-**Key tools:**
-
| Tool | Purpose |
| ------------------- | ---------------------------------------------------------- |
| `codegraph_context` | **START HERE** — build relevant code context for a task |
@@ -154,11 +152,11 @@ Options: `waitUntil` (load/domcontentloaded/networkidle), `returnHtml`, `waitFor
| `codegraph_node` | Get details and source code for a specific symbol |
| `codegraph_files` | Get project file structure from the index |
-**Workflow:** `codegraph_context(task=...)` to orient → `codegraph_search` to find symbols → `codegraph_explore(query="SymbolA SymbolB file.ts")` for deep understanding → `codegraph_callers`/`codegraph_callees` to trace flow → `codegraph_impact` before changes
+**Workflow:** `codegraph_context(task=...)` to orient → `codegraph_search` to find symbols → `codegraph_explore(query="SymbolA SymbolB file.ts")` for deep understanding → `codegraph_callers`/`codegraph_callees` to trace flow → `codegraph_impact` before changes.
-**`codegraph_explore` tips:** Use specific symbol names and file names as query terms — NOT natural language. Run `codegraph_search` first to discover symbol names, then pass those names to `codegraph_explore`. Follow the call budget in the tool description.
+**`codegraph_explore` tips:** use specific symbol names and file names as query terms — NOT natural language. Run `codegraph_search` first to discover symbol names. Follow the call budget in the tool description.
-**⛔ NEVER pass `projectPath` when searching the current project.** The MCP server already defaults to the current project. Passing `projectPath` explicitly triggers a different code path that fails if `.codegraph/` isn't at that exact path. Only use `projectPath` for querying a genuinely different codebase.
+**⛔ NEVER pass `projectPath` when searching the current project.** The MCP server defaults to the current project. Passing `projectPath` explicitly triggers a different code path that fails if `.codegraph/` isn't at that exact path. Only use `projectPath` for querying a genuinely different codebase.
```
codegraph_search(query="Handler", kind="function")
@@ -169,27 +167,16 @@ codegraph_context(task="refactor authentication flow")
codegraph_node(symbol="MyClass", includeCode=true)
```
-**Primary use cases (Probe can't do these):**
-
-- **`codegraph_context`** — task-driven context retrieval. **⛔ MUST use at the start of every task to orient.**
-- **`codegraph_explore`** — deep dive with full source code. **⛔ Use for thorough understanding — one call replaces 10+ file reads.**
-- **`codegraph_callers`/`codegraph_callees`** — caller/callee graph (may miss some indirect callers — supplement with Grep). **⛔ MUST use before modifying any function.**
-- **`codegraph_impact`** — transitive blast radius analysis. **⛔ MUST use during planning to scope impact.**
-
-**⛔ CodeGraph replaces Grep/Glob for these — not "prefer", REPLACE:**
-
-- `codegraph_context` → task orientation (nothing else does this)
-- `codegraph_explore` → deep code understanding (NOT multiple Read calls)
-- `codegraph_search` → finding symbols (NOT Grep)
-- `codegraph_callers`/`codegraph_callees` → tracing code flow (NOT Grep)
-- `codegraph_impact` → pre-change analysis (nothing else does this)
-- `codegraph_files` → project file structure (NOT Glob/ls)
+**⛔ CodeGraph replaces Grep/Glob for code search:**
-**When Probe is better:**
+- `codegraph_context` → task orientation. **MUST use first on every task.**
+- `codegraph_explore` → deep code understanding (NOT multiple Read calls).
+- `codegraph_search` → symbol search (NOT Grep).
+- `codegraph_callers`/`codegraph_callees` → call-flow tracing (NOT Grep). Supplement with Grep as a *completeness check* for indirect/dynamic callers.
+- `codegraph_impact` → pre-change blast radius.
+- `codegraph_files` → project file structure (NOT Glob/ls).
-- Intent-based search ("how does authentication work?")
-- Natural language queries
-- AST-aware code extraction by line/symbol
+For intent-based search ("how does authentication work?") and AST-aware extraction by line/symbol, use Probe CLI instead.
---
diff --git a/pilot/rules/task-and-workflow.md b/pilot/rules/task-and-workflow.md
index 896da8d8..6574b552 100644
--- a/pilot/rules/task-and-workflow.md
+++ b/pilot/rules/task-and-workflow.md
@@ -167,11 +167,17 @@ Call after creating plan header, reading existing plan, and after status changes
**⛔ When `/spec` is invoked, the structured workflow is MANDATORY.** Everything after `/spec` is the task description.
```
-/spec → Dispatcher → Detect type (LLM intent) → Feature: Skill('spec-plan') → Plan, verify, approve
- → Bugfix: Skill('spec-bugfix-plan') → Root cause investigation, plan, approve
- → Skill('spec-implement') → TDD loop for each task (both types)
- → Feature: Skill('spec-verify') → Tests, code review, structured E2E scenarios (TS-NNN)
- → Bugfix: Skill('spec-bugfix-verify') → Tests, quality checks, verification scenario
+/spec → Dispatcher → Detect type (LLM intent)
+ → Feature: Skill('spec-plan') → Plan, verify, approve
+ → Skill('spec-implement') → TDD loop for each task
+ → Skill('spec-verify') → Tests, code review, structured E2E (TS-NNN)
+ → Bugfix: Skill('spec-bugfix-plan') → Root-cause investigation, plan, approve
+ → Skill('spec-implement') → TDD loop for each task
+ → Skill('spec-bugfix-verify') → Behavior Contract audit, revert-test proof
+
+/fix → Skill('fix') → Investigate, RED, fix, audit, done.
+ Always quick. If bug exceeds quick-lane scope, STOPS and tells the user to re-invoke with /spec.
+ Honour the user's command choice — don't silently switch lanes.
```
### ⛔ Dispatcher Integrity
@@ -208,7 +214,7 @@ spec-verify (or spec-bugfix-verify) finds issues → Status: PENDING → spec-im
1. **Worktree Choice + Type Confirmation** (new plans only, in dispatcher — type only asked when ambiguous; worktree skipped when `$PILOT_WORKTREE_ENABLED=false`; Codex controlled entirely by Console Settings)
2. **Plan Approval** (in spec-plan or spec-bugfix-plan; skipped when `$PILOT_PLAN_APPROVAL_ENABLED=false`)
3. **Worktree Sync Approval** (in spec-verify/spec-bugfix-verify, only when `Worktree: Yes`)
-4. **Code Review Gate** (in spec-verify Step 18 / spec-bugfix-verify Step 10 — uses `AskUserQuestion` so the stop guard allows session exit while waiting)
+4. **Code Review Gate** (in spec-verify Step 18 / spec-bugfix-verify Step 7 — uses `AskUserQuestion` so the stop guard allows session exit while waiting)
Everything else is automatic. **NEVER ask "Should I fix these findings?"** — verification fixes are part of the approved plan.
diff --git a/pilot/scripts/mcp-server.cjs b/pilot/scripts/mcp-server.cjs
index f64224f5..129160ff 100755
--- a/pilot/scripts/mcp-server.cjs
+++ b/pilot/scripts/mcp-server.cjs
@@ -41,7 +41,7 @@ ${s.stack}`:` ${s.message}`:this.getLevel()===0&&typeof s=="object"?l=`
path: iss.path ? [${mt(b)}, ...iss.path] : [${mt(b)}]
})));`),p.write(`newResult[${mt(b)}] = ${$}.value`)}p.write("payload.value = newResult;"),p.write("return payload;");let v=p.compile();return(b,$)=>v(d,b,$)},n,s=Pt,i=!no.jitless,c=i&&jn.value,u=e.catchall,l;t._zod.parse=(d,p)=>{l??(l=r.value);let m=d.value;if(!s(m))return d.issues.push({expected:"object",code:"invalid_type",input:m,inst:t}),d;let g=[];if(i&&c&&p?.async===!1&&p.jitless!==!0)n||(n=o(e.shape)),d=n(d,p);else{d.value={};let $=l.shape;for(let E of l.keys){let T=$[E],he=T._zod.run({value:m[E],issues:[]},p),ze=T._zod.optin==="optional"&&T._zod.optout==="optional";he instanceof Promise?g.push(he.then(Tt=>ze?Zc(Tt,d,E,m):po(Tt,d,E))):ze?Zc(he,d,E,m):po(he,d,E)}}if(!u)return g.length?Promise.all(g).then(()=>d):d;let _=[],y=l.keySet,v=u._zod,b=v.def.type;for(let $ of Object.keys(m)){if(y.has($))continue;if(b==="never"){_.push($);continue}let E=v.run({value:m[$],issues:[]},p);E instanceof Promise?g.push(E.then(T=>po(T,d,$))):po(E,d,$)}return _.length&&d.issues.push({code:"unrecognized_keys",keys:_,input:m,inst:t}),g.length?Promise.all(g).then(()=>d):d}});function Mc(t,e,r,o){for(let n of t)if(n.issues.length===0)return e.value=n.value,e;return e.issues.push({code:"invalid_union",input:e.value,inst:r,errors:t.map(n=>n.issues.map(s=>Ne(s,o,Ee())))}),e}var Qn=h("$ZodUnion",(t,e)=>{K.init(t,e),H(t._zod,"optin",()=>e.options.some(r=>r._zod.optin==="optional")?"optional":void 0),H(t._zod,"optout",()=>e.options.some(r=>r._zod.optout==="optional")?"optional":void 0),H(t._zod,"values",()=>{if(e.options.every(r=>r._zod.values))return new Set(e.options.flatMap(r=>Array.from(r._zod.values)))}),H(t._zod,"pattern",()=>{if(e.options.every(r=>r._zod.pattern)){let r=e.options.map(o=>o._zod.pattern);return new RegExp(`^(${r.map(o=>sr(o.source)).join("|")})$`)}}),t._zod.parse=(r,o)=>{let n=!1,s=[];for(let i of e.options){let a=i._zod.run({value:r.value,issues:[]},o);if(a instanceof Promise)s.push(a),n=!0;else{if(a.issues.length===0)return a;s.push(a)}}return n?Promise.all(s).then(i=>Mc(i,r,t,o)):Mc(s,r,t,o)}}),xu=h("$ZodDiscriminatedUnion",(t,e)=>{Qn.init(t,e);let r=t._zod.parse;H(t._zod,"propValues",()=>{let n={};for(let s of e.options){let i=s._zod.propValues;if(!i||Object.keys(i).length===0)throw new Error(`Invalid discriminated union option at index "${e.options.indexOf(s)}"`);for(let[a,c]of Object.entries(i)){n[a]||(n[a]=new Set);for(let u of c)n[a].add(u)}}return n});let o=or(()=>{let n=e.options,s=new Map;for(let i of n){let a=i._zod.propValues[e.discriminator];if(!a||a.size===0)throw new Error(`Invalid discriminated union option at index "${e.options.indexOf(i)}"`);for(let c of a){if(s.has(c))throw new Error(`Duplicate discriminator value "${String(c)}"`);s.set(c,i)}}return s});t._zod.parse=(n,s)=>{let i=n.value;if(!Pt(i))return n.issues.push({code:"invalid_type",expected:"object",input:i,inst:t}),n;let a=o.value.get(i?.[e.discriminator]);return a?a._zod.run(n,s):e.unionFallback?r(n,s):(n.issues.push({code:"invalid_union",errors:[],note:"No matching discriminator",input:i,path:[e.discriminator],inst:t}),n)}}),zu=h("$ZodIntersection",(t,e)=>{K.init(t,e),t._zod.parse=(r,o)=>{let n=r.value,s=e.left._zod.run({value:n,issues:[]},o),i=e.right._zod.run({value:n,issues:[]},o);return s instanceof Promise||i instanceof Promise?Promise.all([s,i]).then(([c,u])=>qc(r,c,u)):qc(r,s,i)}});function Yn(t,e){if(t===e)return{valid:!0,data:t};if(t instanceof Date&&e instanceof Date&&+t==+e)return{valid:!0,data:t};if(Ot(t)&&Ot(e)){let r=Object.keys(e),o=Object.keys(t).filter(s=>r.indexOf(s)!==-1),n={...t,...e};for(let s of o){let i=Yn(t[s],e[s]);if(!i.valid)return{valid:!1,mergeErrorPath:[s,...i.mergeErrorPath]};n[s]=i.data}return{valid:!0,data:n}}if(Array.isArray(t)&&Array.isArray(e)){if(t.length!==e.length)return{valid:!1,mergeErrorPath:[]};let r=[];for(let o=0;o{K.init(t,e),t._zod.parse=(r,o)=>{let n=r.value;if(!Ot(n))return r.issues.push({expected:"record",code:"invalid_type",input:n,inst:t}),r;let s=[];if(e.keyType._zod.values){let i=e.keyType._zod.values;r.value={};for(let c of i)if(typeof c=="string"||typeof c=="number"||typeof c=="symbol"){let u=e.valueType._zod.run({value:n[c],issues:[]},o);u instanceof Promise?s.push(u.then(l=>{l.issues.length&&r.issues.push(...qe(c,l.issues)),r.value[c]=l.value})):(u.issues.length&&r.issues.push(...qe(c,u.issues)),r.value[c]=u.value)}let a;for(let c in n)i.has(c)||(a=a??[],a.push(c));a&&a.length>0&&r.issues.push({code:"unrecognized_keys",input:n,inst:t,keys:a})}else{r.value={};for(let i of Reflect.ownKeys(n)){if(i==="__proto__")continue;let a=e.keyType._zod.run({value:i,issues:[]},o);if(a instanceof Promise)throw new Error("Async schemas not supported in object keys currently");if(a.issues.length){r.issues.push({origin:"record",code:"invalid_key",issues:a.issues.map(u=>Ne(u,o,Ee())),input:i,path:[i],inst:t}),r.value[a.value]=a.value;continue}let c=e.valueType._zod.run({value:n[i],issues:[]},o);c instanceof Promise?s.push(c.then(u=>{u.issues.length&&r.issues.push(...qe(i,u.issues)),r.value[a.value]=u.value})):(c.issues.length&&r.issues.push(...qe(i,c.issues)),r.value[a.value]=c.value)}}return s.length?Promise.all(s).then(()=>r):r}});var ku=h("$ZodEnum",(t,e)=>{K.init(t,e);let r=Cn(e.entries);t._zod.values=new Set(r),t._zod.pattern=new RegExp(`^(${r.filter(o=>Zn.has(typeof o)).map(o=>typeof o=="string"?rt(o):o.toString()).join("|")})$`),t._zod.parse=(o,n)=>{let s=o.value;return t._zod.values.has(s)||o.issues.push({code:"invalid_value",values:r,input:s,inst:t}),o}}),Tu=h("$ZodLiteral",(t,e)=>{K.init(t,e),t._zod.values=new Set(e.values),t._zod.pattern=new RegExp(`^(${e.values.map(r=>typeof r=="string"?rt(r):r?r.toString():String(r)).join("|")})$`),t._zod.parse=(r,o)=>{let n=r.value;return t._zod.values.has(n)||r.issues.push({code:"invalid_value",values:e.values,input:n,inst:t}),r}});var Pu=h("$ZodTransform",(t,e)=>{K.init(t,e),t._zod.parse=(r,o)=>{let n=e.transform(r.value,r);if(o.async)return(n instanceof Promise?n:Promise.resolve(n)).then(i=>(r.value=i,r));if(n instanceof Promise)throw new We;return r.value=n,r}}),Ou=h("$ZodOptional",(t,e)=>{K.init(t,e),t._zod.optin="optional",t._zod.optout="optional",H(t._zod,"values",()=>e.innerType._zod.values?new Set([...e.innerType._zod.values,void 0]):void 0),H(t._zod,"pattern",()=>{let r=e.innerType._zod.pattern;return r?new RegExp(`^(${sr(r.source)})?$`):void 0}),t._zod.parse=(r,o)=>e.innerType._zod.optin==="optional"?e.innerType._zod.run(r,o):r.value===void 0?r:e.innerType._zod.run(r,o)}),Iu=h("$ZodNullable",(t,e)=>{K.init(t,e),H(t._zod,"optin",()=>e.innerType._zod.optin),H(t._zod,"optout",()=>e.innerType._zod.optout),H(t._zod,"pattern",()=>{let r=e.innerType._zod.pattern;return r?new RegExp(`^(${sr(r.source)}|null)$`):void 0}),H(t._zod,"values",()=>e.innerType._zod.values?new Set([...e.innerType._zod.values,null]):void 0),t._zod.parse=(r,o)=>r.value===null?r:e.innerType._zod.run(r,o)}),Ru=h("$ZodDefault",(t,e)=>{K.init(t,e),t._zod.optin="optional",H(t._zod,"values",()=>e.innerType._zod.values),t._zod.parse=(r,o)=>{if(r.value===void 0)return r.value=e.defaultValue,r;let n=e.innerType._zod.run(r,o);return n instanceof Promise?n.then(s=>Uc(s,e)):Uc(n,e)}});function Uc(t,e){return t.value===void 0&&(t.value=e.defaultValue),t}var Nu=h("$ZodPrefault",(t,e)=>{K.init(t,e),t._zod.optin="optional",H(t._zod,"values",()=>e.innerType._zod.values),t._zod.parse=(r,o)=>(r.value===void 0&&(r.value=e.defaultValue),e.innerType._zod.run(r,o))}),Cu=h("$ZodNonOptional",(t,e)=>{K.init(t,e),H(t._zod,"values",()=>{let r=e.innerType._zod.values;return r?new Set([...r].filter(o=>o!==void 0)):void 0}),t._zod.parse=(r,o)=>{let n=e.innerType._zod.run(r,o);return n instanceof Promise?n.then(s=>Fc(s,t)):Fc(n,t)}});function Fc(t,e){return!t.issues.length&&t.value===void 0&&t.issues.push({code:"invalid_type",expected:"nonoptional",input:t.value,inst:e}),t}var Au=h("$ZodCatch",(t,e)=>{K.init(t,e),t._zod.optin="optional",H(t._zod,"optout",()=>e.innerType._zod.optout),H(t._zod,"values",()=>e.innerType._zod.values),t._zod.parse=(r,o)=>{let n=e.innerType._zod.run(r,o);return n instanceof Promise?n.then(s=>(r.value=s.value,s.issues.length&&(r.value=e.catchValue({...r,error:{issues:s.issues.map(i=>Ne(i,o,Ee()))},input:r.value}),r.issues=[]),r)):(r.value=n.value,n.issues.length&&(r.value=e.catchValue({...r,error:{issues:n.issues.map(s=>Ne(s,o,Ee()))},input:r.value}),r.issues=[]),r)}});var Du=h("$ZodPipe",(t,e)=>{K.init(t,e),H(t._zod,"values",()=>e.in._zod.values),H(t._zod,"optin",()=>e.in._zod.optin),H(t._zod,"optout",()=>e.out._zod.optout),t._zod.parse=(r,o)=>{let n=e.in._zod.run(r,o);return n instanceof Promise?n.then(s=>Vc(s,e,o)):Vc(n,e,o)}});function Vc(t,e,r){return ht(t)?t:e.out._zod.run({value:t.value,issues:t.issues},r)}var Lu=h("$ZodReadonly",(t,e)=>{K.init(t,e),H(t._zod,"propValues",()=>e.innerType._zod.propValues),H(t._zod,"values",()=>e.innerType._zod.values),H(t._zod,"optin",()=>e.innerType._zod.optin),H(t._zod,"optout",()=>e.innerType._zod.optout),t._zod.parse=(r,o)=>{let n=e.innerType._zod.run(r,o);return n instanceof Promise?n.then(Hc):Hc(n)}});function Hc(t){return t.value=Object.freeze(t.value),t}var ju=h("$ZodCustom",(t,e)=>{de.init(t,e),K.init(t,e),t._zod.parse=(r,o)=>r,t._zod.check=r=>{let o=r.value,n=e.fn(o);if(n instanceof Promise)return n.then(s=>Kc(s,r,o,t));Kc(n,r,o,t)}});function Kc(t,e,r,o){if(!t){let n={code:"custom",input:r,inst:o,path:[...o._zod.def.path??[]],continue:!o._zod.def.abort};o._zod.def.params&&(n.params=o._zod.def.params),e.issues.push(Un(n))}}var jm=t=>{let e=typeof t;switch(e){case"number":return Number.isNaN(t)?"NaN":"number";case"object":{if(Array.isArray(t))return"array";if(t===null)return"null";if(Object.getPrototypeOf(t)!==Object.prototype&&t.constructor)return t.constructor.name}}return e},Zm=()=>{let t={string:{unit:"characters",verb:"to have"},file:{unit:"bytes",verb:"to have"},array:{unit:"items",verb:"to have"},set:{unit:"items",verb:"to have"}};function e(o){return t[o]??null}let r={regex:"input",email:"email address",url:"URL",emoji:"emoji",uuid:"UUID",uuidv4:"UUIDv4",uuidv6:"UUIDv6",nanoid:"nanoid",guid:"GUID",cuid:"cuid",cuid2:"cuid2",ulid:"ULID",xid:"XID",ksuid:"KSUID",datetime:"ISO datetime",date:"ISO date",time:"ISO time",duration:"ISO duration",ipv4:"IPv4 address",ipv6:"IPv6 address",cidrv4:"IPv4 range",cidrv6:"IPv6 range",base64:"base64-encoded string",base64url:"base64url-encoded string",json_string:"JSON string",e164:"E.164 number",jwt:"JWT",template_literal:"input"};return o=>{switch(o.code){case"invalid_type":return`Invalid input: expected ${o.expected}, received ${jm(o.input)}`;case"invalid_value":return o.values.length===1?`Invalid input: expected ${ao(o.values[0])}`:`Invalid option: expected one of ${so(o.values,"|")}`;case"too_big":{let n=o.inclusive?"<=":"<",s=e(o.origin);return s?`Too big: expected ${o.origin??"value"} to have ${n}${o.maximum.toString()} ${s.unit??"elements"}`:`Too big: expected ${o.origin??"value"} to be ${n}${o.maximum.toString()}`}case"too_small":{let n=o.inclusive?">=":">",s=e(o.origin);return s?`Too small: expected ${o.origin} to have ${n}${o.minimum.toString()} ${s.unit}`:`Too small: expected ${o.origin} to be ${n}${o.minimum.toString()}`}case"invalid_format":{let n=o;return n.format==="starts_with"?`Invalid string: must start with "${n.prefix}"`:n.format==="ends_with"?`Invalid string: must end with "${n.suffix}"`:n.format==="includes"?`Invalid string: must include "${n.includes}"`:n.format==="regex"?`Invalid string: must match pattern ${n.pattern}`:`Invalid ${r[n.format]??o.format}`}case"not_multiple_of":return`Invalid number: must be a multiple of ${o.divisor}`;case"unrecognized_keys":return`Unrecognized key${o.keys.length>1?"s":""}: ${so(o.keys,", ")}`;case"invalid_key":return`Invalid key in ${o.origin}`;case"invalid_union":return"Invalid input";case"invalid_element":return`Invalid value in ${o.origin}`;default:return"Invalid input"}}};function Zu(){return{localeError:Zm()}}var es=class{constructor(){this._map=new Map,this._idmap=new Map}add(e,...r){let o=r[0];if(this._map.set(e,o),o&&typeof o=="object"&&"id"in o){if(this._idmap.has(o.id))throw new Error(`ID ${o.id} already exists in the registry`);this._idmap.set(o.id,e)}return this}clear(){return this._map=new Map,this._idmap=new Map,this}remove(e){let r=this._map.get(e);return r&&typeof r=="object"&&"id"in r&&this._idmap.delete(r.id),this._map.delete(e),this}get(e){let r=e._zod.parent;if(r){let o={...this.get(r)??{}};return delete o.id,{...o,...this._map.get(e)}}return this._map.get(e)}has(e){return this._map.has(e)}};function Mm(){return new es}var ur=Mm();function Mu(t,e){return new t({type:"string",...k(e)})}function qu(t,e){return new t({type:"string",format:"email",check:"string_format",abort:!1,...k(e)})}function ts(t,e){return new t({type:"string",format:"guid",check:"string_format",abort:!1,...k(e)})}function Uu(t,e){return new t({type:"string",format:"uuid",check:"string_format",abort:!1,...k(e)})}function Fu(t,e){return new t({type:"string",format:"uuid",check:"string_format",abort:!1,version:"v4",...k(e)})}function Vu(t,e){return new t({type:"string",format:"uuid",check:"string_format",abort:!1,version:"v6",...k(e)})}function Hu(t,e){return new t({type:"string",format:"uuid",check:"string_format",abort:!1,version:"v7",...k(e)})}function Ku(t,e){return new t({type:"string",format:"url",check:"string_format",abort:!1,...k(e)})}function Bu(t,e){return new t({type:"string",format:"emoji",check:"string_format",abort:!1,...k(e)})}function Gu(t,e){return new t({type:"string",format:"nanoid",check:"string_format",abort:!1,...k(e)})}function Wu(t,e){return new t({type:"string",format:"cuid",check:"string_format",abort:!1,...k(e)})}function Ju(t,e){return new t({type:"string",format:"cuid2",check:"string_format",abort:!1,...k(e)})}function Yu(t,e){return new t({type:"string",format:"ulid",check:"string_format",abort:!1,...k(e)})}function Xu(t,e){return new t({type:"string",format:"xid",check:"string_format",abort:!1,...k(e)})}function Qu(t,e){return new t({type:"string",format:"ksuid",check:"string_format",abort:!1,...k(e)})}function el(t,e){return new t({type:"string",format:"ipv4",check:"string_format",abort:!1,...k(e)})}function tl(t,e){return new t({type:"string",format:"ipv6",check:"string_format",abort:!1,...k(e)})}function rl(t,e){return new t({type:"string",format:"cidrv4",check:"string_format",abort:!1,...k(e)})}function ol(t,e){return new t({type:"string",format:"cidrv6",check:"string_format",abort:!1,...k(e)})}function nl(t,e){return new t({type:"string",format:"base64",check:"string_format",abort:!1,...k(e)})}function sl(t,e){return new t({type:"string",format:"base64url",check:"string_format",abort:!1,...k(e)})}function il(t,e){return new t({type:"string",format:"e164",check:"string_format",abort:!1,...k(e)})}function al(t,e){return new t({type:"string",format:"jwt",check:"string_format",abort:!1,...k(e)})}function cl(t,e){return new t({type:"string",format:"datetime",check:"string_format",offset:!1,local:!1,precision:null,...k(e)})}function ul(t,e){return new t({type:"string",format:"date",check:"string_format",...k(e)})}function ll(t,e){return new t({type:"string",format:"time",check:"string_format",precision:null,...k(e)})}function dl(t,e){return new t({type:"string",format:"duration",check:"string_format",...k(e)})}function pl(t,e){return new t({type:"number",checks:[],...k(e)})}function fl(t,e){return new t({type:"number",check:"number_format",abort:!1,format:"safeint",...k(e)})}function ml(t,e){return new t({type:"boolean",...k(e)})}function hl(t,e){return new t({type:"null",...k(e)})}function gl(t){return new t({type:"unknown"})}function _l(t,e){return new t({type:"never",...k(e)})}function mo(t,e){return new Wn({check:"less_than",...k(e),value:t,inclusive:!1})}function lr(t,e){return new Wn({check:"less_than",...k(e),value:t,inclusive:!0})}function ho(t,e){return new Jn({check:"greater_than",...k(e),value:t,inclusive:!1})}function dr(t,e){return new Jn({check:"greater_than",...k(e),value:t,inclusive:!0})}function go(t,e){return new xc({check:"multiple_of",...k(e),value:t})}function _o(t,e){return new Ec({check:"max_length",...k(e),maximum:t})}function It(t,e){return new kc({check:"min_length",...k(e),minimum:t})}function yo(t,e){return new Tc({check:"length_equals",...k(e),length:t})}function rs(t,e){return new Pc({check:"string_format",format:"regex",...k(e),pattern:t})}function os(t){return new Oc({check:"string_format",format:"lowercase",...k(t)})}function ns(t){return new Ic({check:"string_format",format:"uppercase",...k(t)})}function ss(t,e){return new Rc({check:"string_format",format:"includes",...k(e),includes:t})}function is(t,e){return new Nc({check:"string_format",format:"starts_with",...k(e),prefix:t})}function as(t,e){return new Cc({check:"string_format",format:"ends_with",...k(e),suffix:t})}function gt(t){return new Ac({check:"overwrite",tx:t})}function cs(t){return gt(e=>e.normalize(t))}function us(){return gt(t=>t.trim())}function ls(){return gt(t=>t.toLowerCase())}function ds(){return gt(t=>t.toUpperCase())}function yl(t,e,r){return new t({type:"array",element:e,...k(r)})}function vl(t,e,r){let o=k(r);return o.abort??(o.abort=!0),new t({type:"custom",check:"custom",fn:e,...o})}function $l(t,e,r){return new t({type:"custom",check:"custom",fn:e,...k(r)})}function Rt(t){return!!t._zod}function ot(t,e){return Rt(t)?ar(t,e):t.safeParse(e)}function vo(t){if(!t)return;let e;if(Rt(t)?e=t._zod?.def?.shape:e=t.shape,!!e){if(typeof e=="function")try{return e()}catch{return}return e}}function bl(t){if(Rt(t)){let s=t._zod?.def;if(s){if(s.value!==void 0)return s.value;if(Array.isArray(s.values)&&s.values.length>0)return s.values[0]}}let r=t._def;if(r){if(r.value!==void 0)return r.value;if(Array.isArray(r.values)&&r.values.length>0)return r.values[0]}let o=t.value;if(o!==void 0)return o}var fr={};La(fr,{ZodISODate:()=>wl,ZodISODateTime:()=>Sl,ZodISODuration:()=>zl,ZodISOTime:()=>xl,date:()=>fs,datetime:()=>ps,duration:()=>hs,time:()=>ms});var Sl=h("ZodISODateTime",(t,e)=>{nu.init(t,e),X.init(t,e)});function ps(t){return cl(Sl,t)}var wl=h("ZodISODate",(t,e)=>{su.init(t,e),X.init(t,e)});function fs(t){return ul(wl,t)}var xl=h("ZodISOTime",(t,e)=>{iu.init(t,e),X.init(t,e)});function ms(t){return ll(xl,t)}var zl=h("ZodISODuration",(t,e)=>{au.init(t,e),X.init(t,e)});function hs(t){return dl(zl,t)}var El=(t,e)=>{co.init(t,e),t.name="ZodError",Object.defineProperties(t,{format:{value:r=>Ha(t,r)},flatten:{value:r=>Va(t,r)},addIssue:{value:r=>t.issues.push(r)},addIssues:{value:r=>t.issues.push(...r)},isEmpty:{get(){return t.issues.length===0}}})},hw=h("ZodError",El),mr=h("ZodError",El,{Parent:Error});var kl=Ka(mr),Tl=Ba(mr),Pl=Vn(mr),Ol=Hn(mr);var te=h("ZodType",(t,e)=>(K.init(t,e),t.def=e,Object.defineProperty(t,"_def",{value:e}),t.check=(...r)=>t.clone({...e,checks:[...e.checks??[],...r.map(o=>typeof o=="function"?{_zod:{check:o,def:{check:"custom"},onattach:[]}}:o)]}),t.clone=(r,o)=>Me(t,r,o),t.brand=()=>t,t.register=((r,o)=>(r.add(t,o),t)),t.parse=(r,o)=>kl(t,r,o,{callee:t.parse}),t.safeParse=(r,o)=>Pl(t,r,o),t.parseAsync=async(r,o)=>Tl(t,r,o,{callee:t.parseAsync}),t.safeParseAsync=async(r,o)=>Ol(t,r,o),t.spa=t.safeParseAsync,t.refine=(r,o)=>t.check(Lh(r,o)),t.superRefine=r=>t.check(jh(r)),t.overwrite=r=>t.check(gt(r)),t.optional=()=>ee(t),t.nullable=()=>Nl(t),t.nullish=()=>ee(Nl(t)),t.nonoptional=r=>Oh(t,r),t.array=()=>D(t),t.or=r=>W([t,r]),t.and=r=>bo(t,r),t.transform=r=>_s(t,Zl(r)),t.default=r=>kh(t,r),t.prefault=r=>Ph(t,r),t.catch=r=>Rh(t,r),t.pipe=r=>_s(t,r),t.readonly=()=>Ah(t),t.describe=r=>{let o=t.clone();return ur.add(o,{description:r}),o},Object.defineProperty(t,"description",{get(){return ur.get(t)?.description},configurable:!0}),t.meta=(...r)=>{if(r.length===0)return ur.get(t);let o=t.clone();return ur.add(o,r[0]),o},t.isOptional=()=>t.safeParse(void 0).success,t.isNullable=()=>t.safeParse(null).success,t)),Cl=h("_ZodString",(t,e)=>{fo.init(t,e),te.init(t,e);let r=t._zod.bag;t.format=r.format??null,t.minLength=r.minimum??null,t.maxLength=r.maximum??null,t.regex=(...o)=>t.check(rs(...o)),t.includes=(...o)=>t.check(ss(...o)),t.startsWith=(...o)=>t.check(is(...o)),t.endsWith=(...o)=>t.check(as(...o)),t.min=(...o)=>t.check(It(...o)),t.max=(...o)=>t.check(_o(...o)),t.length=(...o)=>t.check(yo(...o)),t.nonempty=(...o)=>t.check(It(1,...o)),t.lowercase=o=>t.check(os(o)),t.uppercase=o=>t.check(ns(o)),t.trim=()=>t.check(us()),t.normalize=(...o)=>t.check(cs(...o)),t.toLowerCase=()=>t.check(ls()),t.toUpperCase=()=>t.check(ds())}),Wm=h("ZodString",(t,e)=>{fo.init(t,e),Cl.init(t,e),t.email=r=>t.check(qu(Jm,r)),t.url=r=>t.check(Ku(Ym,r)),t.jwt=r=>t.check(al(ph,r)),t.emoji=r=>t.check(Bu(Xm,r)),t.guid=r=>t.check(ts(Il,r)),t.uuid=r=>t.check(Uu($o,r)),t.uuidv4=r=>t.check(Fu($o,r)),t.uuidv6=r=>t.check(Vu($o,r)),t.uuidv7=r=>t.check(Hu($o,r)),t.nanoid=r=>t.check(Gu(Qm,r)),t.guid=r=>t.check(ts(Il,r)),t.cuid=r=>t.check(Wu(eh,r)),t.cuid2=r=>t.check(Ju(th,r)),t.ulid=r=>t.check(Yu(rh,r)),t.base64=r=>t.check(nl(uh,r)),t.base64url=r=>t.check(sl(lh,r)),t.xid=r=>t.check(Xu(oh,r)),t.ksuid=r=>t.check(Qu(nh,r)),t.ipv4=r=>t.check(el(sh,r)),t.ipv6=r=>t.check(tl(ih,r)),t.cidrv4=r=>t.check(rl(ah,r)),t.cidrv6=r=>t.check(ol(ch,r)),t.e164=r=>t.check(il(dh,r)),t.datetime=r=>t.check(ps(r)),t.date=r=>t.check(fs(r)),t.time=r=>t.check(ms(r)),t.duration=r=>t.check(hs(r))});function f(t){return Mu(Wm,t)}var X=h("ZodStringFormat",(t,e)=>{G.init(t,e),Cl.init(t,e)}),Jm=h("ZodEmail",(t,e)=>{Wc.init(t,e),X.init(t,e)});var Il=h("ZodGUID",(t,e)=>{Bc.init(t,e),X.init(t,e)});var $o=h("ZodUUID",(t,e)=>{Gc.init(t,e),X.init(t,e)});var Ym=h("ZodURL",(t,e)=>{Jc.init(t,e),X.init(t,e)});var Xm=h("ZodEmoji",(t,e)=>{Yc.init(t,e),X.init(t,e)});var Qm=h("ZodNanoID",(t,e)=>{Xc.init(t,e),X.init(t,e)});var eh=h("ZodCUID",(t,e)=>{Qc.init(t,e),X.init(t,e)});var th=h("ZodCUID2",(t,e)=>{eu.init(t,e),X.init(t,e)});var rh=h("ZodULID",(t,e)=>{tu.init(t,e),X.init(t,e)});var oh=h("ZodXID",(t,e)=>{ru.init(t,e),X.init(t,e)});var nh=h("ZodKSUID",(t,e)=>{ou.init(t,e),X.init(t,e)});var sh=h("ZodIPv4",(t,e)=>{cu.init(t,e),X.init(t,e)});var ih=h("ZodIPv6",(t,e)=>{uu.init(t,e),X.init(t,e)});var ah=h("ZodCIDRv4",(t,e)=>{lu.init(t,e),X.init(t,e)});var ch=h("ZodCIDRv6",(t,e)=>{du.init(t,e),X.init(t,e)});var uh=h("ZodBase64",(t,e)=>{fu.init(t,e),X.init(t,e)});var lh=h("ZodBase64URL",(t,e)=>{mu.init(t,e),X.init(t,e)});var dh=h("ZodE164",(t,e)=>{hu.init(t,e),X.init(t,e)});var ph=h("ZodJWT",(t,e)=>{gu.init(t,e),X.init(t,e)});var Al=h("ZodNumber",(t,e)=>{Xn.init(t,e),te.init(t,e),t.gt=(o,n)=>t.check(ho(o,n)),t.gte=(o,n)=>t.check(dr(o,n)),t.min=(o,n)=>t.check(dr(o,n)),t.lt=(o,n)=>t.check(mo(o,n)),t.lte=(o,n)=>t.check(lr(o,n)),t.max=(o,n)=>t.check(lr(o,n)),t.int=o=>t.check(Rl(o)),t.safe=o=>t.check(Rl(o)),t.positive=o=>t.check(ho(0,o)),t.nonnegative=o=>t.check(dr(0,o)),t.negative=o=>t.check(mo(0,o)),t.nonpositive=o=>t.check(lr(0,o)),t.multipleOf=(o,n)=>t.check(go(o,n)),t.step=(o,n)=>t.check(go(o,n)),t.finite=()=>t;let r=t._zod.bag;t.minValue=Math.max(r.minimum??Number.NEGATIVE_INFINITY,r.exclusiveMinimum??Number.NEGATIVE_INFINITY)??null,t.maxValue=Math.min(r.maximum??Number.POSITIVE_INFINITY,r.exclusiveMaximum??Number.POSITIVE_INFINITY)??null,t.isInt=(r.format??"").includes("int")||Number.isSafeInteger(r.multipleOf??.5),t.isFinite=!0,t.format=r.format??null});function U(t){return pl(Al,t)}var fh=h("ZodNumberFormat",(t,e)=>{_u.init(t,e),Al.init(t,e)});function Rl(t){return fl(fh,t)}var mh=h("ZodBoolean",(t,e)=>{yu.init(t,e),te.init(t,e)});function ne(t){return ml(mh,t)}var hh=h("ZodNull",(t,e)=>{vu.init(t,e),te.init(t,e)});function Dl(t){return hl(hh,t)}var gh=h("ZodUnknown",(t,e)=>{$u.init(t,e),te.init(t,e)});function Q(){return gl(gh)}var _h=h("ZodNever",(t,e)=>{bu.init(t,e),te.init(t,e)});function yh(t){return _l(_h,t)}var vh=h("ZodArray",(t,e)=>{Su.init(t,e),te.init(t,e),t.element=e.element,t.min=(r,o)=>t.check(It(r,o)),t.nonempty=r=>t.check(It(1,r)),t.max=(r,o)=>t.check(_o(r,o)),t.length=(r,o)=>t.check(yo(r,o)),t.unwrap=()=>t.element});function D(t,e){return yl(vh,t,e)}var Ll=h("ZodObject",(t,e)=>{wu.init(t,e),te.init(t,e),q.defineLazy(t,"shape",()=>e.shape),t.keyof=()=>ve(Object.keys(t._zod.def.shape)),t.catchall=r=>t.clone({...t._zod.def,catchall:r}),t.passthrough=()=>t.clone({...t._zod.def,catchall:Q()}),t.loose=()=>t.clone({...t._zod.def,catchall:Q()}),t.strict=()=>t.clone({...t._zod.def,catchall:yh()}),t.strip=()=>t.clone({...t._zod.def,catchall:void 0}),t.extend=r=>q.extend(t,r),t.merge=r=>q.merge(t,r),t.pick=r=>q.pick(t,r),t.omit=r=>q.omit(t,r),t.partial=(...r)=>q.partial(Ml,t,r[0]),t.required=(...r)=>q.required(ql,t,r[0])});function w(t,e){let r={type:"object",get shape(){return q.assignProp(this,"shape",{...t}),this.shape},...q.normalizeParams(e)};return new Ll(r)}function ge(t,e){return new Ll({type:"object",get shape(){return q.assignProp(this,"shape",{...t}),this.shape},catchall:Q(),...q.normalizeParams(e)})}var jl=h("ZodUnion",(t,e)=>{Qn.init(t,e),te.init(t,e),t.options=e.options});function W(t,e){return new jl({type:"union",options:t,...q.normalizeParams(e)})}var $h=h("ZodDiscriminatedUnion",(t,e)=>{jl.init(t,e),xu.init(t,e)});function ys(t,e,r){return new $h({type:"union",options:e,discriminator:t,...q.normalizeParams(r)})}var bh=h("ZodIntersection",(t,e)=>{zu.init(t,e),te.init(t,e)});function bo(t,e){return new bh({type:"intersection",left:t,right:e})}var Sh=h("ZodRecord",(t,e)=>{Eu.init(t,e),te.init(t,e),t.keyType=e.keyType,t.valueType=e.valueType});function B(t,e,r){return new Sh({type:"record",keyType:t,valueType:e,...q.normalizeParams(r)})}var gs=h("ZodEnum",(t,e)=>{ku.init(t,e),te.init(t,e),t.enum=e.entries,t.options=Object.values(e.entries);let r=new Set(Object.keys(e.entries));t.extract=(o,n)=>{let s={};for(let i of o)if(r.has(i))s[i]=e.entries[i];else throw new Error(`Key ${i} not found in enum`);return new gs({...e,checks:[],...q.normalizeParams(n),entries:s})},t.exclude=(o,n)=>{let s={...e.entries};for(let i of o)if(r.has(i))delete s[i];else throw new Error(`Key ${i} not found in enum`);return new gs({...e,checks:[],...q.normalizeParams(n),entries:s})}});function ve(t,e){let r=Array.isArray(t)?Object.fromEntries(t.map(o=>[o,o])):t;return new gs({type:"enum",entries:r,...q.normalizeParams(e)})}var wh=h("ZodLiteral",(t,e)=>{Tu.init(t,e),te.init(t,e),t.values=new Set(e.values),Object.defineProperty(t,"value",{get(){if(e.values.length>1)throw new Error("This schema contains multiple valid literal values. Use `.values` instead.");return e.values[0]}})});function x(t,e){return new wh({type:"literal",values:Array.isArray(t)?t:[t],...q.normalizeParams(e)})}var xh=h("ZodTransform",(t,e)=>{Pu.init(t,e),te.init(t,e),t._zod.parse=(r,o)=>{r.addIssue=s=>{if(typeof s=="string")r.issues.push(q.issue(s,r.value,e));else{let i=s;i.fatal&&(i.continue=!1),i.code??(i.code="custom"),i.input??(i.input=r.value),i.inst??(i.inst=t),i.continue??(i.continue=!0),r.issues.push(q.issue(i))}};let n=e.transform(r.value,r);return n instanceof Promise?n.then(s=>(r.value=s,r)):(r.value=n,r)}});function Zl(t){return new xh({type:"transform",transform:t})}var Ml=h("ZodOptional",(t,e)=>{Ou.init(t,e),te.init(t,e),t.unwrap=()=>t._zod.def.innerType});function ee(t){return new Ml({type:"optional",innerType:t})}var zh=h("ZodNullable",(t,e)=>{Iu.init(t,e),te.init(t,e),t.unwrap=()=>t._zod.def.innerType});function Nl(t){return new zh({type:"nullable",innerType:t})}var Eh=h("ZodDefault",(t,e)=>{Ru.init(t,e),te.init(t,e),t.unwrap=()=>t._zod.def.innerType,t.removeDefault=t.unwrap});function kh(t,e){return new Eh({type:"default",innerType:t,get defaultValue(){return typeof e=="function"?e():e}})}var Th=h("ZodPrefault",(t,e)=>{Nu.init(t,e),te.init(t,e),t.unwrap=()=>t._zod.def.innerType});function Ph(t,e){return new Th({type:"prefault",innerType:t,get defaultValue(){return typeof e=="function"?e():e}})}var ql=h("ZodNonOptional",(t,e)=>{Cu.init(t,e),te.init(t,e),t.unwrap=()=>t._zod.def.innerType});function Oh(t,e){return new ql({type:"nonoptional",innerType:t,...q.normalizeParams(e)})}var Ih=h("ZodCatch",(t,e)=>{Au.init(t,e),te.init(t,e),t.unwrap=()=>t._zod.def.innerType,t.removeCatch=t.unwrap});function Rh(t,e){return new Ih({type:"catch",innerType:t,catchValue:typeof e=="function"?e:()=>e})}var Nh=h("ZodPipe",(t,e)=>{Du.init(t,e),te.init(t,e),t.in=e.in,t.out=e.out});function _s(t,e){return new Nh({type:"pipe",in:t,out:e})}var Ch=h("ZodReadonly",(t,e)=>{Lu.init(t,e),te.init(t,e)});function Ah(t){return new Ch({type:"readonly",innerType:t})}var Ul=h("ZodCustom",(t,e)=>{ju.init(t,e),te.init(t,e)});function Dh(t){let e=new de({check:"custom"});return e._zod.check=t,e}function Fl(t,e){return vl(Ul,t??(()=>!0),e)}function Lh(t,e={}){return $l(Ul,t,e)}function jh(t){let e=Dh(r=>(r.addIssue=o=>{if(typeof o=="string")r.issues.push(q.issue(o,r.value,e._zod.def));else{let n=o;n.fatal&&(n.continue=!1),n.code??(n.code="custom"),n.input??(n.input=r.value),n.inst??(n.inst=e),n.continue??(n.continue=!e._zod.def.abort),r.issues.push(q.issue(n))}},t(r.value,r)));return e}function vs(t,e){return _s(Zl(t),e)}Ee(Zu());var bs="2025-11-25";var Vl=[bs,"2025-06-18","2025-03-26","2024-11-05","2024-10-07"],nt="io.modelcontextprotocol/related-task",wo="2.0",oe=Fl(t=>t!==null&&(typeof t=="object"||typeof t=="function")),Hl=W([f(),U().int()]),Kl=f(),cx=ge({ttl:U().optional(),pollInterval:U().optional()}),Zh=w({ttl:U().optional()}),Mh=w({taskId:f()}),Ss=ge({progressToken:Hl.optional(),[nt]:Mh.optional()}),xe=w({_meta:Ss.optional()}),hr=xe.extend({task:Zh.optional()}),Bl=t=>hr.safeParse(t).success,ie=w({method:f(),params:xe.loose().optional()}),ke=w({_meta:Ss.optional()}),Te=w({method:f(),params:ke.loose().optional()}),ae=ge({_meta:Ss.optional()}),xo=W([f(),U().int()]),Gl=w({jsonrpc:x(wo),id:xo,...ie.shape}).strict(),ws=t=>Gl.safeParse(t).success,Wl=w({jsonrpc:x(wo),...Te.shape}).strict(),Jl=t=>Wl.safeParse(t).success,xs=w({jsonrpc:x(wo),id:xo,result:ae}).strict(),gr=t=>xs.safeParse(t).success;var A;(function(t){t[t.ConnectionClosed=-32e3]="ConnectionClosed",t[t.RequestTimeout=-32001]="RequestTimeout",t[t.ParseError=-32700]="ParseError",t[t.InvalidRequest=-32600]="InvalidRequest",t[t.MethodNotFound=-32601]="MethodNotFound",t[t.InvalidParams=-32602]="InvalidParams",t[t.InternalError=-32603]="InternalError",t[t.UrlElicitationRequired=-32042]="UrlElicitationRequired"})(A||(A={}));var zs=w({jsonrpc:x(wo),id:xo.optional(),error:w({code:U().int(),message:f(),data:Q().optional()})}).strict();var Yl=t=>zs.safeParse(t).success;var Xl=W([Gl,Wl,xs,zs]),ux=W([xs,zs]),zo=ae.strict(),qh=ke.extend({requestId:xo.optional(),reason:f().optional()}),Eo=Te.extend({method:x("notifications/cancelled"),params:qh}),Uh=w({src:f(),mimeType:f().optional(),sizes:D(f()).optional(),theme:ve(["light","dark"]).optional()}),_r=w({icons:D(Uh).optional()}),Nt=w({name:f(),title:f().optional()}),Ql=Nt.extend({...Nt.shape,..._r.shape,version:f(),websiteUrl:f().optional(),description:f().optional()}),Fh=bo(w({applyDefaults:ne().optional()}),B(f(),Q())),Vh=vs(t=>t&&typeof t=="object"&&!Array.isArray(t)&&Object.keys(t).length===0?{form:{}}:t,bo(w({form:Fh.optional(),url:oe.optional()}),B(f(),Q()).optional())),Hh=ge({list:oe.optional(),cancel:oe.optional(),requests:ge({sampling:ge({createMessage:oe.optional()}).optional(),elicitation:ge({create:oe.optional()}).optional()}).optional()}),Kh=ge({list:oe.optional(),cancel:oe.optional(),requests:ge({tools:ge({call:oe.optional()}).optional()}).optional()}),Bh=w({experimental:B(f(),oe).optional(),sampling:w({context:oe.optional(),tools:oe.optional()}).optional(),elicitation:Vh.optional(),roots:w({listChanged:ne().optional()}).optional(),tasks:Hh.optional(),extensions:B(f(),oe).optional()}),Gh=xe.extend({protocolVersion:f(),capabilities:Bh,clientInfo:Ql}),Es=ie.extend({method:x("initialize"),params:Gh});var Wh=w({experimental:B(f(),oe).optional(),logging:oe.optional(),completions:oe.optional(),prompts:w({listChanged:ne().optional()}).optional(),resources:w({subscribe:ne().optional(),listChanged:ne().optional()}).optional(),tools:w({listChanged:ne().optional()}).optional(),tasks:Kh.optional(),extensions:B(f(),oe).optional()}),Jh=ae.extend({protocolVersion:f(),capabilities:Wh,serverInfo:Ql,instructions:f().optional()}),ks=Te.extend({method:x("notifications/initialized"),params:ke.optional()});var ko=ie.extend({method:x("ping"),params:xe.optional()}),Yh=w({progress:U(),total:ee(U()),message:ee(f())}),Xh=w({...ke.shape,...Yh.shape,progressToken:Hl}),To=Te.extend({method:x("notifications/progress"),params:Xh}),Qh=xe.extend({cursor:Kl.optional()}),yr=ie.extend({params:Qh.optional()}),vr=ae.extend({nextCursor:Kl.optional()}),eg=ve(["working","input_required","completed","failed","cancelled"]),$r=w({taskId:f(),status:eg,ttl:W([U(),Dl()]),createdAt:f(),lastUpdatedAt:f(),pollInterval:ee(U()),statusMessage:ee(f())}),Ct=ae.extend({task:$r}),tg=ke.merge($r),br=Te.extend({method:x("notifications/tasks/status"),params:tg}),Po=ie.extend({method:x("tasks/get"),params:xe.extend({taskId:f()})}),Oo=ae.merge($r),Io=ie.extend({method:x("tasks/result"),params:xe.extend({taskId:f()})}),lx=ae.loose(),Ro=yr.extend({method:x("tasks/list")}),No=vr.extend({tasks:D($r)}),Co=ie.extend({method:x("tasks/cancel"),params:xe.extend({taskId:f()})}),ed=ae.merge($r),td=w({uri:f(),mimeType:ee(f()),_meta:B(f(),Q()).optional()}),rd=td.extend({text:f()}),Ts=f().refine(t=>{try{return atob(t),!0}catch{return!1}},{message:"Invalid Base64 string"}),od=td.extend({blob:Ts}),Sr=ve(["user","assistant"]),At=w({audience:D(Sr).optional(),priority:U().min(0).max(1).optional(),lastModified:fr.datetime({offset:!0}).optional()}),nd=w({...Nt.shape,..._r.shape,uri:f(),description:ee(f()),mimeType:ee(f()),size:ee(U()),annotations:At.optional(),_meta:ee(ge({}))}),rg=w({...Nt.shape,..._r.shape,uriTemplate:f(),description:ee(f()),mimeType:ee(f()),annotations:At.optional(),_meta:ee(ge({}))}),og=yr.extend({method:x("resources/list")}),ng=vr.extend({resources:D(nd)}),sg=yr.extend({method:x("resources/templates/list")}),ig=vr.extend({resourceTemplates:D(rg)}),Ps=xe.extend({uri:f()}),ag=Ps,cg=ie.extend({method:x("resources/read"),params:ag}),ug=ae.extend({contents:D(W([rd,od]))}),lg=Te.extend({method:x("notifications/resources/list_changed"),params:ke.optional()}),dg=Ps,pg=ie.extend({method:x("resources/subscribe"),params:dg}),fg=Ps,mg=ie.extend({method:x("resources/unsubscribe"),params:fg}),hg=ke.extend({uri:f()}),gg=Te.extend({method:x("notifications/resources/updated"),params:hg}),_g=w({name:f(),description:ee(f()),required:ee(ne())}),yg=w({...Nt.shape,..._r.shape,description:ee(f()),arguments:ee(D(_g)),_meta:ee(ge({}))}),vg=yr.extend({method:x("prompts/list")}),$g=vr.extend({prompts:D(yg)}),bg=xe.extend({name:f(),arguments:B(f(),f()).optional()}),Sg=ie.extend({method:x("prompts/get"),params:bg}),Os=w({type:x("text"),text:f(),annotations:At.optional(),_meta:B(f(),Q()).optional()}),Is=w({type:x("image"),data:Ts,mimeType:f(),annotations:At.optional(),_meta:B(f(),Q()).optional()}),Rs=w({type:x("audio"),data:Ts,mimeType:f(),annotations:At.optional(),_meta:B(f(),Q()).optional()}),wg=w({type:x("tool_use"),name:f(),id:f(),input:B(f(),Q()),_meta:B(f(),Q()).optional()}),xg=w({type:x("resource"),resource:W([rd,od]),annotations:At.optional(),_meta:B(f(),Q()).optional()}),zg=nd.extend({type:x("resource_link")}),Ns=W([Os,Is,Rs,zg,xg]),Eg=w({role:Sr,content:Ns}),kg=ae.extend({description:f().optional(),messages:D(Eg)}),Tg=Te.extend({method:x("notifications/prompts/list_changed"),params:ke.optional()}),Pg=w({title:f().optional(),readOnlyHint:ne().optional(),destructiveHint:ne().optional(),idempotentHint:ne().optional(),openWorldHint:ne().optional()}),Og=w({taskSupport:ve(["required","optional","forbidden"]).optional()}),sd=w({...Nt.shape,..._r.shape,description:f().optional(),inputSchema:w({type:x("object"),properties:B(f(),oe).optional(),required:D(f()).optional()}).catchall(Q()),outputSchema:w({type:x("object"),properties:B(f(),oe).optional(),required:D(f()).optional()}).catchall(Q()).optional(),annotations:Pg.optional(),execution:Og.optional(),_meta:B(f(),Q()).optional()}),Cs=yr.extend({method:x("tools/list")}),Ig=vr.extend({tools:D(sd)}),Ao=ae.extend({content:D(Ns).default([]),structuredContent:B(f(),Q()).optional(),isError:ne().optional()}),dx=Ao.or(ae.extend({toolResult:Q()})),Rg=hr.extend({name:f(),arguments:B(f(),Q()).optional()}),wr=ie.extend({method:x("tools/call"),params:Rg}),Ng=Te.extend({method:x("notifications/tools/list_changed"),params:ke.optional()}),px=w({autoRefresh:ne().default(!0),debounceMs:U().int().nonnegative().default(300)}),xr=ve(["debug","info","notice","warning","error","critical","alert","emergency"]),Cg=xe.extend({level:xr}),As=ie.extend({method:x("logging/setLevel"),params:Cg}),Ag=ke.extend({level:xr,logger:f().optional(),data:Q()}),Dg=Te.extend({method:x("notifications/message"),params:Ag}),Lg=w({name:f().optional()}),jg=w({hints:D(Lg).optional(),costPriority:U().min(0).max(1).optional(),speedPriority:U().min(0).max(1).optional(),intelligencePriority:U().min(0).max(1).optional()}),Zg=w({mode:ve(["auto","required","none"]).optional()}),Mg=w({type:x("tool_result"),toolUseId:f().describe("The unique identifier for the corresponding tool call."),content:D(Ns).default([]),structuredContent:w({}).loose().optional(),isError:ne().optional(),_meta:B(f(),Q()).optional()}),qg=ys("type",[Os,Is,Rs]),So=ys("type",[Os,Is,Rs,wg,Mg]),Ug=w({role:Sr,content:W([So,D(So)]),_meta:B(f(),Q()).optional()}),Fg=hr.extend({messages:D(Ug),modelPreferences:jg.optional(),systemPrompt:f().optional(),includeContext:ve(["none","thisServer","allServers"]).optional(),temperature:U().optional(),maxTokens:U().int(),stopSequences:D(f()).optional(),metadata:oe.optional(),tools:D(sd).optional(),toolChoice:Zg.optional()}),Vg=ie.extend({method:x("sampling/createMessage"),params:Fg}),zr=ae.extend({model:f(),stopReason:ee(ve(["endTurn","stopSequence","maxTokens"]).or(f())),role:Sr,content:qg}),Ds=ae.extend({model:f(),stopReason:ee(ve(["endTurn","stopSequence","maxTokens","toolUse"]).or(f())),role:Sr,content:W([So,D(So)])}),Hg=w({type:x("boolean"),title:f().optional(),description:f().optional(),default:ne().optional()}),Kg=w({type:x("string"),title:f().optional(),description:f().optional(),minLength:U().optional(),maxLength:U().optional(),format:ve(["email","uri","date","date-time"]).optional(),default:f().optional()}),Bg=w({type:ve(["number","integer"]),title:f().optional(),description:f().optional(),minimum:U().optional(),maximum:U().optional(),default:U().optional()}),Gg=w({type:x("string"),title:f().optional(),description:f().optional(),enum:D(f()),default:f().optional()}),Wg=w({type:x("string"),title:f().optional(),description:f().optional(),oneOf:D(w({const:f(),title:f()})),default:f().optional()}),Jg=w({type:x("string"),title:f().optional(),description:f().optional(),enum:D(f()),enumNames:D(f()).optional(),default:f().optional()}),Yg=W([Gg,Wg]),Xg=w({type:x("array"),title:f().optional(),description:f().optional(),minItems:U().optional(),maxItems:U().optional(),items:w({type:x("string"),enum:D(f())}),default:D(f()).optional()}),Qg=w({type:x("array"),title:f().optional(),description:f().optional(),minItems:U().optional(),maxItems:U().optional(),items:w({anyOf:D(w({const:f(),title:f()}))}),default:D(f()).optional()}),e_=W([Xg,Qg]),t_=W([Jg,Yg,e_]),r_=W([t_,Hg,Kg,Bg]),o_=hr.extend({mode:x("form").optional(),message:f(),requestedSchema:w({type:x("object"),properties:B(f(),r_),required:D(f()).optional()})}),n_=hr.extend({mode:x("url"),message:f(),elicitationId:f(),url:f().url()}),s_=W([o_,n_]),i_=ie.extend({method:x("elicitation/create"),params:s_}),a_=ke.extend({elicitationId:f()}),c_=Te.extend({method:x("notifications/elicitation/complete"),params:a_}),Dt=ae.extend({action:ve(["accept","decline","cancel"]),content:vs(t=>t===null?void 0:t,B(f(),W([f(),U(),ne(),D(f())])).optional())}),u_=w({type:x("ref/resource"),uri:f()});var l_=w({type:x("ref/prompt"),name:f()}),d_=xe.extend({ref:W([l_,u_]),argument:w({name:f(),value:f()}),context:w({arguments:B(f(),f()).optional()}).optional()}),p_=ie.extend({method:x("completion/complete"),params:d_});var f_=ae.extend({completion:ge({values:D(f()).max(100),total:ee(U().int()),hasMore:ee(ne())})}),m_=w({uri:f().startsWith("file://"),name:f().optional(),_meta:B(f(),Q()).optional()}),h_=ie.extend({method:x("roots/list"),params:xe.optional()}),Ls=ae.extend({roots:D(m_)}),g_=Te.extend({method:x("notifications/roots/list_changed"),params:ke.optional()}),fx=W([ko,Es,p_,As,Sg,vg,og,sg,cg,pg,mg,wr,Cs,Po,Io,Ro,Co]),mx=W([Eo,To,ks,g_,br]),hx=W([zo,zr,Ds,Dt,Ls,Oo,No,Ct]),gx=W([ko,Vg,i_,h_,Po,Io,Ro,Co]),_x=W([Eo,To,Dg,gg,lg,Ng,Tg,br,c_]),yx=W([zo,Jh,f_,kg,$g,ng,ig,ug,Ao,Ig,Oo,No,Ct]),O=class t extends Error{constructor(e,r,o){super(`MCP error ${e}: ${r}`),this.code=e,this.data=o,this.name="McpError"}static fromError(e,r,o){if(e===A.UrlElicitationRequired&&o){let n=o;if(n.elicitations)return new $s(n.elicitations,r)}return new t(e,r,o)}},$s=class extends O{constructor(e,r=`URL elicitation${e.length>1?"s":""} required`){super(A.UrlElicitationRequired,r,{elicitations:e})}get elicitations(){return this.data?.elicitations??[]}};function st(t){return t==="completed"||t==="failed"||t==="cancelled"}var Yx=new Set("ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvxyz0123456789");function js(t){let r=vo(t)?.method;if(!r)throw new Error("Schema is missing a method literal");let o=bl(r);if(typeof o!="string")throw new Error("Schema method literal must be a string");return o}function Zs(t,e){let r=ot(t,e);if(!r.success)throw r.error;return r.data}var S_=6e4,Do=class{constructor(e){this._options=e,this._requestMessageId=0,this._requestHandlers=new Map,this._requestHandlerAbortControllers=new Map,this._notificationHandlers=new Map,this._responseHandlers=new Map,this._progressHandlers=new Map,this._timeoutInfo=new Map,this._pendingDebouncedNotifications=new Set,this._taskProgressTokens=new Map,this._requestResolvers=new Map,this.setNotificationHandler(Eo,r=>{this._oncancel(r)}),this.setNotificationHandler(To,r=>{this._onprogress(r)}),this.setRequestHandler(ko,r=>({})),this._taskStore=e?.taskStore,this._taskMessageQueue=e?.taskMessageQueue,this._taskStore&&(this.setRequestHandler(Po,async(r,o)=>{let n=await this._taskStore.getTask(r.params.taskId,o.sessionId);if(!n)throw new O(A.InvalidParams,"Failed to retrieve task: Task not found");return{...n}}),this.setRequestHandler(Io,async(r,o)=>{let n=async()=>{let s=r.params.taskId;if(this._taskMessageQueue){let a;for(;a=await this._taskMessageQueue.dequeue(s,o.sessionId);){if(a.type==="response"||a.type==="error"){let c=a.message,u=c.id,l=this._requestResolvers.get(u);if(l)if(this._requestResolvers.delete(u),a.type==="response")l(c);else{let d=c,p=new O(d.error.code,d.error.message,d.error.data);l(p)}else{let d=a.type==="response"?"Response":"Error";this._onerror(new Error(`${d} handler missing for request ${u}`))}continue}await this._transport?.send(a.message,{relatedRequestId:o.requestId})}}let i=await this._taskStore.getTask(s,o.sessionId);if(!i)throw new O(A.InvalidParams,`Task not found: ${s}`);if(!st(i.status))return await this._waitForTaskUpdate(s,o.signal),await n();if(st(i.status)){let a=await this._taskStore.getTaskResult(s,o.sessionId);return this._clearTaskQueue(s),{...a,_meta:{...a._meta,[nt]:{taskId:s}}}}return await n()};return await n()}),this.setRequestHandler(Ro,async(r,o)=>{try{let{tasks:n,nextCursor:s}=await this._taskStore.listTasks(r.params?.cursor,o.sessionId);return{tasks:n,nextCursor:s,_meta:{}}}catch(n){throw new O(A.InvalidParams,`Failed to list tasks: ${n instanceof Error?n.message:String(n)}`)}}),this.setRequestHandler(Co,async(r,o)=>{try{let n=await this._taskStore.getTask(r.params.taskId,o.sessionId);if(!n)throw new O(A.InvalidParams,`Task not found: ${r.params.taskId}`);if(st(n.status))throw new O(A.InvalidParams,`Cannot cancel task in terminal status: ${n.status}`);await this._taskStore.updateTaskStatus(r.params.taskId,"cancelled","Client cancelled task execution.",o.sessionId),this._clearTaskQueue(r.params.taskId);let s=await this._taskStore.getTask(r.params.taskId,o.sessionId);if(!s)throw new O(A.InvalidParams,`Task not found after cancellation: ${r.params.taskId}`);return{_meta:{},...s}}catch(n){throw n instanceof O?n:new O(A.InvalidRequest,`Failed to cancel task: ${n instanceof Error?n.message:String(n)}`)}}))}async _oncancel(e){if(!e.params.requestId)return;this._requestHandlerAbortControllers.get(e.params.requestId)?.abort(e.params.reason)}_setupTimeout(e,r,o,n,s=!1){this._timeoutInfo.set(e,{timeoutId:setTimeout(n,r),startTime:Date.now(),timeout:r,maxTotalTimeout:o,resetTimeoutOnProgress:s,onTimeout:n})}_resetTimeout(e){let r=this._timeoutInfo.get(e);if(!r)return!1;let o=Date.now()-r.startTime;if(r.maxTotalTimeout&&o>=r.maxTotalTimeout)throw this._timeoutInfo.delete(e),O.fromError(A.RequestTimeout,"Maximum total timeout exceeded",{maxTotalTimeout:r.maxTotalTimeout,totalElapsed:o});return clearTimeout(r.timeoutId),r.timeoutId=setTimeout(r.onTimeout,r.timeout),!0}_cleanupTimeout(e){let r=this._timeoutInfo.get(e);r&&(clearTimeout(r.timeoutId),this._timeoutInfo.delete(e))}async connect(e){if(this._transport)throw new Error("Already connected to a transport. Call close() before connecting to a new transport, or use a separate Protocol instance per connection.");this._transport=e;let r=this.transport?.onclose;this._transport.onclose=()=>{r?.(),this._onclose()};let o=this.transport?.onerror;this._transport.onerror=s=>{o?.(s),this._onerror(s)};let n=this._transport?.onmessage;this._transport.onmessage=(s,i)=>{n?.(s,i),gr(s)||Yl(s)?this._onresponse(s):ws(s)?this._onrequest(s,i):Jl(s)?this._onnotification(s):this._onerror(new Error(`Unknown message type: ${JSON.stringify(s)}`))},await this._transport.start()}_onclose(){let e=this._responseHandlers;this._responseHandlers=new Map,this._progressHandlers.clear(),this._taskProgressTokens.clear(),this._pendingDebouncedNotifications.clear();for(let o of this._timeoutInfo.values())clearTimeout(o.timeoutId);this._timeoutInfo.clear();for(let o of this._requestHandlerAbortControllers.values())o.abort();this._requestHandlerAbortControllers.clear();let r=O.fromError(A.ConnectionClosed,"Connection closed");this._transport=void 0,this.onclose?.();for(let o of e.values())o(r)}_onerror(e){this.onerror?.(e)}_onnotification(e){let r=this._notificationHandlers.get(e.method)??this.fallbackNotificationHandler;r!==void 0&&Promise.resolve().then(()=>r(e)).catch(o=>this._onerror(new Error(`Uncaught error in notification handler: ${o}`)))}_onrequest(e,r){let o=this._requestHandlers.get(e.method)??this.fallbackRequestHandler,n=this._transport,s=e.params?._meta?.[nt]?.taskId;if(o===void 0){let l={jsonrpc:"2.0",id:e.id,error:{code:A.MethodNotFound,message:"Method not found"}};s&&this._taskMessageQueue?this._enqueueTaskMessage(s,{type:"error",message:l,timestamp:Date.now()},n?.sessionId).catch(d=>this._onerror(new Error(`Failed to enqueue error response: ${d}`))):n?.send(l).catch(d=>this._onerror(new Error(`Failed to send an error response: ${d}`)));return}let i=new AbortController;this._requestHandlerAbortControllers.set(e.id,i);let a=Bl(e.params)?e.params.task:void 0,c=this._taskStore?this.requestTaskStore(e,n?.sessionId):void 0,u={signal:i.signal,sessionId:n?.sessionId,_meta:e.params?._meta,sendNotification:async l=>{if(i.signal.aborted)return;let d={relatedRequestId:e.id};s&&(d.relatedTask={taskId:s}),await this.notification(l,d)},sendRequest:async(l,d,p)=>{if(i.signal.aborted)throw new O(A.ConnectionClosed,"Request was cancelled");let m={...p,relatedRequestId:e.id};s&&!m.relatedTask&&(m.relatedTask={taskId:s});let g=m.relatedTask?.taskId??s;return g&&c&&await c.updateTaskStatus(g,"input_required"),await this.request(l,d,m)},authInfo:r?.authInfo,requestId:e.id,requestInfo:r?.requestInfo,taskId:s,taskStore:c,taskRequestedTtl:a?.ttl,closeSSEStream:r?.closeSSEStream,closeStandaloneSSEStream:r?.closeStandaloneSSEStream};Promise.resolve().then(()=>{a&&this.assertTaskHandlerCapability(e.method)}).then(()=>o(e,u)).then(async l=>{if(i.signal.aborted)return;let d={result:l,jsonrpc:"2.0",id:e.id};s&&this._taskMessageQueue?await this._enqueueTaskMessage(s,{type:"response",message:d,timestamp:Date.now()},n?.sessionId):await n?.send(d)},async l=>{if(i.signal.aborted)return;let d={jsonrpc:"2.0",id:e.id,error:{code:Number.isSafeInteger(l.code)?l.code:A.InternalError,message:l.message??"Internal error",...l.data!==void 0&&{data:l.data}}};s&&this._taskMessageQueue?await this._enqueueTaskMessage(s,{type:"error",message:d,timestamp:Date.now()},n?.sessionId):await n?.send(d)}).catch(l=>this._onerror(new Error(`Failed to send response: ${l}`))).finally(()=>{this._requestHandlerAbortControllers.get(e.id)===i&&this._requestHandlerAbortControllers.delete(e.id)})}_onprogress(e){let{progressToken:r,...o}=e.params,n=Number(r),s=this._progressHandlers.get(n);if(!s){this._onerror(new Error(`Received a progress notification for an unknown token: ${JSON.stringify(e)}`));return}let i=this._responseHandlers.get(n),a=this._timeoutInfo.get(n);if(a&&i&&a.resetTimeoutOnProgress)try{this._resetTimeout(n)}catch(c){this._responseHandlers.delete(n),this._progressHandlers.delete(n),this._cleanupTimeout(n),i(c);return}s(o)}_onresponse(e){let r=Number(e.id),o=this._requestResolvers.get(r);if(o){if(this._requestResolvers.delete(r),gr(e))o(e);else{let i=new O(e.error.code,e.error.message,e.error.data);o(i)}return}let n=this._responseHandlers.get(r);if(n===void 0){this._onerror(new Error(`Received a response for an unknown message ID: ${JSON.stringify(e)}`));return}this._responseHandlers.delete(r),this._cleanupTimeout(r);let s=!1;if(gr(e)&&e.result&&typeof e.result=="object"){let i=e.result;if(i.task&&typeof i.task=="object"){let a=i.task;typeof a.taskId=="string"&&(s=!0,this._taskProgressTokens.set(a.taskId,r))}}if(s||this._progressHandlers.delete(r),gr(e))n(e);else{let i=O.fromError(e.error.code,e.error.message,e.error.data);n(i)}}get transport(){return this._transport}async close(){await this._transport?.close()}async*requestStream(e,r,o){let{task:n}=o??{};if(!n){try{yield{type:"result",result:await this.request(e,r,o)}}catch(i){yield{type:"error",error:i instanceof O?i:new O(A.InternalError,String(i))}}return}let s;try{let i=await this.request(e,Ct,o);if(i.task)s=i.task.taskId,yield{type:"taskCreated",task:i.task};else throw new O(A.InternalError,"Task creation did not return a task");for(;;){let a=await this.getTask({taskId:s},o);if(yield{type:"taskStatus",task:a},st(a.status)){a.status==="completed"?yield{type:"result",result:await this.getTaskResult({taskId:s},r,o)}:a.status==="failed"?yield{type:"error",error:new O(A.InternalError,`Task ${s} failed`)}:a.status==="cancelled"&&(yield{type:"error",error:new O(A.InternalError,`Task ${s} was cancelled`)});return}if(a.status==="input_required"){yield{type:"result",result:await this.getTaskResult({taskId:s},r,o)};return}let c=a.pollInterval??this._options?.defaultTaskPollInterval??1e3;await new Promise(u=>setTimeout(u,c)),o?.signal?.throwIfAborted()}}catch(i){yield{type:"error",error:i instanceof O?i:new O(A.InternalError,String(i))}}}request(e,r,o){let{relatedRequestId:n,resumptionToken:s,onresumptiontoken:i,task:a,relatedTask:c}=o??{};return new Promise((u,l)=>{let d=b=>{l(b)};if(!this._transport){d(new Error("Not connected"));return}if(this._options?.enforceStrictCapabilities===!0)try{this.assertCapabilityForMethod(e.method),a&&this.assertTaskCapability(e.method)}catch(b){d(b);return}o?.signal?.throwIfAborted();let p=this._requestMessageId++,m={...e,jsonrpc:"2.0",id:p};o?.onprogress&&(this._progressHandlers.set(p,o.onprogress),m.params={...e.params,_meta:{...e.params?._meta||{},progressToken:p}}),a&&(m.params={...m.params,task:a}),c&&(m.params={...m.params,_meta:{...m.params?._meta||{},[nt]:c}});let g=b=>{this._responseHandlers.delete(p),this._progressHandlers.delete(p),this._cleanupTimeout(p),this._transport?.send({jsonrpc:"2.0",method:"notifications/cancelled",params:{requestId:p,reason:String(b)}},{relatedRequestId:n,resumptionToken:s,onresumptiontoken:i}).catch(E=>this._onerror(new Error(`Failed to send cancellation: ${E}`)));let $=b instanceof O?b:new O(A.RequestTimeout,String(b));l($)};this._responseHandlers.set(p,b=>{if(!o?.signal?.aborted){if(b instanceof Error)return l(b);try{let $=ot(r,b.result);$.success?u($.data):l($.error)}catch($){l($)}}}),o?.signal?.addEventListener("abort",()=>{g(o?.signal?.reason)});let _=o?.timeout??S_,y=()=>g(O.fromError(A.RequestTimeout,"Request timed out",{timeout:_}));this._setupTimeout(p,_,o?.maxTotalTimeout,y,o?.resetTimeoutOnProgress??!1);let v=c?.taskId;if(v){let b=$=>{let E=this._responseHandlers.get(p);E?E($):this._onerror(new Error(`Response handler missing for side-channeled request ${p}`))};this._requestResolvers.set(p,b),this._enqueueTaskMessage(v,{type:"request",message:m,timestamp:Date.now()}).catch($=>{this._cleanupTimeout(p),l($)})}else this._transport.send(m,{relatedRequestId:n,resumptionToken:s,onresumptiontoken:i}).catch(b=>{this._cleanupTimeout(p),l(b)})})}async getTask(e,r){return this.request({method:"tasks/get",params:e},Oo,r)}async getTaskResult(e,r,o){return this.request({method:"tasks/result",params:e},r,o)}async listTasks(e,r){return this.request({method:"tasks/list",params:e},No,r)}async cancelTask(e,r){return this.request({method:"tasks/cancel",params:e},ed,r)}async notification(e,r){if(!this._transport)throw new Error("Not connected");this.assertNotificationCapability(e.method);let o=r?.relatedTask?.taskId;if(o){let a={...e,jsonrpc:"2.0",params:{...e.params,_meta:{...e.params?._meta||{},[nt]:r.relatedTask}}};await this._enqueueTaskMessage(o,{type:"notification",message:a,timestamp:Date.now()});return}if((this._options?.debouncedNotificationMethods??[]).includes(e.method)&&!e.params&&!r?.relatedRequestId&&!r?.relatedTask){if(this._pendingDebouncedNotifications.has(e.method))return;this._pendingDebouncedNotifications.add(e.method),Promise.resolve().then(()=>{if(this._pendingDebouncedNotifications.delete(e.method),!this._transport)return;let a={...e,jsonrpc:"2.0"};r?.relatedTask&&(a={...a,params:{...a.params,_meta:{...a.params?._meta||{},[nt]:r.relatedTask}}}),this._transport?.send(a,r).catch(c=>this._onerror(c))});return}let i={...e,jsonrpc:"2.0"};r?.relatedTask&&(i={...i,params:{...i.params,_meta:{...i.params?._meta||{},[nt]:r.relatedTask}}}),await this._transport.send(i,r)}setRequestHandler(e,r){let o=js(e);this.assertRequestHandlerCapability(o),this._requestHandlers.set(o,(n,s)=>{let i=Zs(e,n);return Promise.resolve(r(i,s))})}removeRequestHandler(e){this._requestHandlers.delete(e)}assertCanSetRequestHandler(e){if(this._requestHandlers.has(e))throw new Error(`A request handler for ${e} already exists, which would be overridden`)}setNotificationHandler(e,r){let o=js(e);this._notificationHandlers.set(o,n=>{let s=Zs(e,n);return Promise.resolve(r(s))})}removeNotificationHandler(e){this._notificationHandlers.delete(e)}_cleanupTaskProgressHandler(e){let r=this._taskProgressTokens.get(e);r!==void 0&&(this._progressHandlers.delete(r),this._taskProgressTokens.delete(e))}async _enqueueTaskMessage(e,r,o){if(!this._taskStore||!this._taskMessageQueue)throw new Error("Cannot enqueue task message: taskStore and taskMessageQueue are not configured");let n=this._options?.maxTaskQueueSize;await this._taskMessageQueue.enqueue(e,r,o,n)}async _clearTaskQueue(e,r){if(this._taskMessageQueue){let o=await this._taskMessageQueue.dequeueAll(e,r);for(let n of o)if(n.type==="request"&&ws(n.message)){let s=n.message.id,i=this._requestResolvers.get(s);i?(i(new O(A.InternalError,"Task cancelled or completed")),this._requestResolvers.delete(s)):this._onerror(new Error(`Resolver missing for request ${s} during task ${e} cleanup`))}}}async _waitForTaskUpdate(e,r){let o=this._options?.defaultTaskPollInterval??1e3;try{let n=await this._taskStore?.getTask(e);n?.pollInterval&&(o=n.pollInterval)}catch{}return new Promise((n,s)=>{if(r.aborted){s(new O(A.InvalidRequest,"Request cancelled"));return}let i=setTimeout(n,o);r.addEventListener("abort",()=>{clearTimeout(i),s(new O(A.InvalidRequest,"Request cancelled"))},{once:!0})})}requestTaskStore(e,r){let o=this._taskStore;if(!o)throw new Error("No task store configured");return{createTask:async n=>{if(!e)throw new Error("No request provided");return await o.createTask(n,e.id,{method:e.method,params:e.params},r)},getTask:async n=>{let s=await o.getTask(n,r);if(!s)throw new O(A.InvalidParams,"Failed to retrieve task: Task not found");return s},storeTaskResult:async(n,s,i)=>{await o.storeTaskResult(n,s,i,r);let a=await o.getTask(n,r);if(a){let c=br.parse({method:"notifications/tasks/status",params:a});await this.notification(c),st(a.status)&&this._cleanupTaskProgressHandler(n)}},getTaskResult:n=>o.getTaskResult(n,r),updateTaskStatus:async(n,s,i)=>{let a=await o.getTask(n,r);if(!a)throw new O(A.InvalidParams,`Task "${n}" not found - it may have been cleaned up`);if(st(a.status))throw new O(A.InvalidParams,`Cannot update task "${n}" from terminal status "${a.status}" to "${s}". Terminal states (completed, failed, cancelled) cannot transition to other states.`);await o.updateTaskStatus(n,s,i,r);let c=await o.getTask(n,r);if(c){let u=br.parse({method:"notifications/tasks/status",params:c});await this.notification(u),st(c.status)&&this._cleanupTaskProgressHandler(n)}},listTasks:n=>o.listTasks(n,r)}}};function id(t){return t!==null&&typeof t=="object"&&!Array.isArray(t)}function ad(t,e){let r={...t};for(let o in e){let n=o,s=e[n];if(s===void 0)continue;let i=r[n];id(i)&&id(s)?r[n]={...i,...s}:r[n]=s}return r}var Gf=oo(xa(),1),Wf=oo(Bf(),1);function fS(){let t=new Gf.default({strict:!1,validateFormats:!0,validateSchema:!1,allErrors:!0});return(0,Wf.default)(t),t}var vn=class{constructor(e){this._ajv=e??fS()}getValidator(e){let r="$id"in e&&typeof e.$id=="string"?this._ajv.getSchema(e.$id)??this._ajv.compile(e):this._ajv.compile(e);return o=>r(o)?{valid:!0,data:o,errorMessage:void 0}:{valid:!1,data:void 0,errorMessage:this._ajv.errorsText(r.errors)}}};var $n=class{constructor(e){this._server=e}requestStream(e,r,o){return this._server.requestStream(e,r,o)}createMessageStream(e,r){let o=this._server.getClientCapabilities();if((e.tools||e.toolChoice)&&!o?.sampling?.tools)throw new Error("Client does not support sampling tools capability.");if(e.messages.length>0){let n=e.messages[e.messages.length-1],s=Array.isArray(n.content)?n.content:[n.content],i=s.some(l=>l.type==="tool_result"),a=e.messages.length>1?e.messages[e.messages.length-2]:void 0,c=a?Array.isArray(a.content)?a.content:[a.content]:[],u=c.some(l=>l.type==="tool_use");if(i){if(s.some(l=>l.type!=="tool_result"))throw new Error("The last message must contain only tool_result content if any is present");if(!u)throw new Error("tool_result blocks are not matching any tool_use from the previous message")}if(u){let l=new Set(c.filter(p=>p.type==="tool_use").map(p=>p.id)),d=new Set(s.filter(p=>p.type==="tool_result").map(p=>p.toolUseId));if(l.size!==d.size||![...l].every(p=>d.has(p)))throw new Error("ids of tool_result blocks and tool_use blocks from previous message do not match")}}return this.requestStream({method:"sampling/createMessage",params:e},zr,r)}elicitInputStream(e,r){let o=this._server.getClientCapabilities(),n=e.mode??"form";switch(n){case"url":{if(!o?.elicitation?.url)throw new Error("Client does not support url elicitation.");break}case"form":{if(!o?.elicitation?.form)throw new Error("Client does not support form elicitation.");break}}let s=n==="form"&&e.mode===void 0?{...e,mode:"form"}:e;return this.requestStream({method:"elicitation/create",params:s},Dt,r)}async getTask(e,r){return this._server.getTask({taskId:e},r)}async getTaskResult(e,r,o){return this._server.getTaskResult({taskId:e},r,o)}async listTasks(e,r){return this._server.listTasks(e?{cursor:e}:void 0,r)}async cancelTask(e,r){return this._server.cancelTask({taskId:e},r)}};function Jf(t,e,r){if(!t)throw new Error(`${r} does not support task creation (required for ${e})`);switch(e){case"tools/call":if(!t.tools?.call)throw new Error(`${r} does not support task creation for tools/call (required for ${e})`);break;default:break}}function Yf(t,e,r){if(!t)throw new Error(`${r} does not support task creation (required for ${e})`);switch(e){case"sampling/createMessage":if(!t.sampling?.createMessage)throw new Error(`${r} does not support task creation for sampling/createMessage (required for ${e})`);break;case"elicitation/create":if(!t.elicitation?.create)throw new Error(`${r} does not support task creation for elicitation/create (required for ${e})`);break;default:break}}var bn=class extends Do{constructor(e,r){super(r),this._serverInfo=e,this._loggingLevels=new Map,this.LOG_LEVEL_SEVERITY=new Map(xr.options.map((o,n)=>[o,n])),this.isMessageIgnored=(o,n)=>{let s=this._loggingLevels.get(n);return s?this.LOG_LEVEL_SEVERITY.get(o)this._oninitialize(o)),this.setNotificationHandler(ks,()=>this.oninitialized?.()),this._capabilities.logging&&this.setRequestHandler(As,async(o,n)=>{let s=n.sessionId||n.requestInfo?.headers["mcp-session-id"]||void 0,{level:i}=o.params,a=xr.safeParse(i);return a.success&&this._loggingLevels.set(s,a.data),{}})}get experimental(){return this._experimental||(this._experimental={tasks:new $n(this)}),this._experimental}registerCapabilities(e){if(this.transport)throw new Error("Cannot register capabilities after connecting to transport");this._capabilities=ad(this._capabilities,e)}setRequestHandler(e,r){let n=vo(e)?.method;if(!n)throw new Error("Schema is missing a method literal");let s;if(Rt(n)){let a=n;s=a._zod?.def?.value??a.value}else{let a=n;s=a._def?.value??a.value}if(typeof s!="string")throw new Error("Schema method literal must be a string");if(s==="tools/call"){let a=async(c,u)=>{let l=ot(wr,c);if(!l.success){let g=l.error instanceof Error?l.error.message:String(l.error);throw new O(A.InvalidParams,`Invalid tools/call request: ${g}`)}let{params:d}=l.data,p=await Promise.resolve(r(c,u));if(d.task){let g=ot(Ct,p);if(!g.success){let _=g.error instanceof Error?g.error.message:String(g.error);throw new O(A.InvalidParams,`Invalid task creation result: ${_}`)}return g.data}let m=ot(Ao,p);if(!m.success){let g=m.error instanceof Error?m.error.message:String(m.error);throw new O(A.InvalidParams,`Invalid tools/call result: ${g}`)}return m.data};return super.setRequestHandler(e,a)}return super.setRequestHandler(e,r)}assertCapabilityForMethod(e){switch(e){case"sampling/createMessage":if(!this._clientCapabilities?.sampling)throw new Error(`Client does not support sampling (required for ${e})`);break;case"elicitation/create":if(!this._clientCapabilities?.elicitation)throw new Error(`Client does not support elicitation (required for ${e})`);break;case"roots/list":if(!this._clientCapabilities?.roots)throw new Error(`Client does not support listing roots (required for ${e})`);break;case"ping":break}}assertNotificationCapability(e){switch(e){case"notifications/message":if(!this._capabilities.logging)throw new Error(`Server does not support logging (required for ${e})`);break;case"notifications/resources/updated":case"notifications/resources/list_changed":if(!this._capabilities.resources)throw new Error(`Server does not support notifying about resources (required for ${e})`);break;case"notifications/tools/list_changed":if(!this._capabilities.tools)throw new Error(`Server does not support notifying of tool list changes (required for ${e})`);break;case"notifications/prompts/list_changed":if(!this._capabilities.prompts)throw new Error(`Server does not support notifying of prompt list changes (required for ${e})`);break;case"notifications/elicitation/complete":if(!this._clientCapabilities?.elicitation?.url)throw new Error(`Client does not support URL elicitation (required for ${e})`);break;case"notifications/cancelled":break;case"notifications/progress":break}}assertRequestHandlerCapability(e){if(this._capabilities)switch(e){case"completion/complete":if(!this._capabilities.completions)throw new Error(`Server does not support completions (required for ${e})`);break;case"logging/setLevel":if(!this._capabilities.logging)throw new Error(`Server does not support logging (required for ${e})`);break;case"prompts/get":case"prompts/list":if(!this._capabilities.prompts)throw new Error(`Server does not support prompts (required for ${e})`);break;case"resources/list":case"resources/templates/list":case"resources/read":if(!this._capabilities.resources)throw new Error(`Server does not support resources (required for ${e})`);break;case"tools/call":case"tools/list":if(!this._capabilities.tools)throw new Error(`Server does not support tools (required for ${e})`);break;case"tasks/get":case"tasks/list":case"tasks/result":case"tasks/cancel":if(!this._capabilities.tasks)throw new Error(`Server does not support tasks capability (required for ${e})`);break;case"ping":case"initialize":break}}assertTaskCapability(e){Yf(this._clientCapabilities?.tasks?.requests,e,"Client")}assertTaskHandlerCapability(e){this._capabilities&&Jf(this._capabilities.tasks?.requests,e,"Server")}async _oninitialize(e){let r=e.params.protocolVersion;return this._clientCapabilities=e.params.capabilities,this._clientVersion=e.params.clientInfo,{protocolVersion:Vl.includes(r)?r:bs,capabilities:this.getCapabilities(),serverInfo:this._serverInfo,...this._instructions&&{instructions:this._instructions}}}getClientCapabilities(){return this._clientCapabilities}getClientVersion(){return this._clientVersion}getCapabilities(){return this._capabilities}async ping(){return this.request({method:"ping"},zo)}async createMessage(e,r){if((e.tools||e.toolChoice)&&!this._clientCapabilities?.sampling?.tools)throw new Error("Client does not support sampling tools capability.");if(e.messages.length>0){let o=e.messages[e.messages.length-1],n=Array.isArray(o.content)?o.content:[o.content],s=n.some(u=>u.type==="tool_result"),i=e.messages.length>1?e.messages[e.messages.length-2]:void 0,a=i?Array.isArray(i.content)?i.content:[i.content]:[],c=a.some(u=>u.type==="tool_use");if(s){if(n.some(u=>u.type!=="tool_result"))throw new Error("The last message must contain only tool_result content if any is present");if(!c)throw new Error("tool_result blocks are not matching any tool_use from the previous message")}if(c){let u=new Set(a.filter(d=>d.type==="tool_use").map(d=>d.id)),l=new Set(n.filter(d=>d.type==="tool_result").map(d=>d.toolUseId));if(u.size!==l.size||![...u].every(d=>l.has(d)))throw new Error("ids of tool_result blocks and tool_use blocks from previous message do not match")}}return e.tools?this.request({method:"sampling/createMessage",params:e},Ds,r):this.request({method:"sampling/createMessage",params:e},zr,r)}async elicitInput(e,r){switch(e.mode??"form"){case"url":{if(!this._clientCapabilities?.elicitation?.url)throw new Error("Client does not support url elicitation.");let n=e;return this.request({method:"elicitation/create",params:n},Dt,r)}case"form":{if(!this._clientCapabilities?.elicitation?.form)throw new Error("Client does not support form elicitation.");let n=e.mode==="form"?e:{...e,mode:"form"},s=await this.request({method:"elicitation/create",params:n},Dt,r);if(s.action==="accept"&&s.content&&n.requestedSchema)try{let a=this._jsonSchemaValidator.getValidator(n.requestedSchema)(s.content);if(!a.valid)throw new O(A.InvalidParams,`Elicitation response content does not match requested schema: ${a.errorMessage}`)}catch(i){throw i instanceof O?i:new O(A.InternalError,`Error validating elicitation response: ${i instanceof Error?i.message:String(i)}`)}return s}}}createElicitationCompletionNotifier(e,r){if(!this._clientCapabilities?.elicitation?.url)throw new Error("Client does not support URL elicitation (required for notifications/elicitation/complete)");return()=>this.notification({method:"notifications/elicitation/complete",params:{elicitationId:e}},r)}async listRoots(e,r){return this.request({method:"roots/list",params:e},Ls,r)}async sendLoggingMessage(e,r){if(this._capabilities.logging&&!this.isMessageIgnored(e.level,r))return this.notification({method:"notifications/message",params:e})}async sendResourceUpdated(e){return this.notification({method:"notifications/resources/updated",params:e})}async sendResourceListChanged(){return this.notification({method:"notifications/resources/list_changed"})}async sendToolListChanged(){return this.notification({method:"notifications/tools/list_changed"})}async sendPromptListChanged(){return this.notification({method:"notifications/prompts/list_changed"})}};var Ra=oo(require("node:process"),1);var Sn=class{append(e){this._buffer=this._buffer?Buffer.concat([this._buffer,e]):e}readMessage(){if(!this._buffer)return null;let e=this._buffer.indexOf(`
`);if(e===-1)return null;let r=this._buffer.toString("utf8",0,e).replace(/\r$/,"");return this._buffer=this._buffer.subarray(e+1),mS(r)}clear(){this._buffer=void 0}};function mS(t){return Xl.parse(JSON.parse(t))}function Xf(t){return JSON.stringify(t)+`
-`}var wn=class{constructor(e=Ra.default.stdin,r=Ra.default.stdout){this._stdin=e,this._stdout=r,this._readBuffer=new Sn,this._started=!1,this._ondata=o=>{this._readBuffer.append(o),this.processReadBuffer()},this._onerror=o=>{this.onerror?.(o)}}async start(){if(this._started)throw new Error("StdioServerTransport already started! If using Server class, note that connect() calls start() automatically.");this._started=!0,this._stdin.on("data",this._ondata),this._stdin.on("error",this._onerror)}processReadBuffer(){for(;;)try{let e=this._readBuffer.readMessage();if(e===null)break;this.onmessage?.(e)}catch(e){this.onerror?.(e)}}async close(){this._stdin.off("data",this._ondata),this._stdin.off("error",this._onerror),this._stdin.listenerCount("data")===0&&this._stdin.pause(),this._readBuffer.clear(),this.onclose?.()}send(e){return new Promise(r=>{let o=Xf(e);this._stdout.write(o)?r():this._stdout.once("drain",r)})}};var Na=oo(require("path"),1);var Ze=require("fs"),xn=require("path"),tm=require("os");var Qf="bugfix,feature,refactor,discovery,decision,change",em="how-it-works,why-it-exists,what-changed,problem-solution,gotcha,pattern,trade-off";var kt=class{static DEFAULTS={CLAUDE_PILOT_MODEL:"haiku",CLAUDE_PILOT_CONTEXT_OBSERVATIONS:"50",CLAUDE_PILOT_WORKER_PORT:"41777",CLAUDE_PILOT_WORKER_HOST:"127.0.0.1",CLAUDE_PILOT_WORKER_BIND:"127.0.0.1",CLAUDE_PILOT_SKIP_TOOLS:"ListMcpResourcesTool,SlashCommand,Skill,TodoWrite,AskUserQuestion",CLAUDE_PILOT_DATA_DIR:(0,xn.join)((0,tm.homedir)(),".pilot/memory"),CLAUDE_PILOT_LOG_LEVEL:"INFO",CLAUDE_PILOT_PYTHON_VERSION:"3.12",CLAUDE_CODE_PATH:"",CLAUDE_PILOT_CONTEXT_SHOW_READ_TOKENS:!1,CLAUDE_PILOT_CONTEXT_SHOW_WORK_TOKENS:!1,CLAUDE_PILOT_CONTEXT_SHOW_SAVINGS_AMOUNT:!1,CLAUDE_PILOT_CONTEXT_SHOW_SAVINGS_PERCENT:!1,CLAUDE_PILOT_CONTEXT_OBSERVATION_TYPES:Qf,CLAUDE_PILOT_CONTEXT_OBSERVATION_CONCEPTS:em,CLAUDE_PILOT_CONTEXT_FULL_COUNT:"10",CLAUDE_PILOT_CONTEXT_FULL_FIELD:"facts",CLAUDE_PILOT_CONTEXT_SESSION_COUNT:"10",CLAUDE_PILOT_CONTEXT_SHOW_LAST_SUMMARY:!0,CLAUDE_PILOT_CONTEXT_SHOW_LAST_MESSAGE:!0,CLAUDE_PILOT_FOLDER_CLAUDEMD_ENABLED:!1,CLAUDE_PILOT_FOLDER_MD_EXCLUDE:"[]",CLAUDE_PILOT_CHROMA_ENABLED:!0,CLAUDE_PILOT_VECTOR_DB:"chroma",CLAUDE_PILOT_EMBEDDING_MODEL:"Xenova/all-MiniLM-L6-v2",CLAUDE_PILOT_EXCLUDE_PROJECTS:"[]",CLAUDE_PILOT_REMOTE_TOKEN:"",CLAUDE_PILOT_RETENTION_ENABLED:!0,CLAUDE_PILOT_RETENTION_MAX_AGE_DAYS:"31",CLAUDE_PILOT_RETENTION_MAX_COUNT:"5000",CLAUDE_PILOT_RETENTION_EXCLUDE_TYPES:'["summary"]',CLAUDE_PILOT_RETENTION_SOFT_DELETE:!1,CLAUDE_PILOT_BATCH_SIZE:"5",CLAUDE_PILOT_VECTOR_DB_MAX_PHYSICAL_MB:"2048",CLAUDE_PILOT_VECTOR_DB_MAX_LOGICAL_MB:"51200"};static getAllDefaults(){return{...this.DEFAULTS}}static get(e){return this.DEFAULTS[e]}static getInt(e){let r=this.get(e);return parseInt(r,10)}static getBool(e){return this.get(e)==="true"}static loadFromFile(e){try{if(!(0,Ze.existsSync)(e)){let c=this.getAllDefaults();try{let u=(0,xn.dirname)(e);(0,Ze.existsSync)(u)||(0,Ze.mkdirSync)(u,{recursive:!0}),(0,Ze.writeFileSync)(e,JSON.stringify(c,null,2),"utf-8"),console.log("[SETTINGS] Created settings file with defaults:",e)}catch(u){console.warn("[SETTINGS] Failed to create settings file, using in-memory defaults:",e,u)}return c}let r=(0,Ze.readFileSync)(e,"utf-8"),o=JSON.parse(r),n=o;if(o.env&&typeof o.env=="object"){n=o.env;try{(0,Ze.writeFileSync)(e,JSON.stringify(n,null,2),"utf-8"),console.log("[SETTINGS] Migrated settings file from nested to flat schema:",e)}catch(c){console.warn("[SETTINGS] Failed to auto-migrate settings file:",e,c)}}let s=["CLAUDE_PILOT_CONTEXT_SHOW_READ_TOKENS","CLAUDE_PILOT_CONTEXT_SHOW_WORK_TOKENS","CLAUDE_PILOT_CONTEXT_SHOW_SAVINGS_AMOUNT","CLAUDE_PILOT_CONTEXT_SHOW_SAVINGS_PERCENT","CLAUDE_PILOT_CONTEXT_SHOW_LAST_SUMMARY","CLAUDE_PILOT_CONTEXT_SHOW_LAST_MESSAGE","CLAUDE_PILOT_FOLDER_CLAUDEMD_ENABLED","CLAUDE_PILOT_CHROMA_ENABLED","CLAUDE_PILOT_RETENTION_ENABLED","CLAUDE_PILOT_RETENTION_SOFT_DELETE"],i={...this.DEFAULTS},a=!1;for(let c of Object.keys(this.DEFAULTS))if(n[c]!==void 0)if(s.includes(c)){let u=n[c];typeof u=="string"?(i[c]=u==="true",a=!0):i[c]=u}else i[c]=n[c];if(a)try{(0,Ze.writeFileSync)(e,JSON.stringify(i,null,2),"utf-8"),console.log("[SETTINGS] Migrated boolean settings from strings to actual booleans:",e)}catch(c){console.warn("[SETTINGS] Failed to auto-migrate boolean settings:",e,c)}return i}catch(r){return console.warn("[SETTINGS] Failed to load settings, using defaults:",e,r),this.getAllDefaults()}}};var zn=null,En=null;function rm(){if(zn!==null)return zn;let t=Na.default.join(kt.get("CLAUDE_PILOT_DATA_DIR"),"settings.json"),e=kt.loadFromFile(t);return zn=parseInt(e.CLAUDE_PILOT_WORKER_PORT,10),zn}function om(){if(En!==null)return En;let t=Na.default.join(kt.get("CLAUDE_PILOT_DATA_DIR"),"settings.json");return En=kt.loadFromFile(t).CLAUDE_PILOT_WORKER_HOST,En}var hS="8.4.0";console.log=(...t)=>{se.error("CONSOLE","Intercepted console output (MCP protocol protection)",void 0,{args:t})};var gS=rm(),_S=om(),ro=`http://${_S}:${gS}`,nm={search:"/api/search",timeline:"/api/timeline"};async function sm(t,e){se.debug("SYSTEM","\u2192 Worker API",void 0,{endpoint:t,params:e});try{let r=new URLSearchParams;for(let[i,a]of Object.entries(e))a!=null&&r.append(i,String(a));let o=`${ro}${t}?${r}`,n=await fetch(o);if(!n.ok){let i=await n.text();throw new Error(`Worker API error (${n.status}): ${i}`)}let s=await n.json();return se.debug("SYSTEM","\u2190 Worker API success",void 0,{endpoint:t}),s}catch(r){return se.error("SYSTEM","\u2190 Worker API error",{endpoint:t},r),{content:[{type:"text",text:`Error calling Worker API: ${r instanceof Error?r.message:String(r)}`}],isError:!0}}}async function im(t,e){se.debug("HTTP","Worker API request (POST)",void 0,{endpoint:t});try{let r=`${ro}${t}`,o=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)});if(!o.ok){let s=await o.text();throw new Error(`Worker API error (${o.status}): ${s}`)}let n=await o.json();return se.debug("HTTP","Worker API success (POST)",void 0,{endpoint:t}),{content:[{type:"text",text:JSON.stringify(n,null,2)}]}}catch(r){return se.error("HTTP","Worker API error (POST)",{endpoint:t},r),{content:[{type:"text",text:`Error calling Worker API: ${r instanceof Error?r.message:String(r)}`}],isError:!0}}}async function yS(){try{return(await fetch(`${ro}/api/health`)).ok}catch(t){return se.debug("SYSTEM","Worker health check failed",{},t),!1}}var am=[{name:"__IMPORTANT",description:`3-LAYER WORKFLOW (ALWAYS FOLLOW):
+`}var wn=class{constructor(e=Ra.default.stdin,r=Ra.default.stdout){this._stdin=e,this._stdout=r,this._readBuffer=new Sn,this._started=!1,this._ondata=o=>{this._readBuffer.append(o),this.processReadBuffer()},this._onerror=o=>{this.onerror?.(o)}}async start(){if(this._started)throw new Error("StdioServerTransport already started! If using Server class, note that connect() calls start() automatically.");this._started=!0,this._stdin.on("data",this._ondata),this._stdin.on("error",this._onerror)}processReadBuffer(){for(;;)try{let e=this._readBuffer.readMessage();if(e===null)break;this.onmessage?.(e)}catch(e){this.onerror?.(e)}}async close(){this._stdin.off("data",this._ondata),this._stdin.off("error",this._onerror),this._stdin.listenerCount("data")===0&&this._stdin.pause(),this._readBuffer.clear(),this.onclose?.()}send(e){return new Promise(r=>{let o=Xf(e);this._stdout.write(o)?r():this._stdout.once("drain",r)})}};var Na=oo(require("path"),1);var Ze=require("fs"),xn=require("path"),tm=require("os");var Qf="bugfix,feature,refactor,discovery,decision,change",em="how-it-works,why-it-exists,what-changed,problem-solution,gotcha,pattern,trade-off";var kt=class{static DEFAULTS={CLAUDE_PILOT_MODEL:"haiku",CLAUDE_PILOT_CONTEXT_OBSERVATIONS:"50",CLAUDE_PILOT_WORKER_PORT:"41777",CLAUDE_PILOT_WORKER_HOST:"127.0.0.1",CLAUDE_PILOT_WORKER_BIND:"127.0.0.1",CLAUDE_PILOT_SKIP_TOOLS:"ListMcpResourcesTool,SlashCommand,Skill,TodoWrite,AskUserQuestion",CLAUDE_PILOT_DATA_DIR:(0,xn.join)((0,tm.homedir)(),".pilot/memory"),CLAUDE_PILOT_LOG_LEVEL:"INFO",CLAUDE_PILOT_PYTHON_VERSION:"3.12",CLAUDE_CODE_PATH:"",CLAUDE_PILOT_CONTEXT_SHOW_READ_TOKENS:!1,CLAUDE_PILOT_CONTEXT_SHOW_WORK_TOKENS:!1,CLAUDE_PILOT_CONTEXT_SHOW_SAVINGS_AMOUNT:!1,CLAUDE_PILOT_CONTEXT_SHOW_SAVINGS_PERCENT:!1,CLAUDE_PILOT_CONTEXT_OBSERVATION_TYPES:Qf,CLAUDE_PILOT_CONTEXT_OBSERVATION_CONCEPTS:em,CLAUDE_PILOT_CONTEXT_FULL_COUNT:"10",CLAUDE_PILOT_CONTEXT_FULL_FIELD:"facts",CLAUDE_PILOT_CONTEXT_SESSION_COUNT:"10",CLAUDE_PILOT_CONTEXT_SHOW_LAST_SUMMARY:!0,CLAUDE_PILOT_CONTEXT_SHOW_LAST_MESSAGE:!0,CLAUDE_PILOT_FOLDER_CLAUDEMD_ENABLED:!1,CLAUDE_PILOT_FOLDER_MD_EXCLUDE:"[]",CLAUDE_PILOT_CHROMA_ENABLED:!0,CLAUDE_PILOT_VECTOR_DB:"chroma",CLAUDE_PILOT_EMBEDDING_MODEL:"Xenova/all-MiniLM-L6-v2",CLAUDE_PILOT_EXCLUDE_PROJECTS:"[]",CLAUDE_PILOT_REMOTE_TOKEN:"",CLAUDE_PILOT_RETENTION_ENABLED:!0,CLAUDE_PILOT_RETENTION_MAX_AGE_DAYS:"31",CLAUDE_PILOT_RETENTION_MAX_COUNT:"5000",CLAUDE_PILOT_RETENTION_EXCLUDE_TYPES:'["summary"]',CLAUDE_PILOT_RETENTION_SOFT_DELETE:!1,CLAUDE_PILOT_BATCH_SIZE:"5",CLAUDE_PILOT_VECTOR_DB_MAX_PHYSICAL_MB:"2048",CLAUDE_PILOT_VECTOR_DB_MAX_LOGICAL_MB:"51200"};static getAllDefaults(){return{...this.DEFAULTS}}static get(e){return this.DEFAULTS[e]}static getInt(e){let r=this.get(e);return parseInt(r,10)}static getBool(e){return this.get(e)==="true"}static loadFromFile(e){try{if(!(0,Ze.existsSync)(e)){let c=this.getAllDefaults();try{let u=(0,xn.dirname)(e);(0,Ze.existsSync)(u)||(0,Ze.mkdirSync)(u,{recursive:!0}),(0,Ze.writeFileSync)(e,JSON.stringify(c,null,2),"utf-8"),console.log("[SETTINGS] Created settings file with defaults:",e)}catch(u){console.warn("[SETTINGS] Failed to create settings file, using in-memory defaults:",e,u)}return c}let r=(0,Ze.readFileSync)(e,"utf-8"),o=JSON.parse(r),n=o;if(o.env&&typeof o.env=="object"){n=o.env;try{(0,Ze.writeFileSync)(e,JSON.stringify(n,null,2),"utf-8"),console.log("[SETTINGS] Migrated settings file from nested to flat schema:",e)}catch(c){console.warn("[SETTINGS] Failed to auto-migrate settings file:",e,c)}}let s=["CLAUDE_PILOT_CONTEXT_SHOW_READ_TOKENS","CLAUDE_PILOT_CONTEXT_SHOW_WORK_TOKENS","CLAUDE_PILOT_CONTEXT_SHOW_SAVINGS_AMOUNT","CLAUDE_PILOT_CONTEXT_SHOW_SAVINGS_PERCENT","CLAUDE_PILOT_CONTEXT_SHOW_LAST_SUMMARY","CLAUDE_PILOT_CONTEXT_SHOW_LAST_MESSAGE","CLAUDE_PILOT_FOLDER_CLAUDEMD_ENABLED","CLAUDE_PILOT_CHROMA_ENABLED","CLAUDE_PILOT_RETENTION_ENABLED","CLAUDE_PILOT_RETENTION_SOFT_DELETE"],i={...this.DEFAULTS},a=!1;for(let c of Object.keys(this.DEFAULTS))if(n[c]!==void 0)if(s.includes(c)){let u=n[c];typeof u=="string"?(i[c]=u==="true",a=!0):i[c]=u}else i[c]=n[c];if(a)try{(0,Ze.writeFileSync)(e,JSON.stringify(i,null,2),"utf-8"),console.log("[SETTINGS] Migrated boolean settings from strings to actual booleans:",e)}catch(c){console.warn("[SETTINGS] Failed to auto-migrate boolean settings:",e,c)}return i}catch(r){return console.warn("[SETTINGS] Failed to load settings, using defaults:",e,r),this.getAllDefaults()}}};var zn=null,En=null;function rm(){if(zn!==null)return zn;let t=Na.default.join(kt.get("CLAUDE_PILOT_DATA_DIR"),"settings.json"),e=kt.loadFromFile(t);return zn=parseInt(e.CLAUDE_PILOT_WORKER_PORT,10),zn}function om(){if(En!==null)return En;let t=Na.default.join(kt.get("CLAUDE_PILOT_DATA_DIR"),"settings.json");return En=kt.loadFromFile(t).CLAUDE_PILOT_WORKER_HOST,En}var hS="8.4.1";console.log=(...t)=>{se.error("CONSOLE","Intercepted console output (MCP protocol protection)",void 0,{args:t})};var gS=rm(),_S=om(),ro=`http://${_S}:${gS}`,nm={search:"/api/search",timeline:"/api/timeline"};async function sm(t,e){se.debug("SYSTEM","\u2192 Worker API",void 0,{endpoint:t,params:e});try{let r=new URLSearchParams;for(let[i,a]of Object.entries(e))a!=null&&r.append(i,String(a));let o=`${ro}${t}?${r}`,n=await fetch(o);if(!n.ok){let i=await n.text();throw new Error(`Worker API error (${n.status}): ${i}`)}let s=await n.json();return se.debug("SYSTEM","\u2190 Worker API success",void 0,{endpoint:t}),s}catch(r){return se.error("SYSTEM","\u2190 Worker API error",{endpoint:t},r),{content:[{type:"text",text:`Error calling Worker API: ${r instanceof Error?r.message:String(r)}`}],isError:!0}}}async function im(t,e){se.debug("HTTP","Worker API request (POST)",void 0,{endpoint:t});try{let r=`${ro}${t}`,o=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)});if(!o.ok){let s=await o.text();throw new Error(`Worker API error (${o.status}): ${s}`)}let n=await o.json();return se.debug("HTTP","Worker API success (POST)",void 0,{endpoint:t}),{content:[{type:"text",text:JSON.stringify(n,null,2)}]}}catch(r){return se.error("HTTP","Worker API error (POST)",{endpoint:t},r),{content:[{type:"text",text:`Error calling Worker API: ${r instanceof Error?r.message:String(r)}`}],isError:!0}}}async function yS(){try{return(await fetch(`${ro}/api/health`)).ok}catch(t){return se.debug("SYSTEM","Worker health check failed",{},t),!1}}var am=[{name:"__IMPORTANT",description:`3-LAYER WORKFLOW (ALWAYS FOLLOW):
1. search(query) \u2192 Get index with IDs (~50-100 tokens/result)
2. timeline(anchor=ID) \u2192 Get context around interesting results
3. get_observations([IDs]) \u2192 Fetch full details ONLY for filtered IDs
diff --git a/pilot/scripts/worker-service.cjs b/pilot/scripts/worker-service.cjs
index 58a1935d..099972a7 100755
--- a/pilot/scripts/worker-service.cjs
+++ b/pilot/scripts/worker-service.cjs
@@ -953,7 +953,7 @@ ${Y.dim}No previous sessions found for this project yet.${Y.reset}
path: iss.path ? [${aa(y)}, ...iss.path] : [${aa(y)}]
})));`),d.write(`newResult[${aa(y)}] = ${b}.value`)}d.write("payload.value = newResult;"),d.write("return payload;");let h=d.compile();return(y,b)=>h(p,y,b)},s,i=bo,a=!Pm.jitless,c=a&&Kb.value,l=e.catchall,u;t._zod.parse=(p,d)=>{u??(u=r.value);let m=p.value;if(!i(m))return p.issues.push({expected:"object",code:"invalid_type",input:m,inst:t}),p;let f=[];if(a&&c&&d?.async===!1&&d.jitless!==!0)s||(s=n(e.shape)),p=s(p,d);else{p.value={};let b=u.shape;for(let x of u.keys){let w=b[x],S=w._zod.run({value:m[x],issues:[]},d),k=w._zod.optin==="optional"&&w._zod.optout==="optional";S instanceof Promise?f.push(S.then(E=>k?dI(E,p,x,m):Dm(E,p,x))):k?dI(S,p,x,m):Dm(S,p,x)}}if(!l)return f.length?Promise.all(f).then(()=>p):p;let g=[],v=u.keySet,h=l._zod,y=h.def.type;for(let b of Object.keys(m)){if(v.has(b))continue;if(y==="never"){g.push(b);continue}let x=h.run({value:m[b],issues:[]},d);x instanceof Promise?f.push(x.then(w=>Dm(w,p,b))):Dm(x,p,b)}return g.length&&p.issues.push({code:"unrecognized_keys",keys:g,input:m,inst:t}),f.length?Promise.all(f).then(()=>p):p}});function mI(t,e,r,n){for(let s of t)if(s.issues.length===0)return e.value=s.value,e;return e.issues.push({code:"invalid_union",input:e.value,inst:r,errors:t.map(s=>s.issues.map(i=>ts(i,n,jn())))}),e}var ux=F("$ZodUnion",(t,e)=>{wt.init(t,e),_t(t._zod,"optin",()=>e.options.some(r=>r._zod.optin==="optional")?"optional":void 0),_t(t._zod,"optout",()=>e.options.some(r=>r._zod.optout==="optional")?"optional":void 0),_t(t._zod,"values",()=>{if(e.options.every(r=>r._zod.values))return new Set(e.options.flatMap(r=>Array.from(r._zod.values)))}),_t(t._zod,"pattern",()=>{if(e.options.every(r=>r._zod.pattern)){let r=e.options.map(n=>n._zod.pattern);return new RegExp(`^(${r.map(n=>Fl(n.source)).join("|")})$`)}}),t._zod.parse=(r,n)=>{let s=!1,i=[];for(let a of e.options){let o=a._zod.run({value:r.value,issues:[]},n);if(o instanceof Promise)i.push(o),s=!0;else{if(o.issues.length===0)return o;i.push(o)}}return s?Promise.all(i).then(a=>mI(a,r,t,n)):mI(i,r,t,n)}}),QI=F("$ZodDiscriminatedUnion",(t,e)=>{ux.init(t,e);let r=t._zod.parse;_t(t._zod,"propValues",()=>{let s={};for(let i of e.options){let a=i._zod.propValues;if(!a||Object.keys(a).length===0)throw new Error(`Invalid discriminated union option at index "${e.options.indexOf(i)}"`);for(let[o,c]of Object.entries(a)){s[o]||(s[o]=new Set);for(let l of c)s[o].add(l)}}return s});let n=Ul(()=>{let s=e.options,i=new Map;for(let a of s){let o=a._zod.propValues[e.discriminator];if(!o||o.size===0)throw new Error(`Invalid discriminated union option at index "${e.options.indexOf(a)}"`);for(let c of o){if(i.has(c))throw new Error(`Duplicate discriminator value "${String(c)}"`);i.set(c,a)}}return i});t._zod.parse=(s,i)=>{let a=s.value;if(!bo(a))return s.issues.push({code:"invalid_type",expected:"object",input:a,inst:t}),s;let o=n.value.get(a?.[e.discriminator]);return o?o._zod.run(s,i):e.unionFallback?r(s,i):(s.issues.push({code:"invalid_union",errors:[],note:"No matching discriminator",input:a,path:[e.discriminator],inst:t}),s)}}),YI=F("$ZodIntersection",(t,e)=>{wt.init(t,e),t._zod.parse=(r,n)=>{let s=r.value,i=e.left._zod.run({value:s,issues:[]},n),a=e.right._zod.run({value:s,issues:[]},n);return i instanceof Promise||a instanceof Promise?Promise.all([i,a]).then(([c,l])=>fI(r,c,l)):fI(r,i,a)}});function cx(t,e){if(t===e)return{valid:!0,data:t};if(t instanceof Date&&e instanceof Date&&+t==+e)return{valid:!0,data:t};if(xo(t)&&xo(e)){let r=Object.keys(e),n=Object.keys(t).filter(i=>r.indexOf(i)!==-1),s={...t,...e};for(let i of n){let a=cx(t[i],e[i]);if(!a.valid)return{valid:!1,mergeErrorPath:[i,...a.mergeErrorPath]};s[i]=a.data}return{valid:!0,data:s}}if(Array.isArray(t)&&Array.isArray(e)){if(t.length!==e.length)return{valid:!1,mergeErrorPath:[]};let r=[];for(let n=0;n{wt.init(t,e),t._zod.parse=(r,n)=>{let s=r.value;if(!xo(s))return r.issues.push({expected:"record",code:"invalid_type",input:s,inst:t}),r;let i=[];if(e.keyType._zod.values){let a=e.keyType._zod.values;r.value={};for(let c of a)if(typeof c=="string"||typeof c=="number"||typeof c=="symbol"){let l=e.valueType._zod.run({value:s[c],issues:[]},n);l instanceof Promise?i.push(l.then(u=>{u.issues.length&&r.issues.push(...Ts(c,u.issues)),r.value[c]=u.value})):(l.issues.length&&r.issues.push(...Ts(c,l.issues)),r.value[c]=l.value)}let o;for(let c in s)a.has(c)||(o=o??[],o.push(c));o&&o.length>0&&r.issues.push({code:"unrecognized_keys",input:s,inst:t,keys:o})}else{r.value={};for(let a of Reflect.ownKeys(s)){if(a==="__proto__")continue;let o=e.keyType._zod.run({value:a,issues:[]},n);if(o instanceof Promise)throw new Error("Async schemas not supported in object keys currently");if(o.issues.length){r.issues.push({origin:"record",code:"invalid_key",issues:o.issues.map(l=>ts(l,n,jn())),input:a,path:[a],inst:t}),r.value[o.value]=o.value;continue}let c=e.valueType._zod.run({value:s[a],issues:[]},n);c instanceof Promise?i.push(c.then(l=>{l.issues.length&&r.issues.push(...Ts(a,l.issues)),r.value[o.value]=l.value})):(c.issues.length&&r.issues.push(...Ts(a,c.issues)),r.value[o.value]=c.value)}}return i.length?Promise.all(i).then(()=>r):r}});var eC=F("$ZodEnum",(t,e)=>{wt.init(t,e);let r=Wb(e.entries);t._zod.values=new Set(r),t._zod.pattern=new RegExp(`^(${r.filter(n=>Jb.has(typeof n)).map(n=>typeof n=="string"?xi(n):n.toString()).join("|")})$`),t._zod.parse=(n,s)=>{let i=n.value;return t._zod.values.has(i)||n.issues.push({code:"invalid_value",values:r,input:i,inst:t}),n}}),tC=F("$ZodLiteral",(t,e)=>{wt.init(t,e),t._zod.values=new Set(e.values),t._zod.pattern=new RegExp(`^(${e.values.map(r=>typeof r=="string"?xi(r):r?r.toString():String(r)).join("|")})$`),t._zod.parse=(r,n)=>{let s=r.value;return t._zod.values.has(s)||r.issues.push({code:"invalid_value",values:e.values,input:s,inst:t}),r}});var rC=F("$ZodTransform",(t,e)=>{wt.init(t,e),t._zod.parse=(r,n)=>{let s=e.transform(r.value,r);if(n.async)return(s instanceof Promise?s:Promise.resolve(s)).then(a=>(r.value=a,r));if(s instanceof Promise)throw new Ks;return r.value=s,r}}),nC=F("$ZodOptional",(t,e)=>{wt.init(t,e),t._zod.optin="optional",t._zod.optout="optional",_t(t._zod,"values",()=>e.innerType._zod.values?new Set([...e.innerType._zod.values,void 0]):void 0),_t(t._zod,"pattern",()=>{let r=e.innerType._zod.pattern;return r?new RegExp(`^(${Fl(r.source)})?$`):void 0}),t._zod.parse=(r,n)=>e.innerType._zod.optin==="optional"?e.innerType._zod.run(r,n):r.value===void 0?r:e.innerType._zod.run(r,n)}),sC=F("$ZodNullable",(t,e)=>{wt.init(t,e),_t(t._zod,"optin",()=>e.innerType._zod.optin),_t(t._zod,"optout",()=>e.innerType._zod.optout),_t(t._zod,"pattern",()=>{let r=e.innerType._zod.pattern;return r?new RegExp(`^(${Fl(r.source)}|null)$`):void 0}),_t(t._zod,"values",()=>e.innerType._zod.values?new Set([...e.innerType._zod.values,null]):void 0),t._zod.parse=(r,n)=>r.value===null?r:e.innerType._zod.run(r,n)}),iC=F("$ZodDefault",(t,e)=>{wt.init(t,e),t._zod.optin="optional",_t(t._zod,"values",()=>e.innerType._zod.values),t._zod.parse=(r,n)=>{if(r.value===void 0)return r.value=e.defaultValue,r;let s=e.innerType._zod.run(r,n);return s instanceof Promise?s.then(i=>hI(i,e)):hI(s,e)}});function hI(t,e){return t.value===void 0&&(t.value=e.defaultValue),t}var aC=F("$ZodPrefault",(t,e)=>{wt.init(t,e),t._zod.optin="optional",_t(t._zod,"values",()=>e.innerType._zod.values),t._zod.parse=(r,n)=>(r.value===void 0&&(r.value=e.defaultValue),e.innerType._zod.run(r,n))}),oC=F("$ZodNonOptional",(t,e)=>{wt.init(t,e),_t(t._zod,"values",()=>{let r=e.innerType._zod.values;return r?new Set([...r].filter(n=>n!==void 0)):void 0}),t._zod.parse=(r,n)=>{let s=e.innerType._zod.run(r,n);return s instanceof Promise?s.then(i=>gI(i,t)):gI(s,t)}});function gI(t,e){return!t.issues.length&&t.value===void 0&&t.issues.push({code:"invalid_type",expected:"nonoptional",input:t.value,inst:e}),t}var cC=F("$ZodCatch",(t,e)=>{wt.init(t,e),t._zod.optin="optional",_t(t._zod,"optout",()=>e.innerType._zod.optout),_t(t._zod,"values",()=>e.innerType._zod.values),t._zod.parse=(r,n)=>{let s=e.innerType._zod.run(r,n);return s instanceof Promise?s.then(i=>(r.value=i.value,i.issues.length&&(r.value=e.catchValue({...r,error:{issues:i.issues.map(a=>ts(a,n,jn()))},input:r.value}),r.issues=[]),r)):(r.value=s.value,s.issues.length&&(r.value=e.catchValue({...r,error:{issues:s.issues.map(i=>ts(i,n,jn()))},input:r.value}),r.issues=[]),r)}});var lC=F("$ZodPipe",(t,e)=>{wt.init(t,e),_t(t._zod,"values",()=>e.in._zod.values),_t(t._zod,"optin",()=>e.in._zod.optin),_t(t._zod,"optout",()=>e.out._zod.optout),t._zod.parse=(r,n)=>{let s=e.in._zod.run(r,n);return s instanceof Promise?s.then(i=>vI(i,e,n)):vI(s,e,n)}});function vI(t,e,r){return oa(t)?t:e.out._zod.run({value:t.value,issues:t.issues},r)}var uC=F("$ZodReadonly",(t,e)=>{wt.init(t,e),_t(t._zod,"propValues",()=>e.innerType._zod.propValues),_t(t._zod,"values",()=>e.innerType._zod.values),_t(t._zod,"optin",()=>e.innerType._zod.optin),_t(t._zod,"optout",()=>e.innerType._zod.optout),t._zod.parse=(r,n)=>{let s=e.innerType._zod.run(r,n);return s instanceof Promise?s.then(yI):yI(s)}});function yI(t){return t.value=Object.freeze(t.value),t}var pC=F("$ZodCustom",(t,e)=>{Or.init(t,e),wt.init(t,e),t._zod.parse=(r,n)=>r,t._zod.check=r=>{let n=r.value,s=e.fn(n);if(s instanceof Promise)return s.then(i=>bI(i,r,n,t));bI(s,r,n,t)}});function bI(t,e,r,n){if(!t){let s={code:"custom",input:r,inst:n,path:[...n._zod.def.path??[]],continue:!n._zod.def.abort};n._zod.def.params&&(s.params=n._zod.def.params),e.issues.push(Xb(s))}}var BG=t=>{let e=typeof t;switch(e){case"number":return Number.isNaN(t)?"NaN":"number";case"object":{if(Array.isArray(t))return"array";if(t===null)return"null";if(Object.getPrototypeOf(t)!==Object.prototype&&t.constructor)return t.constructor.name}}return e},WG=()=>{let t={string:{unit:"characters",verb:"to have"},file:{unit:"bytes",verb:"to have"},array:{unit:"items",verb:"to have"},set:{unit:"items",verb:"to have"}};function e(n){return t[n]??null}let r={regex:"input",email:"email address",url:"URL",emoji:"emoji",uuid:"UUID",uuidv4:"UUIDv4",uuidv6:"UUIDv6",nanoid:"nanoid",guid:"GUID",cuid:"cuid",cuid2:"cuid2",ulid:"ULID",xid:"XID",ksuid:"KSUID",datetime:"ISO datetime",date:"ISO date",time:"ISO time",duration:"ISO duration",ipv4:"IPv4 address",ipv6:"IPv6 address",cidrv4:"IPv4 range",cidrv6:"IPv6 range",base64:"base64-encoded string",base64url:"base64url-encoded string",json_string:"JSON string",e164:"E.164 number",jwt:"JWT",template_literal:"input"};return n=>{switch(n.code){case"invalid_type":return`Invalid input: expected ${n.expected}, received ${BG(n.input)}`;case"invalid_value":return n.values.length===1?`Invalid input: expected ${Om(n.values[0])}`:`Invalid option: expected one of ${Im(n.values,"|")}`;case"too_big":{let s=n.inclusive?"<=":"<",i=e(n.origin);return i?`Too big: expected ${n.origin??"value"} to have ${s}${n.maximum.toString()} ${i.unit??"elements"}`:`Too big: expected ${n.origin??"value"} to be ${s}${n.maximum.toString()}`}case"too_small":{let s=n.inclusive?">=":">",i=e(n.origin);return i?`Too small: expected ${n.origin} to have ${s}${n.minimum.toString()} ${i.unit}`:`Too small: expected ${n.origin} to be ${s}${n.minimum.toString()}`}case"invalid_format":{let s=n;return s.format==="starts_with"?`Invalid string: must start with "${s.prefix}"`:s.format==="ends_with"?`Invalid string: must end with "${s.suffix}"`:s.format==="includes"?`Invalid string: must include "${s.includes}"`:s.format==="regex"?`Invalid string: must match pattern ${s.pattern}`:`Invalid ${r[s.format]??n.format}`}case"not_multiple_of":return`Invalid number: must be a multiple of ${n.divisor}`;case"unrecognized_keys":return`Unrecognized key${n.keys.length>1?"s":""}: ${Im(n.keys,", ")}`;case"invalid_key":return`Invalid key in ${n.origin}`;case"invalid_union":return"Invalid input";case"invalid_element":return`Invalid value in ${n.origin}`;default:return"Invalid input"}}};function dC(){return{localeError:WG()}}var px=class{constructor(){this._map=new Map,this._idmap=new Map}add(e,...r){let n=r[0];if(this._map.set(e,n),n&&typeof n=="object"&&"id"in n){if(this._idmap.has(n.id))throw new Error(`ID ${n.id} already exists in the registry`);this._idmap.set(n.id,e)}return this}clear(){return this._map=new Map,this._idmap=new Map,this}remove(e){let r=this._map.get(e);return r&&typeof r=="object"&&"id"in r&&this._idmap.delete(r.id),this._map.delete(e),this}get(e){let r=e._zod.parent;if(r){let n={...this.get(r)??{}};return delete n.id,{...n,...this._map.get(e)}}return this._map.get(e)}has(e){return this._map.has(e)}};function ZG(){return new px}var Zl=ZG();function mC(t,e){return new t({type:"string",...ye(e)})}function fC(t,e){return new t({type:"string",format:"email",check:"string_format",abort:!1,...ye(e)})}function dx(t,e){return new t({type:"string",format:"guid",check:"string_format",abort:!1,...ye(e)})}function hC(t,e){return new t({type:"string",format:"uuid",check:"string_format",abort:!1,...ye(e)})}function gC(t,e){return new t({type:"string",format:"uuid",check:"string_format",abort:!1,version:"v4",...ye(e)})}function vC(t,e){return new t({type:"string",format:"uuid",check:"string_format",abort:!1,version:"v6",...ye(e)})}function yC(t,e){return new t({type:"string",format:"uuid",check:"string_format",abort:!1,version:"v7",...ye(e)})}function bC(t,e){return new t({type:"string",format:"url",check:"string_format",abort:!1,...ye(e)})}function xC(t,e){return new t({type:"string",format:"emoji",check:"string_format",abort:!1,...ye(e)})}function _C(t,e){return new t({type:"string",format:"nanoid",check:"string_format",abort:!1,...ye(e)})}function wC(t,e){return new t({type:"string",format:"cuid",check:"string_format",abort:!1,...ye(e)})}function SC(t,e){return new t({type:"string",format:"cuid2",check:"string_format",abort:!1,...ye(e)})}function kC(t,e){return new t({type:"string",format:"ulid",check:"string_format",abort:!1,...ye(e)})}function EC(t,e){return new t({type:"string",format:"xid",check:"string_format",abort:!1,...ye(e)})}function TC(t,e){return new t({type:"string",format:"ksuid",check:"string_format",abort:!1,...ye(e)})}function RC(t,e){return new t({type:"string",format:"ipv4",check:"string_format",abort:!1,...ye(e)})}function PC(t,e){return new t({type:"string",format:"ipv6",check:"string_format",abort:!1,...ye(e)})}function IC(t,e){return new t({type:"string",format:"cidrv4",check:"string_format",abort:!1,...ye(e)})}function CC(t,e){return new t({type:"string",format:"cidrv6",check:"string_format",abort:!1,...ye(e)})}function OC(t,e){return new t({type:"string",format:"base64",check:"string_format",abort:!1,...ye(e)})}function jC(t,e){return new t({type:"string",format:"base64url",check:"string_format",abort:!1,...ye(e)})}function AC(t,e){return new t({type:"string",format:"e164",check:"string_format",abort:!1,...ye(e)})}function NC(t,e){return new t({type:"string",format:"jwt",check:"string_format",abort:!1,...ye(e)})}function DC(t,e){return new t({type:"string",format:"datetime",check:"string_format",offset:!1,local:!1,precision:null,...ye(e)})}function zC(t,e){return new t({type:"string",format:"date",check:"string_format",...ye(e)})}function MC(t,e){return new t({type:"string",format:"time",check:"string_format",precision:null,...ye(e)})}function $C(t,e){return new t({type:"string",format:"duration",check:"string_format",...ye(e)})}function LC(t,e){return new t({type:"number",checks:[],...ye(e)})}function UC(t,e){return new t({type:"number",check:"number_format",abort:!1,format:"safeint",...ye(e)})}function qC(t,e){return new t({type:"boolean",...ye(e)})}function FC(t,e){return new t({type:"null",...ye(e)})}function HC(t){return new t({type:"unknown"})}function BC(t,e){return new t({type:"never",...ye(e)})}function Mm(t,e){return new ax({check:"less_than",...ye(e),value:t,inclusive:!1})}function Gl(t,e){return new ax({check:"less_than",...ye(e),value:t,inclusive:!0})}function $m(t,e){return new ox({check:"greater_than",...ye(e),value:t,inclusive:!1})}function Vl(t,e){return new ox({check:"greater_than",...ye(e),value:t,inclusive:!0})}function Lm(t,e){return new QP({check:"multiple_of",...ye(e),value:t})}function Um(t,e){return new XP({check:"max_length",...ye(e),maximum:t})}function _o(t,e){return new eI({check:"min_length",...ye(e),minimum:t})}function qm(t,e){return new tI({check:"length_equals",...ye(e),length:t})}function mx(t,e){return new rI({check:"string_format",format:"regex",...ye(e),pattern:t})}function fx(t){return new nI({check:"string_format",format:"lowercase",...ye(t)})}function hx(t){return new sI({check:"string_format",format:"uppercase",...ye(t)})}function gx(t,e){return new iI({check:"string_format",format:"includes",...ye(e),includes:t})}function vx(t,e){return new aI({check:"string_format",format:"starts_with",...ye(e),prefix:t})}function yx(t,e){return new oI({check:"string_format",format:"ends_with",...ye(e),suffix:t})}function ca(t){return new cI({check:"overwrite",tx:t})}function bx(t){return ca(e=>e.normalize(t))}function xx(){return ca(t=>t.trim())}function _x(){return ca(t=>t.toLowerCase())}function wx(){return ca(t=>t.toUpperCase())}function WC(t,e,r){return new t({type:"array",element:e,...ye(r)})}function ZC(t,e,r){let n=ye(r);return n.abort??(n.abort=!0),new t({type:"custom",check:"custom",fn:e,...n})}function GC(t,e,r){return new t({type:"custom",check:"custom",fn:e,...ye(r)})}function wo(t){return!!t._zod}function rs(t,e){return wo(t)?Bl(t,e):t.safeParse(e)}function Fm(t){if(!t)return;let e;if(wo(t)?e=t._zod?.def?.shape:e=t.shape,!!e){if(typeof e=="function")try{return e()}catch{return}return e}}function VC(t){if(wo(t)){let i=t._zod?.def;if(i){if(i.value!==void 0)return i.value;if(Array.isArray(i.values)&&i.values.length>0)return i.values[0]}}let r=t._def;if(r){if(r.value!==void 0)return r.value;if(Array.isArray(r.values)&&r.values.length>0)return r.values[0]}let n=t.value;if(n!==void 0)return n}var Jl={};ks(Jl,{ZodISODate:()=>JC,ZodISODateTime:()=>KC,ZodISODuration:()=>YC,ZodISOTime:()=>QC,date:()=>kx,datetime:()=>Sx,duration:()=>Tx,time:()=>Ex});var KC=F("ZodISODateTime",(t,e)=>{OI.init(t,e),Dt.init(t,e)});function Sx(t){return DC(KC,t)}var JC=F("ZodISODate",(t,e)=>{jI.init(t,e),Dt.init(t,e)});function kx(t){return zC(JC,t)}var QC=F("ZodISOTime",(t,e)=>{AI.init(t,e),Dt.init(t,e)});function Ex(t){return MC(QC,t)}var YC=F("ZodISODuration",(t,e)=>{NI.init(t,e),Dt.init(t,e)});function Tx(t){return $C(YC,t)}var XC=(t,e)=>{jm.init(t,e),t.name="ZodError",Object.defineProperties(t,{format:{value:r=>yP(t,r)},flatten:{value:r=>vP(t,r)},addIssue:{value:r=>t.issues.push(r)},addIssues:{value:r=>t.issues.push(...r)},isEmpty:{get(){return t.issues.length===0}}})},ITe=F("ZodError",XC),Ql=F("ZodError",XC,{Parent:Error});var eO=bP(Ql),tO=xP(Ql),rO=tx(Ql),nO=rx(Ql);var Ut=F("ZodType",(t,e)=>(wt.init(t,e),t.def=e,Object.defineProperty(t,"_def",{value:e}),t.check=(...r)=>t.clone({...e,checks:[...e.checks??[],...r.map(n=>typeof n=="function"?{_zod:{check:n,def:{check:"custom"},onattach:[]}}:n)]}),t.clone=(r,n)=>Es(t,r,n),t.brand=()=>t,t.register=((r,n)=>(r.add(t,n),t)),t.parse=(r,n)=>eO(t,r,n,{callee:t.parse}),t.safeParse=(r,n)=>rO(t,r,n),t.parseAsync=async(r,n)=>tO(t,r,n,{callee:t.parseAsync}),t.safeParseAsync=async(r,n)=>nO(t,r,n),t.spa=t.safeParseAsync,t.refine=(r,n)=>t.check(HV(r,n)),t.superRefine=r=>t.check(BV(r)),t.overwrite=r=>t.check(ca(r)),t.optional=()=>Mt(t),t.nullable=()=>aO(t),t.nullish=()=>Mt(aO(t)),t.nonoptional=r=>zV(t,r),t.array=()=>Ze(t),t.or=r=>Pt([t,r]),t.and=r=>Bm(t,r),t.transform=r=>Px(t,dO(r)),t.default=r=>AV(t,r),t.prefault=r=>DV(t,r),t.catch=r=>$V(t,r),t.pipe=r=>Px(t,r),t.readonly=()=>qV(t),t.describe=r=>{let n=t.clone();return Zl.add(n,{description:r}),n},Object.defineProperty(t,"description",{get(){return Zl.get(t)?.description},configurable:!0}),t.meta=(...r)=>{if(r.length===0)return Zl.get(t);let n=t.clone();return Zl.add(n,r[0]),n},t.isOptional=()=>t.safeParse(void 0).success,t.isNullable=()=>t.safeParse(null).success,t)),oO=F("_ZodString",(t,e)=>{zm.init(t,e),Ut.init(t,e);let r=t._zod.bag;t.format=r.format??null,t.minLength=r.minimum??null,t.maxLength=r.maximum??null,t.regex=(...n)=>t.check(mx(...n)),t.includes=(...n)=>t.check(gx(...n)),t.startsWith=(...n)=>t.check(vx(...n)),t.endsWith=(...n)=>t.check(yx(...n)),t.min=(...n)=>t.check(_o(...n)),t.max=(...n)=>t.check(Um(...n)),t.length=(...n)=>t.check(qm(...n)),t.nonempty=(...n)=>t.check(_o(1,...n)),t.lowercase=n=>t.check(fx(n)),t.uppercase=n=>t.check(hx(n)),t.trim=()=>t.check(xx()),t.normalize=(...n)=>t.check(bx(...n)),t.toLowerCase=()=>t.check(_x()),t.toUpperCase=()=>t.check(wx())}),tV=F("ZodString",(t,e)=>{zm.init(t,e),oO.init(t,e),t.email=r=>t.check(fC(rV,r)),t.url=r=>t.check(bC(nV,r)),t.jwt=r=>t.check(NC(yV,r)),t.emoji=r=>t.check(xC(sV,r)),t.guid=r=>t.check(dx(sO,r)),t.uuid=r=>t.check(hC(Hm,r)),t.uuidv4=r=>t.check(gC(Hm,r)),t.uuidv6=r=>t.check(vC(Hm,r)),t.uuidv7=r=>t.check(yC(Hm,r)),t.nanoid=r=>t.check(_C(iV,r)),t.guid=r=>t.check(dx(sO,r)),t.cuid=r=>t.check(wC(aV,r)),t.cuid2=r=>t.check(SC(oV,r)),t.ulid=r=>t.check(kC(cV,r)),t.base64=r=>t.check(OC(hV,r)),t.base64url=r=>t.check(jC(gV,r)),t.xid=r=>t.check(EC(lV,r)),t.ksuid=r=>t.check(TC(uV,r)),t.ipv4=r=>t.check(RC(pV,r)),t.ipv6=r=>t.check(PC(dV,r)),t.cidrv4=r=>t.check(IC(mV,r)),t.cidrv6=r=>t.check(CC(fV,r)),t.e164=r=>t.check(AC(vV,r)),t.datetime=r=>t.check(Sx(r)),t.date=r=>t.check(kx(r)),t.time=r=>t.check(Ex(r)),t.duration=r=>t.check(Tx(r))});function L(t){return mC(tV,t)}var Dt=F("ZodStringFormat",(t,e)=>{Rt.init(t,e),oO.init(t,e)}),rV=F("ZodEmail",(t,e)=>{wI.init(t,e),Dt.init(t,e)});var sO=F("ZodGUID",(t,e)=>{xI.init(t,e),Dt.init(t,e)});var Hm=F("ZodUUID",(t,e)=>{_I.init(t,e),Dt.init(t,e)});var nV=F("ZodURL",(t,e)=>{SI.init(t,e),Dt.init(t,e)});var sV=F("ZodEmoji",(t,e)=>{kI.init(t,e),Dt.init(t,e)});var iV=F("ZodNanoID",(t,e)=>{EI.init(t,e),Dt.init(t,e)});var aV=F("ZodCUID",(t,e)=>{TI.init(t,e),Dt.init(t,e)});var oV=F("ZodCUID2",(t,e)=>{RI.init(t,e),Dt.init(t,e)});var cV=F("ZodULID",(t,e)=>{PI.init(t,e),Dt.init(t,e)});var lV=F("ZodXID",(t,e)=>{II.init(t,e),Dt.init(t,e)});var uV=F("ZodKSUID",(t,e)=>{CI.init(t,e),Dt.init(t,e)});var pV=F("ZodIPv4",(t,e)=>{DI.init(t,e),Dt.init(t,e)});var dV=F("ZodIPv6",(t,e)=>{zI.init(t,e),Dt.init(t,e)});var mV=F("ZodCIDRv4",(t,e)=>{MI.init(t,e),Dt.init(t,e)});var fV=F("ZodCIDRv6",(t,e)=>{$I.init(t,e),Dt.init(t,e)});var hV=F("ZodBase64",(t,e)=>{UI.init(t,e),Dt.init(t,e)});var gV=F("ZodBase64URL",(t,e)=>{qI.init(t,e),Dt.init(t,e)});var vV=F("ZodE164",(t,e)=>{FI.init(t,e),Dt.init(t,e)});var yV=F("ZodJWT",(t,e)=>{HI.init(t,e),Dt.init(t,e)});var cO=F("ZodNumber",(t,e)=>{lx.init(t,e),Ut.init(t,e),t.gt=(n,s)=>t.check($m(n,s)),t.gte=(n,s)=>t.check(Vl(n,s)),t.min=(n,s)=>t.check(Vl(n,s)),t.lt=(n,s)=>t.check(Mm(n,s)),t.lte=(n,s)=>t.check(Gl(n,s)),t.max=(n,s)=>t.check(Gl(n,s)),t.int=n=>t.check(iO(n)),t.safe=n=>t.check(iO(n)),t.positive=n=>t.check($m(0,n)),t.nonnegative=n=>t.check(Vl(0,n)),t.negative=n=>t.check(Mm(0,n)),t.nonpositive=n=>t.check(Gl(0,n)),t.multipleOf=(n,s)=>t.check(Lm(n,s)),t.step=(n,s)=>t.check(Lm(n,s)),t.finite=()=>t;let r=t._zod.bag;t.minValue=Math.max(r.minimum??Number.NEGATIVE_INFINITY,r.exclusiveMinimum??Number.NEGATIVE_INFINITY)??null,t.maxValue=Math.min(r.maximum??Number.POSITIVE_INFINITY,r.exclusiveMaximum??Number.POSITIVE_INFINITY)??null,t.isInt=(r.format??"").includes("int")||Number.isSafeInteger(r.multipleOf??.5),t.isFinite=!0,t.format=r.format??null});function at(t){return LC(cO,t)}var bV=F("ZodNumberFormat",(t,e)=>{BI.init(t,e),cO.init(t,e)});function iO(t){return UC(bV,t)}var xV=F("ZodBoolean",(t,e)=>{WI.init(t,e),Ut.init(t,e)});function lr(t){return qC(xV,t)}var _V=F("ZodNull",(t,e)=>{ZI.init(t,e),Ut.init(t,e)});function lO(t){return FC(_V,t)}var wV=F("ZodUnknown",(t,e)=>{GI.init(t,e),Ut.init(t,e)});function zt(){return HC(wV)}var SV=F("ZodNever",(t,e)=>{VI.init(t,e),Ut.init(t,e)});function kV(t){return BC(SV,t)}var EV=F("ZodArray",(t,e)=>{KI.init(t,e),Ut.init(t,e),t.element=e.element,t.min=(r,n)=>t.check(_o(r,n)),t.nonempty=r=>t.check(_o(1,r)),t.max=(r,n)=>t.check(Um(r,n)),t.length=(r,n)=>t.check(qm(r,n)),t.unwrap=()=>t.element});function Ze(t,e){return WC(EV,t,e)}var uO=F("ZodObject",(t,e)=>{JI.init(t,e),Ut.init(t,e),nt.defineLazy(t,"shape",()=>e.shape),t.keyof=()=>sn(Object.keys(t._zod.def.shape)),t.catchall=r=>t.clone({...t._zod.def,catchall:r}),t.passthrough=()=>t.clone({...t._zod.def,catchall:zt()}),t.loose=()=>t.clone({...t._zod.def,catchall:zt()}),t.strict=()=>t.clone({...t._zod.def,catchall:kV()}),t.strip=()=>t.clone({...t._zod.def,catchall:void 0}),t.extend=r=>nt.extend(t,r),t.merge=r=>nt.merge(t,r),t.pick=r=>nt.pick(t,r),t.omit=r=>nt.omit(t,r),t.partial=(...r)=>nt.partial(mO,t,r[0]),t.required=(...r)=>nt.required(fO,t,r[0])});function ie(t,e){let r={type:"object",get shape(){return nt.assignProp(this,"shape",{...t}),this.shape},...nt.normalizeParams(e)};return new uO(r)}function Mr(t,e){return new uO({type:"object",get shape(){return nt.assignProp(this,"shape",{...t}),this.shape},catchall:zt(),...nt.normalizeParams(e)})}var pO=F("ZodUnion",(t,e)=>{ux.init(t,e),Ut.init(t,e),t.options=e.options});function Pt(t,e){return new pO({type:"union",options:t,...nt.normalizeParams(e)})}var TV=F("ZodDiscriminatedUnion",(t,e)=>{pO.init(t,e),QI.init(t,e)});function Ix(t,e,r){return new TV({type:"union",options:e,discriminator:t,...nt.normalizeParams(r)})}var RV=F("ZodIntersection",(t,e)=>{YI.init(t,e),Ut.init(t,e)});function Bm(t,e){return new RV({type:"intersection",left:t,right:e})}var PV=F("ZodRecord",(t,e)=>{XI.init(t,e),Ut.init(t,e),t.keyType=e.keyType,t.valueType=e.valueType});function St(t,e,r){return new PV({type:"record",keyType:t,valueType:e,...nt.normalizeParams(r)})}var Rx=F("ZodEnum",(t,e)=>{eC.init(t,e),Ut.init(t,e),t.enum=e.entries,t.options=Object.values(e.entries);let r=new Set(Object.keys(e.entries));t.extract=(n,s)=>{let i={};for(let a of n)if(r.has(a))i[a]=e.entries[a];else throw new Error(`Key ${a} not found in enum`);return new Rx({...e,checks:[],...nt.normalizeParams(s),entries:i})},t.exclude=(n,s)=>{let i={...e.entries};for(let a of n)if(r.has(a))delete i[a];else throw new Error(`Key ${a} not found in enum`);return new Rx({...e,checks:[],...nt.normalizeParams(s),entries:i})}});function sn(t,e){let r=Array.isArray(t)?Object.fromEntries(t.map(n=>[n,n])):t;return new Rx({type:"enum",entries:r,...nt.normalizeParams(e)})}var IV=F("ZodLiteral",(t,e)=>{tC.init(t,e),Ut.init(t,e),t.values=new Set(e.values),Object.defineProperty(t,"value",{get(){if(e.values.length>1)throw new Error("This schema contains multiple valid literal values. Use `.values` instead.");return e.values[0]}})});function me(t,e){return new IV({type:"literal",values:Array.isArray(t)?t:[t],...nt.normalizeParams(e)})}var CV=F("ZodTransform",(t,e)=>{rC.init(t,e),Ut.init(t,e),t._zod.parse=(r,n)=>{r.addIssue=i=>{if(typeof i=="string")r.issues.push(nt.issue(i,r.value,e));else{let a=i;a.fatal&&(a.continue=!1),a.code??(a.code="custom"),a.input??(a.input=r.value),a.inst??(a.inst=t),a.continue??(a.continue=!0),r.issues.push(nt.issue(a))}};let s=e.transform(r.value,r);return s instanceof Promise?s.then(i=>(r.value=i,r)):(r.value=s,r)}});function dO(t){return new CV({type:"transform",transform:t})}var mO=F("ZodOptional",(t,e)=>{nC.init(t,e),Ut.init(t,e),t.unwrap=()=>t._zod.def.innerType});function Mt(t){return new mO({type:"optional",innerType:t})}var OV=F("ZodNullable",(t,e)=>{sC.init(t,e),Ut.init(t,e),t.unwrap=()=>t._zod.def.innerType});function aO(t){return new OV({type:"nullable",innerType:t})}var jV=F("ZodDefault",(t,e)=>{iC.init(t,e),Ut.init(t,e),t.unwrap=()=>t._zod.def.innerType,t.removeDefault=t.unwrap});function AV(t,e){return new jV({type:"default",innerType:t,get defaultValue(){return typeof e=="function"?e():e}})}var NV=F("ZodPrefault",(t,e)=>{aC.init(t,e),Ut.init(t,e),t.unwrap=()=>t._zod.def.innerType});function DV(t,e){return new NV({type:"prefault",innerType:t,get defaultValue(){return typeof e=="function"?e():e}})}var fO=F("ZodNonOptional",(t,e)=>{oC.init(t,e),Ut.init(t,e),t.unwrap=()=>t._zod.def.innerType});function zV(t,e){return new fO({type:"nonoptional",innerType:t,...nt.normalizeParams(e)})}var MV=F("ZodCatch",(t,e)=>{cC.init(t,e),Ut.init(t,e),t.unwrap=()=>t._zod.def.innerType,t.removeCatch=t.unwrap});function $V(t,e){return new MV({type:"catch",innerType:t,catchValue:typeof e=="function"?e:()=>e})}var LV=F("ZodPipe",(t,e)=>{lC.init(t,e),Ut.init(t,e),t.in=e.in,t.out=e.out});function Px(t,e){return new LV({type:"pipe",in:t,out:e})}var UV=F("ZodReadonly",(t,e)=>{uC.init(t,e),Ut.init(t,e)});function qV(t){return new UV({type:"readonly",innerType:t})}var hO=F("ZodCustom",(t,e)=>{pC.init(t,e),Ut.init(t,e)});function FV(t){let e=new Or({check:"custom"});return e._zod.check=t,e}function gO(t,e){return ZC(hO,t??(()=>!0),e)}function HV(t,e={}){return GC(hO,t,e)}function BV(t){let e=FV(r=>(r.addIssue=n=>{if(typeof n=="string")r.issues.push(nt.issue(n,r.value,e._zod.def));else{let s=n;s.fatal&&(s.continue=!1),s.code??(s.code="custom"),s.input??(s.input=r.value),s.inst??(s.inst=e),s.continue??(s.continue=!e._zod.def.abort),r.issues.push(nt.issue(s))}},t(r.value,r)));return e}function Cx(t,e){return Px(dO(t),e)}jn(dC());var jx="2025-11-25";var vO=[jx,"2025-06-18","2025-03-26","2024-11-05","2024-10-07"],_i="io.modelcontextprotocol/related-task",Zm="2.0",rr=gO(t=>t!==null&&(typeof t=="object"||typeof t=="function")),yO=Pt([L(),at().int()]),bO=L(),wRe=Mr({ttl:at().optional(),pollInterval:at().optional()}),WV=ie({ttl:at().optional()}),ZV=ie({taskId:L()}),Ax=Mr({progressToken:yO.optional(),[_i]:ZV.optional()}),_n=ie({_meta:Ax.optional()}),Yl=_n.extend({task:WV.optional()}),xO=t=>Yl.safeParse(t).success,xr=ie({method:L(),params:_n.loose().optional()}),An=ie({_meta:Ax.optional()}),Nn=ie({method:L(),params:An.loose().optional()}),_r=Mr({_meta:Ax.optional()}),Gm=Pt([L(),at().int()]),_O=ie({jsonrpc:me(Zm),id:Gm,...xr.shape}).strict(),Nx=t=>_O.safeParse(t).success,wO=ie({jsonrpc:me(Zm),...Nn.shape}).strict(),SO=t=>wO.safeParse(t).success,Dx=ie({jsonrpc:me(Zm),id:Gm,result:_r}).strict(),Xl=t=>Dx.safeParse(t).success;var Se;(function(t){t[t.ConnectionClosed=-32e3]="ConnectionClosed",t[t.RequestTimeout=-32001]="RequestTimeout",t[t.ParseError=-32700]="ParseError",t[t.InvalidRequest=-32600]="InvalidRequest",t[t.MethodNotFound=-32601]="MethodNotFound",t[t.InvalidParams=-32602]="InvalidParams",t[t.InternalError=-32603]="InternalError",t[t.UrlElicitationRequired=-32042]="UrlElicitationRequired"})(Se||(Se={}));var zx=ie({jsonrpc:me(Zm),id:Gm.optional(),error:ie({code:at().int(),message:L(),data:zt().optional()})}).strict();var kO=t=>zx.safeParse(t).success;var EO=Pt([_O,wO,Dx,zx]),SRe=Pt([Dx,zx]),la=_r.strict(),GV=An.extend({requestId:Gm.optional(),reason:L().optional()}),Vm=Nn.extend({method:me("notifications/cancelled"),params:GV}),VV=ie({src:L(),mimeType:L().optional(),sizes:Ze(L()).optional(),theme:sn(["light","dark"]).optional()}),eu=ie({icons:Ze(VV).optional()}),So=ie({name:L(),title:L().optional()}),TO=So.extend({...So.shape,...eu.shape,version:L(),websiteUrl:L().optional(),description:L().optional()}),KV=Bm(ie({applyDefaults:lr().optional()}),St(L(),zt())),JV=Cx(t=>t&&typeof t=="object"&&!Array.isArray(t)&&Object.keys(t).length===0?{form:{}}:t,Bm(ie({form:KV.optional(),url:rr.optional()}),St(L(),zt()).optional())),QV=Mr({list:rr.optional(),cancel:rr.optional(),requests:Mr({sampling:Mr({createMessage:rr.optional()}).optional(),elicitation:Mr({create:rr.optional()}).optional()}).optional()}),YV=Mr({list:rr.optional(),cancel:rr.optional(),requests:Mr({tools:Mr({call:rr.optional()}).optional()}).optional()}),XV=ie({experimental:St(L(),rr).optional(),sampling:ie({context:rr.optional(),tools:rr.optional()}).optional(),elicitation:JV.optional(),roots:ie({listChanged:lr().optional()}).optional(),tasks:QV.optional(),extensions:St(L(),rr).optional()}),e7=_n.extend({protocolVersion:L(),capabilities:XV,clientInfo:TO}),t7=xr.extend({method:me("initialize"),params:e7});var r7=ie({experimental:St(L(),rr).optional(),logging:rr.optional(),completions:rr.optional(),prompts:ie({listChanged:lr().optional()}).optional(),resources:ie({subscribe:lr().optional(),listChanged:lr().optional()}).optional(),tools:ie({listChanged:lr().optional()}).optional(),tasks:YV.optional(),extensions:St(L(),rr).optional()}),Mx=_r.extend({protocolVersion:L(),capabilities:r7,serverInfo:TO,instructions:L().optional()}),n7=Nn.extend({method:me("notifications/initialized"),params:An.optional()});var Km=xr.extend({method:me("ping"),params:_n.optional()}),s7=ie({progress:at(),total:Mt(at()),message:Mt(L())}),i7=ie({...An.shape,...s7.shape,progressToken:yO}),Jm=Nn.extend({method:me("notifications/progress"),params:i7}),a7=_n.extend({cursor:bO.optional()}),tu=xr.extend({params:a7.optional()}),ru=_r.extend({nextCursor:bO.optional()}),o7=sn(["working","input_required","completed","failed","cancelled"]),nu=ie({taskId:L(),status:o7,ttl:Pt([at(),lO()]),createdAt:L(),lastUpdatedAt:L(),pollInterval:Mt(at()),statusMessage:Mt(L())}),ua=_r.extend({task:nu}),c7=An.merge(nu),su=Nn.extend({method:me("notifications/tasks/status"),params:c7}),Qm=xr.extend({method:me("tasks/get"),params:_n.extend({taskId:L()})}),Ym=_r.merge(nu),Xm=xr.extend({method:me("tasks/result"),params:_n.extend({taskId:L()})}),kRe=_r.loose(),ef=tu.extend({method:me("tasks/list")}),tf=ru.extend({tasks:Ze(nu)}),rf=xr.extend({method:me("tasks/cancel"),params:_n.extend({taskId:L()})}),RO=_r.merge(nu),PO=ie({uri:L(),mimeType:Mt(L()),_meta:St(L(),zt()).optional()}),IO=PO.extend({text:L()}),$x=L().refine(t=>{try{return atob(t),!0}catch{return!1}},{message:"Invalid Base64 string"}),CO=PO.extend({blob:$x}),iu=sn(["user","assistant"]),ko=ie({audience:Ze(iu).optional(),priority:at().min(0).max(1).optional(),lastModified:Jl.datetime({offset:!0}).optional()}),OO=ie({...So.shape,...eu.shape,uri:L(),description:Mt(L()),mimeType:Mt(L()),size:Mt(at()),annotations:ko.optional(),_meta:Mt(Mr({}))}),l7=ie({...So.shape,...eu.shape,uriTemplate:L(),description:Mt(L()),mimeType:Mt(L()),annotations:ko.optional(),_meta:Mt(Mr({}))}),u7=tu.extend({method:me("resources/list")}),Lx=ru.extend({resources:Ze(OO)}),p7=tu.extend({method:me("resources/templates/list")}),Ux=ru.extend({resourceTemplates:Ze(l7)}),qx=_n.extend({uri:L()}),d7=qx,m7=xr.extend({method:me("resources/read"),params:d7}),Fx=_r.extend({contents:Ze(Pt([IO,CO]))}),Hx=Nn.extend({method:me("notifications/resources/list_changed"),params:An.optional()}),f7=qx,h7=xr.extend({method:me("resources/subscribe"),params:f7}),g7=qx,v7=xr.extend({method:me("resources/unsubscribe"),params:g7}),y7=An.extend({uri:L()}),b7=Nn.extend({method:me("notifications/resources/updated"),params:y7}),x7=ie({name:L(),description:Mt(L()),required:Mt(lr())}),_7=ie({...So.shape,...eu.shape,description:Mt(L()),arguments:Mt(Ze(x7)),_meta:Mt(Mr({}))}),w7=tu.extend({method:me("prompts/list")}),Bx=ru.extend({prompts:Ze(_7)}),S7=_n.extend({name:L(),arguments:St(L(),L()).optional()}),k7=xr.extend({method:me("prompts/get"),params:S7}),Wx=ie({type:me("text"),text:L(),annotations:ko.optional(),_meta:St(L(),zt()).optional()}),Zx=ie({type:me("image"),data:$x,mimeType:L(),annotations:ko.optional(),_meta:St(L(),zt()).optional()}),Gx=ie({type:me("audio"),data:$x,mimeType:L(),annotations:ko.optional(),_meta:St(L(),zt()).optional()}),E7=ie({type:me("tool_use"),name:L(),id:L(),input:St(L(),zt()),_meta:St(L(),zt()).optional()}),T7=ie({type:me("resource"),resource:Pt([IO,CO]),annotations:ko.optional(),_meta:St(L(),zt()).optional()}),R7=OO.extend({type:me("resource_link")}),Vx=Pt([Wx,Zx,Gx,R7,T7]),P7=ie({role:iu,content:Vx}),Kx=_r.extend({description:L().optional(),messages:Ze(P7)}),Jx=Nn.extend({method:me("notifications/prompts/list_changed"),params:An.optional()}),I7=ie({title:L().optional(),readOnlyHint:lr().optional(),destructiveHint:lr().optional(),idempotentHint:lr().optional(),openWorldHint:lr().optional()}),C7=ie({taskSupport:sn(["required","optional","forbidden"]).optional()}),jO=ie({...So.shape,...eu.shape,description:L().optional(),inputSchema:ie({type:me("object"),properties:St(L(),rr).optional(),required:Ze(L()).optional()}).catchall(zt()),outputSchema:ie({type:me("object"),properties:St(L(),rr).optional(),required:Ze(L()).optional()}).catchall(zt()).optional(),annotations:I7.optional(),execution:C7.optional(),_meta:St(L(),zt()).optional()}),O7=tu.extend({method:me("tools/list")}),Qx=ru.extend({tools:Ze(jO)}),Eo=_r.extend({content:Ze(Vx).default([]),structuredContent:St(L(),zt()).optional(),isError:lr().optional()}),ERe=Eo.or(_r.extend({toolResult:zt()})),j7=Yl.extend({name:L(),arguments:St(L(),zt()).optional()}),A7=xr.extend({method:me("tools/call"),params:j7}),Yx=Nn.extend({method:me("notifications/tools/list_changed"),params:An.optional()}),AO=ie({autoRefresh:lr().default(!0),debounceMs:at().int().nonnegative().default(300)}),NO=sn(["debug","info","notice","warning","error","critical","alert","emergency"]),N7=_n.extend({level:NO}),D7=xr.extend({method:me("logging/setLevel"),params:N7}),z7=An.extend({level:NO,logger:L().optional(),data:zt()}),M7=Nn.extend({method:me("notifications/message"),params:z7}),$7=ie({name:L().optional()}),L7=ie({hints:Ze($7).optional(),costPriority:at().min(0).max(1).optional(),speedPriority:at().min(0).max(1).optional(),intelligencePriority:at().min(0).max(1).optional()}),U7=ie({mode:sn(["auto","required","none"]).optional()}),q7=ie({type:me("tool_result"),toolUseId:L().describe("The unique identifier for the corresponding tool call."),content:Ze(Vx).default([]),structuredContent:ie({}).loose().optional(),isError:lr().optional(),_meta:St(L(),zt()).optional()}),F7=Ix("type",[Wx,Zx,Gx]),Wm=Ix("type",[Wx,Zx,Gx,E7,q7]),H7=ie({role:iu,content:Pt([Wm,Ze(Wm)]),_meta:St(L(),zt()).optional()}),B7=Yl.extend({messages:Ze(H7),modelPreferences:L7.optional(),systemPrompt:L().optional(),includeContext:sn(["none","thisServer","allServers"]).optional(),temperature:at().optional(),maxTokens:at().int(),stopSequences:Ze(L()).optional(),metadata:rr.optional(),tools:Ze(jO).optional(),toolChoice:U7.optional()}),Xx=xr.extend({method:me("sampling/createMessage"),params:B7}),e_=_r.extend({model:L(),stopReason:Mt(sn(["endTurn","stopSequence","maxTokens"]).or(L())),role:iu,content:F7}),t_=_r.extend({model:L(),stopReason:Mt(sn(["endTurn","stopSequence","maxTokens","toolUse"]).or(L())),role:iu,content:Pt([Wm,Ze(Wm)])}),W7=ie({type:me("boolean"),title:L().optional(),description:L().optional(),default:lr().optional()}),Z7=ie({type:me("string"),title:L().optional(),description:L().optional(),minLength:at().optional(),maxLength:at().optional(),format:sn(["email","uri","date","date-time"]).optional(),default:L().optional()}),G7=ie({type:sn(["number","integer"]),title:L().optional(),description:L().optional(),minimum:at().optional(),maximum:at().optional(),default:at().optional()}),V7=ie({type:me("string"),title:L().optional(),description:L().optional(),enum:Ze(L()),default:L().optional()}),K7=ie({type:me("string"),title:L().optional(),description:L().optional(),oneOf:Ze(ie({const:L(),title:L()})),default:L().optional()}),J7=ie({type:me("string"),title:L().optional(),description:L().optional(),enum:Ze(L()),enumNames:Ze(L()).optional(),default:L().optional()}),Q7=Pt([V7,K7]),Y7=ie({type:me("array"),title:L().optional(),description:L().optional(),minItems:at().optional(),maxItems:at().optional(),items:ie({type:me("string"),enum:Ze(L())}),default:Ze(L()).optional()}),X7=ie({type:me("array"),title:L().optional(),description:L().optional(),minItems:at().optional(),maxItems:at().optional(),items:ie({anyOf:Ze(ie({const:L(),title:L()}))}),default:Ze(L()).optional()}),eK=Pt([Y7,X7]),tK=Pt([J7,Q7,eK]),rK=Pt([tK,W7,Z7,G7]),nK=Yl.extend({mode:me("form").optional(),message:L(),requestedSchema:ie({type:me("object"),properties:St(L(),rK),required:Ze(L()).optional()})}),sK=Yl.extend({mode:me("url"),message:L(),elicitationId:L(),url:L().url()}),iK=Pt([nK,sK]),r_=xr.extend({method:me("elicitation/create"),params:iK}),aK=An.extend({elicitationId:L()}),oK=Nn.extend({method:me("notifications/elicitation/complete"),params:aK}),n_=_r.extend({action:sn(["accept","decline","cancel"]),content:Cx(t=>t===null?void 0:t,St(L(),Pt([L(),at(),lr(),Ze(L())])).optional())}),cK=ie({type:me("ref/resource"),uri:L()});var lK=ie({type:me("ref/prompt"),name:L()}),uK=_n.extend({ref:Pt([lK,cK]),argument:ie({name:L(),value:L()}),context:ie({arguments:St(L(),L()).optional()}).optional()}),pK=xr.extend({method:me("completion/complete"),params:uK});var s_=_r.extend({completion:Mr({values:Ze(L()).max(100),total:Mt(at().int()),hasMore:Mt(lr())})}),dK=ie({uri:L().startsWith("file://"),name:L().optional(),_meta:St(L(),zt()).optional()}),mK=xr.extend({method:me("roots/list"),params:_n.optional()}),fK=_r.extend({roots:Ze(dK)}),hK=Nn.extend({method:me("notifications/roots/list_changed"),params:An.optional()}),TRe=Pt([Km,t7,pK,D7,k7,w7,u7,p7,m7,h7,v7,A7,O7,Qm,Xm,ef,rf]),RRe=Pt([Vm,Jm,n7,hK,su]),PRe=Pt([la,e_,t_,n_,fK,Ym,tf,ua]),IRe=Pt([Km,Xx,r_,mK,Qm,Xm,ef,rf]),CRe=Pt([Vm,Jm,M7,b7,Hx,Yx,Jx,su,oK]),ORe=Pt([la,Mx,s_,Kx,Bx,Lx,Ux,Fx,Eo,Qx,Ym,tf,ua]),ve=class t extends Error{constructor(e,r,n){super(`MCP error ${e}: ${r}`),this.code=e,this.data=n,this.name="McpError"}static fromError(e,r,n){if(e===Se.UrlElicitationRequired&&n){let s=n;if(s.elicitations)return new Ox(s.elicitations,r)}return new t(e,r,n)}},Ox=class extends ve{constructor(e,r=`URL elicitation${e.length>1?"s":""} required`){super(Se.UrlElicitationRequired,r,{elicitations:e})}get elicitations(){return this.data?.elicitations??[]}};function wi(t){return t==="completed"||t==="failed"||t==="cancelled"}var u1e=new Set("ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvxyz0123456789");function i_(t){let r=Fm(t)?.method;if(!r)throw new Error("Schema is missing a method literal");let n=VC(r);if(typeof n!="string")throw new Error("Schema method literal must be a string");return n}function a_(t,e){let r=rs(t,e);if(!r.success)throw r.error;return r.data}var _K=6e4,nf=class{constructor(e){this._options=e,this._requestMessageId=0,this._requestHandlers=new Map,this._requestHandlerAbortControllers=new Map,this._notificationHandlers=new Map,this._responseHandlers=new Map,this._progressHandlers=new Map,this._timeoutInfo=new Map,this._pendingDebouncedNotifications=new Set,this._taskProgressTokens=new Map,this._requestResolvers=new Map,this.setNotificationHandler(Vm,r=>{this._oncancel(r)}),this.setNotificationHandler(Jm,r=>{this._onprogress(r)}),this.setRequestHandler(Km,r=>({})),this._taskStore=e?.taskStore,this._taskMessageQueue=e?.taskMessageQueue,this._taskStore&&(this.setRequestHandler(Qm,async(r,n)=>{let s=await this._taskStore.getTask(r.params.taskId,n.sessionId);if(!s)throw new ve(Se.InvalidParams,"Failed to retrieve task: Task not found");return{...s}}),this.setRequestHandler(Xm,async(r,n)=>{let s=async()=>{let i=r.params.taskId;if(this._taskMessageQueue){let o;for(;o=await this._taskMessageQueue.dequeue(i,n.sessionId);){if(o.type==="response"||o.type==="error"){let c=o.message,l=c.id,u=this._requestResolvers.get(l);if(u)if(this._requestResolvers.delete(l),o.type==="response")u(c);else{let p=c,d=new ve(p.error.code,p.error.message,p.error.data);u(d)}else{let p=o.type==="response"?"Response":"Error";this._onerror(new Error(`${p} handler missing for request ${l}`))}continue}await this._transport?.send(o.message,{relatedRequestId:n.requestId})}}let a=await this._taskStore.getTask(i,n.sessionId);if(!a)throw new ve(Se.InvalidParams,`Task not found: ${i}`);if(!wi(a.status))return await this._waitForTaskUpdate(i,n.signal),await s();if(wi(a.status)){let o=await this._taskStore.getTaskResult(i,n.sessionId);return this._clearTaskQueue(i),{...o,_meta:{...o._meta,[_i]:{taskId:i}}}}return await s()};return await s()}),this.setRequestHandler(ef,async(r,n)=>{try{let{tasks:s,nextCursor:i}=await this._taskStore.listTasks(r.params?.cursor,n.sessionId);return{tasks:s,nextCursor:i,_meta:{}}}catch(s){throw new ve(Se.InvalidParams,`Failed to list tasks: ${s instanceof Error?s.message:String(s)}`)}}),this.setRequestHandler(rf,async(r,n)=>{try{let s=await this._taskStore.getTask(r.params.taskId,n.sessionId);if(!s)throw new ve(Se.InvalidParams,`Task not found: ${r.params.taskId}`);if(wi(s.status))throw new ve(Se.InvalidParams,`Cannot cancel task in terminal status: ${s.status}`);await this._taskStore.updateTaskStatus(r.params.taskId,"cancelled","Client cancelled task execution.",n.sessionId),this._clearTaskQueue(r.params.taskId);let i=await this._taskStore.getTask(r.params.taskId,n.sessionId);if(!i)throw new ve(Se.InvalidParams,`Task not found after cancellation: ${r.params.taskId}`);return{_meta:{},...i}}catch(s){throw s instanceof ve?s:new ve(Se.InvalidRequest,`Failed to cancel task: ${s instanceof Error?s.message:String(s)}`)}}))}async _oncancel(e){if(!e.params.requestId)return;this._requestHandlerAbortControllers.get(e.params.requestId)?.abort(e.params.reason)}_setupTimeout(e,r,n,s,i=!1){this._timeoutInfo.set(e,{timeoutId:setTimeout(s,r),startTime:Date.now(),timeout:r,maxTotalTimeout:n,resetTimeoutOnProgress:i,onTimeout:s})}_resetTimeout(e){let r=this._timeoutInfo.get(e);if(!r)return!1;let n=Date.now()-r.startTime;if(r.maxTotalTimeout&&n>=r.maxTotalTimeout)throw this._timeoutInfo.delete(e),ve.fromError(Se.RequestTimeout,"Maximum total timeout exceeded",{maxTotalTimeout:r.maxTotalTimeout,totalElapsed:n});return clearTimeout(r.timeoutId),r.timeoutId=setTimeout(r.onTimeout,r.timeout),!0}_cleanupTimeout(e){let r=this._timeoutInfo.get(e);r&&(clearTimeout(r.timeoutId),this._timeoutInfo.delete(e))}async connect(e){if(this._transport)throw new Error("Already connected to a transport. Call close() before connecting to a new transport, or use a separate Protocol instance per connection.");this._transport=e;let r=this.transport?.onclose;this._transport.onclose=()=>{r?.(),this._onclose()};let n=this.transport?.onerror;this._transport.onerror=i=>{n?.(i),this._onerror(i)};let s=this._transport?.onmessage;this._transport.onmessage=(i,a)=>{s?.(i,a),Xl(i)||kO(i)?this._onresponse(i):Nx(i)?this._onrequest(i,a):SO(i)?this._onnotification(i):this._onerror(new Error(`Unknown message type: ${JSON.stringify(i)}`))},await this._transport.start()}_onclose(){let e=this._responseHandlers;this._responseHandlers=new Map,this._progressHandlers.clear(),this._taskProgressTokens.clear(),this._pendingDebouncedNotifications.clear();for(let n of this._timeoutInfo.values())clearTimeout(n.timeoutId);this._timeoutInfo.clear();for(let n of this._requestHandlerAbortControllers.values())n.abort();this._requestHandlerAbortControllers.clear();let r=ve.fromError(Se.ConnectionClosed,"Connection closed");this._transport=void 0,this.onclose?.();for(let n of e.values())n(r)}_onerror(e){this.onerror?.(e)}_onnotification(e){let r=this._notificationHandlers.get(e.method)??this.fallbackNotificationHandler;r!==void 0&&Promise.resolve().then(()=>r(e)).catch(n=>this._onerror(new Error(`Uncaught error in notification handler: ${n}`)))}_onrequest(e,r){let n=this._requestHandlers.get(e.method)??this.fallbackRequestHandler,s=this._transport,i=e.params?._meta?.[_i]?.taskId;if(n===void 0){let u={jsonrpc:"2.0",id:e.id,error:{code:Se.MethodNotFound,message:"Method not found"}};i&&this._taskMessageQueue?this._enqueueTaskMessage(i,{type:"error",message:u,timestamp:Date.now()},s?.sessionId).catch(p=>this._onerror(new Error(`Failed to enqueue error response: ${p}`))):s?.send(u).catch(p=>this._onerror(new Error(`Failed to send an error response: ${p}`)));return}let a=new AbortController;this._requestHandlerAbortControllers.set(e.id,a);let o=xO(e.params)?e.params.task:void 0,c=this._taskStore?this.requestTaskStore(e,s?.sessionId):void 0,l={signal:a.signal,sessionId:s?.sessionId,_meta:e.params?._meta,sendNotification:async u=>{if(a.signal.aborted)return;let p={relatedRequestId:e.id};i&&(p.relatedTask={taskId:i}),await this.notification(u,p)},sendRequest:async(u,p,d)=>{if(a.signal.aborted)throw new ve(Se.ConnectionClosed,"Request was cancelled");let m={...d,relatedRequestId:e.id};i&&!m.relatedTask&&(m.relatedTask={taskId:i});let f=m.relatedTask?.taskId??i;return f&&c&&await c.updateTaskStatus(f,"input_required"),await this.request(u,p,m)},authInfo:r?.authInfo,requestId:e.id,requestInfo:r?.requestInfo,taskId:i,taskStore:c,taskRequestedTtl:o?.ttl,closeSSEStream:r?.closeSSEStream,closeStandaloneSSEStream:r?.closeStandaloneSSEStream};Promise.resolve().then(()=>{o&&this.assertTaskHandlerCapability(e.method)}).then(()=>n(e,l)).then(async u=>{if(a.signal.aborted)return;let p={result:u,jsonrpc:"2.0",id:e.id};i&&this._taskMessageQueue?await this._enqueueTaskMessage(i,{type:"response",message:p,timestamp:Date.now()},s?.sessionId):await s?.send(p)},async u=>{if(a.signal.aborted)return;let p={jsonrpc:"2.0",id:e.id,error:{code:Number.isSafeInteger(u.code)?u.code:Se.InternalError,message:u.message??"Internal error",...u.data!==void 0&&{data:u.data}}};i&&this._taskMessageQueue?await this._enqueueTaskMessage(i,{type:"error",message:p,timestamp:Date.now()},s?.sessionId):await s?.send(p)}).catch(u=>this._onerror(new Error(`Failed to send response: ${u}`))).finally(()=>{this._requestHandlerAbortControllers.get(e.id)===a&&this._requestHandlerAbortControllers.delete(e.id)})}_onprogress(e){let{progressToken:r,...n}=e.params,s=Number(r),i=this._progressHandlers.get(s);if(!i){this._onerror(new Error(`Received a progress notification for an unknown token: ${JSON.stringify(e)}`));return}let a=this._responseHandlers.get(s),o=this._timeoutInfo.get(s);if(o&&a&&o.resetTimeoutOnProgress)try{this._resetTimeout(s)}catch(c){this._responseHandlers.delete(s),this._progressHandlers.delete(s),this._cleanupTimeout(s),a(c);return}i(n)}_onresponse(e){let r=Number(e.id),n=this._requestResolvers.get(r);if(n){if(this._requestResolvers.delete(r),Xl(e))n(e);else{let a=new ve(e.error.code,e.error.message,e.error.data);n(a)}return}let s=this._responseHandlers.get(r);if(s===void 0){this._onerror(new Error(`Received a response for an unknown message ID: ${JSON.stringify(e)}`));return}this._responseHandlers.delete(r),this._cleanupTimeout(r);let i=!1;if(Xl(e)&&e.result&&typeof e.result=="object"){let a=e.result;if(a.task&&typeof a.task=="object"){let o=a.task;typeof o.taskId=="string"&&(i=!0,this._taskProgressTokens.set(o.taskId,r))}}if(i||this._progressHandlers.delete(r),Xl(e))s(e);else{let a=ve.fromError(e.error.code,e.error.message,e.error.data);s(a)}}get transport(){return this._transport}async close(){await this._transport?.close()}async*requestStream(e,r,n){let{task:s}=n??{};if(!s){try{yield{type:"result",result:await this.request(e,r,n)}}catch(a){yield{type:"error",error:a instanceof ve?a:new ve(Se.InternalError,String(a))}}return}let i;try{let a=await this.request(e,ua,n);if(a.task)i=a.task.taskId,yield{type:"taskCreated",task:a.task};else throw new ve(Se.InternalError,"Task creation did not return a task");for(;;){let o=await this.getTask({taskId:i},n);if(yield{type:"taskStatus",task:o},wi(o.status)){o.status==="completed"?yield{type:"result",result:await this.getTaskResult({taskId:i},r,n)}:o.status==="failed"?yield{type:"error",error:new ve(Se.InternalError,`Task ${i} failed`)}:o.status==="cancelled"&&(yield{type:"error",error:new ve(Se.InternalError,`Task ${i} was cancelled`)});return}if(o.status==="input_required"){yield{type:"result",result:await this.getTaskResult({taskId:i},r,n)};return}let c=o.pollInterval??this._options?.defaultTaskPollInterval??1e3;await new Promise(l=>setTimeout(l,c)),n?.signal?.throwIfAborted()}}catch(a){yield{type:"error",error:a instanceof ve?a:new ve(Se.InternalError,String(a))}}}request(e,r,n){let{relatedRequestId:s,resumptionToken:i,onresumptiontoken:a,task:o,relatedTask:c}=n??{};return new Promise((l,u)=>{let p=y=>{u(y)};if(!this._transport){p(new Error("Not connected"));return}if(this._options?.enforceStrictCapabilities===!0)try{this.assertCapabilityForMethod(e.method),o&&this.assertTaskCapability(e.method)}catch(y){p(y);return}n?.signal?.throwIfAborted();let d=this._requestMessageId++,m={...e,jsonrpc:"2.0",id:d};n?.onprogress&&(this._progressHandlers.set(d,n.onprogress),m.params={...e.params,_meta:{...e.params?._meta||{},progressToken:d}}),o&&(m.params={...m.params,task:o}),c&&(m.params={...m.params,_meta:{...m.params?._meta||{},[_i]:c}});let f=y=>{this._responseHandlers.delete(d),this._progressHandlers.delete(d),this._cleanupTimeout(d),this._transport?.send({jsonrpc:"2.0",method:"notifications/cancelled",params:{requestId:d,reason:String(y)}},{relatedRequestId:s,resumptionToken:i,onresumptiontoken:a}).catch(x=>this._onerror(new Error(`Failed to send cancellation: ${x}`)));let b=y instanceof ve?y:new ve(Se.RequestTimeout,String(y));u(b)};this._responseHandlers.set(d,y=>{if(!n?.signal?.aborted){if(y instanceof Error)return u(y);try{let b=rs(r,y.result);b.success?l(b.data):u(b.error)}catch(b){u(b)}}}),n?.signal?.addEventListener("abort",()=>{f(n?.signal?.reason)});let g=n?.timeout??_K,v=()=>f(ve.fromError(Se.RequestTimeout,"Request timed out",{timeout:g}));this._setupTimeout(d,g,n?.maxTotalTimeout,v,n?.resetTimeoutOnProgress??!1);let h=c?.taskId;if(h){let y=b=>{let x=this._responseHandlers.get(d);x?x(b):this._onerror(new Error(`Response handler missing for side-channeled request ${d}`))};this._requestResolvers.set(d,y),this._enqueueTaskMessage(h,{type:"request",message:m,timestamp:Date.now()}).catch(b=>{this._cleanupTimeout(d),u(b)})}else this._transport.send(m,{relatedRequestId:s,resumptionToken:i,onresumptiontoken:a}).catch(y=>{this._cleanupTimeout(d),u(y)})})}async getTask(e,r){return this.request({method:"tasks/get",params:e},Ym,r)}async getTaskResult(e,r,n){return this.request({method:"tasks/result",params:e},r,n)}async listTasks(e,r){return this.request({method:"tasks/list",params:e},tf,r)}async cancelTask(e,r){return this.request({method:"tasks/cancel",params:e},RO,r)}async notification(e,r){if(!this._transport)throw new Error("Not connected");this.assertNotificationCapability(e.method);let n=r?.relatedTask?.taskId;if(n){let o={...e,jsonrpc:"2.0",params:{...e.params,_meta:{...e.params?._meta||{},[_i]:r.relatedTask}}};await this._enqueueTaskMessage(n,{type:"notification",message:o,timestamp:Date.now()});return}if((this._options?.debouncedNotificationMethods??[]).includes(e.method)&&!e.params&&!r?.relatedRequestId&&!r?.relatedTask){if(this._pendingDebouncedNotifications.has(e.method))return;this._pendingDebouncedNotifications.add(e.method),Promise.resolve().then(()=>{if(this._pendingDebouncedNotifications.delete(e.method),!this._transport)return;let o={...e,jsonrpc:"2.0"};r?.relatedTask&&(o={...o,params:{...o.params,_meta:{...o.params?._meta||{},[_i]:r.relatedTask}}}),this._transport?.send(o,r).catch(c=>this._onerror(c))});return}let a={...e,jsonrpc:"2.0"};r?.relatedTask&&(a={...a,params:{...a.params,_meta:{...a.params?._meta||{},[_i]:r.relatedTask}}}),await this._transport.send(a,r)}setRequestHandler(e,r){let n=i_(e);this.assertRequestHandlerCapability(n),this._requestHandlers.set(n,(s,i)=>{let a=a_(e,s);return Promise.resolve(r(a,i))})}removeRequestHandler(e){this._requestHandlers.delete(e)}assertCanSetRequestHandler(e){if(this._requestHandlers.has(e))throw new Error(`A request handler for ${e} already exists, which would be overridden`)}setNotificationHandler(e,r){let n=i_(e);this._notificationHandlers.set(n,s=>{let i=a_(e,s);return Promise.resolve(r(i))})}removeNotificationHandler(e){this._notificationHandlers.delete(e)}_cleanupTaskProgressHandler(e){let r=this._taskProgressTokens.get(e);r!==void 0&&(this._progressHandlers.delete(r),this._taskProgressTokens.delete(e))}async _enqueueTaskMessage(e,r,n){if(!this._taskStore||!this._taskMessageQueue)throw new Error("Cannot enqueue task message: taskStore and taskMessageQueue are not configured");let s=this._options?.maxTaskQueueSize;await this._taskMessageQueue.enqueue(e,r,n,s)}async _clearTaskQueue(e,r){if(this._taskMessageQueue){let n=await this._taskMessageQueue.dequeueAll(e,r);for(let s of n)if(s.type==="request"&&Nx(s.message)){let i=s.message.id,a=this._requestResolvers.get(i);a?(a(new ve(Se.InternalError,"Task cancelled or completed")),this._requestResolvers.delete(i)):this._onerror(new Error(`Resolver missing for request ${i} during task ${e} cleanup`))}}}async _waitForTaskUpdate(e,r){let n=this._options?.defaultTaskPollInterval??1e3;try{let s=await this._taskStore?.getTask(e);s?.pollInterval&&(n=s.pollInterval)}catch{}return new Promise((s,i)=>{if(r.aborted){i(new ve(Se.InvalidRequest,"Request cancelled"));return}let a=setTimeout(s,n);r.addEventListener("abort",()=>{clearTimeout(a),i(new ve(Se.InvalidRequest,"Request cancelled"))},{once:!0})})}requestTaskStore(e,r){let n=this._taskStore;if(!n)throw new Error("No task store configured");return{createTask:async s=>{if(!e)throw new Error("No request provided");return await n.createTask(s,e.id,{method:e.method,params:e.params},r)},getTask:async s=>{let i=await n.getTask(s,r);if(!i)throw new ve(Se.InvalidParams,"Failed to retrieve task: Task not found");return i},storeTaskResult:async(s,i,a)=>{await n.storeTaskResult(s,i,a,r);let o=await n.getTask(s,r);if(o){let c=su.parse({method:"notifications/tasks/status",params:o});await this.notification(c),wi(o.status)&&this._cleanupTaskProgressHandler(s)}},getTaskResult:s=>n.getTaskResult(s,r),updateTaskStatus:async(s,i,a)=>{let o=await n.getTask(s,r);if(!o)throw new ve(Se.InvalidParams,`Task "${s}" not found - it may have been cleaned up`);if(wi(o.status))throw new ve(Se.InvalidParams,`Cannot update task "${s}" from terminal status "${o.status}" to "${i}". Terminal states (completed, failed, cancelled) cannot transition to other states.`);await n.updateTaskStatus(s,i,a,r);let c=await n.getTask(s,r);if(c){let l=su.parse({method:"notifications/tasks/status",params:c});await this.notification(l),wi(c.status)&&this._cleanupTaskProgressHandler(s)}},listTasks:s=>n.listTasks(s,r)}}};function DO(t){return t!==null&&typeof t=="object"&&!Array.isArray(t)}function zO(t,e){let r={...t};for(let n in e){let s=n,i=e[s];if(i===void 0)continue;let a=r[s];DO(a)&&DO(i)?r[s]={...a,...i}:r[s]=i}return r}var wN=X(W0(),1),SN=X(_N(),1);function dte(){let t=new wN.default({strict:!1,validateFormats:!0,validateSchema:!1,allErrors:!0});return(0,SN.default)(t),t}var Uf=class{constructor(e){this._ajv=e??dte()}getValidator(e){let r="$id"in e&&typeof e.$id=="string"?this._ajv.getSchema(e.$id)??this._ajv.compile(e):this._ajv.compile(e);return n=>r(n)?{valid:!0,data:n,errorMessage:void 0}:{valid:!1,data:void 0,errorMessage:this._ajv.errorsText(r.errors)}}};var qf=class{constructor(e){this._client=e}async*callToolStream(e,r=Eo,n){let s=this._client,i={...n,task:n?.task??(s.isToolTask(e.name)?{}:void 0)},a=s.requestStream({method:"tools/call",params:e},r,i),o=s.getToolOutputValidator(e.name);for await(let c of a){if(c.type==="result"&&o){let l=c.result;if(!l.structuredContent&&!l.isError){yield{type:"error",error:new ve(Se.InvalidRequest,`Tool ${e.name} has an output schema but did not return structured content`)};return}if(l.structuredContent)try{let u=o(l.structuredContent);if(!u.valid){yield{type:"error",error:new ve(Se.InvalidParams,`Structured content does not match the tool's output schema: ${u.errorMessage}`)};return}}catch(u){if(u instanceof ve){yield{type:"error",error:u};return}yield{type:"error",error:new ve(Se.InvalidParams,`Failed to validate structured content: ${u instanceof Error?u.message:String(u)}`)};return}}yield c}}async getTask(e,r){return this._client.getTask({taskId:e},r)}async getTaskResult(e,r,n){return this._client.getTaskResult({taskId:e},r,n)}async listTasks(e,r){return this._client.listTasks(e?{cursor:e}:void 0,r)}async cancelTask(e,r){return this._client.cancelTask({taskId:e},r)}requestStream(e,r,n){return this._client.requestStream(e,r,n)}};function kN(t,e,r){if(!t)throw new Error(`${r} does not support task creation (required for ${e})`);switch(e){case"tools/call":if(!t.tools?.call)throw new Error(`${r} does not support task creation for tools/call (required for ${e})`);break;default:break}}function EN(t,e,r){if(!t)throw new Error(`${r} does not support task creation (required for ${e})`);switch(e){case"sampling/createMessage":if(!t.sampling?.createMessage)throw new Error(`${r} does not support task creation for sampling/createMessage (required for ${e})`);break;case"elicitation/create":if(!t.elicitation?.create)throw new Error(`${r} does not support task creation for elicitation/create (required for ${e})`);break;default:break}}function Ff(t,e){if(!(!t||e===null||typeof e!="object")){if(t.type==="object"&&t.properties&&typeof t.properties=="object"){let r=e,n=t.properties;for(let s of Object.keys(n)){let i=n[s];r[s]===void 0&&Object.prototype.hasOwnProperty.call(i,"default")&&(r[s]=i.default),r[s]!==void 0&&Ff(i,r[s])}}if(Array.isArray(t.anyOf))for(let r of t.anyOf)typeof r!="boolean"&&Ff(r,e);if(Array.isArray(t.oneOf))for(let r of t.oneOf)typeof r!="boolean"&&Ff(r,e)}}function mte(t){if(!t)return{supportsFormMode:!1,supportsUrlMode:!1};let e=t.form!==void 0,r=t.url!==void 0;return{supportsFormMode:e||!e&&!r,supportsUrlMode:r}}var Ho=class extends nf{constructor(e,r){super(r),this._clientInfo=e,this._cachedToolOutputValidators=new Map,this._cachedKnownTaskTools=new Set,this._cachedRequiredTaskTools=new Set,this._listChangedDebounceTimers=new Map,this._capabilities=r?.capabilities??{},this._jsonSchemaValidator=r?.jsonSchemaValidator??new Uf,r?.listChanged&&(this._pendingListChangedConfig=r.listChanged)}_setupListChangedHandlers(e){e.tools&&this._serverCapabilities?.tools?.listChanged&&this._setupListChangedHandler("tools",Yx,e.tools,async()=>(await this.listTools()).tools),e.prompts&&this._serverCapabilities?.prompts?.listChanged&&this._setupListChangedHandler("prompts",Jx,e.prompts,async()=>(await this.listPrompts()).prompts),e.resources&&this._serverCapabilities?.resources?.listChanged&&this._setupListChangedHandler("resources",Hx,e.resources,async()=>(await this.listResources()).resources)}get experimental(){return this._experimental||(this._experimental={tasks:new qf(this)}),this._experimental}registerCapabilities(e){if(this.transport)throw new Error("Cannot register capabilities after connecting to transport");this._capabilities=zO(this._capabilities,e)}setRequestHandler(e,r){let s=Fm(e)?.method;if(!s)throw new Error("Schema is missing a method literal");let i;if(wo(s)){let o=s;i=o._zod?.def?.value??o.value}else{let o=s;i=o._def?.value??o.value}if(typeof i!="string")throw new Error("Schema method literal must be a string");let a=i;if(a==="elicitation/create"){let o=async(c,l)=>{let u=rs(r_,c);if(!u.success){let y=u.error instanceof Error?u.error.message:String(u.error);throw new ve(Se.InvalidParams,`Invalid elicitation request: ${y}`)}let{params:p}=u.data;p.mode=p.mode??"form";let{supportsFormMode:d,supportsUrlMode:m}=mte(this._capabilities.elicitation);if(p.mode==="form"&&!d)throw new ve(Se.InvalidParams,"Client does not support form-mode elicitation requests");if(p.mode==="url"&&!m)throw new ve(Se.InvalidParams,"Client does not support URL-mode elicitation requests");let f=await Promise.resolve(r(c,l));if(p.task){let y=rs(ua,f);if(!y.success){let b=y.error instanceof Error?y.error.message:String(y.error);throw new ve(Se.InvalidParams,`Invalid task creation result: ${b}`)}return y.data}let g=rs(n_,f);if(!g.success){let y=g.error instanceof Error?g.error.message:String(g.error);throw new ve(Se.InvalidParams,`Invalid elicitation result: ${y}`)}let v=g.data,h=p.mode==="form"?p.requestedSchema:void 0;if(p.mode==="form"&&v.action==="accept"&&v.content&&h&&this._capabilities.elicitation?.form?.applyDefaults)try{Ff(h,v.content)}catch{}return v};return super.setRequestHandler(e,o)}if(a==="sampling/createMessage"){let o=async(c,l)=>{let u=rs(Xx,c);if(!u.success){let v=u.error instanceof Error?u.error.message:String(u.error);throw new ve(Se.InvalidParams,`Invalid sampling request: ${v}`)}let{params:p}=u.data,d=await Promise.resolve(r(c,l));if(p.task){let v=rs(ua,d);if(!v.success){let h=v.error instanceof Error?v.error.message:String(v.error);throw new ve(Se.InvalidParams,`Invalid task creation result: ${h}`)}return v.data}let f=p.tools||p.toolChoice?t_:e_,g=rs(f,d);if(!g.success){let v=g.error instanceof Error?g.error.message:String(g.error);throw new ve(Se.InvalidParams,`Invalid sampling result: ${v}`)}return g.data};return super.setRequestHandler(e,o)}return super.setRequestHandler(e,r)}assertCapability(e,r){if(!this._serverCapabilities?.[e])throw new Error(`Server does not support ${e} (required for ${r})`)}async connect(e,r){if(await super.connect(e),e.sessionId===void 0)try{let n=await this.request({method:"initialize",params:{protocolVersion:jx,capabilities:this._capabilities,clientInfo:this._clientInfo}},Mx,r);if(n===void 0)throw new Error(`Server sent invalid initialize result: ${n}`);if(!vO.includes(n.protocolVersion))throw new Error(`Server's protocol version is not supported: ${n.protocolVersion}`);this._serverCapabilities=n.capabilities,this._serverVersion=n.serverInfo,e.setProtocolVersion&&e.setProtocolVersion(n.protocolVersion),this._instructions=n.instructions,await this.notification({method:"notifications/initialized"}),this._pendingListChangedConfig&&(this._setupListChangedHandlers(this._pendingListChangedConfig),this._pendingListChangedConfig=void 0)}catch(n){throw this.close(),n}}getServerCapabilities(){return this._serverCapabilities}getServerVersion(){return this._serverVersion}getInstructions(){return this._instructions}assertCapabilityForMethod(e){switch(e){case"logging/setLevel":if(!this._serverCapabilities?.logging)throw new Error(`Server does not support logging (required for ${e})`);break;case"prompts/get":case"prompts/list":if(!this._serverCapabilities?.prompts)throw new Error(`Server does not support prompts (required for ${e})`);break;case"resources/list":case"resources/templates/list":case"resources/read":case"resources/subscribe":case"resources/unsubscribe":if(!this._serverCapabilities?.resources)throw new Error(`Server does not support resources (required for ${e})`);if(e==="resources/subscribe"&&!this._serverCapabilities.resources.subscribe)throw new Error(`Server does not support resource subscriptions (required for ${e})`);break;case"tools/call":case"tools/list":if(!this._serverCapabilities?.tools)throw new Error(`Server does not support tools (required for ${e})`);break;case"completion/complete":if(!this._serverCapabilities?.completions)throw new Error(`Server does not support completions (required for ${e})`);break;case"initialize":break;case"ping":break}}assertNotificationCapability(e){switch(e){case"notifications/roots/list_changed":if(!this._capabilities.roots?.listChanged)throw new Error(`Client does not support roots list changed notifications (required for ${e})`);break;case"notifications/initialized":break;case"notifications/cancelled":break;case"notifications/progress":break}}assertRequestHandlerCapability(e){if(this._capabilities)switch(e){case"sampling/createMessage":if(!this._capabilities.sampling)throw new Error(`Client does not support sampling capability (required for ${e})`);break;case"elicitation/create":if(!this._capabilities.elicitation)throw new Error(`Client does not support elicitation capability (required for ${e})`);break;case"roots/list":if(!this._capabilities.roots)throw new Error(`Client does not support roots capability (required for ${e})`);break;case"tasks/get":case"tasks/list":case"tasks/result":case"tasks/cancel":if(!this._capabilities.tasks)throw new Error(`Client does not support tasks capability (required for ${e})`);break;case"ping":break}}assertTaskCapability(e){kN(this._serverCapabilities?.tasks?.requests,e,"Server")}assertTaskHandlerCapability(e){this._capabilities&&EN(this._capabilities.tasks?.requests,e,"Client")}async ping(e){return this.request({method:"ping"},la,e)}async complete(e,r){return this.request({method:"completion/complete",params:e},s_,r)}async setLoggingLevel(e,r){return this.request({method:"logging/setLevel",params:{level:e}},la,r)}async getPrompt(e,r){return this.request({method:"prompts/get",params:e},Kx,r)}async listPrompts(e,r){return this.request({method:"prompts/list",params:e},Bx,r)}async listResources(e,r){return this.request({method:"resources/list",params:e},Lx,r)}async listResourceTemplates(e,r){return this.request({method:"resources/templates/list",params:e},Ux,r)}async readResource(e,r){return this.request({method:"resources/read",params:e},Fx,r)}async subscribeResource(e,r){return this.request({method:"resources/subscribe",params:e},la,r)}async unsubscribeResource(e,r){return this.request({method:"resources/unsubscribe",params:e},la,r)}async callTool(e,r=Eo,n){if(this.isToolTaskRequired(e.name))throw new ve(Se.InvalidRequest,`Tool "${e.name}" requires task-based execution. Use client.experimental.tasks.callToolStream() instead.`);let s=await this.request({method:"tools/call",params:e},r,n),i=this.getToolOutputValidator(e.name);if(i){if(!s.structuredContent&&!s.isError)throw new ve(Se.InvalidRequest,`Tool ${e.name} has an output schema but did not return structured content`);if(s.structuredContent)try{let a=i(s.structuredContent);if(!a.valid)throw new ve(Se.InvalidParams,`Structured content does not match the tool's output schema: ${a.errorMessage}`)}catch(a){throw a instanceof ve?a:new ve(Se.InvalidParams,`Failed to validate structured content: ${a instanceof Error?a.message:String(a)}`)}}return s}isToolTask(e){return this._serverCapabilities?.tasks?.requests?.tools?.call?this._cachedKnownTaskTools.has(e):!1}isToolTaskRequired(e){return this._cachedRequiredTaskTools.has(e)}cacheToolMetadata(e){this._cachedToolOutputValidators.clear(),this._cachedKnownTaskTools.clear(),this._cachedRequiredTaskTools.clear();for(let r of e){if(r.outputSchema){let s=this._jsonSchemaValidator.getValidator(r.outputSchema);this._cachedToolOutputValidators.set(r.name,s)}let n=r.execution?.taskSupport;(n==="required"||n==="optional")&&this._cachedKnownTaskTools.add(r.name),n==="required"&&this._cachedRequiredTaskTools.add(r.name)}}getToolOutputValidator(e){return this._cachedToolOutputValidators.get(e)}async listTools(e,r){let n=await this.request({method:"tools/list",params:e},Qx,r);return this.cacheToolMetadata(n.tools),n}_setupListChangedHandler(e,r,n,s){let i=AO.safeParse(n);if(!i.success)throw new Error(`Invalid ${e} listChanged options: ${i.error.message}`);if(typeof n.onChanged!="function")throw new Error(`Invalid ${e} listChanged options: onChanged must be a function`);let{autoRefresh:a,debounceMs:o}=i.data,{onChanged:c}=n,l=async()=>{if(!a){c(null,null);return}try{let p=await s();c(null,p)}catch(p){let d=p instanceof Error?p:new Error(String(p));c(d,null)}},u=()=>{if(o){let p=this._listChangedDebounceTimers.get(e);p&&clearTimeout(p);let d=setTimeout(l,o);this._listChangedDebounceTimers.set(e,d)}else l()};this.setNotificationHandler(r,u)}async sendRootsListChanged(){return this.notification({method:"notifications/roots/list_changed"})}};var hD=X(mD(),1),Wf=X(require("node:process"),1),gD=require("node:stream");var Bf=class{append(e){this._buffer=this._buffer?Buffer.concat([this._buffer,e]):e}readMessage(){if(!this._buffer)return null;let e=this._buffer.indexOf(`
`);if(e===-1)return null;let r=this._buffer.toString("utf8",0,e).replace(/\r$/,"");return this._buffer=this._buffer.subarray(e+1),Ute(r)}clear(){this._buffer=void 0}};function Ute(t){return EO.parse(JSON.parse(t))}function fD(t){return JSON.stringify(t)+`
-`}var qte=Wf.default.platform==="win32"?["APPDATA","HOMEDRIVE","HOMEPATH","LOCALAPPDATA","PATH","PROCESSOR_ARCHITECTURE","SYSTEMDRIVE","SYSTEMROOT","TEMP","USERNAME","USERPROFILE","PROGRAMFILES"]:["HOME","LOGNAME","PATH","SHELL","TERM","USER"];function Fte(){let t={};for(let e of qte){let r=Wf.default.env[e];r!==void 0&&(r.startsWith("()")||(t[e]=r))}return t}var Zo=class{constructor(e){this._readBuffer=new Bf,this._stderrStream=null,this._serverParams=e,(e.stderr==="pipe"||e.stderr==="overlapped")&&(this._stderrStream=new gD.PassThrough)}async start(){if(this._process)throw new Error("StdioClientTransport already started! If using Client class, note that connect() calls start() automatically.");return new Promise((e,r)=>{this._process=(0,hD.default)(this._serverParams.command,this._serverParams.args??[],{env:{...Fte(),...this._serverParams.env},stdio:["pipe","pipe",this._serverParams.stderr??"inherit"],shell:!1,windowsHide:Wf.default.platform==="win32",cwd:this._serverParams.cwd}),this._process.on("error",n=>{r(n),this.onerror?.(n)}),this._process.on("spawn",()=>{e()}),this._process.on("close",n=>{this._process=void 0,this.onclose?.()}),this._process.stdin?.on("error",n=>{this.onerror?.(n)}),this._process.stdout?.on("data",n=>{this._readBuffer.append(n),this.processReadBuffer()}),this._process.stdout?.on("error",n=>{this.onerror?.(n)}),this._stderrStream&&this._process.stderr&&this._process.stderr.pipe(this._stderrStream)})}get stderr(){return this._stderrStream?this._stderrStream:this._process?.stderr??null}get pid(){return this._process?.pid??null}processReadBuffer(){for(;;)try{let e=this._readBuffer.readMessage();if(e===null)break;this.onmessage?.(e)}catch(e){this.onerror?.(e)}}async close(){if(this._process){let e=this._process;this._process=void 0;let r=new Promise(n=>{e.once("close",()=>{n()})});try{e.stdin?.end()}catch{}if(await Promise.race([r,new Promise(n=>setTimeout(n,2e3).unref())]),e.exitCode===null){try{e.kill("SIGTERM")}catch{}await Promise.race([r,new Promise(n=>setTimeout(n,2e3).unref())])}if(e.exitCode===null)try{e.kill("SIGKILL")}catch{}}this._readBuffer.clear()}send(e){return new Promise(r=>{if(!this._process?.stdin)throw new Error("Not connected");let n=fD(e);this._process.stdin.write(n)?r():this._process.stdin.once("drain",r)})}};ls();Gf();se();var uw=require("os"),pw=require("path"),Wte=["/opt/homebrew/bin","/usr/local/bin","/home/linuxbrew/.linuxbrew/bin",`${(0,uw.homedir)()}/.cargo/bin`,`${(0,uw.homedir)()}/.local/bin`];function Zte(t=process.env.PATH){let e=t?t.split(pw.delimiter).filter(n=>n.length>0):[],r=new Set(e);for(let n of Wte)r.has(n)||(e.push(n),r.add(n));return e.join(pw.delimiter)}function Mu(t=process.env){return{...t,PATH:Zte(t.PATH)}}Hu();se();ls();var Kte=5e3;async function oh(t,e={},r=Kte){let n=new Promise((s,i)=>setTimeout(()=>i(new Error(`Fetch timeout after ${r}ms`)),r));return Promise.race([fetch(t,e),n])}var Jte="8.4.0";function ch(t){let e=cs();return`http://${e.includes(":")&&!e.startsWith("[")?`[${e}]`:e}:${t}`}async function _w(t){try{return(await oh(`${ch(t)}/api/health`)).ok}catch{return!1}}async function Bu(t,e=3e4){let r=Date.now();for(;Date.now()-rsetTimeout(n,500))}return!1}async function Wu(t,e=1e4){let r=Date.now();for(;Date.now()-rsetTimeout(n,500))}return!1}async function Zu(t){try{let e=await oh(`${ch(t)}/api/admin/shutdown`,{method:"POST"});return e.ok?!0:(_.warn("SYSTEM","Shutdown request returned error",{port:t,status:e.status}),!1)}catch(e){return e instanceof Error&&(e.message?.includes("ECONNREFUSED")||e.message?.includes("Fetch timeout"))?(_.debug("SYSTEM","Worker already stopped or not responding",{port:t}),!1):(_.error("SYSTEM","Shutdown request failed unexpectedly",{port:t},e),!1)}}function Qte(){return Jte}async function Yte(t){try{let e=await oh(`${ch(t)}/api/version`);return e.ok?(await e.json()).version:null}catch{return _.debug("SYSTEM","Could not fetch worker version",{port:t}),null}}async function WD(t){let e=Qte(),r=await Yte(t);return r?{matches:e===r,pluginVersion:e,workerVersion:r}:{matches:!0,pluginVersion:e,workerVersion:r}}se();Hu();var Gu=5e3;async function Vu(t,e,r){let n=new Promise(i=>setTimeout(()=>{_.warn("SYSTEM",`${r} timed out after ${e}ms`),i({completed:!1})},e)),s=t.then(i=>({completed:!0,result:i}));return Promise.race([s,n])}async function ZD(t){_.info("SYSTEM","Shutdown initiated"),ps();let e=await Vu(vw(process.pid),Gu,"Enumerate child processes"),r=e.completed?e.result??[]:[];if(_.info("SYSTEM","Found child processes",{count:r.length,pids:r}),t.server&&(await Vu(Xte(t.server),Gu,"Close HTTP server"),_.info("SYSTEM","HTTP server closed")),await Vu(t.sessionManager.shutdownAll(),Gu,"Shutdown sessions"),t.mcpClient&&(await Vu(t.mcpClient.close(),Gu,"Close MCP client"),_.info("SYSTEM","MCP client closed")),t.dbManager&&await Vu(t.dbManager.close(),Gu,"Close database"),r.length>0){_.info("SYSTEM","Force killing remaining children");for(let n of r)await yw(n);await bw(r,5e3)}_.info("SYSTEM","Worker shutdown complete")}async function Xte(t){t.closeAllConnections(),process.platform==="win32"&&await new Promise(e=>setTimeout(e,500)),await new Promise((e,r)=>{t.close(n=>n?r(n):e())}),process.platform==="win32"&&(await new Promise(e=>setTimeout(e,500)),_.info("SYSTEM","Waited for Windows port cleanup"))}Hu();se();As();var ere={waitForHealth:Bu,checkVersionMatch:WD,httpShutdown:Zu,waitForPortFree:Wu,isPortInUse:_w,spawnDaemon:Fu,writePidFile:qu,removePidFile:ps,cleanStalePidFile:gw,getPlatformTimeout:ka};async function ww(t,e,r=ere){if(r.cleanStalePidFile(),await r.waitForHealth(t,1e3)){let i=await r.checkVersionMatch(t);if(i.matches)return{ready:!0};if(_.info("SYSTEM","Worker version mismatch detected - auto-restarting",{pluginVersion:i.pluginVersion,workerVersion:i.workerVersion}),await r.httpShutdown(t),!await r.waitForPortFree(t,r.getPlatformTimeout(qt.PORT_IN_USE_WAIT)))return{ready:!1,error:"Port did not free after version mismatch restart"};r.removePidFile()}if(await r.isPortInUse(t))return _.info("SYSTEM","Port in use, waiting for worker to become healthy"),await r.waitForHealth(t,r.getPlatformTimeout(qt.PORT_IN_USE_WAIT))?{ready:!0}:{ready:!1,error:"Port in use but worker not responding"};_.info("SYSTEM","Starting worker daemon");let n=r.spawnDaemon(e,t);return n===void 0?{ready:!1,error:"Failed to spawn worker daemon"}:(r.writePidFile({pid:n,port:t,startedAt:new Date().toISOString()}),await r.waitForHealth(t,r.getPlatformTimeout(qt.POST_SPAWN_WAIT))?{ready:!0}:(r.removePidFile(),{ready:!1,error:"Worker failed to start (health check timeout)"}))}var Gq=X(Vp(),1),Bk=X(require("fs"),1),Wk=X(require("path"),1);se();var Lk=X(Vp(),1),Dq=X(Cq(),1),zq=X(Nq(),1),Mq=X(require("path"),1);er();se();Gf();var bme=[/^https?:\/\/localhost(:\d+)?$/,/^https?:\/\/127\.0\.0\.1(:\d+)?$/,/^https?:\/\/\[::1\](:\d+)?$/];function xme(t){if(t===void 0||bme.some(e=>e.test(t)))return!0;if(wa()){let e=yD();if(e&&t&&new RegExp(`^https?://${e.replace(/\./g,"\\.")}(:\\d+)?$`).test(t))return!0}return!1}function Uk(t){let e=[];e.push(Lk.default.json({limit:"5mb"})),e.push((0,Dq.default)({origin:(s,i)=>{xme(s)?i(null,!0):(_.warn("SECURITY","CORS request blocked",{origin:s}),i(null,!1))}})),e.push((0,zq.default)()),e.push((s,i,a)=>{let c=[".html",".js",".css",".svg",".png",".jpg",".jpeg",".webp",".woff",".woff2",".ttf",".eot"].some(f=>s.path.endsWith(f)),l=s.path==="/api/logs";if(s.path.startsWith("/health")||s.path==="/"||c||l)return a();let u=Date.now(),p=`${s.method}-${Date.now()}`,d=t(s.method,s.path,s.body);_.info("HTTP",`\u2192 ${s.method} ${s.path}`,{requestId:p},d);let m=i.send.bind(i);i.send=function(f){let g=Date.now()-u;return _.info("HTTP",`\u2190 ${i.statusCode} ${s.path}`,{requestId:p,duration:`${g}ms`}),m(f)},a()});let r=Vs(),n=Mq.default.join(r,"plugin","ui");return e.push(Lk.default.static(n)),e}function bg(t,e,r){let n=t.ip||t.connection.remoteAddress||"";if(!(n==="127.0.0.1"||n==="::1"||n==="::ffff:127.0.0.1"||n==="localhost")){_.warn("SECURITY","Admin endpoint access denied - not localhost",{endpoint:t.path,clientIp:n,method:t.method}),e.status(403).json({error:"Forbidden",message:"Admin endpoints are only accessible from localhost"});return}r()}function qk(t,e,r){if(!r||Object.keys(r).length===0||e.includes("/init"))return"";if(e.includes("/observations")){let n=r.tool_name||"?",s=r.tool_input;return`tool=${_.formatTool(n,s)}`}return e.includes("/summarize")?"requesting summary":""}se();var Kp=class extends Error{constructor(r,n=500,s,i){super(r);this.statusCode=n;this.code=s;this.details=i;this.name="AppError"}statusCode;code;details};function $q(t,e,r,n){let s={error:t,message:e};return r&&(s.code=r),n&&(s.details=n),s}var Lq=(t,e,r,n)=>{let s=t instanceof Kp?t.statusCode:500;_.error("HTTP",`Error handling ${e.method} ${e.path}`,{statusCode:s,error:t.message,code:t instanceof Kp?t.code:void 0},t);let i=t instanceof Kp,a=$q(i&&t.name||"Error",i?t.message:"Internal server error",i?t.code:void 0,i?t.details:void 0);r.status(s).json(a)};function Uq(t,e){e.status(404).json($q("NotFound",`Cannot ${t.method} ${t.path}`))}var xg=X(require("crypto"),1);se();zr();er();function _me(t,e){let r=Buffer.from(t),n=Buffer.from(e);return r.length!==n.length?(xg.default.timingSafeEqual(r,r),!1):xg.default.timingSafeEqual(r,n)}var qq="claude_pilot_session",Fq=1440*60*1e3,Rc=new Map;function wme(t){let e=t.ip||t.socket.remoteAddress||"";return e==="127.0.0.1"||e==="::1"||e==="::ffff:127.0.0.1"||e==="localhost"}function _g(){return Le.loadFromFile(Ht).CLAUDE_PILOT_REMOTE_TOKEN}function Sme(){return xg.default.randomBytes(32).toString("hex")}function kme(t,e){let r=Rc.get(t);return r?Date.now()-r.createdAt>Fq?(Rc.delete(t),!1):r.ip!==e?(_.warn("SECURITY","Session IP mismatch - possible session replay",{sessionIp:r.ip,requestIp:e}),!1):!0:!1}function Hq(t){let e=Sme();return Rc.set(e,{createdAt:Date.now(),ip:t}),e}function Bq(t){Rc.delete(t)}function Eme(){let t=Date.now();for(let[e,r]of Rc.entries())t-r.createdAt>Fq&&Rc.delete(e)}setInterval(Eme,3600*1e3);function Fk(t,e,r){if(wme(t))return t.auth={isLocal:!0,scopes:["*"]},r();if(t.path==="/login"||t.path.startsWith("/api/auth/"))return r();let n=t.ip||t.socket.remoteAddress||"unknown",s=t.cookies?.[qq];if(s&&kme(s,n))return t.auth={isLocal:!1,clientId:"web-session",scopes:["*"]},r();let i=t.headers.authorization;if(i&&i.startsWith("Bearer ")){let c=i.slice(7),l=_g();if(l&&_me(c,l))return t.auth={isLocal:!1,clientId:"api-client",scopes:["*"]},r()}if((t.headers.accept||"").includes("text/html")&&(t.path==="/"||t.path==="/viewer.html")){e.redirect("/login");return}_.warn("SECURITY","Unauthorized request",{path:t.path,ip:n}),e.status(401).json({code:"UNAUTHORIZED",message:"Authentication required"})}function Hk(){return qq}function Pc(){return!!_g()}var Zq=X(require("crypto"),1);se();var Wq=new Map;function Tme(t){let e=t.ip||t.socket.remoteAddress||"";return e==="127.0.0.1"||e==="::1"||e==="::ffff:127.0.0.1"}function Rme(t){let e=t.headers.authorization;return e&&e.startsWith("Bearer ")?`token:${Zq.default.createHash("sha256").update(e.slice(7)).digest("hex").slice(0,16)}`:`ip:${t.ip||t.socket.remoteAddress||"unknown"}`}function wg(t=1e3,e=6e4){return(r,n,s)=>{if(Tme(r))return s();let i=Rme(r),a=Date.now(),o=a-e,c=Wq.get(i);if(c||(c={timestamps:[]},Wq.set(i,c)),c.timestamps=c.timestamps.filter(u=>u>o),c.timestamps.length>=t){let u=Math.ceil(e/1e3);_.warn("SECURITY","Rate limit exceeded",{key:i,requests:c.timestamps.length,limit:t}),n.setHeader("Retry-After",u.toString()),n.setHeader("X-RateLimit-Limit",t.toString()),n.setHeader("X-RateLimit-Remaining","0"),n.setHeader("X-RateLimit-Reset",Math.ceil((a+e)/1e3).toString()),n.status(429).json({code:"RATE_LIMITED",message:"Too many requests",retryAfter:u});return}c.timestamps.push(a);let l=t-c.timestamps.length;n.setHeader("X-RateLimit-Limit",t.toString()),n.setHeader("X-RateLimit-Remaining",l.toString()),n.setHeader("X-RateLimit-Reset",Math.ceil((a+e)/1e3).toString()),s()}}ls();var Pme="8.4.0",Sg=class{app;server=null;options;startTime=Date.now();constructor(e){this.options=e,this.app=(0,Gq.default)(),this.setupMiddleware(),this.setupCoreRoutes()}getHttpServer(){return this.server}async listen(e,r){return new Promise((n,s)=>{this.server=this.app.listen(e,r,()=>{_.info("SYSTEM","HTTP server started",{host:r,port:e,pid:process.pid}),n()}),this.server.on("error",s)})}async close(){this.server&&(this.server.closeAllConnections(),process.platform==="win32"&&await new Promise(e=>setTimeout(e,500)),await new Promise((e,r)=>{this.server.close(n=>n?r(n):e())}),process.platform==="win32"&&await new Promise(e=>setTimeout(e,500)),this.server=null,_.info("SYSTEM","HTTP server closed"))}registerRoutes(e){e.setupRoutes(this.app)}finalizeRoutes(){this.app.use(Uq),this.app.use(Lq)}setupMiddleware(){Uk(qk).forEach(s=>this.app.use(s)),this.app.use("/api/auth/login",wg(10,6e4)),this.app.use(wg(1e3,6e4));let r=Yf();if(r!=="127.0.0.1"&&r!=="localhost"){let s=Pc();_.info("SYSTEM","Enabling authentication middleware for network access",{bind:r,tokenConfigured:s}),s||_.warn("SYSTEM","No CLAUDE_PILOT_REMOTE_TOKEN set - all remote requests will be rejected until a token is configured",{bind:r}),this.app.use(Fk)}}setupCoreRoutes(){let e="TEST-008-wrapper-ipc";this.app.get("/api/health",(r,n)=>{n.status(200).json({status:"ok",build:e,managed:process.env.CLAUDE_PILOT_MANAGED==="true",hasIpc:typeof process.send=="function",platform:process.platform,pid:process.pid,initialized:this.options.getInitializationComplete(),coreReady:this.options.getCoreReady(),mcpReady:this.options.getMcpReady()})}),this.app.get("/api/core-ready",(r,n)=>{this.options.getCoreReady()?n.status(200).json({status:"ready",message:"Core services ready (Database + SearchManager)"}):n.status(503).json({status:"initializing",message:"Core services still initializing, please retry"})}),this.app.get("/api/readiness",(r,n)=>{this.options.getInitializationComplete()?n.status(200).json({status:"ready",mcpReady:this.options.getMcpReady()}):n.status(503).json({status:"initializing",message:"Worker is still initializing, please retry"})}),this.app.get("/api/version",(r,n)=>{n.status(200).json({version:Pme})}),this.app.get("/api/process-stats",async(r,n)=>{try{let{getProcessStats:s}=await Promise.resolve().then(()=>(Hu(),BD)),i=await s();n.status(200).json({...i,uptime:Math.round((Date.now()-this.startTime)/1e3),platform:process.platform,pid:process.pid})}catch(s){_.error("SYSTEM","Failed to get process stats",{},s),n.status(500).json({error:"Failed to get process stats"})}}),this.app.get("/api/instructions",async(r,n)=>{let s=r.query.topic||"all",i=r.query.operation;try{let a;if(i){let o=Wk.default.join(__dirname,"../skills/mem-search/operations",`${i}.md`);a=await Bk.promises.readFile(o,"utf-8")}else{let o=Wk.default.join(__dirname,"../skills/mem-search/SKILL.md"),c=await Bk.promises.readFile(o,"utf-8");a=this.extractInstructionSection(c,s)}n.json({content:[{type:"text",text:a}]})}catch{n.status(404).json({error:"Instruction not found"})}}),this.app.post("/api/admin/restart",bg,async(r,n)=>{n.json({status:"restarting"}),process.platform==="win32"&&process.env.CLAUDE_PILOT_MANAGED==="true"&&process.send?(_.info("SYSTEM","Sending restart request to wrapper"),process.send({type:"restart"})):setTimeout(async()=>{await this.options.onRestart()},100)}),this.app.post("/api/admin/shutdown",bg,async(r,n)=>{n.json({status:"shutting_down"}),process.platform==="win32"&&process.env.CLAUDE_PILOT_MANAGED==="true"&&process.send?(_.info("SYSTEM","Sending shutdown request to wrapper"),process.send({type:"shutdown"})):setTimeout(async()=>{await this.options.onShutdown()},100)})}extractInstructionSection(e,r){let n={workflow:this.extractBetween(e,"## The Workflow","## Search Parameters"),search_params:this.extractBetween(e,"## Search Parameters","## Examples"),examples:this.extractBetween(e,"## Examples","## Why This Workflow"),all:e};return n[r]||n.all}extractBetween(e,r,n){let s=e.indexOf(r),i=e.indexOf(n);return s===-1?e:i===-1?e.substring(s):e.substring(s,i).trim()}};kg();var Kq=require("bun:sqlite");er();se();var Eg=class{db;constructor(e){e||(es(rn),e=Ml),this.db=new Kq.Database(e),this.db.run("PRAGMA journal_mode = WAL"),this.ensureFTSTables()}ensureFTSTables(){this.db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name LIKE '%_fts'").all().some(n=>n.name==="observations_fts"||n.name==="session_summaries_fts")||(_.info("DB","Creating FTS5 tables"),this.db.run(`
+`}var qte=Wf.default.platform==="win32"?["APPDATA","HOMEDRIVE","HOMEPATH","LOCALAPPDATA","PATH","PROCESSOR_ARCHITECTURE","SYSTEMDRIVE","SYSTEMROOT","TEMP","USERNAME","USERPROFILE","PROGRAMFILES"]:["HOME","LOGNAME","PATH","SHELL","TERM","USER"];function Fte(){let t={};for(let e of qte){let r=Wf.default.env[e];r!==void 0&&(r.startsWith("()")||(t[e]=r))}return t}var Zo=class{constructor(e){this._readBuffer=new Bf,this._stderrStream=null,this._serverParams=e,(e.stderr==="pipe"||e.stderr==="overlapped")&&(this._stderrStream=new gD.PassThrough)}async start(){if(this._process)throw new Error("StdioClientTransport already started! If using Client class, note that connect() calls start() automatically.");return new Promise((e,r)=>{this._process=(0,hD.default)(this._serverParams.command,this._serverParams.args??[],{env:{...Fte(),...this._serverParams.env},stdio:["pipe","pipe",this._serverParams.stderr??"inherit"],shell:!1,windowsHide:Wf.default.platform==="win32",cwd:this._serverParams.cwd}),this._process.on("error",n=>{r(n),this.onerror?.(n)}),this._process.on("spawn",()=>{e()}),this._process.on("close",n=>{this._process=void 0,this.onclose?.()}),this._process.stdin?.on("error",n=>{this.onerror?.(n)}),this._process.stdout?.on("data",n=>{this._readBuffer.append(n),this.processReadBuffer()}),this._process.stdout?.on("error",n=>{this.onerror?.(n)}),this._stderrStream&&this._process.stderr&&this._process.stderr.pipe(this._stderrStream)})}get stderr(){return this._stderrStream?this._stderrStream:this._process?.stderr??null}get pid(){return this._process?.pid??null}processReadBuffer(){for(;;)try{let e=this._readBuffer.readMessage();if(e===null)break;this.onmessage?.(e)}catch(e){this.onerror?.(e)}}async close(){if(this._process){let e=this._process;this._process=void 0;let r=new Promise(n=>{e.once("close",()=>{n()})});try{e.stdin?.end()}catch{}if(await Promise.race([r,new Promise(n=>setTimeout(n,2e3).unref())]),e.exitCode===null){try{e.kill("SIGTERM")}catch{}await Promise.race([r,new Promise(n=>setTimeout(n,2e3).unref())])}if(e.exitCode===null)try{e.kill("SIGKILL")}catch{}}this._readBuffer.clear()}send(e){return new Promise(r=>{if(!this._process?.stdin)throw new Error("Not connected");let n=fD(e);this._process.stdin.write(n)?r():this._process.stdin.once("drain",r)})}};ls();Gf();se();var uw=require("os"),pw=require("path"),Wte=["/opt/homebrew/bin","/usr/local/bin","/home/linuxbrew/.linuxbrew/bin",`${(0,uw.homedir)()}/.cargo/bin`,`${(0,uw.homedir)()}/.local/bin`];function Zte(t=process.env.PATH){let e=t?t.split(pw.delimiter).filter(n=>n.length>0):[],r=new Set(e);for(let n of Wte)r.has(n)||(e.push(n),r.add(n));return e.join(pw.delimiter)}function Mu(t=process.env){return{...t,PATH:Zte(t.PATH)}}Hu();se();ls();var Kte=5e3;async function oh(t,e={},r=Kte){let n=new Promise((s,i)=>setTimeout(()=>i(new Error(`Fetch timeout after ${r}ms`)),r));return Promise.race([fetch(t,e),n])}var Jte="8.4.1";function ch(t){let e=cs();return`http://${e.includes(":")&&!e.startsWith("[")?`[${e}]`:e}:${t}`}async function _w(t){try{return(await oh(`${ch(t)}/api/health`)).ok}catch{return!1}}async function Bu(t,e=3e4){let r=Date.now();for(;Date.now()-rsetTimeout(n,500))}return!1}async function Wu(t,e=1e4){let r=Date.now();for(;Date.now()-rsetTimeout(n,500))}return!1}async function Zu(t){try{let e=await oh(`${ch(t)}/api/admin/shutdown`,{method:"POST"});return e.ok?!0:(_.warn("SYSTEM","Shutdown request returned error",{port:t,status:e.status}),!1)}catch(e){return e instanceof Error&&(e.message?.includes("ECONNREFUSED")||e.message?.includes("Fetch timeout"))?(_.debug("SYSTEM","Worker already stopped or not responding",{port:t}),!1):(_.error("SYSTEM","Shutdown request failed unexpectedly",{port:t},e),!1)}}function Qte(){return Jte}async function Yte(t){try{let e=await oh(`${ch(t)}/api/version`);return e.ok?(await e.json()).version:null}catch{return _.debug("SYSTEM","Could not fetch worker version",{port:t}),null}}async function WD(t){let e=Qte(),r=await Yte(t);return r?{matches:e===r,pluginVersion:e,workerVersion:r}:{matches:!0,pluginVersion:e,workerVersion:r}}se();Hu();var Gu=5e3;async function Vu(t,e,r){let n=new Promise(i=>setTimeout(()=>{_.warn("SYSTEM",`${r} timed out after ${e}ms`),i({completed:!1})},e)),s=t.then(i=>({completed:!0,result:i}));return Promise.race([s,n])}async function ZD(t){_.info("SYSTEM","Shutdown initiated"),ps();let e=await Vu(vw(process.pid),Gu,"Enumerate child processes"),r=e.completed?e.result??[]:[];if(_.info("SYSTEM","Found child processes",{count:r.length,pids:r}),t.server&&(await Vu(Xte(t.server),Gu,"Close HTTP server"),_.info("SYSTEM","HTTP server closed")),await Vu(t.sessionManager.shutdownAll(),Gu,"Shutdown sessions"),t.mcpClient&&(await Vu(t.mcpClient.close(),Gu,"Close MCP client"),_.info("SYSTEM","MCP client closed")),t.dbManager&&await Vu(t.dbManager.close(),Gu,"Close database"),r.length>0){_.info("SYSTEM","Force killing remaining children");for(let n of r)await yw(n);await bw(r,5e3)}_.info("SYSTEM","Worker shutdown complete")}async function Xte(t){t.closeAllConnections(),process.platform==="win32"&&await new Promise(e=>setTimeout(e,500)),await new Promise((e,r)=>{t.close(n=>n?r(n):e())}),process.platform==="win32"&&(await new Promise(e=>setTimeout(e,500)),_.info("SYSTEM","Waited for Windows port cleanup"))}Hu();se();As();var ere={waitForHealth:Bu,checkVersionMatch:WD,httpShutdown:Zu,waitForPortFree:Wu,isPortInUse:_w,spawnDaemon:Fu,writePidFile:qu,removePidFile:ps,cleanStalePidFile:gw,getPlatformTimeout:ka};async function ww(t,e,r=ere){if(r.cleanStalePidFile(),await r.waitForHealth(t,1e3)){let i=await r.checkVersionMatch(t);if(i.matches)return{ready:!0};if(_.info("SYSTEM","Worker version mismatch detected - auto-restarting",{pluginVersion:i.pluginVersion,workerVersion:i.workerVersion}),await r.httpShutdown(t),!await r.waitForPortFree(t,r.getPlatformTimeout(qt.PORT_IN_USE_WAIT)))return{ready:!1,error:"Port did not free after version mismatch restart"};r.removePidFile()}if(await r.isPortInUse(t))return _.info("SYSTEM","Port in use, waiting for worker to become healthy"),await r.waitForHealth(t,r.getPlatformTimeout(qt.PORT_IN_USE_WAIT))?{ready:!0}:{ready:!1,error:"Port in use but worker not responding"};_.info("SYSTEM","Starting worker daemon");let n=r.spawnDaemon(e,t);return n===void 0?{ready:!1,error:"Failed to spawn worker daemon"}:(r.writePidFile({pid:n,port:t,startedAt:new Date().toISOString()}),await r.waitForHealth(t,r.getPlatformTimeout(qt.POST_SPAWN_WAIT))?{ready:!0}:(r.removePidFile(),{ready:!1,error:"Worker failed to start (health check timeout)"}))}var Gq=X(Vp(),1),Bk=X(require("fs"),1),Wk=X(require("path"),1);se();var Lk=X(Vp(),1),Dq=X(Cq(),1),zq=X(Nq(),1),Mq=X(require("path"),1);er();se();Gf();var bme=[/^https?:\/\/localhost(:\d+)?$/,/^https?:\/\/127\.0\.0\.1(:\d+)?$/,/^https?:\/\/\[::1\](:\d+)?$/];function xme(t){if(t===void 0||bme.some(e=>e.test(t)))return!0;if(wa()){let e=yD();if(e&&t&&new RegExp(`^https?://${e.replace(/\./g,"\\.")}(:\\d+)?$`).test(t))return!0}return!1}function Uk(t){let e=[];e.push(Lk.default.json({limit:"5mb"})),e.push((0,Dq.default)({origin:(s,i)=>{xme(s)?i(null,!0):(_.warn("SECURITY","CORS request blocked",{origin:s}),i(null,!1))}})),e.push((0,zq.default)()),e.push((s,i,a)=>{let c=[".html",".js",".css",".svg",".png",".jpg",".jpeg",".webp",".woff",".woff2",".ttf",".eot"].some(f=>s.path.endsWith(f)),l=s.path==="/api/logs";if(s.path.startsWith("/health")||s.path==="/"||c||l)return a();let u=Date.now(),p=`${s.method}-${Date.now()}`,d=t(s.method,s.path,s.body);_.info("HTTP",`\u2192 ${s.method} ${s.path}`,{requestId:p},d);let m=i.send.bind(i);i.send=function(f){let g=Date.now()-u;return _.info("HTTP",`\u2190 ${i.statusCode} ${s.path}`,{requestId:p,duration:`${g}ms`}),m(f)},a()});let r=Vs(),n=Mq.default.join(r,"plugin","ui");return e.push(Lk.default.static(n)),e}function bg(t,e,r){let n=t.ip||t.connection.remoteAddress||"";if(!(n==="127.0.0.1"||n==="::1"||n==="::ffff:127.0.0.1"||n==="localhost")){_.warn("SECURITY","Admin endpoint access denied - not localhost",{endpoint:t.path,clientIp:n,method:t.method}),e.status(403).json({error:"Forbidden",message:"Admin endpoints are only accessible from localhost"});return}r()}function qk(t,e,r){if(!r||Object.keys(r).length===0||e.includes("/init"))return"";if(e.includes("/observations")){let n=r.tool_name||"?",s=r.tool_input;return`tool=${_.formatTool(n,s)}`}return e.includes("/summarize")?"requesting summary":""}se();var Kp=class extends Error{constructor(r,n=500,s,i){super(r);this.statusCode=n;this.code=s;this.details=i;this.name="AppError"}statusCode;code;details};function $q(t,e,r,n){let s={error:t,message:e};return r&&(s.code=r),n&&(s.details=n),s}var Lq=(t,e,r,n)=>{let s=t instanceof Kp?t.statusCode:500;_.error("HTTP",`Error handling ${e.method} ${e.path}`,{statusCode:s,error:t.message,code:t instanceof Kp?t.code:void 0},t);let i=t instanceof Kp,a=$q(i&&t.name||"Error",i?t.message:"Internal server error",i?t.code:void 0,i?t.details:void 0);r.status(s).json(a)};function Uq(t,e){e.status(404).json($q("NotFound",`Cannot ${t.method} ${t.path}`))}var xg=X(require("crypto"),1);se();zr();er();function _me(t,e){let r=Buffer.from(t),n=Buffer.from(e);return r.length!==n.length?(xg.default.timingSafeEqual(r,r),!1):xg.default.timingSafeEqual(r,n)}var qq="claude_pilot_session",Fq=1440*60*1e3,Rc=new Map;function wme(t){let e=t.ip||t.socket.remoteAddress||"";return e==="127.0.0.1"||e==="::1"||e==="::ffff:127.0.0.1"||e==="localhost"}function _g(){return Le.loadFromFile(Ht).CLAUDE_PILOT_REMOTE_TOKEN}function Sme(){return xg.default.randomBytes(32).toString("hex")}function kme(t,e){let r=Rc.get(t);return r?Date.now()-r.createdAt>Fq?(Rc.delete(t),!1):r.ip!==e?(_.warn("SECURITY","Session IP mismatch - possible session replay",{sessionIp:r.ip,requestIp:e}),!1):!0:!1}function Hq(t){let e=Sme();return Rc.set(e,{createdAt:Date.now(),ip:t}),e}function Bq(t){Rc.delete(t)}function Eme(){let t=Date.now();for(let[e,r]of Rc.entries())t-r.createdAt>Fq&&Rc.delete(e)}setInterval(Eme,3600*1e3);function Fk(t,e,r){if(wme(t))return t.auth={isLocal:!0,scopes:["*"]},r();if(t.path==="/login"||t.path.startsWith("/api/auth/"))return r();let n=t.ip||t.socket.remoteAddress||"unknown",s=t.cookies?.[qq];if(s&&kme(s,n))return t.auth={isLocal:!1,clientId:"web-session",scopes:["*"]},r();let i=t.headers.authorization;if(i&&i.startsWith("Bearer ")){let c=i.slice(7),l=_g();if(l&&_me(c,l))return t.auth={isLocal:!1,clientId:"api-client",scopes:["*"]},r()}if((t.headers.accept||"").includes("text/html")&&(t.path==="/"||t.path==="/viewer.html")){e.redirect("/login");return}_.warn("SECURITY","Unauthorized request",{path:t.path,ip:n}),e.status(401).json({code:"UNAUTHORIZED",message:"Authentication required"})}function Hk(){return qq}function Pc(){return!!_g()}var Zq=X(require("crypto"),1);se();var Wq=new Map;function Tme(t){let e=t.ip||t.socket.remoteAddress||"";return e==="127.0.0.1"||e==="::1"||e==="::ffff:127.0.0.1"}function Rme(t){let e=t.headers.authorization;return e&&e.startsWith("Bearer ")?`token:${Zq.default.createHash("sha256").update(e.slice(7)).digest("hex").slice(0,16)}`:`ip:${t.ip||t.socket.remoteAddress||"unknown"}`}function wg(t=1e3,e=6e4){return(r,n,s)=>{if(Tme(r))return s();let i=Rme(r),a=Date.now(),o=a-e,c=Wq.get(i);if(c||(c={timestamps:[]},Wq.set(i,c)),c.timestamps=c.timestamps.filter(u=>u>o),c.timestamps.length>=t){let u=Math.ceil(e/1e3);_.warn("SECURITY","Rate limit exceeded",{key:i,requests:c.timestamps.length,limit:t}),n.setHeader("Retry-After",u.toString()),n.setHeader("X-RateLimit-Limit",t.toString()),n.setHeader("X-RateLimit-Remaining","0"),n.setHeader("X-RateLimit-Reset",Math.ceil((a+e)/1e3).toString()),n.status(429).json({code:"RATE_LIMITED",message:"Too many requests",retryAfter:u});return}c.timestamps.push(a);let l=t-c.timestamps.length;n.setHeader("X-RateLimit-Limit",t.toString()),n.setHeader("X-RateLimit-Remaining",l.toString()),n.setHeader("X-RateLimit-Reset",Math.ceil((a+e)/1e3).toString()),s()}}ls();var Pme="8.4.1",Sg=class{app;server=null;options;startTime=Date.now();constructor(e){this.options=e,this.app=(0,Gq.default)(),this.setupMiddleware(),this.setupCoreRoutes()}getHttpServer(){return this.server}async listen(e,r){return new Promise((n,s)=>{this.server=this.app.listen(e,r,()=>{_.info("SYSTEM","HTTP server started",{host:r,port:e,pid:process.pid}),n()}),this.server.on("error",s)})}async close(){this.server&&(this.server.closeAllConnections(),process.platform==="win32"&&await new Promise(e=>setTimeout(e,500)),await new Promise((e,r)=>{this.server.close(n=>n?r(n):e())}),process.platform==="win32"&&await new Promise(e=>setTimeout(e,500)),this.server=null,_.info("SYSTEM","HTTP server closed"))}registerRoutes(e){e.setupRoutes(this.app)}finalizeRoutes(){this.app.use(Uq),this.app.use(Lq)}setupMiddleware(){Uk(qk).forEach(s=>this.app.use(s)),this.app.use("/api/auth/login",wg(10,6e4)),this.app.use(wg(1e3,6e4));let r=Yf();if(r!=="127.0.0.1"&&r!=="localhost"){let s=Pc();_.info("SYSTEM","Enabling authentication middleware for network access",{bind:r,tokenConfigured:s}),s||_.warn("SYSTEM","No CLAUDE_PILOT_REMOTE_TOKEN set - all remote requests will be rejected until a token is configured",{bind:r}),this.app.use(Fk)}}setupCoreRoutes(){let e="TEST-008-wrapper-ipc";this.app.get("/api/health",(r,n)=>{n.status(200).json({status:"ok",build:e,managed:process.env.CLAUDE_PILOT_MANAGED==="true",hasIpc:typeof process.send=="function",platform:process.platform,pid:process.pid,initialized:this.options.getInitializationComplete(),coreReady:this.options.getCoreReady(),mcpReady:this.options.getMcpReady()})}),this.app.get("/api/core-ready",(r,n)=>{this.options.getCoreReady()?n.status(200).json({status:"ready",message:"Core services ready (Database + SearchManager)"}):n.status(503).json({status:"initializing",message:"Core services still initializing, please retry"})}),this.app.get("/api/readiness",(r,n)=>{this.options.getInitializationComplete()?n.status(200).json({status:"ready",mcpReady:this.options.getMcpReady()}):n.status(503).json({status:"initializing",message:"Worker is still initializing, please retry"})}),this.app.get("/api/version",(r,n)=>{n.status(200).json({version:Pme})}),this.app.get("/api/process-stats",async(r,n)=>{try{let{getProcessStats:s}=await Promise.resolve().then(()=>(Hu(),BD)),i=await s();n.status(200).json({...i,uptime:Math.round((Date.now()-this.startTime)/1e3),platform:process.platform,pid:process.pid})}catch(s){_.error("SYSTEM","Failed to get process stats",{},s),n.status(500).json({error:"Failed to get process stats"})}}),this.app.get("/api/instructions",async(r,n)=>{let s=r.query.topic||"all",i=r.query.operation;try{let a;if(i){let o=Wk.default.join(__dirname,"../skills/mem-search/operations",`${i}.md`);a=await Bk.promises.readFile(o,"utf-8")}else{let o=Wk.default.join(__dirname,"../skills/mem-search/SKILL.md"),c=await Bk.promises.readFile(o,"utf-8");a=this.extractInstructionSection(c,s)}n.json({content:[{type:"text",text:a}]})}catch{n.status(404).json({error:"Instruction not found"})}}),this.app.post("/api/admin/restart",bg,async(r,n)=>{n.json({status:"restarting"}),process.platform==="win32"&&process.env.CLAUDE_PILOT_MANAGED==="true"&&process.send?(_.info("SYSTEM","Sending restart request to wrapper"),process.send({type:"restart"})):setTimeout(async()=>{await this.options.onRestart()},100)}),this.app.post("/api/admin/shutdown",bg,async(r,n)=>{n.json({status:"shutting_down"}),process.platform==="win32"&&process.env.CLAUDE_PILOT_MANAGED==="true"&&process.send?(_.info("SYSTEM","Sending shutdown request to wrapper"),process.send({type:"shutdown"})):setTimeout(async()=>{await this.options.onShutdown()},100)})}extractInstructionSection(e,r){let n={workflow:this.extractBetween(e,"## The Workflow","## Search Parameters"),search_params:this.extractBetween(e,"## Search Parameters","## Examples"),examples:this.extractBetween(e,"## Examples","## Why This Workflow"),all:e};return n[r]||n.all}extractBetween(e,r,n){let s=e.indexOf(r),i=e.indexOf(n);return s===-1?e:i===-1?e.substring(s):e.substring(s,i).trim()}};kg();var Kq=require("bun:sqlite");er();se();var Eg=class{db;constructor(e){e||(es(rn),e=Ml),this.db=new Kq.Database(e),this.db.run("PRAGMA journal_mode = WAL"),this.ensureFTSTables()}ensureFTSTables(){this.db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name LIKE '%_fts'").all().some(n=>n.name==="observations_fts"||n.name==="session_summaries_fts")||(_.info("DB","Creating FTS5 tables"),this.db.run(`
CREATE VIRTUAL TABLE IF NOT EXISTS observations_fts USING fts5(
title,
subtitle,
@@ -1944,7 +1944,7 @@ ${s}`;try{let a=(0,qe.execSync)(`echo ${JSON.stringify(i)} | claude -p --model c
`).map(n=>n.trim()).filter(Boolean).map(n=>({path:n,status:"?",staged:!1,additions:0,deletions:0}))}catch{return[]}}getChangedFilesInRange(e,r){try{let n=(0,qe.execFileSync)("git",["diff","--name-status",r],{cwd:e,encoding:"utf-8",timeout:1e4,env:Qe}),s=(0,qe.execFileSync)("git",["diff","--numstat",r],{cwd:e,encoding:"utf-8",timeout:1e4,env:Qe});return this.parseChangedFiles(n,s,!0)}catch{return[]}}parseChangedFiles(e,r,n){let s=new Map;for(let a of r.split(`
`)){if(!a.trim())continue;let o=a.split(" ");if(o.length>=3){let c=o[0],l=o[1],u=o[o.length-1];s.set(u,{additions:c==="-"?0:parseInt(c,10)||0,deletions:l==="-"?0:parseInt(l,10)||0})}}let i=[];for(let a of e.split(`
`)){if(!a.trim())continue;let o=a.split(" ");if(o.length>=2){let c=o[0].charAt(0),l=o[o.length-1],u=s.get(l)||{additions:0,deletions:0};i.push({path:l,status:c,staged:n,...u})}}return i}isValidFilePath(e){return!(!e||e.trim()===""||na.default.isAbsolute(e)||na.default.normalize(e).startsWith(".."))}isValidBranchName(e){return!(!e||e.trim()===""||/\.\.|\x00-\x1f|[\x7f~^:?*\[\\]|@\{/.test(e)||e.startsWith("-")||e.startsWith(".")||e.endsWith(".lock"))}gitShowFile(e,r,n){try{return(0,qe.execFileSync)("git",["show",`${r}:${n}`],{cwd:e,encoding:"utf-8",timeout:5e3,env:Qe,maxBuffer:10*1024*1024})}catch{return""}}hasBinaryContent(e){return e.includes("\0")}getMainRepoRoot(e){try{let r=na.default.join(e,".git");if((0,sa.existsSync)(r))try{let n=(0,sa.readFileSync)(r,"utf-8").trim();if(n.startsWith("gitdir:")){let s=n.replace("gitdir:","").trim(),i=na.default.resolve(e,s,"..","..");return na.default.dirname(i)}}catch{return e}return e}catch{return null}}};var gZ=X(require("path"),1);var Zs=require("node:fs"),yi=X(require("node:path"),1);function uZ(t){return yi.default.join(yi.default.dirname(t),".annotations")}function N1(t,e){let r=yi.default.basename(e).replace(/\.md$/,".json");if(yi.default.isAbsolute(e))return yi.default.join(uZ(e),r);let n=yi.default.resolve(t,e);return yi.default.join(uZ(n),r)}function oEe(t){(0,Zs.mkdirSync)(yi.default.dirname(t),{recursive:!0})}function A1(t){return{planPath:t,planAnnotations:[],codeReviewAnnotations:[],updatedAt:Date.now()}}function Pl(t,e){let r=N1(t,e);if(!(0,Zs.existsSync)(r))return A1(e);try{let n=(0,Zs.readFileSync)(r,"utf-8"),s=JSON.parse(n);if(Array.isArray(s.planAnnotations))return{planPath:s.planPath??e,planAnnotations:s.planAnnotations,codeReviewAnnotations:Array.isArray(s.codeReviewAnnotations)?s.codeReviewAnnotations:[],updatedAt:s.updatedAt??Date.now()};if(Array.isArray(s.annotations)){let i=s.annotations.map(a=>({id:a.id,blockId:a.blockId,originalText:a.originalText??"",text:a.text??"",createdAt:a.createdAt??Date.now()}));return{planPath:s.planPath??e,planAnnotations:i,codeReviewAnnotations:[],updatedAt:s.updatedAt??Date.now()}}return A1(e)}catch{return A1(e)}}function Eb(t,e){let r=N1(t,e.planPath);oEe(r),(0,Zs.writeFileSync)(r,JSON.stringify({...e,updatedAt:Date.now()},null,2),"utf-8")}function pZ(t,e,r){let n=Pl(t,e);Eb(t,{...n,planPath:e,planAnnotations:r})}function dZ(t,e){let r=Pl(t,e);Eb(t,{...r,planAnnotations:[]})}function mZ(t,e,r){let n=Pl(t,e);Eb(t,{...n,planPath:e,codeReviewAnnotations:r})}function fZ(t,e){let r=Pl(t,e);Eb(t,{...r,codeReviewAnnotations:[]})}function hZ(t,e){let r=N1(t,e);try{(0,Zs.unlinkSync)(r)}catch(n){if(n.code!=="ENOENT")throw n}}var Tb=class extends Te{dbManager;constructor(e){super(),this.dbManager=e??null}setupRoutes(e){e.get("/api/annotations",this.handleGet.bind(this)),e.post("/api/annotations/plan",this.handleSavePlan.bind(this)),e.post("/api/annotations/code-review",this.handleSaveCodeReview.bind(this)),e.delete("/api/annotations",this.handleDeleteAll.bind(this)),e.delete("/api/annotations/plan",this.handleClearPlan.bind(this)),e.delete("/api/annotations/code-review",this.handleClearCodeReview.bind(this))}resolvePlanPath(e,r,n){let s=gZ.default.resolve(r,n);return ym(r,s)?s:(this.badRequest(e,"Invalid plan path"),null)}requirePath(e,r){let n=e.query.project,s=e.query.path;if(!s)return this.badRequest(r,"Missing path query parameter"),null;let i=cr(this.dbManager,n),a=this.resolvePlanPath(r,i,s);return a?{projectRoot:i,resolvedPlanPath:a}:null}handleGet=this.wrapHandler((e,r)=>{let n=this.requirePath(e,r);if(!n)return;let s=Pl(n.projectRoot,n.resolvedPlanPath);r.json({planAnnotations:s.planAnnotations,codeReviewAnnotations:s.codeReviewAnnotations})});handleSavePlan=this.wrapHandler((e,r)=>{let n=this.requirePath(e,r);if(!n)return;let s=e.body.annotations;if(!Array.isArray(s)){this.badRequest(r,"annotations must be an array");return}pZ(n.projectRoot,n.resolvedPlanPath,s),r.json({ok:!0})});handleSaveCodeReview=this.wrapHandler((e,r)=>{let n=this.requirePath(e,r);if(!n)return;let s=e.body.annotations;if(!Array.isArray(s)){this.badRequest(r,"annotations must be an array");return}mZ(n.projectRoot,n.resolvedPlanPath,s),r.json({ok:!0})});handleDeleteAll=this.wrapHandler((e,r)=>{let n=this.requirePath(e,r);n&&(hZ(n.projectRoot,n.resolvedPlanPath),r.json({ok:!0}))});handleClearPlan=this.wrapHandler((e,r)=>{let n=this.requirePath(e,r);n&&(dZ(n.projectRoot,n.resolvedPlanPath),r.json({ok:!0}))});handleClearCodeReview=this.wrapHandler((e,r)=>{let n=this.requirePath(e,r);n&&(fZ(n.projectRoot,n.resolvedPlanPath),r.json({ok:!0}))})};var xZ=require("os"),_Z=require("path");var xn=require("fs"),Il=require("path"),vZ=512*1024,yZ=8,D1="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",cEe=256-256%D1.length;function lEe(){let t=[];for(;t.lengthvZ)throw new Error(`Payload too large (max ${vZ/1024} KB)`);let n=lEe(),s={data:e,expiresAt:Date.now()+r*1e3};return(0,xn.writeFileSync)(this.safePath(n),JSON.stringify(s),"utf-8"),n}async get(e){let r=this.safePath(e);if(!(0,xn.existsSync)(r))return null;try{let n=JSON.parse((0,xn.readFileSync)(r,"utf-8"));return Date.now()>n.expiresAt?((0,xn.unlinkSync)(r),null):n.data}catch{return null}}sweep(){try{let e=(0,xn.readdirSync)(this.dataDir).filter(n=>n.endsWith(".json")),r=Date.now();for(let n of e){let s=(0,Il.join)(this.dataDir,n);try{let i=(0,xn.readFileSync)(s,"utf-8"),a=JSON.parse(i);r>a.expiresAt&&(0,xn.unlinkSync)(s)}catch{}}}catch{}}},bZ=4320*60;var uEe=(0,_Z.join)((0,xZ.homedir)(),".pilot","share"),Pb=class extends Te{store;constructor(e=uEe){super(),this.store=new Rb(e)}setupRoutes(e){e.post("/api/share",this.handlePost.bind(this)),e.get("/api/share/:id",this.handleGet.bind(this))}handlePost=this.wrapHandler(async(e,r)=>{let{data:n}=e.body;if(typeof n!="string"||!n){this.badRequest(r,"Missing or invalid data field");return}try{let s=await this.store.put(n,bZ);r.status(201).json({id:s})}catch(s){let i=s instanceof Error?s.message:"Failed to store";if(i.includes("too large"))r.status(413).json({error:i});else throw s}});handleGet=this.wrapHandler(async(e,r)=>{let{id:n}=e.params;try{let s=await this.store.get(n);if(s===null){this.notFound(r,"Share not found or expired");return}r.setHeader("Cache-Control","private, no-store"),r.json({data:s})}catch(s){let i=s instanceof Error?s.message:"";if(i.includes("Invalid share ID")||i.includes("traversal"))this.badRequest(r,"Invalid share ID");else throw s}})};var Ib=class{dbManager;sessionManager;startTime;requestMetrics=[];providerRequests=0;providerTokens=0;providerErrors=0;providerName="unknown";METRICS_WINDOW_MS=300*1e3;constructor(e,r,n){this.dbManager=e,this.sessionManager=r,this.startTime=n,setInterval(()=>this.cleanupOldMetrics(),6e4)}recordRequest(e,r,n=!1){this.requestMetrics.push({endpoint:e,responseTimeMs:r,timestamp:Date.now(),error:n})}recordProviderUsage(e,r,n=!1){this.providerName=e,this.providerRequests++,this.providerTokens+=r,n&&this.providerErrors++}cleanupOldMetrics(){let e=Date.now()-this.METRICS_WINDOW_MS;this.requestMetrics=this.requestMetrics.filter(r=>r.timestamp>e)}async getMetrics(){let r=this.dbManager.getSessionStore().db,n=R=>{try{return r.prepare(`SELECT COUNT(*) as count FROM ${R}`).get().count}catch{return 0}},s=n("observations"),i=n("sdk_sessions"),a=n("session_summaries"),o=n("prompts"),{DATA_DIR:c}=await Promise.resolve().then(()=>(er(),dP)),l=await import("fs"),p=(await import("path")).join(c,"pilot-memory.db"),d=0;try{d=l.statSync(p).size}catch{}let m=process.memoryUsage(),f=this.requestMetrics.filter(R=>R.timestamp>Date.now()-this.METRICS_WINDOW_MS),g=f.length,v=f.filter(R=>R.error).length,h=g>0?f.reduce((R,O)=>R+O.responseTimeMs,0)/g:0,y={};for(let R of f)y[R.endpoint]=(y[R.endpoint]||0)+1;let b=Date.now()-6e4,x=0;try{x=r.prepare("SELECT COUNT(*) as count FROM observations WHERE created_at_epoch > ?").get(b).count}catch{}let w=f.filter(R=>R.timestamp>b).length,S=this.sessionManager.isAnySessionProcessing(),k=this.sessionManager.getTotalActiveWork(),E=this.sessionManager.getActiveSessionCount();return{uptime:Math.floor((Date.now()-this.startTime)/1e3),memoryUsage:{heapUsed:m.heapUsed,heapTotal:m.heapTotal,rss:m.rss,external:m.external},database:{observations:s,sessions:i,summaries:a,prompts:o,sizeBytes:d},processing:{activeSessions:E,queueDepth:k,isProcessing:S},requests:{total:g,byEndpoint:y,errors:v,avgResponseTimeMs:Math.round(h)},provider:{name:this.providerName,requestsTotal:this.providerRequests,tokensTotal:this.providerTokens,errorsTotal:this.providerErrors},rates:{observationsPerMinute:x,requestsPerMinute:w}}}async toPrometheus(){let e=await this.getMetrics(),r=[],n=(s,i,a,o="gauge",c={})=>{r.push(`# HELP claude_pilot_${s} ${a}`),r.push(`# TYPE claude_pilot_${s} ${o}`);let l=Object.entries(c).map(([p,d])=>`${p}="${d}"`).join(","),u=l?`{${l}}`:"";r.push(`claude_pilot_${s}${u} ${i}`)};return n("uptime_seconds",e.uptime,"Worker uptime in seconds"),n("memory_heap_used_bytes",e.memoryUsage.heapUsed,"Heap memory used"),n("memory_heap_total_bytes",e.memoryUsage.heapTotal,"Total heap memory"),n("memory_rss_bytes",e.memoryUsage.rss,"Resident set size"),n("database_observations_total",e.database.observations,"Total observations"),n("database_sessions_total",e.database.sessions,"Total sessions"),n("database_summaries_total",e.database.summaries,"Total summaries"),n("database_prompts_total",e.database.prompts,"Total prompts"),n("database_size_bytes",e.database.sizeBytes,"Database file size"),n("processing_active_sessions",e.processing.activeSessions,"Active processing sessions"),n("processing_queue_depth",e.processing.queueDepth,"Queue depth"),n("processing_is_active",e.processing.isProcessing?1:0,"Is processing active"),n("requests_total",e.requests.total,"Total requests in window","counter"),n("requests_errors_total",e.requests.errors,"Total request errors","counter"),n("requests_response_time_avg_ms",e.requests.avgResponseTimeMs,"Average response time"),n("provider_requests_total",e.provider.requestsTotal,"Provider requests","counter",{provider:e.provider.name}),n("provider_tokens_total",e.provider.tokensTotal,"Provider tokens used","counter",{provider:e.provider.name}),n("provider_errors_total",e.provider.errorsTotal,"Provider errors","counter",{provider:e.provider.name}),n("observations_per_minute",e.rates.observationsPerMinute,"Observations created per minute"),n("requests_per_minute",e.rates.requestsPerMinute,"Requests per minute"),r.join(`
-`)}};se();er();zr();var pEe=1440*60*1e3,dEe=3e4,Cb=null,Ob=null;async function wZ(t){let e=t.getVectorSyncOrNull(),r=new Sl(t,e),n=r.getPolicy();if(!n.enabled){_.debug("RETENTION","Auto-cleanup skipped: retention policy is disabled");return}_.info("RETENTION","Running scheduled auto-cleanup",{maxAgeDays:n.maxAgeDays,maxCount:n.maxCount});let s=await r.run();_.info("RETENTION","Auto-cleanup complete",{deleted:s.deleted,archived:s.archived,errors:s.errors.length,duration:s.duration}),await mEe(e)}async function mEe(t){try{let e=Le.loadFromFile(Ht),r=parseInt(e.CLAUDE_PILOT_VECTOR_DB_MAX_PHYSICAL_MB,10)||Qp,n=parseInt(e.CLAUDE_PILOT_VECTOR_DB_MAX_LOGICAL_MB,10)||Yp,s=Cg($l,{maxPhysicalBytes:r*1024*1024,maxLogicalBytes:n*1024*1024,settingsPathForAutoDisable:Ht});if(!s.evicted)return;_.warn("VECTOR_DB_GUARD","Retention detected oversized vector DB \u2014 evicted, will rebuild on next sync",{reason:s.reason,logicalBytes:s.before.logical,physicalBytes:s.before.physical,largestFile:s.before.largestFile?.path,backupPath:s.backupPath,recentEvictionCount:s.recentEvictionCount,chromaAutoDisabled:s.chromaAutoDisabled}),t&&await t.close()}catch(e){_.error("VECTOR_DB_GUARD","Post-retention vector DB guard failed (non-fatal)",{},e)}}function SZ(t){z1(),Ob=setTimeout(async()=>{try{await wZ(t)}catch(e){_.error("RETENTION","Scheduled retention failed",{},e)}Cb=setInterval(async()=>{try{await wZ(t)}catch(e){_.error("RETENTION","Scheduled retention failed",{},e)}},pEe),_.info("RETENTION","Scheduled daily auto-cleanup")},dEe),_.info("RETENTION","Retention scheduler initialized (first run in 30s)")}function z1(){Ob&&(clearTimeout(Ob),Ob=null),Cb&&(clearInterval(Cb),Cb=null),_.debug("RETENTION","Retention scheduler stopped")}var CEe={},TEe="8.4.0";function iG(t,e){return{continue:!0,suppressOutput:!0,status:t,...e&&{message:e}}}function aG(){let t=`${(0,sG.homedir)()}/.pilot/bin/pilot`;if(!(0,J1.existsSync)(t))return _.warn("SYSTEM","Pilot binary not found, skipping license check"),!0;try{return(0,nG.execSync)(`"${t}" verify`,{stdio:"pipe",timeout:5e3,env:Mu()}),!0}catch{return!1}}var $b=class{server;startTime=Date.now();mcpClient;coreReady=!1;mcpReady=!1;initializationCompleteFlag=!1;isShuttingDown=!1;dbManager;sessionManager;sseBroadcaster;sdkAgent;paginationHelper;sessionEventBroadcaster;searchRoutes=null;metricsService=null;initializationComplete;resolveInitialization;cleanupInterval=null;constructor(){this.initializationComplete=new Promise(e=>{this.resolveInitialization=e}),this.dbManager=new jg,this.sessionManager=new Ag(this.dbManager),this.sseBroadcaster=new Ng,this.sdkAgent=new Ty(this.dbManager,this.sessionManager),this.paginationHelper=new Ry(this.dbManager),this.sessionEventBroadcaster=new Oy(this.sseBroadcaster,this),this.sessionManager.setOnSessionDeleted(()=>{this.broadcastProcessingStatus()}),this.mcpClient=new Ho({name:"worker-search-proxy",version:TEe},{capabilities:{}}),this.server=new Sg({getInitializationComplete:()=>this.initializationCompleteFlag,getCoreReady:()=>this.coreReady,getMcpReady:()=>this.mcpReady,onShutdown:()=>this.shutdown(),onRestart:()=>this.shutdown()}),this.registerRoutes(),this.registerSignalHandlers()}registerSignalHandlers(){let e={value:this.isShuttingDown},r=xw(()=>this.shutdown(),e);process.on("SIGTERM",()=>{this.isShuttingDown=e.value,r("SIGTERM")}),process.on("SIGINT",()=>{this.isShuttingDown=e.value,r("SIGINT")}),process.platform!=="win32"&&process.on("SIGHUP",()=>{process.argv.includes("--daemon")?_.info("SYSTEM","Received SIGHUP in daemon mode, ignoring",{}):(this.isShuttingDown=e.value,r("SIGHUP"))})}registerRoutes(){this.server.app.get("/api/context/inject",async(e,r,n)=>{try{let i=new Promise((a,o)=>setTimeout(()=>o(new Error("Initialization timeout")),3e5));if(await Promise.race([this.initializationComplete,i]),!this.searchRoutes){r.status(503).json({error:"Search routes not initialized"});return}n()}catch{r.status(503).json({error:"Service initialization timed out"})}}),this.server.registerRoutes(new Yy),this.server.registerRoutes(new Ay(this.sseBroadcaster,this.dbManager,this.sessionManager)),this.server.registerRoutes(new Dy(this.sessionManager,this.dbManager,this.sdkAgent,this.sessionEventBroadcaster,this)),this.server.registerRoutes(new zy(this.paginationHelper,this.dbManager,this.sessionManager,this.sseBroadcaster,this,this.startTime,new Ly)),this.server.registerRoutes(new Zy),this.server.registerRoutes(new Gy(this.dbManager,"pilot-memory")),this.server.registerRoutes(new Ky(this.dbManager)),this.server.registerRoutes(new Jy(this.dbManager)),this.server.registerRoutes(new ab(this.dbManager,this.sseBroadcaster)),this.server.registerRoutes(new Tb(this.dbManager)),this.server.registerRoutes(new Pb),this.server.registerRoutes(new ob(this.dbManager,this.sseBroadcaster)),this.server.registerRoutes(new lb),this.metricsService=new Ib(this.dbManager,this.sessionManager,this.startTime),this.server.registerRoutes(new Qy(this.metricsService)),this.server.registerRoutes(new fb),this.server.registerRoutes(new hb),this.server.registerRoutes(new yb),this.server.registerRoutes(new bb(this.dbManager)),this.server.registerRoutes(new _b),this.server.registerRoutes(new Sb),this.server.registerRoutes(new kb(this.dbManager)),SZ(this.dbManager)}async start(){let e=un(),r=Yf(),n=cs();await this.server.listen(e,r),_.info("SYSTEM","Worker started",{bind:r,host:n,port:e,pid:process.pid}),wa()&&_.info("SYSTEM","WSL2 detected \u2014 Console bound to 0.0.0.0 for Windows host access",{url:`http://localhost:${e}`}),this.initializeBackground().catch(s=>{_.error("SYSTEM","Background initialization failed",{},s)})}async initializeBackground(){try{await sh(),await Uu(),await Lu();let{ModeManager:e}=await Promise.resolve().then(()=>(Fn(),o6));e.getInstance().loadMode(),_.info("SYSTEM","Mode loaded: Code Development"),await this.dbManager.initialize();let r=nn(process.env.CLAUDE_PROJECT_ROOT||process.cwd()),n=km.default.basename(r);this.dbManager.getSessionStore().upsertProjectRoot(n,r);let{PendingMessageStore:s}=await Promise.resolve().then(()=>(Fi(),Fa)),i=new s(this.dbManager.getSessionStore().db,3),a=300*1e3,o=i.resetStuckMessages(a);o>0&&_.info("SYSTEM",`Recovered ${o} stuck messages from previous session`,{thresholdMinutes:5});let c=new Iy,l=new Cy,u=new Py(this.dbManager.getSessionSearch(),this.dbManager.getSessionStore(),this.dbManager.getVectorSync(),c,l);this.searchRoutes=new By(u),this.server.registerRoutes(this.searchRoutes),_.info("WORKER","SearchManager initialized and search routes registered"),this.coreReady=!0,_.info("SYSTEM","Core services ready (hooks can proceed)");let p=[km.default.join(__dirname,"mcp-server.cjs"),km.default.join(__dirname,"..","servers","mcp-server.ts"),km.default.join(__dirname,"..","..","servers","mcp-server.ts")],d=p.find(x=>(0,J1.existsSync)(x))||p[0],m=d.endsWith(".ts"),f=new Zo({command:m?"bun":"node",args:[d],env:process.env}),g=3e5,v=this.mcpClient.connect(f),h=new Promise((x,w)=>setTimeout(()=>w(new Error("MCP connection timeout after 5 minutes")),g));await Promise.race([v,h]),this.mcpReady=!0,_.success("WORKER","Connected to MCP server"),this.initializationCompleteFlag=!0,this.resolveInitialization(),_.info("SYSTEM","Background initialization complete"),this.processPendingQueues(50).then(x=>{x.sessionsStarted>0&&_.info("SYSTEM",`Auto-recovered ${x.sessionsStarted} sessions with pending work`,{totalPending:x.totalPendingSessions,started:x.sessionsStarted,sessionIds:x.startedSessionIds})}).catch(x=>{_.error("SYSTEM","Auto-recovery of pending queues failed",{},x)});let y=300*1e3,b=3600*1e3;this.cleanupInterval=setInterval(async()=>{try{let x=await this.sessionManager.cleanupStaleSessions(b);x>0&&_.info("SYSTEM",`Periodic cleanup: removed ${x} stale sessions`),await Uu(),await Lu(),_.debug("SYSTEM","Periodic cleanup completed")}catch(x){_.error("SYSTEM","Periodic cleanup failed",{},x)}},y),_.info("SYSTEM","Started periodic cleanup (every 5 minutes)")}catch(e){throw _.error("SYSTEM","Background initialization failed",{},e),e}}getActiveAgent(){return this.sdkAgent}startSessionProcessor(e,r){if(!e)return;e.abortController.signal.aborted&&(e.abortController=new AbortController,_.debug("SYSTEM","Reset AbortController for session restart",{sessionId:e.sessionDbId}));let n=e.sessionDbId,s=this.getActiveAgent(),i=s.constructor.name;_.info("SYSTEM",`Starting generator (${r}) using ${i}`,{sessionId:n}),e.generatorPromise=s.startSession(e,this).catch(a=>{_.error("SDK","Session generator failed",{sessionId:e.sessionDbId,project:e.project,provider:i},a)}).finally(()=>{e.generatorPromise=null,this.broadcastProcessingStatus()})}async processPendingQueues(e=10){let{PendingMessageStore:r}=await Promise.resolve().then(()=>(Fi(),Fa)),n=new r(this.dbManager.getSessionStore().db,3),s=this.dbManager.getSessionStore(),i=1800*1e3,a=Date.now()-i;try{let l=s.db.prepare(`
+`)}};se();er();zr();var pEe=1440*60*1e3,dEe=3e4,Cb=null,Ob=null;async function wZ(t){let e=t.getVectorSyncOrNull(),r=new Sl(t,e),n=r.getPolicy();if(!n.enabled){_.debug("RETENTION","Auto-cleanup skipped: retention policy is disabled");return}_.info("RETENTION","Running scheduled auto-cleanup",{maxAgeDays:n.maxAgeDays,maxCount:n.maxCount});let s=await r.run();_.info("RETENTION","Auto-cleanup complete",{deleted:s.deleted,archived:s.archived,errors:s.errors.length,duration:s.duration}),await mEe(e)}async function mEe(t){try{let e=Le.loadFromFile(Ht),r=parseInt(e.CLAUDE_PILOT_VECTOR_DB_MAX_PHYSICAL_MB,10)||Qp,n=parseInt(e.CLAUDE_PILOT_VECTOR_DB_MAX_LOGICAL_MB,10)||Yp,s=Cg($l,{maxPhysicalBytes:r*1024*1024,maxLogicalBytes:n*1024*1024,settingsPathForAutoDisable:Ht});if(!s.evicted)return;_.warn("VECTOR_DB_GUARD","Retention detected oversized vector DB \u2014 evicted, will rebuild on next sync",{reason:s.reason,logicalBytes:s.before.logical,physicalBytes:s.before.physical,largestFile:s.before.largestFile?.path,backupPath:s.backupPath,recentEvictionCount:s.recentEvictionCount,chromaAutoDisabled:s.chromaAutoDisabled}),t&&await t.close()}catch(e){_.error("VECTOR_DB_GUARD","Post-retention vector DB guard failed (non-fatal)",{},e)}}function SZ(t){z1(),Ob=setTimeout(async()=>{try{await wZ(t)}catch(e){_.error("RETENTION","Scheduled retention failed",{},e)}Cb=setInterval(async()=>{try{await wZ(t)}catch(e){_.error("RETENTION","Scheduled retention failed",{},e)}},pEe),_.info("RETENTION","Scheduled daily auto-cleanup")},dEe),_.info("RETENTION","Retention scheduler initialized (first run in 30s)")}function z1(){Ob&&(clearTimeout(Ob),Ob=null),Cb&&(clearInterval(Cb),Cb=null),_.debug("RETENTION","Retention scheduler stopped")}var CEe={},TEe="8.4.1";function iG(t,e){return{continue:!0,suppressOutput:!0,status:t,...e&&{message:e}}}function aG(){let t=`${(0,sG.homedir)()}/.pilot/bin/pilot`;if(!(0,J1.existsSync)(t))return _.warn("SYSTEM","Pilot binary not found, skipping license check"),!0;try{return(0,nG.execSync)(`"${t}" verify`,{stdio:"pipe",timeout:5e3,env:Mu()}),!0}catch{return!1}}var $b=class{server;startTime=Date.now();mcpClient;coreReady=!1;mcpReady=!1;initializationCompleteFlag=!1;isShuttingDown=!1;dbManager;sessionManager;sseBroadcaster;sdkAgent;paginationHelper;sessionEventBroadcaster;searchRoutes=null;metricsService=null;initializationComplete;resolveInitialization;cleanupInterval=null;constructor(){this.initializationComplete=new Promise(e=>{this.resolveInitialization=e}),this.dbManager=new jg,this.sessionManager=new Ag(this.dbManager),this.sseBroadcaster=new Ng,this.sdkAgent=new Ty(this.dbManager,this.sessionManager),this.paginationHelper=new Ry(this.dbManager),this.sessionEventBroadcaster=new Oy(this.sseBroadcaster,this),this.sessionManager.setOnSessionDeleted(()=>{this.broadcastProcessingStatus()}),this.mcpClient=new Ho({name:"worker-search-proxy",version:TEe},{capabilities:{}}),this.server=new Sg({getInitializationComplete:()=>this.initializationCompleteFlag,getCoreReady:()=>this.coreReady,getMcpReady:()=>this.mcpReady,onShutdown:()=>this.shutdown(),onRestart:()=>this.shutdown()}),this.registerRoutes(),this.registerSignalHandlers()}registerSignalHandlers(){let e={value:this.isShuttingDown},r=xw(()=>this.shutdown(),e);process.on("SIGTERM",()=>{this.isShuttingDown=e.value,r("SIGTERM")}),process.on("SIGINT",()=>{this.isShuttingDown=e.value,r("SIGINT")}),process.platform!=="win32"&&process.on("SIGHUP",()=>{process.argv.includes("--daemon")?_.info("SYSTEM","Received SIGHUP in daemon mode, ignoring",{}):(this.isShuttingDown=e.value,r("SIGHUP"))})}registerRoutes(){this.server.app.get("/api/context/inject",async(e,r,n)=>{try{let i=new Promise((a,o)=>setTimeout(()=>o(new Error("Initialization timeout")),3e5));if(await Promise.race([this.initializationComplete,i]),!this.searchRoutes){r.status(503).json({error:"Search routes not initialized"});return}n()}catch{r.status(503).json({error:"Service initialization timed out"})}}),this.server.registerRoutes(new Yy),this.server.registerRoutes(new Ay(this.sseBroadcaster,this.dbManager,this.sessionManager)),this.server.registerRoutes(new Dy(this.sessionManager,this.dbManager,this.sdkAgent,this.sessionEventBroadcaster,this)),this.server.registerRoutes(new zy(this.paginationHelper,this.dbManager,this.sessionManager,this.sseBroadcaster,this,this.startTime,new Ly)),this.server.registerRoutes(new Zy),this.server.registerRoutes(new Gy(this.dbManager,"pilot-memory")),this.server.registerRoutes(new Ky(this.dbManager)),this.server.registerRoutes(new Jy(this.dbManager)),this.server.registerRoutes(new ab(this.dbManager,this.sseBroadcaster)),this.server.registerRoutes(new Tb(this.dbManager)),this.server.registerRoutes(new Pb),this.server.registerRoutes(new ob(this.dbManager,this.sseBroadcaster)),this.server.registerRoutes(new lb),this.metricsService=new Ib(this.dbManager,this.sessionManager,this.startTime),this.server.registerRoutes(new Qy(this.metricsService)),this.server.registerRoutes(new fb),this.server.registerRoutes(new hb),this.server.registerRoutes(new yb),this.server.registerRoutes(new bb(this.dbManager)),this.server.registerRoutes(new _b),this.server.registerRoutes(new Sb),this.server.registerRoutes(new kb(this.dbManager)),SZ(this.dbManager)}async start(){let e=un(),r=Yf(),n=cs();await this.server.listen(e,r),_.info("SYSTEM","Worker started",{bind:r,host:n,port:e,pid:process.pid}),wa()&&_.info("SYSTEM","WSL2 detected \u2014 Console bound to 0.0.0.0 for Windows host access",{url:`http://localhost:${e}`}),this.initializeBackground().catch(s=>{_.error("SYSTEM","Background initialization failed",{},s)})}async initializeBackground(){try{await sh(),await Uu(),await Lu();let{ModeManager:e}=await Promise.resolve().then(()=>(Fn(),o6));e.getInstance().loadMode(),_.info("SYSTEM","Mode loaded: Code Development"),await this.dbManager.initialize();let r=nn(process.env.CLAUDE_PROJECT_ROOT||process.cwd()),n=km.default.basename(r);this.dbManager.getSessionStore().upsertProjectRoot(n,r);let{PendingMessageStore:s}=await Promise.resolve().then(()=>(Fi(),Fa)),i=new s(this.dbManager.getSessionStore().db,3),a=300*1e3,o=i.resetStuckMessages(a);o>0&&_.info("SYSTEM",`Recovered ${o} stuck messages from previous session`,{thresholdMinutes:5});let c=new Iy,l=new Cy,u=new Py(this.dbManager.getSessionSearch(),this.dbManager.getSessionStore(),this.dbManager.getVectorSync(),c,l);this.searchRoutes=new By(u),this.server.registerRoutes(this.searchRoutes),_.info("WORKER","SearchManager initialized and search routes registered"),this.coreReady=!0,_.info("SYSTEM","Core services ready (hooks can proceed)");let p=[km.default.join(__dirname,"mcp-server.cjs"),km.default.join(__dirname,"..","servers","mcp-server.ts"),km.default.join(__dirname,"..","..","servers","mcp-server.ts")],d=p.find(x=>(0,J1.existsSync)(x))||p[0],m=d.endsWith(".ts"),f=new Zo({command:m?"bun":"node",args:[d],env:process.env}),g=3e5,v=this.mcpClient.connect(f),h=new Promise((x,w)=>setTimeout(()=>w(new Error("MCP connection timeout after 5 minutes")),g));await Promise.race([v,h]),this.mcpReady=!0,_.success("WORKER","Connected to MCP server"),this.initializationCompleteFlag=!0,this.resolveInitialization(),_.info("SYSTEM","Background initialization complete"),this.processPendingQueues(50).then(x=>{x.sessionsStarted>0&&_.info("SYSTEM",`Auto-recovered ${x.sessionsStarted} sessions with pending work`,{totalPending:x.totalPendingSessions,started:x.sessionsStarted,sessionIds:x.startedSessionIds})}).catch(x=>{_.error("SYSTEM","Auto-recovery of pending queues failed",{},x)});let y=300*1e3,b=3600*1e3;this.cleanupInterval=setInterval(async()=>{try{let x=await this.sessionManager.cleanupStaleSessions(b);x>0&&_.info("SYSTEM",`Periodic cleanup: removed ${x} stale sessions`),await Uu(),await Lu(),_.debug("SYSTEM","Periodic cleanup completed")}catch(x){_.error("SYSTEM","Periodic cleanup failed",{},x)}},y),_.info("SYSTEM","Started periodic cleanup (every 5 minutes)")}catch(e){throw _.error("SYSTEM","Background initialization failed",{},e),e}}getActiveAgent(){return this.sdkAgent}startSessionProcessor(e,r){if(!e)return;e.abortController.signal.aborted&&(e.abortController=new AbortController,_.debug("SYSTEM","Reset AbortController for session restart",{sessionId:e.sessionDbId}));let n=e.sessionDbId,s=this.getActiveAgent(),i=s.constructor.name;_.info("SYSTEM",`Starting generator (${r}) using ${i}`,{sessionId:n}),e.generatorPromise=s.startSession(e,this).catch(a=>{_.error("SDK","Session generator failed",{sessionId:e.sessionDbId,project:e.project,provider:i},a)}).finally(()=>{e.generatorPromise=null,this.broadcastProcessingStatus()})}async processPendingQueues(e=10){let{PendingMessageStore:r}=await Promise.resolve().then(()=>(Fi(),Fa)),n=new r(this.dbManager.getSessionStore().db,3),s=this.dbManager.getSessionStore(),i=1800*1e3,a=Date.now()-i;try{let l=s.db.prepare(`
SELECT s.id FROM sdk_sessions s
WHERE s.status = 'active'
AND s.started_at_epoch < ?
diff --git a/pilot/settings.json b/pilot/settings.json
index 655f2b35..bd727284 100644
--- a/pilot/settings.json
+++ b/pilot/settings.json
@@ -26,7 +26,7 @@
"spinnerTipsOverride": {
"tips": [
"[PILOT] Run /setup-rules after installation to generate project rules",
- "[PILOT] Use /spec for features AND bug fixes — structured planning, TDD, and code review for both",
+ "[PILOT] Use /spec for features and /fix for bugs — structured planning, TDD, and code review for both",
"[PILOT] Quick Mode: Just chat for small changes and exploration (all quality hooks still apply)",
"[PILOT] Press Ctrl+R to search command history | Ctrl+C to cancel current operation",
"[PILOT] Press Escape twice to cancel a running operation",
@@ -111,6 +111,6 @@
"padding": 0
},
"companyAnnouncements": [
- "/spec — features & bugfixes | /prd — requirements with research | /setup-rules — modular rules | /create-skill — optimized skills"
+ "features: /spec | bugfixes: /fix | requirements: /prd | rules & skills: /setup-rules, /create-skill, /benchmark"
]
}
diff --git a/pilot/skills/fix/manifest.json b/pilot/skills/fix/manifest.json
new file mode 100644
index 00000000..c3a97202
--- /dev/null
+++ b/pilot/skills/fix/manifest.json
@@ -0,0 +1,30 @@
+{
+ "version": 1,
+ "orchestrator": "orchestrator.md",
+ "steps": [
+ {
+ "id": "step-1-investigate",
+ "file": "steps/01-investigate.md"
+ },
+ {
+ "id": "step-2-red",
+ "file": "steps/02-red.md"
+ },
+ {
+ "id": "step-3-fix",
+ "file": "steps/03-fix.md"
+ },
+ {
+ "id": "step-4-verify-e2e",
+ "file": "steps/04-verify-e2e.md"
+ },
+ {
+ "id": "step-5-quality",
+ "file": "steps/05-quality.md"
+ },
+ {
+ "id": "step-6-finalise",
+ "file": "steps/06-finalise.md"
+ }
+ ]
+}
diff --git a/pilot/skills/fix/orchestrator.md b/pilot/skills/fix/orchestrator.md
new file mode 100644
index 00000000..c87b9978
--- /dev/null
+++ b/pilot/skills/fix/orchestrator.md
@@ -0,0 +1,66 @@
+---
+name: fix
+description: "Bugfix workflow — investigate, RED test, fix, verify end-to-end, done. Standard command for bugs. Stops cleanly and asks the user to re-invoke with /spec when the bug exceeds this workflow's scope."
+argument-hint: ""
+user-invocable: true
+model: opus
+---
+
+# /fix — Bugfix Workflow
+
+Bugfix workflow with TDD. Investigate the bug, write the failing test, fix at the root cause, verify the fix end-to-end, done. No plan file, no approval gate mid-flow, no separate verify phase.
+
+```bash
+> /fix "annotation persistence drops fields between save and reload"
+> /fix "off-by-one in pagination at boundary"
+> /fix "wrong default for max_retries"
+```
+
+**Always quick.** If investigation reveals the bug is multi-component, architectural, or otherwise larger than a quick fix, STOP cleanly and tell the user to re-invoke with `/spec`. Do NOT silently switch lanes — `/fix` means quick, `/spec` means the full workflow. Honour the user's command choice.
+
+---
+
+## Iron Laws
+
+```
+1. NO FIXES WITHOUT ROOT CAUSE — traced to file:line, explained WHY.
+2. NO CODE WITHOUT A FAILING REPRODUCING TEST — TDD.
+3. FIX AT THE SOURCE — not where the error appears.
+4. END-TO-END VERIFICATION IS MANDATORY — Step 4 runs the actual program (UI: Claude Code Chrome / Chrome DevTools MCP / playwright-cli / agent-browser; CLI/API/library: real invocation) and captures concrete evidence. Unit tests alone are never accepted as proof.
+5. STOP WHEN OVER YOUR HEAD — multi-component / architectural bugs need /spec.
+```
+
+---
+
+## Critical Constraints
+
+- **No plan file.** All state lives in this conversation. If compaction happens mid-fix, re-read the conversation summary and resume.
+- **No `Iterations:` counter.** If your fix doesn't work after one re-attempt, stop and tell the user to switch to `/spec` — don't loop.
+- **No approval mid-flow.** Single end-of-flow confirmation only when `PILOT_PLAN_APPROVAL_ENABLED` is enabled.
+- **Stopping is success, not failure.** Recognising "this is bigger than a quick fix" and bailing out is the right call. Wasting time in the quick lane on a multi-component bug is the failure.
+
+---
+
+## Bail-Out Triggers — Stop and Tell the User to Use `/spec`
+
+You MUST stop and tell the user to re-invoke with `/spec` when ANY of these is true after Step 1 investigation:
+
+- Bug spans **3+ files** or **2+ components** (e.g. frontend + backend, multiple services).
+- Root cause is **architectural** (the pattern itself is wrong, not a single line).
+- Fix requires **defense-in-depth at multiple layers** (entry validation + business logic + storage).
+- **Confidence is Low** — you can't pin root cause to `file:line`.
+- The fix has **non-trivial UI implications** that warrant a recorded Verification Scenario.
+- Two quick-lane fix attempts have already failed.
+
+**How to bail out** — do all four:
+
+1. Summarise what you found (root cause hypothesis, files involved, why it exceeds quick-lane scope).
+2. Tell the user explicitly: "This bug needs the full workflow. Please re-invoke with `/spec ''`."
+3. Do NOT invoke `spec-bugfix-plan` yourself. Honour the command boundary — the user chose `/fix`.
+4. Stop.
+
+---
+
+## Workflow — Six Steps, No Ceremony
+
+See `steps/01-investigate.md` through `steps/06-finalise.md`.
diff --git a/pilot/skills/fix/steps/01-investigate.md b/pilot/skills/fix/steps/01-investigate.md
new file mode 100644
index 00000000..bb0bb9f6
--- /dev/null
+++ b/pilot/skills/fix/steps/01-investigate.md
@@ -0,0 +1,57 @@
+## Step 1: Investigate Root Cause
+
+**Goal:** trace the bug to `file:lineN — function() does X but should do Y` with High or Medium confidence. If you can't, bail out (see orchestrator).
+
+### 1.1 Reproduce & understand
+
+- Restate **symptom**, **trigger**, **expected behaviour**.
+- If too vague: one focused `AskUserQuestion` (only when `PILOT_PLAN_QUESTIONS_ENABLED` is not `"false"`).
+- If you can't trigger it after 2 attempts: bail out. Tell the user the bug isn't reproducible from the description alone, ask them to either provide more detail or re-invoke with `/spec` for the full investigation workflow. The quick lane is for reproducible bugs.
+
+### 1.2 Recent changes (one bash call, then move on)
+
+```bash
+git log --oneline -10 -- 2>/dev/null
+```
+
+Look for the commit that introduced the bug. If recent, read that diff. If nothing obvious, skip.
+
+### 1.3 Trace to root cause
+
+**Start with `codegraph_context(task="")`** — single call, returns entry points and related symbols. Read it carefully.
+
+For local bugs (single file, single function): one or two targeted `Read`s on the file from the codegraph output is enough. **Do not** run `codegraph_callers`/`callees`/`impact` for local bugs — that's the full-lane bias and it's the single biggest time sink for trivial fixes.
+
+For bugs that span 2 files in the same component (e.g. service.ts + service.test.ts): targeted `Read`s. Still no full call-graph traversal.
+
+**Bail-out check at end of 1.3:** if your trace touched 3+ files, or you found yourself running `codegraph_callers`, or you can't pin file:line — stop and tell the user to use `/spec` (see orchestrator's bail-out triggers). Don't switch lanes silently.
+
+### 1.4 Instrument when needed (UI / async / race / timing bugs)
+
+For bugs that don't surface clearly through stack traces or static reading — UI rendering glitches, async timing, race conditions, integration-layer issues — add **temporary diagnostic logging** to the production code and trigger the bug to read the output:
+
+- Log input values entering the suspect function.
+- Log branch conditions (which path executed?).
+- Log computed intermediate results.
+- Log return values at layer boundaries.
+
+**Mark every temporary log with `SPEC-DEBUG:`** (e.g. `console.log("SPEC-DEBUG: filters=", filters)`). Step 3.5 greps for this marker — any unremoved match fails the diff sanity check.
+
+Skip 1.4 when the stack trace already names the failing line, or when a static read of the file is enough to see the bug. Skip is the default.
+
+### 1.5 State the root cause
+
+Out loud, in one sentence to the user, before writing any test:
+
+> "Root cause: `:` — `()` does , should do . This causes the symptom because . Confidence: ."
+
+If confidence is Low: bail out. Don't guess in the quick lane.
+
+### Red flags — STOP and re-investigate
+
+- "Quick fix for now, investigate later" → STOP, this IS the quick lane.
+- "I'll just try changing X" → STOP, trace it first.
+- "It's probably X" → STOP, prove it.
+- "I see the symptom, let me fix it" → seeing symptoms ≠ understanding root cause.
+
+If the user says "stop guessing", "is that not happening?", "ultrathink this" — STOP, return to 1.3.
diff --git a/pilot/skills/fix/steps/02-red.md b/pilot/skills/fix/steps/02-red.md
new file mode 100644
index 00000000..b376a412
--- /dev/null
+++ b/pilot/skills/fix/steps/02-red.md
@@ -0,0 +1,31 @@
+## Step 2: Write the Reproducing Test (RED)
+
+**No production code yet.** A bugfix without a failing test is a rubber-stamp fix. The quick lane keeps this step minimal — but it does not skip it.
+
+### 2.1 Pick the entry point
+
+Use an **existing public entry point** the bug is reachable through (function, endpoint, CLI command). Don't write a test that calls a helper you're about to create — those tests can't fail before the fix.
+
+If no clean entry point exists: that's a design smell. Document it briefly and use the closest stable one. Don't refactor "to make it testable" in the quick lane — bail out (tell the user to re-invoke with `/spec`) if the smell is large.
+
+### 2.2 Encode `Currently → Expected`
+
+The test asserts the **correct** behaviour. Against the buggy code, the assertion must fail with an error matching the symptom you stated in Step 1.4.
+
+Naming: `test___` (Python) or `it("should when ", ...)` (TS/JS). Keep it boring — this is regression insurance, not a showcase.
+
+### 2.3 Run it — it MUST fail
+
+```bash
+
+```
+
+**Outcome interpretation:**
+
+- **Fails with the expected error** → RED proven, proceed to Step 3.
+- **Passes** → the test does not encode the bug, OR the bug is already fixed. STOP. Re-read Step 1.5 — did you trace the actual root cause? Re-investigate. Do NOT write fix code.
+- **Errors for an unrelated reason** (import error, missing fixture) → fix the test setup first, re-run. Don't proceed until RED is genuine.
+
+### 2.4 No commit yet
+
+Worktree mode: do not commit the test alone. The quick lane bundles test + fix into one commit at finalise. (Full lane uses separate commits because the cp+trap RED proof in verify needs them — quick lane skips that proof, so commit-bundling is fine.)
diff --git a/pilot/skills/fix/steps/03-fix.md b/pilot/skills/fix/steps/03-fix.md
new file mode 100644
index 00000000..67d5a669
--- /dev/null
+++ b/pilot/skills/fix/steps/03-fix.md
@@ -0,0 +1,56 @@
+## Step 3: Fix at the Root Cause
+
+### 3.1 Make the minimal change
+
+Edit only the file at the root cause. One change, one variable, one logical fix. No "while I'm here" cleanups, no bundled refactoring, no formatting passes. **Lineage rule:** every changed line traces directly to the bug.
+
+### 3.2 Forbidden patterns — fix at source, not symptom
+
+If the buggy data flows from upstream, fix upstream. Red flags in the diff:
+
+- Broad new `try/except` around the failing call.
+- `if value is None: return default` at the caller when the bug is that `value` is wrong upstream.
+- Swallowed exceptions, silently normalised bad inputs.
+- Early return that hides wrong state from the caller.
+- Renamed/suppressed log lines that previously surfaced the bug.
+
+A defensive layer is occasionally legitimate (defense-in-depth). When it is, document it explicitly in the Step 6 summary. Otherwise revert it.
+
+### 3.3 Run the reproducing test — it MUST pass
+
+```bash
+
+```
+
+If it doesn't pass: stop adding more code. Revert your edit. Return to Step 1.3 — your root cause hypothesis was wrong.
+
+### 3.4 Run the targeted scope (NOT full suite)
+
+Run the test module(s) covering the file you just changed. Fast, scoped:
+
+```bash
+# Python example
+uv run pytest -q
+# TypeScript example
+bun test
+```
+
+Zero failures. The full anti-regression suite runs once at Step 5 — running it after every fix iteration is the quick-lane anti-pattern.
+
+### 3.5 Diff sanity
+
+```bash
+git diff --name-only
+git diff | grep -E "^\+.*\b(try:|except|catch \(|return None|return \[\]|return \{\}|console\.log|print\()"
+```
+
+- **Root-cause file IS in the diff.** If not, the fix is at a symptom — return to 3.1.
+- **No unplanned files appear.** If they do, revert them now.
+- **Diff is small** — usually < 20 lines. If it ballooned, the bug exceeds the quick lane — bail out.
+- **Every grep match must be justified or reverted.** Look for symptom-patching, swallowed returns, or leftover `print` / `console.log` / `SPEC-DEBUG:` markers.
+
+### 3.6 If your first fix doesn't work — one re-attempt, then bail out
+
+If Step 3.3 fails: revert, re-investigate, try once more.
+
+If the second attempt also fails: **stop and tell the user to re-invoke with `/spec`**. Two failed quick-lane attempts means the bug is deeper than the lane is built for.
diff --git a/pilot/skills/fix/steps/04-verify-e2e.md b/pilot/skills/fix/steps/04-verify-e2e.md
new file mode 100644
index 00000000..a5f6ea5f
--- /dev/null
+++ b/pilot/skills/fix/steps/04-verify-e2e.md
@@ -0,0 +1,31 @@
+## Step 4: Verify End-to-End
+
+⛔ **The primary proof that the bug is fixed.** Run the actual program with the original input and observe the symptom is gone. A passing unit test alone is never accepted.
+
+This is the most important step in the workflow. Skip is NOT an option — no exceptions for "small fix", "obvious fix", "test covers it", "I'm confident".
+
+### Pick the lane that matches the bug
+
+| Bug surface | Tool | Evidence to capture |
+|-------------|------|---------------------|
+| **UI / web frontend** | 4-tier resolution from `browser-automation.md`: **Claude Code Chrome** → **Chrome DevTools MCP** → **playwright-cli** → **agent-browser**. Walk the user's repro steps. | Page state and element values that prove the correct behaviour |
+| **CLI** | The exact command the user ran, with original args + env | Stdout/stderr lines + exit code |
+| **HTTP API** | `curl` / HTTP client with the user's body and headers | Status code + the response field that proves the fix |
+| **Library / SDK / function** | `python -c '…'`, `node -e '…'`, REPL, or scratch script with the user's args | Returned value |
+| **Background job / cron / worker** | Trigger the job manually with the failing input | Relevant log lines |
+
+### Proof requirement
+
+Concrete evidence is mandatory in the Step 6 report. Bare assertions are insufficient:
+
+- ❌ "Looks fixed", "behaves correctly", "tests pass"
+- ✅ `curl /search -d '{}' → 200, response.results.length=42`
+- ✅ "Saved end_date 2026-05-15, list shows 2026-05-15 (read_page after save confirms)"
+
+### When the symptom persists
+
+The unit test is at the wrong layer — it sits below the user's interaction point. Move the assertion up to the user's actual entry point (API, browser, CLI), then re-run **Step 2.3 (RED) → Step 3.3 (test passes) → Step 4 (E2E re-check)**.
+
+### When the running program is unavailable
+
+Build broken, infra missing, integration env down? Stop and tell the user. Do not finalise the fix without E2E verification — that is the failure mode this step prevents.
diff --git a/pilot/skills/fix/steps/05-quality.md b/pilot/skills/fix/steps/05-quality.md
new file mode 100644
index 00000000..42f34566
--- /dev/null
+++ b/pilot/skills/fix/steps/05-quality.md
@@ -0,0 +1,32 @@
+## Step 5: Quality Gate
+
+Automated checks — the last green-bar gate before finalise.
+
+### 5.1 Lint + types + build
+
+```bash
+# Python project example
+ruff check . --fix && ruff format . && basedpyright 2>&1 | tail -5
+# TypeScript project example
+bun run typecheck && bun run lint
+```
+
+Build only when the project has a build step that could surface fix-related errors (TS compile, native compile). Skip for plain Python or pure JS.
+
+### 5.2 Full anti-regression suite
+
+```bash
+# Python
+uv run pytest -q
+# TypeScript
+bun test
+```
+
+Zero failures. If anything broke that's not in the immediate neighbourhood of your fix:
+
+- **Localised to the same module:** fix it inline, re-run.
+- **Far from your fix:** the fix has unintended cross-coupling. **Stop and tell the user to re-invoke with `/spec`** — the bug is bigger than you thought.
+
+### 5.3 Auto-fix re-run
+
+If lint/format/types auto-modified files in 5.1, re-run the suite to confirm those auto-fixes didn't break anything. (This is the only reason 5.2 might run twice.)
diff --git a/pilot/skills/fix/steps/06-finalise.md b/pilot/skills/fix/steps/06-finalise.md
new file mode 100644
index 00000000..bc207f1f
--- /dev/null
+++ b/pilot/skills/fix/steps/06-finalise.md
@@ -0,0 +1,60 @@
+## Step 6: Finalise
+
+### 6.1 Worktree mode — single commit
+
+If a worktree was created: bundle test + fix into one commit.
+
+```bash
+git add
+git commit -m "fix: "
+```
+
+The conventional `fix:` prefix triggers a patch release if/when this branch ships. Do not split into multiple commits in the quick lane.
+
+### 6.2 Approval gate (only when enabled)
+
+⛔ **Before showing the approval question, you MUST have completed Step 4 (Verify End-to-End) with evidence.** "Tests pass" is not enough — the approval summary must include what you actually ran and what you observed. If you cannot fill in `**E2E:**` below with concrete evidence, you have not finished Step 4 — go back, do not ask for approval.
+
+Read `PILOT_PLAN_APPROVAL_ENABLED`. If `"false"` → skip 6.2 entirely, mark done.
+
+When approval is enabled, summarise + ask:
+
+```
+AskUserQuestion(
+ question="Bugfix complete.\n\n**Bug:** \n**Root cause:** `:` — \n**Fix:** \n**Tests:** reproducing test added (``), full suite green.\n**E2E:** \n\nReview the diff in the Console's Changes tab. Approve when ready:",
+ options=[
+ "Approve — done",
+ "Issues — describe them, I'll address",
+ "Manual — let me test, I'll come back"
+ ]
+)
+```
+
+Handle:
+
+- **Approve** → done.
+- **Issues** → user describes problem. Treat as a new investigation: re-run Step 1.3 (re-trace) → Step 2 onward.
+- **Manual** → ask once more (`AskUserQuestion` for the stop-guard) and wait. On user return, treat new content as either approval or new issues.
+
+### 6.3 Console notification (always, when binary present)
+
+```bash
+~/.pilot/bin/pilot notify plan_approval "Bugfix complete" "" 2>/dev/null || true
+```
+
+Best-effort — don't block on failure.
+
+### 6.4 Report
+
+```
+Bugfix complete — .
+Root cause: :.
+Tests: 1 new reproducing test, full suite green.
+E2E: → .
+
+Run /clear before starting new work — this resets context while keeping project rules loaded.
+```
+
+The `E2E:` line is **mandatory** — it documents that the actual program was exercised, not just the unit tests.
+
+ARGUMENTS: $ARGUMENTS
diff --git a/pilot/skills/spec-bugfix-plan/manifest.json b/pilot/skills/spec-bugfix-plan/manifest.json
index 038e1fe9..2bf615ef 100644
--- a/pilot/skills/spec-bugfix-plan/manifest.json
+++ b/pilot/skills/spec-bugfix-plan/manifest.json
@@ -31,16 +31,12 @@
"file": "steps/06-annotation-check.md"
},
{
- "id": "step-7-codex-review",
- "file": "steps/07-codex-review.md"
+ "id": "step-7-approval",
+ "file": "steps/07-approval.md"
},
{
- "id": "step-8-approval",
- "file": "steps/08-approval.md"
- },
- {
- "id": "step-9-continuing",
- "file": "steps/09-continuing.md"
+ "id": "step-8-continuing",
+ "file": "steps/08-continuing.md"
}
]
}
diff --git a/pilot/skills/spec-bugfix-plan/orchestrator.md b/pilot/skills/spec-bugfix-plan/orchestrator.md
index b2b71764..67cb9247 100644
--- a/pilot/skills/spec-bugfix-plan/orchestrator.md
+++ b/pilot/skills/spec-bugfix-plan/orchestrator.md
@@ -17,6 +17,8 @@ hooks:
**Output:** Approved bugfix plan at `docs/plans/YYYY-MM-DD-.md` with `Type: Bugfix`
**Next:** On approval → `Skill(skill='spec-implement', args='')`
+**Note:** This skill is invoked when the user types `/spec ""` — they chose the full spec workflow. For a bugfix workflow without a plan file, users invoke `/fix` directly (separate user-facing command). The two are distinct entry points — honour the user's choice.
+
---
## Iron Laws
diff --git a/pilot/skills/spec-bugfix-plan/steps/00-toggles.md b/pilot/skills/spec-bugfix-plan/steps/00-toggles.md
index 7debd8ff..8ac88adc 100644
--- a/pilot/skills/spec-bugfix-plan/steps/00-toggles.md
+++ b/pilot/skills/spec-bugfix-plan/steps/00-toggles.md
@@ -5,7 +5,7 @@
**⛔ Run FIRST, before any other step.** Read all toggle env vars in a single Bash call:
```bash
-echo "QUESTIONS=$PILOT_PLAN_QUESTIONS_ENABLED CODEX_SPEC=$PILOT_CODEX_SPEC_REVIEW_ENABLED APPROVAL=$PILOT_PLAN_APPROVAL_ENABLED"
+echo "QUESTIONS=$PILOT_PLAN_QUESTIONS_ENABLED APPROVAL=$PILOT_PLAN_APPROVAL_ENABLED"
```
-Reference these values throughout: Steps 3.1/3.5 (questions), 7 (Codex — controlled by Console Settings), and 8 (approval).
+Reference these values throughout: Steps 3.1/3.5 (questions) and 7 (approval). Bugfix planning does not run Codex — adversarial review only runs once per `/spec` invocation, on the implementation in `spec-verify`.
diff --git a/pilot/skills/spec-bugfix-plan/steps/01-red-flags.md b/pilot/skills/spec-bugfix-plan/steps/01-red-flags.md
index 3b948451..573aa685 100644
--- a/pilot/skills/spec-bugfix-plan/steps/01-red-flags.md
+++ b/pilot/skills/spec-bugfix-plan/steps/01-red-flags.md
@@ -2,7 +2,9 @@
## Step 1: Red Flags — STOP and Follow Process
-**This is a gate, not a reminder.** If any of the following applies, you are NOT allowed to proceed to Step 4 until Step 3 is fully complete with root cause traced to file:line.
+**This is a gate, not a reminder.** If any red flag below applies, you are NOT allowed to proceed to Step 4 until Step 3 is fully complete with root cause traced to file:line.
+
+### Internal red flags (your own thoughts)
- "Quick fix for now, investigate later"
- "Just try changing X and see if it works"
@@ -14,11 +16,32 @@
- "One more fix attempt" (when already tried 2+)
- Each fix reveals a new problem in a different place
-**Enforcement:** Before writing any task in Step 4, you must be able to answer YES to all of these:
+### Common Rationalizations
+
+| Excuse | Reality |
+|--------|---------|
+| "Issue is simple, don't need process" | Simple bugs have root causes too. The process is fast for simple bugs. |
+| "Just try this first, then investigate" | First fix sets the pattern. Do it right from the start. |
+| "I'll write the test after confirming the fix works" | Untested fixes don't stick. Test first proves the bug exists. |
+| "I see the problem, let me fix it" | Seeing symptoms ≠ understanding root cause. |
+| "One more fix attempt" (after 2+ failures) | 3+ failures = architectural problem. Question the pattern, don't fix again. |
+
+### User signals you're off track
+
+If the user says any of these, STOP and return to investigation — you assumed without verifying:
+
+- "Stop guessing"
+- "Is that not happening?" / "Will it show us…?"
+- "Ultrathink this"
+- "We're stuck?" (frustrated tone)
+- Any redirect implying "you should have checked first"
+
+### Enforcement
+
+Before writing any task in Step 4, you must answer YES to all of these:
1. Can I state the root cause as `file/path:lineN — function_name() does X but should do Y`?
2. Can I explain WHY this causes the symptom (not just what is wrong)?
-3. Have I run `codegraph_callers`/`codegraph_callees` on the function at the root cause?
-4. Is my confidence High or Medium (not Low)?
+3. Is my confidence High or Medium (not Low)?
-If any answer is NO → return to Step 3 before continuing. No exceptions, no shortcuts — even for "obvious" bugs.
+If any answer is NO → return to Step 3. No exceptions, even for "obvious" bugs. Call-graph traversal (`codegraph_callers`/`codegraph_callees`) is required only for cross-component bugs (Step 3.3) — not for local fixes.
diff --git a/pilot/skills/spec-bugfix-plan/steps/03-investigation.md b/pilot/skills/spec-bugfix-plan/steps/03-investigation.md
index 079370b8..53c172bb 100644
--- a/pilot/skills/spec-bugfix-plan/steps/03-investigation.md
+++ b/pilot/skills/spec-bugfix-plan/steps/03-investigation.md
@@ -2,69 +2,73 @@
## Step 3: Root Cause Investigation
-**Complete each sub-step before the next. No shortcuts.**
+Complete each sub-step before the next. No shortcuts.
-### 3.1: Reproduce & Understand
+### 3.1 Reproduce & understand
-1. Restate: **symptom** (what user observes), **trigger** (when/how), **expected behavior**
-2. If too vague: `AskUserQuestion` with ONE focused question
-3. Can you trigger it reliably? What are the exact steps?
-4. **If not reproducible after 2 focused attempts:** STOP investigating silently. `AskUserQuestion` for the missing signal — exact command, input, environment, stack trace, or a recording. A speculative fix for an unreproduced bug is roughly 50% wasted effort; asking is cheaper than guessing.
-5. **If intermittent (flaky / race / timing):** trigger it 10+ times, record how often it fires and what state correlates with failures. Flaky bugs need a test that **forces** the race (deterministic ordering, frozen clock, blocked event loop), not a test that hopes to hit it.
+- Restate **symptom** (what user observes), **trigger** (when/how), **expected behaviour**.
+- Vague? One focused `AskUserQuestion`.
+- Reliable repro? Steps?
+- **Not reproducible after 2 attempts:** STOP guessing. `AskUserQuestion` for the missing signal — exact command, input, environment, stack trace, or recording.
+- **Intermittent (flaky / race):** trigger 10+ times, record state at failure. Flaky bugs need a test that **forces** the race (deterministic ordering, frozen clock, blocked event loop), not one that hopes to hit it.
-### 3.2: Check Recent Changes
+### 3.2 Recent changes
-- What changed that could cause this? `git log --oneline -10 -- `, `git diff`
-- **When a specific token appeared or disappeared:** `git log -S "" -- ` finds commits that added/removed that exact string. For regex patterns: `git log -G ""`. Faster than `git bisect` when the bug correlates with a specific symbol.
-- New dependencies, config changes, environmental differences?
+- `git log --oneline -10 -- `, `git diff` for the obvious suspects.
+- **A specific token appeared/disappeared?** `git log -S "" -- ` (added/removed). Regex: `git log -G ""`. Faster than bisect when correlated with a symbol.
+- New deps, config changes, env differences?
-### 3.3: Trace the Root Cause
+### 3.3 Trace the root cause
-**⛔ START WITH CODEGRAPH — before reading any files.**
+**Start with `codegraph_context(task="")`** — single call, returns entry points, related symbols, and code context. Read it before going deeper.
-**Step 1: Orient with CodeGraph (MANDATORY FIRST ACTION):**
-```
-codegraph_context(task="")
-```
-This reveals entry points, related symbols, and code context for the bug area. Read the output carefully before diving deeper.
+**Deep dive when needed:** `codegraph_search` to find a specific symbol, then `codegraph_explore(query="")` for full source from all relevant files in one call.
-**Step 2: Deep dive if needed:** Use `codegraph_search` to find the specific symbol, then `codegraph_explore(query="")` to get full source code from all relevant files in one call.
+**Backward tracing (symptom → source):**
-**Step 3: Trace and investigate.** Use Probe for intent-based search (`probe search`), CodeGraph for structural tracing. Fall back to Grep/Glob only for exact patterns.
+1. Find where the wrong behaviour appears — note `file:line`.
+2. `codegraph_callers` traces what called this with the bad value/state.
+3. Keep tracing until you find the **source** where the bad data originates.
+4. **Fix at the source, not where the error appears.**
-Read as many files as needed. For each: read completely, trace execution path from user action to symptom, note specific lines where behavior diverges.
+**Multi-component systems — instrument at boundaries before concluding:**
-**Backward tracing technique (from symptom to source):**
+```bash
+# Layer 1: entry point
+echo "=== enter handler — input: ==="
+echo "$INPUT"
-1. Find where the error/wrong behavior appears — note file:line
-2. Use `codegraph_callers` to trace what called this with the wrong value/state
-3. Keep tracing until you find the **source** — where the bad data originates
-4. **Fix at the source, not where the error appears**
+# Layer 2: business logic
+echo "=== leave handler / enter service — payload: ==="
+jq . <<< "$PAYLOAD"
+
+# Layer 3: storage
+echo "=== query result: ==="
+psql -c "SELECT id, status FROM jobs WHERE id=$JOB_ID"
+```
-**Multi-component systems:** Before concluding, instrument at component boundaries:
+This reveals **which** layer breaks. Investigate that layer next — don't speculate across layers.
-- What data enters each component? What exits?
-- WHERE does it break? Run once to gather evidence, THEN investigate the failing component.
-- **Mark every temporary log/print with `SPEC-DEBUG:`** (e.g. `console.log("SPEC-DEBUG: filters=", filters)`, `# SPEC-DEBUG: print(x)`). Verification greps the diff for this marker — any match fails verification and forces cleanup. This is the only way temporary diagnostics are allowed in the fix diff.
+**⛔ Mark every temporary log/print with `SPEC-DEBUG:`** (e.g. `console.log("SPEC-DEBUG: filters=", filters)`, `# SPEC-DEBUG: print(x)`). Verification greps the diff for this marker — any match fails verification and forces cleanup. Only way temporary diagnostics are allowed in the fix diff.
-**⛔ Structural tracing (MANDATORY):** Run `codegraph_callers` and `codegraph_callees` on the function where the bug manifests AND the function at the root cause. Then run `codegraph_impact` to see the full blast radius — essential for understanding how bad data flows through the system.
+**Structural tracing — proportional to bug scope.** For bugs spanning 2+ files, modules, or components, run `codegraph_callers` + `codegraph_callees` on the root-cause function plus `codegraph_impact` for blast radius. For local bugs (typo, off-by-one, wrong constant in one function, missing null check at one call site), `codegraph_context` from above plus a targeted Read is enough — skip the full call-graph traversal.
-Tools: CodeGraph (`codegraph_context`, `codegraph_explore`, `codegraph_callers`/`codegraph_callees`, `codegraph_impact`, `codegraph_search`), Probe CLI (`probe search` for intent, `probe extract` for symbols), Read/Grep/Glob for exact patterns.
+Tools: CodeGraph, Probe CLI (`probe search`/`probe extract`), Read/Grep/Glob for exact patterns.
-### 3.4: Pattern Analysis
+### 3.4 Pattern analysis
-1. Find **working examples** — similar code in the codebase that works correctly
+1. Find **working examples** — similar code in the codebase that works correctly.
2. Compare: what's different between working and broken?
-3. List every difference, however small — don't assume "that can't matter"
+3. List every difference — don't assume "that can't matter".
-### 3.5: Root Cause Statement
+### 3.5 Root cause statement
State clearly:
- **Root cause:** `file/path.py:lineN` — `function_name()` does X but should do Y
-- **Why:** Explain WHY it causes the symptom (not just what's wrong)
+- **Why:** WHY it causes the symptom (not just what is wrong)
- **Confidence:** High (traced fully) / Medium (strong hypothesis) / Low (needs more data)
-If confidence is Low: gather more evidence. Don't guess.
+Low confidence → gather more evidence. Don't guess.
-**Escalation:** If 3+ hypotheses have failed, STOP — this is likely an architectural problem, not a simple bug. `AskUserQuestion` to discuss with user before continuing.
+**Escalation:** if 3+ hypotheses have failed, this is likely architectural. STOP and `AskUserQuestion` before continuing.
diff --git a/pilot/skills/spec-bugfix-plan/steps/04-plan-fix.md b/pilot/skills/spec-bugfix-plan/steps/04-plan-fix.md
index ac6bd329..f319f695 100644
--- a/pilot/skills/spec-bugfix-plan/steps/04-plan-fix.md
+++ b/pilot/skills/spec-bugfix-plan/steps/04-plan-fix.md
@@ -2,41 +2,29 @@
## Step 4: Plan the Fix
-### Gate Function — Before Planning
+### Gate — before writing the plan
-```
-BEFORE writing the plan:
- 1. Can I state the root cause with file:line? If NO → back to 1.2
- 2. Can I explain WHY it causes the symptom? If NO → back to 1.2
- 3. Is my confidence High or Medium? If LOW → back to 1.2
-```
+Answer YES to all:
+
+1. Root cause stated as `file:lineN — function() does X but should do Y`?
+2. WHY it causes the symptom is explained?
+3. Confidence is High or Medium?
-### Fix Approach Selection
+If any NO → return to Step 3.
-**After confirming root cause, evaluate fix strategies before committing to one.** Even simple bugs often have multiple valid fixes (patch at symptom vs fix at source vs structural prevention). Making the choice explicit improves plan quality.
+### Fix approach selection
-Propose 2-3 fix approaches. For each:
+**Default: pick the obvious fix.** For most bugs the source-level change at the root cause is the only reasonable fix. Document it in one or two sentences and move on. Don't manufacture fake alternatives.
-- **Name** — short label (e.g., "Patch at call site" vs "Fix at source" vs "Add validation layer")
-- **What it fixes** — which symptoms/failure modes it addresses
-- **Trade-offs** — scope of change, risk of regression, maintenance burden
-- **Recommendation** — mark your preferred approach with reasoning
+**Propose 2–3 approaches only when there is a genuine architectural choice** (patch at call site vs. fix at source vs. add validation layer, with materially different scope/regression/maintenance trade-offs). For each: name, what it fixes, trade-offs, recommendation.
-**When questions are enabled (`PILOT_PLAN_QUESTIONS_ENABLED` is not `"false"`):** Use `AskUserQuestion` to let the user pick the approach. Each approach is an option.
+When a genuine choice exists AND `PILOT_PLAN_QUESTIONS_ENABLED` is not `"false"`: use `AskUserQuestion` to pick.
```bash
~/.pilot/bin/pilot notify plan_approval "Fix Approach" " — fix strategy" --plan-path "" 2>/dev/null || true
```
-**When questions are disabled:** Select the recommended approach and document the reasoning in the plan.
-
-**Skip for trivial bugs:** If there is genuinely only one reasonable fix (e.g., typo, wrong variable name, missing import), note the approach briefly and proceed — don't manufacture fake alternatives.
-
-### Behavior Contract (MANDATORY — write it before task structure)
-
-**Every bugfix plan must pin down the contract as an explicit before/after invariant.** This is what the reproducing test will encode and what verification will audit against. Without this, "the fix works" has no meaning.
-
-Write it in the plan like this:
+### Behavior Contract (MANDATORY)
```markdown
## Behavior Contract
@@ -45,44 +33,29 @@ Write it in the plan like this:
**When:** [the action or call that exercises the code path]
**Currently (bug):** [actual, incorrect behavior — the symptom]
**Expected (fix):** [correct behavior the fix must produce]
-**Anti-regression:** [what must still work — behavior the fix must NOT break]
+**Anti-regression:** [named tests / flows / API contracts that must still pass]
```
-The reproducing test encodes the `Currently → Expected` transition. Verification audits that the fix produced it without breaking `Anti-regression`.
-
-**Write `Anti-regression:` specifically** — name the test(s), user flow, or API contract that must still pass. "Existing functionality" or "nothing else breaks" is not auditable. Example: `Anti-regression: test_search_with_filters_returns_200, test_search_pagination` — not `Anti-regression: existing search tests`.
+`Anti-regression:` must name specific tests or flows — `test_search_with_filters_returns_200, test_search_pagination` not "existing search tests".
-### Task structure — ONE uniform shape for every bugfix
+### Task structure — three tasks, no exceptions
-**⛔ Do NOT collapse these into fewer tasks. Do NOT merge test + fix into a single task.** Separate checkboxes = separate proof. Combining them is exactly where the process falls apart.
+⛔ Do NOT merge tasks. Separate checkboxes = separate proof.
-**Task 1: Write Reproducing Test (RED)**
-- Write a test that encodes the Behavior Contract's `Currently → Expected` transition.
-- Test must exercise an existing public entry point (not helpers you plan to create).
-- Run it → **must FAIL** with an assertion or error that matches the documented symptom.
-- Commit the failing test BEFORE writing any fix code (worktree mode only).
-- Definition of Done: test exists, is named `test___`, runs, fails with the expected error.
+**Task 1 — Write Reproducing Test (RED)**
+Encode `Currently → Expected` via an existing public entry point. Run → must FAIL with the documented symptom. Worktree mode: commit alone before any fix code. Naming: `test___`.
-**Task 2: Implement Fix at Root Cause**
-- Make the minimal change at `Root Cause: file:line` from the plan.
-- Fix at the source, not where the error appears. No catching/hiding/patching around the symptom.
-- Re-run the reproducing test → **must PASS**.
-- Run the full test suite → zero failures (no `Anti-regression` breakage). This is the anti-regression gate for the fix itself.
-- Definition of Done: reproducing test green, full suite green, diff touches root cause file.
+**Task 2 — Implement Fix at Root Cause**
+Minimal change at `Root Cause: file:line`. Fix at source, not symptom. Re-run reproducing test → must PASS. Run targeted test module(s), not full suite — full suite runs at Task 3. Diff must touch the root-cause file.
-**Task 3: Quality Gate**
-- Lint, type check, build (if applicable), performance audit.
-- Re-run the full test suite at the END of this task. Lint/type auto-fixes can silently modify code — the suite must be green **after** those fixes, not before. A task checkbox goes green only when the suite is green for the code as it stands at that moment.
-- For UI-facing bugs: the `Verification Scenario` (TS-001) is executed in the verify phase (step 6), not here.
-- Definition of Done: lint clean, types clean, build green, full suite green, no performance regressions in the diff.
+**Task 3 — Quality Gate**
+Lint, type check, build (if applicable). Re-run full suite at the END (lint/type auto-fixes can break tests). UI-facing bugs: the Verification Scenario runs in verify phase, not here.
-**Scope scaling:** Lean bugs have short tasks (one-line test, one-line fix). Complex bugs have longer tasks (multiple assertions, defense-in-depth fix). The **number** of tasks is always three. The **content** of each task scales with the bug.
+**Scope scaling:** simple bugs get short tasks, complex bugs get longer tasks — but always three tasks.
-**Regression tests must exercise existing public entry points** (not internal helpers you plan to create). The test answers: "Under the bug condition, does the system produce the correct result?"
+**Defense-in-depth:** when the bug propagated through multiple layers, plan validation at each layer (entry point, business logic, environment guards). Document as `Defense-in-depth:` in the Fix Approach section.
-**Defense-in-depth:** When the bug was caused by invalid data flowing through multiple layers, plan validation at every layer the data passes through — not just the source. Entry point validation, business logic validation, environment guards where appropriate.
-
-**Verification Scenario (if UI-facing bug):** If the bug manifests in the UI or through user-visible behavior, add a single structured scenario to the plan describing the user steps that reproduce the bug and confirm the fix. Same format as feature E2E scenarios — concrete browser automation steps with expected results (tool-agnostic: Claude Code Chrome, playwright-cli, or agent-browser). This serves as the acceptance test beyond the regression unit test.
+### Verification Scenario (UI-facing bugs only)
```markdown
### TS-001: [Bug Trigger / Fix Confirmation]
@@ -93,3 +66,5 @@ The reproducing test encodes the `Currently → Expected` transition. Verificati
| 1 | [User action that triggered bug] | [Correct behavior now shown] |
| 2 | [Follow-up verification] | [No regression] |
```
+
+Tool-agnostic — Claude Code Chrome, Chrome DevTools MCP, playwright-cli, or agent-browser per `browser-automation.md`.
diff --git a/pilot/skills/spec-bugfix-plan/steps/06-annotation-check.md b/pilot/skills/spec-bugfix-plan/steps/06-annotation-check.md
index dd644f3c..3320041c 100644
--- a/pilot/skills/spec-bugfix-plan/steps/06-annotation-check.md
+++ b/pilot/skills/spec-bugfix-plan/steps/06-annotation-check.md
@@ -2,9 +2,9 @@
## Step 6: Check for Console Annotation Feedback (Before Approval)
-**⛔ Run this BEFORE Step 8 (approval).** Check if the user has annotated the plan in the Console's Specifications tab. Annotations auto-save to JSON — no "Send Feedback" button needed.
+**⛔ Run this BEFORE Step 7 (approval).** Check if the user has annotated the plan in the Console's Specifications tab. Annotations auto-save to JSON — no "Send Feedback" button needed.
1. Derive annotation file: `docs/plans/.annotations/.json`
2. Read the annotation file with the Read tool. If the file doesn't exist, treat as `NO_FEEDBACK`. If it exists, check whether `planAnnotations` has any entries (`FEEDBACK_EXISTS`) or is empty/missing (`NO_FEEDBACK`).
-3. **If `FEEDBACK_EXISTS`:** Each annotation in `planAnnotations` has `originalText` (selected passage) and `text` (user's note). Incorporate into plan, delete the annotation file via `rm -f ""` (e.g. `rm -f "docs/plans/.annotations/2026-03-26-my-bug.json"`), note changes. Proceed to Step 8.
-4. **If `NO_FEEDBACK`:** proceed directly to Step 8.
+3. **If `FEEDBACK_EXISTS`:** Each annotation in `planAnnotations` has `originalText` (selected passage) and `text` (user's note). Incorporate into plan, delete the annotation file via `rm -f ""` (e.g. `rm -f "docs/plans/.annotations/2026-03-26-my-bug.json"`), note changes. Proceed to Step 7.
+4. **If `NO_FEEDBACK`:** proceed directly to Step 7.
diff --git a/pilot/skills/spec-bugfix-plan/steps/08-approval.md b/pilot/skills/spec-bugfix-plan/steps/07-approval.md
similarity index 97%
rename from pilot/skills/spec-bugfix-plan/steps/08-approval.md
rename to pilot/skills/spec-bugfix-plan/steps/07-approval.md
index d6a98a63..f3f8242e 100644
--- a/pilot/skills/spec-bugfix-plan/steps/08-approval.md
+++ b/pilot/skills/spec-bugfix-plan/steps/07-approval.md
@@ -1,6 +1,6 @@
---
-## Step 8: Get User Approval
+## Step 7: Get User Approval
**⛔ If `PILOT_PLAN_APPROVAL_ENABLED` is `"false"` (from Step 0),** skip this step: set `Approved: Yes` in the plan file automatically and immediately invoke `Skill(skill='spec-implement', args='')`. No AskUserQuestion, no notification.
diff --git a/pilot/skills/spec-bugfix-plan/steps/07-codex-review.md b/pilot/skills/spec-bugfix-plan/steps/07-codex-review.md
deleted file mode 100644
index 7a3f7378..00000000
--- a/pilot/skills/spec-bugfix-plan/steps/07-codex-review.md
+++ /dev/null
@@ -1,23 +0,0 @@
-## Step 7: Codex Adversarial Review (Optional)
-
-**If `PILOT_CODEX_SPEC_REVIEW_ENABLED` is `"true"` (from Step 0):**
-
-1. Detect companion path, project root, and base branch:
-```bash
-CODEX_COMPANION=$(ls ~/.claude/plugins/cache/openai-codex/codex/*/scripts/codex-companion.mjs 2>/dev/null | sort -V | tail -1)
-PROJECT_ROOT="${CLAUDE_PROJECT_ROOT:-$(pwd)}"
-# Use worktree base branch if in worktree, otherwise detect repo default branch
-BASE_BRANCH=$(~/.pilot/bin/pilot worktree status --json 2>/dev/null | grep -o '"base_branch":"[^"]*"' | cut -d'"' -f4)
-[ -z "$BASE_BRANCH" ] && BASE_BRANCH=$(cd "$PROJECT_ROOT" && git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's|refs/remotes/origin/||' || echo "main")
-```
-
-2. Launch adversarial review in background. **⛔ Use `Bash(run_in_background=true)`** — the companion's `--background` flag is a no-op for reviews (only works for `task`), so we use Claude Code's background bash instead:
-```bash
-cd "$PROJECT_ROOT" && node "$CODEX_COMPANION" adversarial-review --base "$BASE_BRANCH" "Challenge this bugfix plan: . Plan: . Focus on: wrong root cause, incomplete fix, missing edge cases, regression risk, and whether the fix addresses symptoms vs cause."
-```
-
-3. **⛔ MANDATORY — NEVER skip or defer.** The completion notification is the ONLY valid signal. Do NOT read the output file to check if the review is done — the file may contain partial output from an in-progress review. Reading it before the notification leads to false conclusions ("no findings" when the review is still running). Wait for the `` with `completed `.
-
-4. **When (and ONLY when) the completion notification arrives**, read the background bash output. **Filter out `[codex]` prefixed log lines** — use `ctx_execute_file` to extract only non-`[codex]` lines. Search for `# Codex Adversarial Review` section via `ctx_search`. Extract `Verdict:` and `Findings:` lines. Map severities: `[high]` / `[critical]` → must_fix, `[medium]` / `[low]` → should_fix. Fix all must_fix/should_fix in the plan.
-
-5. **If the background bash timed out or failed** (exit code non-zero in the notification): Re-launch synchronously and wait. Only skip if the second attempt also fails.
diff --git a/pilot/skills/spec-bugfix-plan/steps/09-continuing.md b/pilot/skills/spec-bugfix-plan/steps/08-continuing.md
similarity index 76%
rename from pilot/skills/spec-bugfix-plan/steps/09-continuing.md
rename to pilot/skills/spec-bugfix-plan/steps/08-continuing.md
index a6700e22..b9ffd436 100644
--- a/pilot/skills/spec-bugfix-plan/steps/09-continuing.md
+++ b/pilot/skills/spec-bugfix-plan/steps/08-continuing.md
@@ -1,7 +1,7 @@
---
-## Step 9: Continuing Unapproved Bugfix Plans
+## Step 8: Continuing Unapproved Bugfix Plans
-When arguments end with `.md`: read plan, check Status/Approved. Resume from wherever planning left off: no investigation yet → Step 3. Has investigation, no tasks → Step 4. Complete but unapproved → Step 8.
+When arguments end with `.md`: read plan, check Status/Approved. Resume from wherever planning left off: no investigation yet → Step 3. Has investigation, no tasks → Step 4. Complete but unapproved → Step 7.
ARGUMENTS: $ARGUMENTS
diff --git a/pilot/skills/spec-bugfix-verify/manifest.json b/pilot/skills/spec-bugfix-verify/manifest.json
index c96051e0..3f9bc755 100644
--- a/pilot/skills/spec-bugfix-verify/manifest.json
+++ b/pilot/skills/spec-bugfix-verify/manifest.json
@@ -15,36 +15,24 @@
"file": "steps/03-quality-checks.md"
},
{
- "id": "step-4-plan-verify",
- "file": "steps/04-plan-verify.md"
+ "id": "step-4-verification-scenario",
+ "file": "steps/04-verification-scenario.md"
},
{
- "id": "step-5-runtime-verification",
- "file": "steps/05-runtime-verification.md"
+ "id": "step-5-final-worktree-sync",
+ "file": "steps/05-final-worktree-sync.md"
},
{
- "id": "step-6-verification-scenario",
- "file": "steps/06-verification-scenario.md"
+ "id": "step-6-check-feedback",
+ "file": "steps/06-check-feedback.md"
},
{
- "id": "step-7-final-worktree-sync",
- "file": "steps/07-final-worktree-sync.md"
+ "id": "step-7-code-review-gate",
+ "file": "steps/07-code-review-gate.md"
},
{
- "id": "step-8-post-merge-verify",
- "file": "steps/08-post-merge-verify.md"
- },
- {
- "id": "step-9-check-feedback",
- "file": "steps/09-check-feedback.md"
- },
- {
- "id": "step-10-code-review-gate",
- "file": "steps/10-code-review-gate.md"
- },
- {
- "id": "step-11-update-status",
- "file": "steps/11-update-status.md"
+ "id": "step-8-update-status",
+ "file": "steps/08-update-status.md"
}
]
}
diff --git a/pilot/skills/spec-bugfix-verify/orchestrator.md b/pilot/skills/spec-bugfix-verify/orchestrator.md
index 4eb5401f..9ac968e6 100644
--- a/pilot/skills/spec-bugfix-verify/orchestrator.md
+++ b/pilot/skills/spec-bugfix-verify/orchestrator.md
@@ -11,18 +11,19 @@ hooks:
# /spec-bugfix-verify - Bugfix Verification Phase
-**Phase 3 (bugfix).** Lightweight verification: run tests, quality checks, confirm fix works.
+**Phase 3 (bugfix).** Lightweight verification: run tests, quality checks, confirm fix works end-to-end.
**Input:** Bugfix plan with `Status: COMPLETE`
**Output:** Plan → VERIFIED (success) or loop back to implementation (failure)
-**Why no sub-agents:** The regression test proves the fix works. The full test suite proves nothing else broke. Sub-agents would re-verify what tests already prove.
+**Why no sub-agents:** The regression test plus end-to-end verification (Step 2.6 / Step 4 Verification Scenario) prove the fix works. The full test suite proves nothing else broke. Sub-agents would re-verify what tests + E2E already prove.
---
## Critical Constraints
-- **NO review sub-agents** — tests prove correctness for bugfixes
+- **NO review sub-agents** — tests + E2E re-check carry the proof for bugfixes
- **NO stopping** — everything automatic. Never ask "Should I fix these?"
- **Fix ALL issues automatically** — no permission needed
- **Plan file is source of truth** — re-read after auto-compaction
+- ⛔ **NEVER claim VERIFIED on tests alone.** Step 2.6 (non-UI) and Step 4 (UI Verification Scenario) require running the actual program — Chrome / Chrome DevTools MCP / playwright-cli / agent-browser for UI; CLI / API / REPL for non-UI. Skip is never an option.
diff --git a/pilot/skills/spec-bugfix-verify/steps/02-verify-fix.md b/pilot/skills/spec-bugfix-verify/steps/02-verify-fix.md
index 58c2b129..0ab8ea2a 100644
--- a/pilot/skills/spec-bugfix-verify/steps/02-verify-fix.md
+++ b/pilot/skills/spec-bugfix-verify/steps/02-verify-fix.md
@@ -1,83 +1,62 @@
## Step 2: Verify the Fix — Behavior Contract Audit
-**This step is the quality gate for bugfixes.** It audits that the process was followed, not just that tests pass. A retroactive test that passes proves nothing.
+Audits that the process was followed. A retroactive test that passes proves nothing.
### 2.1 Read the plan
-1. Read the plan's `## Behavior Contract` section. Note `Given / When / Currently / Expected / Anti-regression`.
-2. Read Task 1's `Entry point:` and the test file/name it specifies.
-3. Read `Root Cause: file:line` from the plan summary.
+Read: `## Behavior Contract`, Task 1's `Entry point:` and test file/name, `Root Cause: file:line` from the summary.
-**If `## Behavior Contract` is missing from the plan:** the plan was written before the updated template. Reconstruct it from Summary + Fix Approach and add it to the plan before continuing.
+If `## Behavior Contract` is missing (older plan): reconstruct from Summary + Fix Approach and add it to the plan before continuing.
### 2.2 Run the reproducing test
-```
+```bash
uv run pytest :: -q # or language-appropriate equivalent
```
-Must PASS on the current (fixed) code. If not, the fix is incomplete — fix immediately, do not advance.
-
-### 2.3 Prove the test is a genuine RED (always run — not optional)
-
-**A test only has value if it would fail without the fix.** Commit order alone does not prove that — a retroactively added `assert True`-style test also satisfies commit order. The only proof is to run the test against the pre-fix code and see it fail.
+Must PASS. If not, fix is incomplete — fix immediately.
-**Always run this, regardless of worktree mode.** Cost is one extra run of the single reproducing test (seconds, not minutes) — cheap insurance that rules out the entire class of retroactive rubber-stamp tests.
+### 2.3 Prove the test is a genuine RED (always run)
-Use one atomic bash block with trap-based cleanup. This script is universal — it works in worktree mode (fix is committed) and non-worktree mode (fix is uncommitted). The `cp + trap` approach restores the file contents reliably regardless of how the fix was applied:
+A test only has value if it would fail without the fix. Run the test against pre-fix code; it must fail. One atomic bash with trap-based cleanup — touches only the root-cause file, always restores it (works in worktree and non-worktree mode):
```bash
ROOT_CAUSE_FILE=""
TEST_CMD=""
-# Back up the current (fixed) version and install a trap that always restores it
BACKUP=$(mktemp)
cp "$ROOT_CAUSE_FILE" "$BACKUP"
trap 'cp "$BACKUP" "$ROOT_CAUSE_FILE" 2>/dev/null; rm -f "$BACKUP"; trap - EXIT INT TERM' EXIT INT TERM
-# Replace the root-cause file with its pre-fix content
if ! git diff --quiet HEAD -- "$ROOT_CAUSE_FILE"; then
- # Non-worktree / uncommitted fix: HEAD is the pre-fix version
git show "HEAD:$ROOT_CAUSE_FILE" > "$ROOT_CAUSE_FILE"
else
- # Worktree / committed fix: last commit touching this file IS the fix commit
FIX_COMMIT=$(git log --format=%H -1 -- "$ROOT_CAUSE_FILE")
git show "${FIX_COMMIT}~1:$ROOT_CAUSE_FILE" > "$ROOT_CAUSE_FILE"
fi
-# Run the reproducing test — must FAIL
eval "$TEST_CMD"
-TEST_EXIT=$?
-# trap restores $ROOT_CAUSE_FILE from backup on exit (success or failure)
```
-Why `cp + trap` instead of `git stash`: stash modifies the index/working tree globally and can leave untracked files or produce merge conflicts on pop. `cp + trap` touches only the one file that matters and always restores it, even on crash.
-
-**Interpretation:**
-
-- Test failed (non-zero exit) with an error matching `Currently (bug)` → RED is proven. Continue to 2.4.
-- Test passed without the fix → the test does not encode the bug. STOP, set `Status: PENDING`, note "reproducing test does not fail without fix" in the plan, and return to `spec-implement` — Task 1 must be rewritten.
-- Test errored for a reason unrelated to the bug (import error, missing fixture introduced by the fix, etc.) → not a valid signal. Investigate: either the test depends on something only the fix creates (design problem — test should target a stable entry point), or an unrelated change snuck into the fix commit. Resolve before accepting.
-
-### 2.4 Root-cause-at-source audit
+`cp + trap` instead of `git stash`: stash modifies index/working-tree globally and can leave untracked files or merge conflicts on pop. `cp + trap` touches one file and always restores it.
-Compare the diff to the plan's `Root Cause: file:line`:
+Outcomes:
-1. `git diff --name-only ..HEAD` — list files changed.
-2. **The root-cause file MUST be in the diff.** If it is not, the fix is at a symptom, not the source. STOP, set `Status: PENDING`, note "fix does not touch stated root cause" in the plan, return to `spec-implement`.
-3. **Flag symptom-patching smells in the diff:** new broad `try/except` around the failing call, `if value is None: return default` at the caller when the bug is that `value` is wrong upstream, swallowed exceptions, silently normalised bad inputs, early-return on error conditions that hide wrong state from the caller, renamed/suppressed log lines that previously surfaced the bug. If present, record a finding and require justification in the plan's Investigation section (sometimes a defensive layer is legitimate — defense-in-depth — but it must be documented, not snuck in).
+- **Test failed with the documented `Currently (bug)` error** → RED proven.
+- **Test passed without fix** → test doesn't encode the bug. Set `Status: PENDING`, note "reproducing test does not fail without fix", return to `spec-implement`.
+- **Test errored unrelated** (import, missing fixture) → not a valid signal. Investigate: test depends on something only the fix creates (design problem) or unrelated change snuck in. Resolve before accepting.
-### 2.5 Anti-regression audit
+### 2.4 Root-cause + scope audit
-Run the full test suite (already done in Step 1, re-run if the revert in 2.3 left artifacts). Zero failures. The Behavior Contract's `Anti-regression:` line states what must still work — spot-check the tests covering it.
-
-### 2.6 Scope check
-
-Read changed files. Confirm changes match plan scope (Task 1 files + Task 2 files). Flag unplanned changes — they either belong in this plan (update the plan) or in a different plan (revert).
+```bash
+git diff --name-only ..HEAD
+```
-### 2.7 Instrumentation cleanup
+1. **Root-cause file MUST be in the diff.** If not, fix is at symptom — set `Status: PENDING`, return to `spec-implement`.
+2. **Symptom-patching smells:** new broad `try/except` around the failing call, `if value is None: return default` at the caller when the bug is upstream, swallowed exceptions, silently normalised bad inputs, early returns hiding wrong state, renamed/suppressed log lines. Record + justify in Investigation, or revert.
+3. **Scope check:** diff matches plan scope (Task 1 tests + Task 2 root-cause file ± documented defense-in-depth). Unplanned changes belong elsewhere — revert or extend the plan.
-Temporary diagnostics added during investigation must be marked `SPEC-DEBUG:` (see `spec-bugfix-plan` Step 3.3). Grep the diff for the marker:
+### 2.5 Instrumentation cleanup
```bash
if git diff ..HEAD | grep -n "SPEC-DEBUG"; then
@@ -86,17 +65,24 @@ if git diff ..HEAD | grep -n "SPEC-DEBUG"; then
fi
```
-Zero matches = clean. Any match = remove the markers in the diff and re-run this step. Non-marked `console.log`/`print` additions are also suspect; inspect them and justify or remove.
+Zero matches = clean. Any match = remove and re-run. Unmarked `console.log`/`print` additions are also suspect — inspect, justify, or remove.
+
+### 2.6 Original symptom re-check — MANDATORY end-to-end verification
+
+⛔ **The regression test passing does NOT prove the bug is fixed.** Unit tests can sit below the user's layer. A green test plus a still-broken app is the most common "fixed but not really" failure mode. You MUST run the actual program with the original input and observe the symptom is gone.
-### 2.8 Original symptom re-check (non-UI bugs)
+**Skip is NOT an option.** Capture concrete evidence (command, output, page state, status code) — bare assertions are insufficient.
-The regression test proves the tested scenario works. It does NOT prove the original symptom the user reported is gone — the test may sit below the layer the user interacts with.
+Re-run the original repro from `## Summary — Trigger:` using the matching lane:
-Re-run the original reproduction from the plan's `## Summary — Trigger:` line:
+| Bug surface | What to run | Evidence to capture |
+|-------------|-------------|---------------------|
+| **CLI** | The exact command the user ran | Command + relevant output lines + exit code |
+| **API** | `curl` / HTTP client with the user's input | Status code + the field/value that proves the fix |
+| **Library / SDK / function** | `python -c '...'`, `node -e '...'`, REPL, or scratch script | Invocation + returned value |
+| **Background job / cron / worker** | Trigger the job manually with the failing input | Run + log lines |
+| **UI** | **Skip here — handled by Step 4 (Verification Scenario)** with browser automation (Claude Code Chrome → Chrome DevTools MCP → playwright-cli → agent-browser per `browser-automation.md`) | — |
-- **CLI bug:** run the exact command the user ran
-- **API bug:** `curl` / HTTP client the endpoint with the user's input
-- **Library/SDK bug:** call the function from a Python/Node REPL with the user's args
-- **UI bug:** skip here — handled by Step 6 (Verification Scenario)
+**If the regression test passes but the original repro still fails:** test is at the wrong layer. Set `Status: PENDING`, note "test green but original repro still fails — layer mismatch", return to `spec-implement` to rewrite Task 1's test at the user's entry point.
-**If the regression test passes but the original repro still shows the bug:** the test is at the wrong layer. Set `Status: PENDING`, note "test green but original repro still fails — layer mismatch" in the plan, and return to `spec-implement` to rewrite Task 1's test at the user's entry point. This is the "test-green but user-broken" failure mode — catching it here is the whole reason this step exists.
+**If the running program is unavailable** (build broken, infra missing, integration env down): set `Status: PENDING`, note the blocker, escalate to the user. Do not advance to VERIFIED on tests alone.
diff --git a/pilot/skills/spec-bugfix-verify/steps/03-quality-checks.md b/pilot/skills/spec-bugfix-verify/steps/03-quality-checks.md
index c611db5a..be808a71 100644
--- a/pilot/skills/spec-bugfix-verify/steps/03-quality-checks.md
+++ b/pilot/skills/spec-bugfix-verify/steps/03-quality-checks.md
@@ -1,6 +1,8 @@
-## Step 3: Quality Checks
+## Step 3: Quality Checks + Residual Plan Verifies
1. **Type checker** — zero new errors
2. **Linter** — errors are blockers, fix immediately
3. **Build** (if applicable) — must succeed
-4. **Performance audit** — For changed files on hot paths: expensive uncached work? Heavy dependency imports with lighter alternatives? Repeated invocations redoing work when input hasn't changed? Structural issues — visible in source, no running program needed.
+4. **Residual `Verify:` commands.** The uniform 3-task plan structure means Task 1's verify (RED) was run by `spec-implement`, Task 2's verify (PASS) was run in Step 2.2, and Task 3's verify (lint/types/build) is covered by 1–3 above. Skip those. Run only **residual** commands a human author added (e.g. `uv run python -c "import foo; foo.smoke()"`, an endpoint smoke test) — usually nothing.
+
+ For server-dependent residuals (containing `curl`, `localhost`, `http://`): start the service → run the command → stop the service → fix failures. Skip this branch entirely if no residuals exist.
diff --git a/pilot/skills/spec-bugfix-verify/steps/04-plan-verify.md b/pilot/skills/spec-bugfix-verify/steps/04-plan-verify.md
deleted file mode 100644
index c849d9e6..00000000
--- a/pilot/skills/spec-bugfix-verify/steps/04-plan-verify.md
+++ /dev/null
@@ -1,16 +0,0 @@
-## Step 4: Plan Verify Commands (conditional — usually a no-op)
-
-**For plans following the uniform 3-task structure (Reproducing Test → Fix → Quality Gate), this step is typically redundant:**
-
-- Task 1's `Verify:` (reproducing test must FAIL): already run as RED by `spec-implement`; running it now expecting FAIL is wrong state.
-- Task 2's `Verify:` (reproducing test must PASS): already run in Step 2.2 of this phase.
-- Task 3's `Verify:` (lint, type check, build): already run in Step 3 of this phase.
-
-**Decision:**
-
-1. Read each task's `Verify:` command.
-2. Skip any command that matches what Steps 1, 2, or 3 already ran (full suite, reproducing test, lint, type check, build).
-3. Run only **residual** commands — typically ad-hoc shell checks a human author added (e.g., `uv run python -c "import foo; foo.smoke()"`, a specific endpoint smoke test).
-4. Defer server-dependent commands (containing `curl`, `localhost`, `http://`) to Step 5.
-
-If nothing residual remains: this step is a no-op. Do not re-run covered commands.
diff --git a/pilot/skills/spec-bugfix-verify/steps/06-verification-scenario.md b/pilot/skills/spec-bugfix-verify/steps/04-verification-scenario.md
similarity index 93%
rename from pilot/skills/spec-bugfix-verify/steps/06-verification-scenario.md
rename to pilot/skills/spec-bugfix-verify/steps/04-verification-scenario.md
index 844a0ed4..4afe3a54 100644
--- a/pilot/skills/spec-bugfix-verify/steps/06-verification-scenario.md
+++ b/pilot/skills/spec-bugfix-verify/steps/04-verification-scenario.md
@@ -1,8 +1,8 @@
-## Step 6: Verification Scenario (if exists in plan)
+## Step 4: Verification Scenario (if exists in plan)
Check whether the plan has a `## Verification Scenario` section (only present for UI-facing bugs).
-**If no Verification Scenario:** proceed to Final.
+**If no Verification Scenario:** proceed to Step 5.
**If Verification Scenario exists:**
@@ -23,7 +23,7 @@ agent-browser --session "$AB_SESSION" open
- **playwright-cli:** `open`/`goto`, `snapshot`, `click`/`fill` (bare refs: `e1`)
- **agent-browser:** `open`/`goto`, `snapshot -i`, `click`/`fill` (refs: `@e1`)
2. Verify the expected result for each step (read page after each interaction)
-3. **PASS:** Scenario confirms fix works — close browser (CLI tools only), proceed to Final
+3. **PASS:** Scenario confirms fix works — close browser (CLI tools only), proceed to Step 5
4. **FAIL (attempt 1):** Analyze root cause, implement fix, re-run tests, re-execute scenario
5. **FAIL (attempt 2):** Implement second fix, re-run tests, re-execute scenario
6. **FAIL after 2 attempts:** The bug is not fully fixed — set `Status: PENDING`, increment `Iterations`, invoke `Skill(skill='spec-implement', args='')`. Do not proceed to VERIFIED.
diff --git a/pilot/skills/spec-bugfix-verify/steps/07-final-worktree-sync.md b/pilot/skills/spec-bugfix-verify/steps/05-final-worktree-sync.md
similarity index 91%
rename from pilot/skills/spec-bugfix-verify/steps/07-final-worktree-sync.md
rename to pilot/skills/spec-bugfix-verify/steps/05-final-worktree-sync.md
index 3b91138e..fd5fce61 100644
--- a/pilot/skills/spec-bugfix-verify/steps/07-final-worktree-sync.md
+++ b/pilot/skills/spec-bugfix-verify/steps/05-final-worktree-sync.md
@@ -1,9 +1,9 @@
---
-## Step 7: Worktree Sync (if worktree active)
+## Step 5: Worktree Sync (if worktree active)
1. Detect: `~/.pilot/bin/pilot worktree detect --json `
-2. If no worktree: skip to Step 10.
+2. If no worktree: skip to Step 7.
3. Save plan to project root (only if gitignored):
`git -C check-ignore -q docs/plans/` — if exit 0: `cp /docs/plans/`; if exit 1 (tracked): skip — squash merge brings the updated plan.
5. Show diff: `~/.pilot/bin/pilot worktree diff --json `
diff --git a/pilot/skills/spec-bugfix-verify/steps/05-runtime-verification.md b/pilot/skills/spec-bugfix-verify/steps/05-runtime-verification.md
deleted file mode 100644
index 9cb28cb4..00000000
--- a/pilot/skills/spec-bugfix-verify/steps/05-runtime-verification.md
+++ /dev/null
@@ -1,5 +0,0 @@
-## Step 5: Runtime Verification (only if deferred commands exist)
-
-If no server-dependent commands were deferred: skip to Step 5b.
-
-Otherwise: start service → run deferred commands → stop service → fix failures.
diff --git a/pilot/skills/spec-bugfix-verify/steps/09-check-feedback.md b/pilot/skills/spec-bugfix-verify/steps/06-check-feedback.md
similarity index 87%
rename from pilot/skills/spec-bugfix-verify/steps/09-check-feedback.md
rename to pilot/skills/spec-bugfix-verify/steps/06-check-feedback.md
index 7243e4ef..0ebb5f34 100644
--- a/pilot/skills/spec-bugfix-verify/steps/09-check-feedback.md
+++ b/pilot/skills/spec-bugfix-verify/steps/06-check-feedback.md
@@ -1,4 +1,4 @@
-## Step 9: Check for Code Review Feedback
+## Step 6: Check for Code Review Feedback
**Run BEFORE marking VERIFIED.** Check if the user left code review annotations in the Console's Changes tab. Annotations auto-save — no "Send Feedback" button needed.
@@ -6,5 +6,5 @@ Derive the annotation file path: `docs/plans/.annotations/.json`
Read the annotation file with the Read tool. If the file doesn't exist, treat as `NO_FEEDBACK`. If it exists, check whether `codeReviewAnnotations` has any entries (`FEEDBACK_EXISTS`) or is empty/missing (`NO_FEEDBACK`).
-**If `FEEDBACK_EXISTS`:** Each annotation in `codeReviewAnnotations` has `filePath`, `lineStart`, `text`. Fix all issues, delete the annotation file via `rm -f ""` (e.g. `rm -f "docs/plans/.annotations/2026-03-26-my-bug.json"`), re-run tests, continue to Step 10.
-**If `NO_FEEDBACK`:** continue to Step 10.
+**If `FEEDBACK_EXISTS`:** Each annotation in `codeReviewAnnotations` has `filePath`, `lineStart`, `text`. Fix all issues, delete the annotation file via `rm -f ""` (e.g. `rm -f "docs/plans/.annotations/2026-03-26-my-bug.json"`), re-run tests, continue to Step 7.
+**If `NO_FEEDBACK`:** continue to Step 7.
diff --git a/pilot/skills/spec-bugfix-verify/steps/10-code-review-gate.md b/pilot/skills/spec-bugfix-verify/steps/07-code-review-gate.md
similarity index 87%
rename from pilot/skills/spec-bugfix-verify/steps/10-code-review-gate.md
rename to pilot/skills/spec-bugfix-verify/steps/07-code-review-gate.md
index 07e9a01d..62e56947 100644
--- a/pilot/skills/spec-bugfix-verify/steps/10-code-review-gate.md
+++ b/pilot/skills/spec-bugfix-verify/steps/07-code-review-gate.md
@@ -1,4 +1,4 @@
-## Step 10: Code Review Gate (User Confirmation)
+## Step 7: Code Review Gate (User Confirmation)
**⛔ MANDATORY before marking VERIFIED.**
@@ -19,8 +19,8 @@
```
3. Handle response — **match strictly, never auto-approve ambiguous input:**
- - **Approve:** Response is one of: "Approve", "approve", "lgtm", "looks good", "continue", "proceed" → proceed to Step 11
- - **Fix:** Response matches "Fix" or mentions annotations/console feedback → re-run Step 9 (check for code review annotations in JSON), fix issues, re-run tests, return to Step 10
+ - **Approve:** Response is one of: "Approve", "approve", "lgtm", "looks good", "continue", "proceed" → proceed to Step 8
+ - **Fix:** Response matches "Fix" or mentions annotations/console feedback → re-run Step 6 (check for code review annotations in JSON), fix issues, re-run tests, return to Step 7
- **Manual / custom text:** Response matches "Manual" OR is ANY other free-text/custom input → the user wants to pause. **Do NOT mark VERIFIED. Do NOT change plan status.** Use `AskUserQuestion` again (required so the stop guard allows the user to exit while waiting):
```
AskUserQuestion(
@@ -30,6 +30,6 @@
```
Then **stop and wait** for the user's next message.
- **⛔ After Manual wait — re-evaluation of follow-up:** When the user responds after a Manual pause:
- - Explicit approval ("approve", "lgtm", "looks good") → proceed to Step 11
- - **Any other content** (error descriptions, screenshots, images, bug reports, or ANY non-approval text) → treat as **bug reports to fix**. Investigate the reported issues, implement fixes, re-run tests, then return to Step 10 (ask again).
- - **⛔ NEVER treat ambiguous or custom responses as approval.** Only the explicit keywords listed under "Approve" advance to Step 11.
+ - Explicit approval ("approve", "lgtm", "looks good") → proceed to Step 8
+ - **Any other content** (error descriptions, screenshots, images, bug reports, or ANY non-approval text) → treat as **bug reports to fix**. Investigate the reported issues, implement fixes, re-run tests, then return to Step 7 (ask again).
+ - **⛔ NEVER treat ambiguous or custom responses as approval.** Only the explicit keywords listed under "Approve" advance to Step 8.
diff --git a/pilot/skills/spec-bugfix-verify/steps/08-post-merge-verify.md b/pilot/skills/spec-bugfix-verify/steps/08-post-merge-verify.md
deleted file mode 100644
index 76103a10..00000000
--- a/pilot/skills/spec-bugfix-verify/steps/08-post-merge-verify.md
+++ /dev/null
@@ -1,3 +0,0 @@
-## Step 8: Post-Merge Verification (after squash merge only)
-
-Full test suite + type checker + build. If any fails: fix on base branch, re-run.
diff --git a/pilot/skills/spec-bugfix-verify/steps/08-update-status.md b/pilot/skills/spec-bugfix-verify/steps/08-update-status.md
new file mode 100644
index 00000000..cf1f58f7
--- /dev/null
+++ b/pilot/skills/spec-bugfix-verify/steps/08-update-status.md
@@ -0,0 +1,35 @@
+## Step 8: Update Plan Status
+
+**All passes and user approves:** Set `Status: VERIFIED`, register:
+```bash
+~/.pilot/bin/pilot register-plan "" "VERIFIED" 2>/dev/null || true
+```
+Report:
+```
+Bugfix verified — regression test passes, full suite green.
+Run /clear before starting new work — this resets context while keeping project rules loaded.
+```
+
+**Fails:**
+
+⛔ **Iteration cap.** Read `Iterations:` from the plan header. If `Iterations >= 3` BEFORE incrementing, stop the fix-on-fix loop:
+
+```
+AskUserQuestion(
+ question="Three fix iterations have failed verification. This pattern usually means the bug is architectural — fixing symptoms in different places, each fix revealing a new failure mode. What now?",
+ options=[
+ "Continue — try one more fix (rarely the right answer)",
+ "Pivot — let me re-investigate root cause with you",
+ "Abandon — leave PENDING, I'll come back to it"
+ ]
+)
+```
+
+Handle:
+- **Continue:** increment `Iterations`, invoke `Skill(skill='spec-implement', args='')` as below.
+- **Pivot:** set `Status: PENDING`, do NOT invoke spec-implement. Tell the user you're standing by for new investigation direction.
+- **Abandon:** leave `Status: PENDING`, do not invoke spec-implement. Stop.
+
+**When `Iterations < 3`:** Add fix tasks, set `Status: PENDING`, increment `Iterations`, invoke `Skill(skill='spec-implement', args='')`.
+
+ARGUMENTS: $ARGUMENTS
diff --git a/pilot/skills/spec-bugfix-verify/steps/11-update-status.md b/pilot/skills/spec-bugfix-verify/steps/11-update-status.md
deleted file mode 100644
index 15af3db7..00000000
--- a/pilot/skills/spec-bugfix-verify/steps/11-update-status.md
+++ /dev/null
@@ -1,15 +0,0 @@
-## Step 11: Update Plan Status
-
-**All passes and user approves:** Set `Status: VERIFIED`, register:
-```bash
-~/.pilot/bin/pilot register-plan "" "VERIFIED" 2>/dev/null || true
-```
-Report:
-```
-Bugfix verified — regression test passes, full suite green.
-Run /clear before starting new work — this resets context while keeping project rules loaded.
-```
-
-**Fails:** Add fix tasks, set `Status: PENDING`, increment `Iterations`, invoke `Skill(skill='spec-implement', args='')`.
-
-ARGUMENTS: $ARGUMENTS
diff --git a/pilot/skills/spec-implement/steps/04-tdd-loop.md b/pilot/skills/spec-implement/steps/04-tdd-loop.md
index ae3cffcd..a4e75700 100644
--- a/pilot/skills/spec-implement/steps/04-tdd-loop.md
+++ b/pilot/skills/spec-implement/steps/04-tdd-loop.md
@@ -50,16 +50,14 @@ Minimal flow. No production code here, so most generic steps (call-chain analysi
#### Task 2 — Implement Fix at Root Cause (GREEN)
-This is the only task that modifies production code. Full TDD discipline applies.
+This is the only task that modifies production code.
1. Call-chain analysis: use plan's Investigation if it covers the function; otherwise run `codegraph_callers` + `codegraph_callees` on the root-cause function only.
2. Make the minimal change at `Root Cause: file:line`. Fix at the source, not at the symptom.
3. Forbidden: new broad `try/except` around the failing call, `if value is None: return default` at the caller when the bug is upstream, swallowed exceptions, silently normalised bad inputs. Legitimate defense-in-depth requires an explicit entry in the plan's `Defense-in-depth:` field.
-4. Re-run the reproducing test → **must PASS**.
-5. Run the full test suite → zero failures. This is the anti-regression check for this task.
-6. Diagnostics zero errors. Performance audit on the diff.
-7. Re-read the plan's `## Behavior Contract` and confirm: (a) reproducing test passes, (b) `Anti-regression` behavior still works, (c) diff touches the root-cause file. If any is false, return to step 2 — do not rationalize forward.
-8. Worktree mode: commit (`fix(spec): `). Update plan, mark task completed.
+4. Re-run the reproducing test → **must PASS**. Then run the test module(s) covering the root-cause file — fast, scoped (e.g. `pytest path/to/test_module.py -q`). The full anti-regression suite runs at the Quality Gate task, not here. Running the full suite per-fix-task is the single biggest token sink in bundled bugfix plans.
+5. Diagnostics zero errors. Confirm the diff touches the root-cause file from the plan.
+6. Worktree mode: commit (`fix(spec): `). Update plan, mark task completed.
#### Task 3 — Quality Gate
diff --git a/pilot/skills/spec-plan/steps/11-plan-verification.md b/pilot/skills/spec-plan/steps/11-plan-verification.md
index afe7fd05..ebbb5487 100644
--- a/pilot/skills/spec-plan/steps/11-plan-verification.md
+++ b/pilot/skills/spec-plan/steps/11-plan-verification.md
@@ -43,6 +43,17 @@ Task(
Launch Codex review NOW — it runs in parallel with the Claude reviewer above.
+**⛔ Codex-once rule.** Codex runs at most once per `/spec` invocation. Before launching, check the sentinel file. If it exists, the review already ran in this session — skip the launch and the collection sub-step below. Plan iterations (annotation feedback, plan edits, fixing prior findings) do NOT trigger another Codex run.
+
+```bash
+SESS_ID="${PILOT_SESSION_ID:-default}"
+CODEX_FLAG="$HOME/.pilot/sessions/$SESS_ID/codex-ran-.flag"
+if [ -f "$CODEX_FLAG" ]; then
+ echo "Codex already reviewed this plan in this session — skipping (codex-once)."
+ # Skip the launch and the Codex collection sub-step. Continue with Claude reviewer results only.
+fi
+```
+
1. Detect companion path, project root, and base branch:
```bash
CODEX_COMPANION=$(ls ~/.claude/plugins/cache/openai-codex/codex/*/scripts/codex-companion.mjs 2>/dev/null | sort -V | tail -1)
@@ -79,7 +90,15 @@ Then Read the file once. If not READY after 5 min, re-launch synchronously.
**⛔ The completion notification is the ONLY valid signal.** Do NOT read the output file to check if the review is done. The file may contain partial output from an in-progress review — reading it before the notification arrives leads to false conclusions ("no findings" when the review is still running). This is the #1 cause of premature Codex skip.
-**⛔ If the notification hasn't arrived yet:** STOP. Do NOT proceed to Step 12 or approval. Do NOT read the output file. Do NOT conclude the review failed. Wait for the `` with `completed `. If you are tempted to check the file — that is the exact mistake this rule prevents.
+**⛔ If the notification hasn't arrived yet:** Do NOT proceed to Step 12 or approval. Do NOT read the output file. Do NOT conclude the review failed. Wait for the `` with `completed `. If you are tempted to check the file — that is the exact mistake this rule prevents.
+
+**⛔ "Wait" does NOT mean "end your turn."** Ending the conversation turn lets the user think the workflow is finished and triggers a stop hook that pulls you out. Do not output a closing text message ("Waiting for codex…", "Holding for completion…"), do not call `ScheduleWakeup` as a substitute for staying engaged. Stay in-turn until the `` arrives. While waiting, do something productive in the same turn:
+- Re-read the plan file once and pre-emptively spot any gaps you would fix anyway.
+- If the user has queued a related request (e.g. a second bug to bundle), investigate / draft plan text for it now so you are ready to act when Codex completes.
+- Run sanity-check Bash one-liners that don't fork long-running processes (path checks, file existence, small `git log` queries).
+- As an absolute last resort with no other useful work, call `AskUserQuestion` to ask a short clarifying question — `AskUserQuestion` is the only tool whitelisted for a legitimate session-pause while a background task is in flight.
+
+The completion notification arrives automatically as a mid-turn tool-result-style event; you do not need to poll for it.
1. **When (and ONLY when) the completion notification arrives**, read the background bash output. **Filter out `[codex]` prefixed log lines** — use `ctx_execute_file` to extract only non-`[codex]` lines. Search for `# Codex Adversarial Review` section via `ctx_search`.
@@ -87,4 +106,9 @@ Then Read the file once. If not READY after 5 min, re-launch synchronously.
3. **If the background bash timed out or failed** (exit code non-zero in the notification): Re-launch synchronously and wait. Only skip if the second attempt also fails.
+4. **Mark Codex as ran** so re-iterations of this plan within the same session do not re-run it:
+```bash
+mkdir -p "$(dirname "$CODEX_FLAG")" && touch "$CODEX_FLAG"
+```
+
**If Codex was NOT launched**, proceed after all Claude reviewer must_fix/should_fix resolved.
diff --git a/pilot/skills/spec-verify/steps/04-launch-review.md b/pilot/skills/spec-verify/steps/04-launch-review.md
index 5b33cf87..7c7f407f 100644
--- a/pilot/skills/spec-verify/steps/04-launch-review.md
+++ b/pilot/skills/spec-verify/steps/04-launch-review.md
@@ -55,6 +55,17 @@ Task(
Launch Codex review NOW — it runs in parallel with the Claude reviewer above.
+**⛔ Codex-once rule.** Codex runs at most once per `/spec` invocation. Before launching, check the sentinel file. If it exists, the review already ran in this session — skip the launch and the collection sub-step in Step 7. Verify-phase iterations (re-verify after fixing findings, code-review-gate annotation fixes) do NOT trigger another Codex run.
+
+```bash
+SESS_ID="${PILOT_SESSION_ID:-default}"
+CODEX_FLAG="$HOME/.pilot/sessions/$SESS_ID/codex-ran-.flag"
+if [ -f "$CODEX_FLAG" ]; then
+ echo "Codex already reviewed this plan in this session — skipping (codex-once)."
+ # Skip the launch below and the Codex collection sub-step in Step 7.
+fi
+```
+
1. Detect companion path and ensure project root:
```bash
CODEX_COMPANION=$(ls ~/.claude/plugins/cache/openai-codex/codex/*/scripts/codex-companion.mjs 2>/dev/null | sort -V | tail -1)
diff --git a/pilot/skills/spec-verify/steps/07-collect-results.md b/pilot/skills/spec-verify/steps/07-collect-results.md
index 91b44531..10ed2f1a 100644
--- a/pilot/skills/spec-verify/steps/07-collect-results.md
+++ b/pilot/skills/spec-verify/steps/07-collect-results.md
@@ -41,6 +41,13 @@ For each fix: implement → run relevant tests → log "Fixed: [title]"
3. **If the background bash timed out or failed** (exit code non-zero in the notification): Re-launch synchronously (not in background) and wait for results. Only skip if the second attempt also fails.
+4. **Mark Codex as ran** so re-verify iterations within the same session do not re-run it:
+```bash
+SESS_ID="${PILOT_SESSION_ID:-default}"
+CODEX_FLAG="$HOME/.pilot/sessions/$SESS_ID/codex-ran-.flag"
+mkdir -p "$(dirname "$CODEX_FLAG")" && touch "$CODEX_FLAG"
+```
+
**Report:**
```
## Code Verification Complete
diff --git a/pilot/skills/spec/orchestrator.md b/pilot/skills/spec/orchestrator.md
index 8b670003..336f8427 100644
--- a/pilot/skills/spec/orchestrator.md
+++ b/pilot/skills/spec/orchestrator.md
@@ -19,10 +19,12 @@ model: sonnet
## Workflow
```
-/spec → Detect type → Feature: Skill('spec-plan') → Plan → Implement → Verify
+/spec → Detect type → Feature: Skill('spec-plan') → Plan → Implement → Verify
→ Bugfix: Skill('spec-bugfix-plan') → Investigate → Plan → Implement → Verify
```
+For a bugfix workflow without a plan file, users invoke `/fix` directly — that's a separate command. `/spec` always runs the full spec workflow.
+
| Phase | Skill | Model |
|-------|-------|-------|
| Feature Planning | `spec-plan` | Opus |
@@ -30,5 +32,6 @@ model: sonnet
| Implementation | `spec-implement` | Sonnet |
| Feature Verification | `spec-verify` | Sonnet |
| Bugfix Verification | `spec-bugfix-verify` | Sonnet |
+| Bugfix (separate command, `/fix`) | `fix` | Opus |
> **Note:** Implementation and verification default to **Sonnet** for most tiers (Pro, Team, Enterprise, API) where Sonnet 1M is included. **Max plan** users default to **Opus** since Sonnet 1M is not available on Max. Users can override via Console Settings.
diff --git a/pilot/skills/spec/steps/01-parse-route.md b/pilot/skills/spec/steps/01-parse-route.md
index 3214ceb3..e0497ecb 100644
--- a/pilot/skills/spec/steps/01-parse-route.md
+++ b/pilot/skills/spec/steps/01-parse-route.md
@@ -59,3 +59,5 @@ When `WORKTREE` is not `"false"` (3 options):
- **Bugfix:** `Skill(skill='spec-bugfix-plan', args=' --worktree=yes|no|--new-branch')`
- **Feature:** `Skill(skill='spec-plan', args=' --worktree=yes|no|--new-branch')`
+
+**Note:** Users who want a bugfix workflow without a plan file invoke `/fix` directly — that's a separate user-facing command. The `/spec` dispatcher does not route to `/fix`. When a user types `/spec`, they want the full spec workflow.
diff --git a/pilot/ui/PlanAnnotator.js b/pilot/ui/PlanAnnotator.js
index 4aa00dee..04d9a7d0 100644
--- a/pilot/ui/PlanAnnotator.js
+++ b/pilot/ui/PlanAnnotator.js
@@ -1 +1,7 @@
-import{a as l,j as e}from"./vendor-markdown.js";import{p as z,u as E,B as $,c as F}from"./useAnnotation.js";import"./vendor-charts.js";import{I as c}from"./viewer-bundle.js";import"./vendor-diff.js";function U({annotation:s,index:r,isSelected:i,isEditing:k,onSelect:N,onRemove:j,onUpdate:u,onStartEdit:x,onStopEdit:p}){const[n,m]=l.useState(s.text??"");return k?e.jsxs("div",{className:"p-2.5 rounded-lg border bg-base-200 border-base-300 space-y-2",children:[s.originalText&&e.jsxs("p",{className:"text-[11px] text-base-content/50 italic break-words",children:["“",s.originalText.slice(0,80),s.originalText.length>80?"…":"","”"]}),e.jsx("textarea",{value:n,onChange:d=>m(d.target.value),rows:2,autoFocus:!0,className:"textarea textarea-bordered textarea-xs w-full text-xs resize-none",placeholder:"Annotation…"}),e.jsxs("div",{className:"flex gap-1 items-center",children:[e.jsx("button",{className:"btn btn-ghost btn-xs text-error",onClick:j,title:"Delete annotation",children:e.jsx(c,{icon:"lucide:trash-2",size:11})}),e.jsxs("div",{className:"flex gap-1 ml-auto",children:[e.jsx("button",{className:"btn btn-ghost btn-xs",onClick:p,children:"Cancel"}),e.jsx("button",{className:"btn btn-neutral btn-xs",disabled:n===(s.text??""),onClick:()=>{u({text:n}),p()},children:"Save"})]})]})]}):e.jsxs("div",{className:`flex items-start gap-2 p-2 rounded-lg cursor-pointer group transition-colors border border-transparent ${i?"bg-base-300 border-base-content/10":"hover:bg-base-200/60"}`,onClick:()=>N(),children:[e.jsx("span",{className:`inline-flex items-center justify-center text-[10px] font-bold rounded-full w-4 h-4 flex-shrink-0 mt-0.5 ${i?"bg-primary text-primary-content":"bg-primary/20 text-primary"}`,children:r}),e.jsxs("div",{className:"flex-1 min-w-0",children:[s.originalText&&e.jsxs("p",{className:"text-[11px] text-base-content/50 italic break-words mb-0.5",children:["“",s.originalText.slice(0,50),s.originalText.length>50?"…":"","”"]}),e.jsxs("p",{className:"text-xs text-base-content/80 break-words",children:[s.text.slice(0,100),s.text.length>100?"…":""]})]}),e.jsxs("div",{className:"flex gap-0.5 flex-shrink-0 opacity-0 group-hover:opacity-100 transition-opacity",children:[e.jsx("button",{className:"btn btn-ghost btn-xs",onClick:d=>{d.stopPropagation(),x()},title:"Edit annotation",children:e.jsx(c,{icon:"lucide:pencil",size:11})}),e.jsx("button",{className:"btn btn-ghost btn-xs text-error",onClick:d=>{d.stopPropagation(),j()},title:"Delete annotation",children:e.jsx(c,{icon:"lucide:x",size:11})})]})]})}function D({annotations:s,selectedAnnotationId:r,onSelectAnnotation:i,onRemoveAnnotation:k,onUpdateAnnotation:N,onClearAll:j,onAcceptFeedback:u,onRejectFeedback:x,onAcceptAllFeedback:p,onRejectAllFeedback:n,onShare:m,onReceiveFeedback:d}){const[A,f]=l.useState(null),h=s.filter(t=>t.feedbackStatus==="pending"),g=s.filter(t=>!t.feedbackStatus||t.feedbackStatus==="accepted");return e.jsxs("div",{className:"flex flex-col h-full border-l-2 border-base-300 bg-base-200/50",children:[e.jsxs("div",{className:"flex items-center gap-2 px-3 py-2.5 border-b border-base-300 flex-shrink-0",children:[e.jsx(c,{icon:"lucide:pencil-line",size:14,className:"text-primary"}),e.jsx("span",{className:"text-sm font-semibold flex-1",children:"Annotations"}),(g.length>0||h.length>0)&&e.jsx("span",{className:"badge badge-primary badge-sm",children:g.length+h.length}),s.length>0&&e.jsx("button",{className:"btn btn-ghost btn-xs text-base-content/50",onClick:j,title:"Clear all annotations",children:e.jsx(c,{icon:"lucide:trash-2",size:12})})]}),(m||d)&&e.jsxs("div",{className:"flex gap-1 px-3 py-1.5 border-b border-base-300 flex-shrink-0",children:[m&&e.jsxs("button",{className:"btn btn-ghost btn-xs gap-1 flex-1",onClick:m,title:"Share spec with a teammate",children:[e.jsx(c,{icon:"lucide:send",size:11}),e.jsx("span",{className:"text-[10px]",children:"Share"})]}),d&&e.jsxs("button",{className:"btn btn-ghost btn-xs gap-1 flex-1",onClick:d,title:"Receive feedback from a colleague",children:[e.jsx(c,{icon:"lucide:inbox",size:11}),e.jsx("span",{className:"text-[10px]",children:"Receive"})]})]}),e.jsxs("div",{className:"flex-1 overflow-y-auto p-2 space-y-1",children:[h.length>0&&e.jsxs("div",{className:"mb-3",children:[e.jsxs("div",{className:"flex items-center justify-between px-1 mb-1",children:[e.jsxs("span",{className:"text-[11px] font-semibold text-info flex items-center gap-1",children:[e.jsx(c,{icon:"lucide:message-square-plus",size:11}),"External Feedback (",h.length,")"]}),e.jsxs("div",{className:"flex gap-1",children:[p&&e.jsx("button",{className:"btn btn-ghost btn-xs text-success text-[10px]",onClick:p,title:"Accept all feedback",children:"Accept All"}),n&&e.jsx("button",{className:"btn btn-ghost btn-xs text-error text-[10px]",onClick:n,title:"Reject all feedback",children:"Reject All"})]})]}),h.map(t=>e.jsxs("div",{className:"p-2 rounded-lg border border-info/20 bg-info/5 space-y-1.5 mb-1 cursor-pointer hover:border-info/40 transition-colors",onClick:()=>i(t.id),children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("span",{className:"text-[10px] font-medium text-info/80 flex items-center gap-1",children:[e.jsx(c,{icon:"lucide:user",size:10}),t.author??"Anonymous"]}),e.jsxs("div",{className:"flex gap-1",children:[u&&e.jsx("button",{className:"btn btn-ghost btn-xs text-success py-0 h-5 min-h-0",onClick:()=>u(t.id),title:"Accept this annotation",children:e.jsx(c,{icon:"lucide:check",size:11})}),x&&e.jsx("button",{className:"btn btn-ghost btn-xs text-error py-0 h-5 min-h-0",onClick:()=>x(t.id),title:"Reject this annotation",children:e.jsx(c,{icon:"lucide:x",size:11})})]})]}),t.originalText&&e.jsxs("p",{className:"text-[10px] text-base-content/50 italic break-words",children:["“",t.originalText.slice(0,60),t.originalText.length>60?"…":"","”"]}),e.jsx("p",{className:"text-xs text-base-content/80 break-words",children:t.text})]},t.id)),e.jsx("hr",{className:"border-base-300/50 mt-2"})]}),g.length===0&&h.length===0?e.jsxs("div",{className:"flex flex-col items-center justify-center py-8 text-center px-3",children:[e.jsx(c,{icon:"lucide:message-square-plus",size:28,className:"text-base-content/15 mb-3"}),e.jsx("p",{className:"text-xs text-base-content/40 font-medium mb-1",children:"No annotations yet"}),e.jsx("p",{className:"text-[10px] text-base-content/30 leading-relaxed",children:"Hover over a block and click the + button to add a note. The agent reads your annotations at review checkpoints."})]}):g.map((t,y)=>e.jsx(U,{annotation:t,index:y+1,isSelected:r===t.id,isEditing:A===t.id,onSelect:()=>i(t.id),onRemove:()=>{f(null),k(t.id)},onUpdate:w=>N(t.id,w),onStartEdit:()=>f(t.id),onStopEdit:()=>f(null)},t.id))]})]})}function J({planContent:s,planPath:r,projectParam:i,onShare:k,onReceiveFeedback:N,reloadKey:j}){const u=l.useRef(null),x=l.useRef(null),p=l.useMemo(()=>z(s),[s]),{state:n,addAnnotation:m,removeAnnotation:d,updateAnnotation:A,clearAll:f,selectAnnotation:h,setAnnotations:g,acceptFeedback:t,rejectFeedback:y,acceptAllFeedback:w,rejectAllFeedback:I}=E(u);l.useEffect(()=>{(async()=>{try{const a=await fetch(`/api/annotations?path=${encodeURIComponent(r)}${i}`);if(a.ok){const b=await a.json();Array.isArray(b.planAnnotations)&&b.planAnnotations.length>0&&g(b.planAnnotations)}}catch{}})()},[r,i,g,j]);const C=l.useRef(0),T=l.useRef(n.annotations.length);l.useEffect(()=>{const o=T.current,a=n.annotations.length;a!==o&&a>0&&(C.current=Date.now()),T.current=a},[n.annotations.length]),l.useEffect(()=>{if(n.annotations.length!==0)return x.current&&clearTimeout(x.current),x.current=setTimeout(async()=>{try{const o=await fetch(`/api/annotations/plan?path=${encodeURIComponent(r)}${i}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({annotations:n.annotations})});if(!o.ok){const a=await o.text().catch(()=>"");console.error(`[PlanAnnotator] Auto-save failed with HTTP ${o.status}: ${a||o.statusText}`,{planPath:r,projectParam:i})}}catch(o){console.error("[PlanAnnotator] Auto-save network error:",o)}},1e3),()=>{x.current&&clearTimeout(x.current)}},[n.annotations,r,i]),l.useEffect(()=>{const o=setInterval(async()=>{if(n.annotations.length!==0&&!(Date.now()-C.current<3e3))try{const a=await fetch(`/api/annotations?path=${encodeURIComponent(r)}${i}`);a.ok&&((await a.json()).planAnnotations??[]).length===0&&f()}catch{}},5e3);return()=>clearInterval(o)},[r,i,n.annotations.length,f]);const R=l.useCallback(o=>{var v;h(o);const a=n.annotations.find(S=>S.id===o);if(!a||!a.originalText)return;const b=(v=u.current)==null?void 0:v.querySelector(`[data-block-id="${a.blockId}"]`);b==null||b.scrollIntoView({behavior:"smooth",block:"center"})},[n.annotations,h]);return e.jsxs("div",{style:{display:"flex",width:"100%",height:"100%",minHeight:0},children:[e.jsx("div",{style:{flex:1,minWidth:0,overflowY:"auto",padding:"1rem"},children:e.jsx("div",{ref:u,children:e.jsx($,{blocks:p,annotations:n.annotations,selectedAnnotationId:n.selectedAnnotationId,onSelectAnnotation:R,onQuickAnnotate:(o,a,b)=>{const v=F(o,a,b);m(v)}})})}),e.jsx("div",{style:{width:256,flexShrink:0,height:"100%"},children:e.jsx(D,{annotations:n.annotations,selectedAnnotationId:n.selectedAnnotationId,onSelectAnnotation:R,onRemoveAnnotation:d,onUpdateAnnotation:A,onClearAll:f,onAcceptFeedback:t,onRejectFeedback:y,onAcceptAllFeedback:w,onRejectAllFeedback:I,onShare:k,onReceiveFeedback:N})})]})}export{J as PlanAnnotator};
+import{j as e,a as c,M,b as U}from"./vendor-markdown.js";import"./vendor-charts.js";import{I as T}from"./viewer-bundle.js";let K=0;function W(){return`block-${K++}`}function q(n){var m;K=0;const o=[],s=n.split(`
+`);let a=0,b=0;const g=(x,l,A,t)=>{!l&&x!=="hr"||o.push({id:W(),type:x,content:l,order:b++,startLine:A,...t})};let i=[],d=1;const h=()=>{i.length>0&&(g("paragraph",i.join(`
+`),d),i=[])};for(;a")){h();const t=l.replace(/^>\s*/,"");g("blockquote",t,A),a++;continue}if(l.match(/^(\*|-|\d+\.)\s/)){h();const u=(((m=x.match(/^(\s*)/))==null?void 0:m[1])??"").replace(/\t/g," ").length,k=Math.floor(u/2);let r=l.replace(/^(\*|-|\d+\.)\s/,""),w;const j=r.match(/^\[([ xX])\]\s*/);j&&(w=j[1].toLowerCase()==="x",r=r.replace(/^\[([ xX])\]\s*/,"")),g("list-item",r,A,{level:k,checked:w}),a++;continue}if(l.startsWith("|")){h();const t=[x],u=A;for(a++;a ${n.content}`;case"list-item":{const o=n.level?" ".repeat(n.level):"",s=n.checked===!0?"[x] ":n.checked===!1?"[ ] ":"";return`${o}- ${s}${n.content}`}case"table":return n.content;case"hr":return"---";default:return n.content}}const G=function({block:o,blockAnnotations:s,allAnnotations:a,selectedAnnotationId:b,onSelectAnnotation:g,onQuickAnnotate:i}){const d=J(o),[h,m]=c.useState(!1),[x,l]=c.useState(""),A=()=>{x.trim()&&i&&i(o.id,o.content.slice(0,80),x.trim()),l(""),m(!1)};return e.jsxs("div",{"data-block-id":o.id,"data-block-type":o.type,className:"annotation-block group/block relative",style:{overflowWrap:"break-word",wordBreak:"break-word",maxWidth:"100%"},children:[i&&!h&&e.jsx("button",{className:"absolute -left-7 top-0.5 w-5 h-5 rounded-full bg-primary/10 text-primary flex items-center justify-center opacity-0 group-hover/block:opacity-100 transition-opacity hover:bg-primary/20 z-10",title:"Add annotation to this block",onClick:t=>{t.stopPropagation(),m(!0)},children:e.jsx("span",{className:"text-sm font-bold leading-none",children:"+"})}),h&&e.jsxs("div",{className:"mb-2 p-2 rounded-lg border border-primary/30 bg-base-200 space-y-1.5",children:[e.jsxs("p",{className:"text-[10px] text-base-content/50 italic truncate",children:["Block: “",o.content.slice(0,60),o.content.length>60?"…":"","”"]}),e.jsx("textarea",{autoFocus:!0,rows:2,value:x,onChange:t=>l(t.target.value),onKeyDown:t=>{t.key==="Enter"&&!t.shiftKey&&(t.preventDefault(),A()),t.key==="Escape"&&(m(!1),l(""))},className:"textarea textarea-bordered textarea-xs w-full text-xs resize-none",placeholder:"Your annotation… (Enter to save, Esc to cancel)"}),e.jsxs("div",{className:"flex gap-1 justify-end",children:[e.jsx("button",{className:"btn btn-ghost btn-xs",onClick:()=>{m(!1),l("")},children:"Cancel"}),e.jsx("button",{className:"btn btn-primary btn-xs",disabled:!x.trim(),onClick:A,children:"Save"})]})]}),e.jsx(M,{remarkPlugins:[U],components:{h1:({children:t})=>e.jsx("h1",{className:"text-xl font-semibold mt-6 mb-3 scroll-mt-4",children:t}),h2:({children:t})=>e.jsx("h2",{className:"text-lg font-semibold mt-6 mb-3 pb-2 border-b border-base-300/50 scroll-mt-4",children:t}),h3:({children:t})=>e.jsx("h3",{className:"text-base font-semibold mt-4 mb-2 scroll-mt-4",children:t}),h4:({children:t})=>e.jsx("h4",{className:"text-sm font-medium mt-3 mb-1",children:t}),h5:({children:t})=>e.jsx("h5",{className:"text-sm font-medium mt-3 mb-1",children:t}),h6:({children:t})=>e.jsx("h6",{className:"text-sm font-medium mt-3 mb-1",children:t}),p:({children:t})=>e.jsx("p",{className:"text-sm text-base-content/80 mb-3 leading-relaxed",style:{overflowWrap:"break-word"},children:t}),ul:({children:t})=>e.jsx("ul",{className:"text-sm space-y-1.5 mb-4 ml-1",children:t}),ol:({children:t})=>e.jsx("ol",{className:"text-sm space-y-1.5 mb-4 ml-1 list-decimal list-inside",children:t}),li:({children:t})=>e.jsxs("li",{className:"text-base-content/80 flex items-start gap-2",children:[e.jsx("span",{className:"text-primary mt-0.5 text-xs select-none",children:"▸"}),e.jsx("span",{className:"flex-1",children:t})]}),blockquote:({children:t})=>e.jsx("blockquote",{className:"border-l-4 border-primary/50 pl-4 py-1 my-3 text-sm text-base-content/70 italic",children:t}),code:({className:t,children:u})=>t?e.jsx("code",{className:"block bg-base-300 p-3 rounded-lg text-xs font-mono overflow-x-auto mb-4 border border-base-content/10",children:u}):e.jsx("code",{className:"bg-base-300 text-primary px-1.5 py-0.5 rounded text-xs font-mono",children:u}),pre:({children:t})=>e.jsx("pre",{className:"bg-base-300 p-3 rounded-lg text-xs font-mono mb-4 border border-base-content/10",style:{whiteSpace:"pre-wrap",overflowWrap:"break-word"},children:t}),strong:({children:t})=>e.jsx("strong",{className:"font-semibold text-base-content",children:t}),table:({children:t})=>e.jsx("div",{className:"overflow-x-auto mb-4",children:e.jsx("table",{className:"table table-sm w-full",children:t})}),thead:({children:t})=>e.jsx("thead",{className:"bg-base-200",children:t}),th:({children:t})=>e.jsx("th",{className:"text-left text-xs font-medium text-base-content/70 p-2",children:t}),td:({children:t})=>e.jsx("td",{className:"text-sm p-2 border-t border-base-300/50",children:t}),hr:()=>e.jsx("hr",{className:"my-6 border-base-300"}),input:({checked:t,...u})=>e.jsx("input",{...u,checked:t,readOnly:!0,className:"mt-0.5 checkbox checkbox-xs checkbox-primary"})},children:d}),s.length>0&&e.jsx("div",{className:"flex flex-wrap gap-1.5 mb-3 -mt-1",children:s.map(t=>{const u=a.findIndex(r=>r.id===t.id)+1,k=t.id===b;return e.jsxs("button",{className:`inline-flex items-center gap-1.5 text-[11px] px-2 py-0.5 rounded-full cursor-pointer transition-colors ${k?"bg-primary text-primary-content font-bold":"bg-info/15 text-info-content border border-info/30 hover:bg-info/25"}`,title:t.text,onClick:r=>{r.stopPropagation(),g==null||g(t.id)},children:[e.jsx("span",{className:`inline-flex items-center justify-center text-[9px] font-bold rounded-full w-4 h-4 ${k?"bg-primary-content/20":"bg-info/30"}`,children:u}),e.jsxs("span",{className:"truncate max-w-48",children:["“",t.originalText.slice(0,40),t.originalText.length>40?"…":"","”"]})]},t.id)})})]})};function H({blocks:n,annotations:o,selectedAnnotationId:s,onBlockMouseUp:a,onSelectAnnotation:b,onQuickAnnotate:g}){const i=o.filter(d=>d.feedbackStatus!=="rejected");return e.jsx("div",{className:"annotation-content select-text spec-markdown pl-8",style:{overflowWrap:"break-word",wordBreak:"break-word"},onMouseUp:a,children:n.map(d=>e.jsx(G,{block:d,blockAnnotations:i.filter(h=>h.blockId===d.id),allAnnotations:i,selectedAnnotationId:s,onSelectAnnotation:b,onQuickAnnotate:g},d.id))})}function V({annotation:n,index:o,isSelected:s,isEditing:a,onSelect:b,onRemove:g,onUpdate:i,onStartEdit:d,onStopEdit:h}){const[m,x]=c.useState(n.text??"");return a?e.jsxs("div",{className:"p-2.5 rounded-lg border bg-base-200 border-base-300 space-y-2",children:[n.originalText&&e.jsxs("p",{className:"text-[11px] text-base-content/50 italic break-words",children:["“",n.originalText.slice(0,80),n.originalText.length>80?"…":"","”"]}),e.jsx("textarea",{value:m,onChange:l=>x(l.target.value),rows:2,autoFocus:!0,className:"textarea textarea-bordered textarea-xs w-full text-xs resize-none",placeholder:"Annotation…"}),e.jsxs("div",{className:"flex gap-1 items-center",children:[e.jsx("button",{className:"btn btn-ghost btn-xs text-error",onClick:g,title:"Delete annotation",children:e.jsx(T,{icon:"lucide:trash-2",size:11})}),e.jsxs("div",{className:"flex gap-1 ml-auto",children:[e.jsx("button",{className:"btn btn-ghost btn-xs",onClick:h,children:"Cancel"}),e.jsx("button",{className:"btn btn-neutral btn-xs",disabled:m===(n.text??""),onClick:()=>{i({text:m}),h()},children:"Save"})]})]})]}):e.jsxs("div",{className:`flex items-start gap-2 p-2 rounded-lg cursor-pointer group transition-colors border border-transparent ${s?"bg-base-300 border-base-content/10":"hover:bg-base-200/60"}`,onClick:()=>b(),children:[e.jsx("span",{className:`inline-flex items-center justify-center text-[10px] font-bold rounded-full w-4 h-4 flex-shrink-0 mt-0.5 ${s?"bg-primary text-primary-content":"bg-primary/20 text-primary"}`,children:o}),e.jsxs("div",{className:"flex-1 min-w-0",children:[n.originalText&&e.jsxs("p",{className:"text-[11px] text-base-content/50 italic break-words mb-0.5",children:["“",n.originalText.slice(0,50),n.originalText.length>50?"…":"","”"]}),e.jsxs("p",{className:"text-xs text-base-content/80 break-words",children:[n.text.slice(0,100),n.text.length>100?"…":""]})]}),e.jsxs("div",{className:"flex gap-0.5 flex-shrink-0 opacity-0 group-hover:opacity-100 transition-opacity",children:[e.jsx("button",{className:"btn btn-ghost btn-xs",onClick:l=>{l.stopPropagation(),d()},title:"Edit annotation",children:e.jsx(T,{icon:"lucide:pencil",size:11})}),e.jsx("button",{className:"btn btn-ghost btn-xs text-error",onClick:l=>{l.stopPropagation(),g()},title:"Delete annotation",children:e.jsx(T,{icon:"lucide:x",size:11})})]})]})}function Q({annotations:n,selectedAnnotationId:o,onSelectAnnotation:s,onRemoveAnnotation:a,onUpdateAnnotation:b,onClearAll:g,onAcceptFeedback:i,onRejectFeedback:d,onAcceptAllFeedback:h,onRejectAllFeedback:m,onShare:x,onReceiveFeedback:l}){const[A,t]=c.useState(null),u=n.filter(r=>r.feedbackStatus==="pending"),k=n.filter(r=>!r.feedbackStatus||r.feedbackStatus==="accepted");return e.jsxs("div",{className:"flex flex-col h-full border-l-2 border-base-300 bg-base-200/50",children:[e.jsxs("div",{className:"flex items-center gap-2 px-3 py-2.5 border-b border-base-300 flex-shrink-0",children:[e.jsx(T,{icon:"lucide:pencil-line",size:14,className:"text-primary"}),e.jsx("span",{className:"text-sm font-semibold flex-1",children:"Annotations"}),(k.length>0||u.length>0)&&e.jsx("span",{className:"badge badge-primary badge-sm",children:k.length+u.length}),n.length>0&&e.jsx("button",{className:"btn btn-ghost btn-xs text-base-content/50",onClick:g,title:"Clear all annotations",children:e.jsx(T,{icon:"lucide:trash-2",size:12})})]}),(x||l)&&e.jsxs("div",{className:"flex gap-1 px-3 py-1.5 border-b border-base-300 flex-shrink-0",children:[x&&e.jsxs("button",{className:"btn btn-ghost btn-xs gap-1 flex-1",onClick:x,title:"Share spec with a teammate",children:[e.jsx(T,{icon:"lucide:send",size:11}),e.jsx("span",{className:"text-[10px]",children:"Share"})]}),l&&e.jsxs("button",{className:"btn btn-ghost btn-xs gap-1 flex-1",onClick:l,title:"Receive feedback from a colleague",children:[e.jsx(T,{icon:"lucide:inbox",size:11}),e.jsx("span",{className:"text-[10px]",children:"Receive"})]})]}),e.jsxs("div",{className:"flex-1 overflow-y-auto p-2 space-y-1",children:[u.length>0&&e.jsxs("div",{className:"mb-3",children:[e.jsxs("div",{className:"flex items-center justify-between px-1 mb-1",children:[e.jsxs("span",{className:"text-[11px] font-semibold text-info flex items-center gap-1",children:[e.jsx(T,{icon:"lucide:message-square-plus",size:11}),"External Feedback (",u.length,")"]}),e.jsxs("div",{className:"flex gap-1",children:[h&&e.jsx("button",{className:"btn btn-ghost btn-xs text-success text-[10px]",onClick:h,title:"Accept all feedback",children:"Accept All"}),m&&e.jsx("button",{className:"btn btn-ghost btn-xs text-error text-[10px]",onClick:m,title:"Reject all feedback",children:"Reject All"})]})]}),u.map(r=>e.jsxs("div",{className:"p-2 rounded-lg border border-info/20 bg-info/5 space-y-1.5 mb-1 cursor-pointer hover:border-info/40 transition-colors",onClick:()=>s(r.id),children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("span",{className:"text-[10px] font-medium text-info/80 flex items-center gap-1",children:[e.jsx(T,{icon:"lucide:user",size:10}),r.author??"Anonymous"]}),e.jsxs("div",{className:"flex gap-1",children:[i&&e.jsx("button",{className:"btn btn-ghost btn-xs text-success py-0 h-5 min-h-0",onClick:()=>i(r.id),title:"Accept this annotation",children:e.jsx(T,{icon:"lucide:check",size:11})}),d&&e.jsx("button",{className:"btn btn-ghost btn-xs text-error py-0 h-5 min-h-0",onClick:()=>d(r.id),title:"Reject this annotation",children:e.jsx(T,{icon:"lucide:x",size:11})})]})]}),r.originalText&&e.jsxs("p",{className:"text-[10px] text-base-content/50 italic break-words",children:["“",r.originalText.slice(0,60),r.originalText.length>60?"…":"","”"]}),e.jsx("p",{className:"text-xs text-base-content/80 break-words",children:r.text})]},r.id)),e.jsx("hr",{className:"border-base-300/50 mt-2"})]}),k.length===0&&u.length===0?e.jsxs("div",{className:"flex flex-col items-center justify-center py-8 text-center px-3",children:[e.jsx(T,{icon:"lucide:message-square-plus",size:28,className:"text-base-content/15 mb-3"}),e.jsx("p",{className:"text-xs text-base-content/40 font-medium mb-1",children:"No annotations yet"}),e.jsx("p",{className:"text-[10px] text-base-content/30 leading-relaxed",children:"Hover over a block and click the + button to add a note. The agent reads your annotations at review checkpoints."})]}):k.map((r,w)=>e.jsx(V,{annotation:r,index:w+1,isSelected:o===r.id,isEditing:A===r.id,onSelect:()=>s(r.id),onRemove:()=>{t(null),a(r.id)},onUpdate:j=>b(r.id,j),onStartEdit:()=>t(r.id),onStopEdit:()=>t(null)},r.id))]})]})}function X(){return{annotations:[],selectedAnnotationId:null,pendingSelection:null}}function F(n,o,s){return{id:crypto.randomUUID(),blockId:n,originalText:o,text:s,createdAt:Date.now()}}function P(n,o){switch(o.type){case"ADD_ANNOTATION":return{...n,annotations:[...n.annotations,o.annotation],pendingSelection:null};case"REMOVE_ANNOTATION":{const s=n.annotations.filter(a=>a.id!==o.id);return{...n,annotations:s,selectedAnnotationId:n.selectedAnnotationId===o.id?null:n.selectedAnnotationId}}case"UPDATE_ANNOTATION":return{...n,annotations:n.annotations.map(s=>s.id===o.id?{...s,...o.updates}:s)};case"CLEAR_ALL":return{...n,annotations:[],selectedAnnotationId:null};case"SET_PENDING_SELECTION":return{...n,pendingSelection:o.selection};case"CLEAR_PENDING_SELECTION":return{...n,pendingSelection:null};case"SELECT_ANNOTATION":return{...n,selectedAnnotationId:o.id};case"SET_ANNOTATIONS":return{...n,annotations:o.annotations};case"ACCEPT_FEEDBACK":return{...n,annotations:n.annotations.map(s=>s.id===o.id?{...s,feedbackStatus:"accepted"}:s)};case"REJECT_FEEDBACK":return{...n,annotations:n.annotations.map(s=>s.id===o.id?{...s,feedbackStatus:"rejected"}:s)};case"ACCEPT_ALL_FEEDBACK":return{...n,annotations:n.annotations.map(s=>s.feedbackStatus==="pending"?{...s,feedbackStatus:"accepted"}:s)};case"REJECT_ALL_FEEDBACK":return{...n,annotations:n.annotations.map(s=>s.feedbackStatus==="pending"?{...s,feedbackStatus:"rejected"}:s)};default:return n}}function Y(n,o,s){const[a,b]=c.useReducer(P,void 0,X),g=c.useRef(!1),i=c.useCallback(()=>{o&&(o.current=!0)},[o]),d=c.useCallback(p=>{if(!s)return;const y=P({annotations:s.current,selectedAnnotationId:null,pendingSelection:null},p);s.current=y.annotations},[s]),h=c.useCallback(p=>{i(),d({type:"ADD_ANNOTATION",annotation:p}),b({type:"ADD_ANNOTATION",annotation:p})},[i,d]),m=c.useCallback(p=>{i(),d({type:"REMOVE_ANNOTATION",id:p}),b({type:"REMOVE_ANNOTATION",id:p})},[i,d]),x=c.useCallback((p,y)=>{i(),d({type:"UPDATE_ANNOTATION",id:p,updates:y}),b({type:"UPDATE_ANNOTATION",id:p,updates:y})},[i,d]),l=c.useCallback(()=>{i(),d({type:"CLEAR_ALL"}),b({type:"CLEAR_ALL"})},[i,d]),A=c.useCallback(p=>{b({type:"SELECT_ANNOTATION",id:p})},[]),t=c.useCallback(p=>{b({type:"SET_PENDING_SELECTION",selection:p})},[]),u=c.useCallback(()=>{b({type:"CLEAR_PENDING_SELECTION"})},[]),k=c.useCallback(p=>{s&&(s.current=p),b({type:"SET_ANNOTATIONS",annotations:p})},[s]),r=c.useCallback(p=>{i(),d({type:"ACCEPT_FEEDBACK",id:p}),b({type:"ACCEPT_FEEDBACK",id:p})},[i,d]),w=c.useCallback(p=>{i(),d({type:"REJECT_FEEDBACK",id:p}),b({type:"REJECT_FEEDBACK",id:p})},[i,d]),j=c.useCallback(()=>{i(),d({type:"ACCEPT_ALL_FEEDBACK"}),b({type:"ACCEPT_ALL_FEEDBACK"})},[i,d]),S=c.useCallback(()=>{i(),d({type:"REJECT_ALL_FEEDBACK"}),b({type:"REJECT_ALL_FEEDBACK"})},[i,d]),_=c.useCallback(p=>{requestAnimationFrame(()=>{var E;const y=(E=window.getSelection)==null?void 0:E.call(window);if(!y||y.isCollapsed||!n.current){u();return}const R=y.toString().trim();if(!R){u();return}const I=y.anchorNode,$=y.focusNode,L=C=>{let v=C;for(;v&&v!==n.current;){if(v instanceof Element&&v.hasAttribute("data-block-id"))return v;v=v.parentNode}return null},O=L(I),D=L($);if(!O||!D||O!==D){y.removeAllRanges(),u();return}const B=O.getAttribute("data-block-id")??"",N=y.getRangeAt(0).getBoundingClientRect();g.current=!0,t({blockId:B,selectedText:R,rect:{top:N.top,left:N.left,width:N.width,height:N.height}})})},[n,u,t]);return{state:a,addAnnotation:h,removeAnnotation:m,updateAnnotation:x,clearAll:l,selectAnnotation:A,setPendingSelection:t,clearPendingSelection:u,setAnnotations:k,acceptFeedback:r,rejectFeedback:w,acceptAllFeedback:j,rejectAllFeedback:S,handleMouseUp:_}}async function z(n,o,s){try{const a=await fetch(`/api/annotations/plan?path=${encodeURIComponent(n)}${o}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({annotations:s})});if(!a.ok){const b=await a.text().catch(()=>"");console.error(`[PlanAnnotator] Auto-save failed with HTTP ${a.status}: ${b||a.statusText}`,{planPath:n})}}catch(a){console.error("[PlanAnnotator] Auto-save network error:",a)}}function Z(n,o,s){const a=`/api/annotations/plan?path=${encodeURIComponent(n)}${o}`,b=JSON.stringify({annotations:s});if(typeof navigator<"u"&&typeof navigator.sendBeacon=="function"){const g=new Blob([b],{type:"application/json"});return navigator.sendBeacon(a,g)}try{return fetch(a,{method:"POST",headers:{"Content-Type":"application/json"},body:b,keepalive:!0}),!0}catch{return!1}}const ee=c.forwardRef(function({planContent:o,planPath:s,projectParam:a,onShare:b,onReceiveFeedback:g,reloadKey:i},d){const h=c.useRef(null),m=c.useRef(null),x=c.useRef(!1),l=c.useRef(0),A=c.useRef(0),t=c.useRef(null),u=c.useRef([]),k=c.useRef(s),r=c.useRef(a),w=c.useMemo(()=>q(o),[o]),{state:j,addAnnotation:S,removeAnnotation:_,updateAnnotation:p,clearAll:y,selectAnnotation:R,setAnnotations:I,acceptFeedback:$,rejectFeedback:L,acceptAllFeedback:O,rejectAllFeedback:D}=Y(h,x,u);k.current=s,r.current=a,c.useEffect(()=>{t.current&&t.current.abort();const f=new AbortController;t.current=f;const N=++A.current;return I([]),(async()=>{try{const C=await fetch(`/api/annotations?path=${encodeURIComponent(s)}${a}`,{signal:f.signal});if(f.signal.aborted||N!==A.current)return;if(C.ok){const v=await C.json();if(f.signal.aborted||N!==A.current)return;I(Array.isArray(v.planAnnotations)?v.planAnnotations:[]),x.current=!1}}catch(C){if((C==null?void 0:C.name)==="AbortError")return}})(),()=>{f.abort()}},[s,a,I,i]),c.useEffect(()=>{x.current&&(l.current=Date.now())},[j.annotations]),c.useEffect(()=>{if(j.annotations.length===0&&!x.current)return;m.current&&clearTimeout(m.current);const f=j.annotations,N=s,E=a;return m.current=setTimeout(async()=>{m.current=null,await z(N,E,f),x.current=!1},1e3),()=>{m.current&&clearTimeout(m.current)}},[j.annotations,s,a]),c.useEffect(()=>{const f=s,N=a;return()=>{if(x.current){m.current&&(clearTimeout(m.current),m.current=null);const E=u.current;z(f,N,E),x.current=!1}}},[s,a]),c.useEffect(()=>{const f=()=>{x.current&&(m.current&&(clearTimeout(m.current),m.current=null),Z(k.current,r.current,u.current),x.current=!1)};return window.addEventListener("pagehide",f),()=>{window.removeEventListener("pagehide",f)}},[]),c.useEffect(()=>{const f=setInterval(async()=>{if(j.annotations.length!==0&&!(Date.now()-l.current<3e3))try{const N=await fetch(`/api/annotations?path=${encodeURIComponent(s)}${a}`);N.ok&&((await N.json()).planAnnotations??[]).length===0&&(I([]),x.current=!1)}catch{}},5e3);return()=>clearInterval(f)},[s,a,j.annotations.length,I]),c.useImperativeHandle(d,()=>({addAnnotation:f=>{const N=F("test-block",f.slice(0,80),f);S(N)},removeAnnotation:f=>_(f),clearAll:()=>y(),getAnnotations:()=>u.current}),[S,_,y]);const B=c.useCallback(f=>{var C;R(f);const N=j.annotations.find(v=>v.id===f);if(!N||!N.originalText)return;const E=(C=h.current)==null?void 0:C.querySelector(`[data-block-id="${N.blockId}"]`);E==null||E.scrollIntoView({behavior:"smooth",block:"center"})},[j.annotations,R]);return e.jsxs("div",{style:{display:"flex",width:"100%",height:"100%",minHeight:0},children:[e.jsx("div",{style:{flex:1,minWidth:0,overflowY:"auto",padding:"1rem"},children:e.jsx("div",{ref:h,children:e.jsx(H,{blocks:w,annotations:j.annotations,selectedAnnotationId:j.selectedAnnotationId,onSelectAnnotation:B,onQuickAnnotate:(f,N,E)=>{const C=F(f,N,E);S(C)}})})}),e.jsx("div",{style:{width:256,flexShrink:0,height:"100%"},children:e.jsx(Q,{annotations:j.annotations,selectedAnnotationId:j.selectedAnnotationId,onSelectAnnotation:B,onRemoveAnnotation:_,onUpdateAnnotation:p,onClearAll:y,onAcceptFeedback:$,onRejectFeedback:L,onAcceptAllFeedback:O,onRejectAllFeedback:D,onShare:b,onReceiveFeedback:g})})]})}),ae=Object.freeze(Object.defineProperty({__proto__:null,PlanAnnotator:ee},Symbol.toStringTag,{value:"Module"}));export{H as B,ae as P,F as c,q as p,Y as u};
diff --git a/pilot/ui/index3.js b/pilot/ui/index3.js
index fb58491e..3b1ac9b7 100644
--- a/pilot/ui/index3.js
+++ b/pilot/ui/index3.js
@@ -1,2 +1,2 @@
-const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./PlanAnnotator.js","./vendor-markdown.js","./useAnnotation.js","./vendor-charts.js","./vendor-diff.js","./viewer-bundle.js","./viewer.css"])))=>i.map(i=>d[i]);
-import{C as P,a as R,B as A,I as r,S as q,T as Q,g as _,b as ne,c as ae,V as M,P as H,h as ie,i as ce,j as le,k as re,_ as oe}from"./viewer-bundle.js";import{j as e,a as n}from"./vendor-markdown.js";import"./vendor-charts.js";import{S as W}from"./Spinner.js";import"./vendor-diff.js";const de={primary:"progress-primary",secondary:"progress-secondary",accent:"progress-accent",info:"progress-info",success:"progress-success",warning:"progress-warning",error:"progress-error"};function xe({value:t,max:a=100,variant:o="primary",className:f=""}){return e.jsx("progress",{className:`progress ${de[o]} ${f}`,value:t,max:a})}const me={PENDING:{color:"warning",icon:"lucide:clock",label:"In Progress"},COMPLETE:{color:"info",icon:"lucide:check-circle",label:"Complete"},VERIFIED:{color:"success",icon:"lucide:shield-check",label:"Verified"}},he={color:"neutral",icon:"lucide:circle-dot",label:""};function ue({parsed:t,spec:a,onTaskClick:o,specContent:f,annotations:l,onImportFeedback:h}){const[d,u]=n.useState(!1),g=me[a.status]??{...he,label:a.status},S=t.tasks.filter(c=>c.completed).length,b=t.tasks.length,p=b>0?S/b*100:0;return e.jsxs(e.Fragment,{children:[e.jsx(P,{children:e.jsxs(R,{className:"p-5",children:[e.jsxs("div",{className:"flex items-start justify-between mb-4",children:[e.jsxs("div",{children:[e.jsx("h2",{className:"text-xl font-semibold",children:t.title}),t.goal&&e.jsx("p",{className:"text-base-content/60 text-sm mt-1",children:t.goal})]}),e.jsxs(A,{variant:g.color,size:"sm",className:"whitespace-nowrap flex-shrink-0",children:[e.jsx(r,{icon:g.icon,size:12,className:"mr-1"}),g.label]})]}),e.jsxs("div",{className:"mb-4",children:[e.jsxs("div",{className:"flex justify-between text-sm mb-1.5",children:[e.jsx("span",{className:"text-base-content/70",children:"Progress"}),e.jsxs("span",{className:"font-medium",children:[S," / ",b," tasks"]})]}),e.jsx(xe,{value:p,max:100,variant:"primary"})]}),e.jsx("div",{className:"space-y-2",children:t.tasks.map(c=>e.jsxs("div",{className:`flex items-center gap-3 p-2 rounded-lg cursor-pointer transition-colors ${c.completed?"bg-success/10 hover:bg-success/15":"bg-base-200/50 hover:bg-base-200"}`,onClick:()=>o==null?void 0:o(c.number),children:[e.jsx("div",{className:`w-5 h-5 rounded-md flex items-center justify-center ${c.completed?"bg-success text-success-content":"bg-base-300"}`,children:c.completed?e.jsx(r,{icon:"lucide:check",size:14}):e.jsx("span",{className:"text-xs text-base-content/50",children:c.number})}),e.jsxs("span",{className:`text-sm ${c.completed?"text-base-content/70":"text-base-content"}`,children:["Task ",c.number,": ",c.title]})]},c.number))}),e.jsxs("div",{className:"flex items-center gap-4 mt-4 pt-4 border-t border-base-300/50 text-xs text-base-content/50",children:[e.jsx(A,{variant:a.specType==="Bugfix"?"warning":"info",size:"xs",children:a.specType==="Bugfix"?"Bugfix":"Feature"}),a.author&&e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(r,{icon:"lucide:user",size:12}),e.jsx("span",{children:a.author})]}),a.iterations>0&&e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(r,{icon:"lucide:repeat",size:12}),e.jsxs("span",{children:[a.iterations," iteration",a.iterations>1?"s":""]})]}),!a.approved&&a.status==="PENDING"&&e.jsx(A,{variant:"warning",size:"xs",children:"Awaiting Approval"}),a.worktree?e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(r,{icon:"lucide:git-branch",size:12}),e.jsx("span",{children:"Worktree"})]}):e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(r,{icon:"lucide:git-commit",size:12}),e.jsx("span",{children:"Direct"})]}),a.modifiedAt&&e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(r,{icon:"lucide:calendar",size:12}),e.jsx("span",{children:new Date(a.modifiedAt).toLocaleString(void 0,{year:"numeric",month:"short",day:"numeric",hour:"2-digit",minute:"2-digit"})})]}),f&&e.jsxs("div",{className:"flex items-center gap-1 ml-auto",children:[e.jsxs("button",{className:"btn btn-ghost btn-xs gap-1",onClick:()=>u(!0),title:"Share spec with a teammate",children:[e.jsx(r,{icon:"lucide:send",size:12}),e.jsx("span",{children:"Share with Teammate"})]}),h&&e.jsxs("button",{className:"btn btn-ghost btn-xs gap-1",onClick:h,title:"Receive feedback from a colleague",children:[e.jsx(r,{icon:"lucide:inbox",size:12}),e.jsx("span",{children:"Receive Feedback"})]})]}),!f&&e.jsxs("div",{className:"flex items-center gap-1 ml-auto",children:[e.jsx(r,{icon:"lucide:file",size:12}),e.jsx("span",{className:"font-mono",children:a.filePath.split("/").pop()})]})]})]})}),f&&e.jsx(q,{isOpen:d,onClose:()=>u(!1),specContent:f,annotations:l??[],planPath:a.filePath,onCopied:()=>{u(!1),setTimeout(()=>h==null?void 0:h(),300)}})]})}const pe={A:"lucide:file-plus",M:"lucide:file-edit",D:"lucide:file-minus"},fe={A:"text-success",M:"text-warning",D:"text-error"};function je(){const[t,a]=n.useState(null),[o,f]=n.useState([]),[l,h]=n.useState(!0),[d,u]=n.useState(!1),[g,S]=n.useState(!1),[b,p]=n.useState(null),c=n.useCallback(async()=>{try{const m=await(await fetch("/api/worktree/status")).json();if(a(m),m.active){const D=await(await fetch("/api/worktree/diff")).json();f(D.files||[])}else f([])}catch{a(null)}finally{h(!1)}},[]);n.useEffect(()=>{c();const i=setInterval(c,Q.SPEC_REFRESH_INTERVAL_MS);return()=>clearInterval(i)},[c]);const j=async()=>{var i;if(confirm("Sync worktree changes to the base branch via squash merge?")){u(!0),p(null);try{const v=await(await fetch("/api/worktree/sync",{method:"POST"})).json();v.success?(p(`Synced ${v.files_changed} files — commit ${(i=v.commit_hash)==null?void 0:i.slice(0,7)}`),await c()):p(`Sync failed: ${v.error}`)}catch{p("Sync failed")}finally{u(!1)}}},w=async()=>{if(confirm("Discard all worktree changes? This cannot be undone.")){S(!0),p(null);try{const m=await(await fetch("/api/worktree/discard",{method:"POST"})).json();m.success?(p("Worktree discarded"),await c()):p(`Discard failed: ${m.error}`)}catch{p("Discard failed")}finally{S(!1)}}};if(l||!(t!=null&&t.active))return null;const C=o.reduce((i,m)=>i+m.additions,0),y=o.reduce((i,m)=>i+m.deletions,0);return e.jsx(P,{children:e.jsxs(R,{className:"p-4",children:[e.jsxs("div",{className:"flex items-center justify-between mb-3",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(r,{icon:"lucide:git-branch",size:16,className:"text-primary"}),e.jsx("span",{className:"text-sm font-medium",children:"Worktree Isolation"}),e.jsx(A,{variant:"info",size:"xs",children:t.branch})]}),e.jsxs("div",{className:"flex items-center gap-1.5",children:[e.jsxs(_,{variant:"primary",size:"xs",onClick:j,disabled:d||g||o.length===0,children:[d?e.jsx(W,{size:"xs"}):e.jsx(r,{icon:"lucide:git-merge",size:12}),e.jsx("span",{className:"ml-1",children:"Sync"})]}),e.jsxs(_,{variant:"ghost",size:"xs",onClick:w,disabled:d||g,children:[g?e.jsx(W,{size:"xs"}):e.jsx(r,{icon:"lucide:trash-2",size:12,className:"text-error"}),e.jsx("span",{className:"ml-1",children:"Discard"})]})]})]}),e.jsxs("div",{className:"flex items-center gap-3 text-xs text-base-content/60 mb-2",children:[e.jsxs("span",{children:[o.length," file",o.length!==1?"s":""," changed"]}),C>0&&e.jsxs("span",{className:"text-success",children:["+",C]}),y>0&&e.jsxs("span",{className:"text-error",children:["-",y]}),e.jsxs("span",{className:"ml-auto",children:["base: ",e.jsx("span",{className:"font-mono text-base-content/80",children:t.baseBranch})]})]}),o.length>0&&e.jsx("div",{className:"space-y-0.5 max-h-40 overflow-y-auto",children:o.map(i=>e.jsxs("div",{className:"flex items-center gap-2 text-xs py-0.5",children:[e.jsx(r,{icon:pe[i.status]||"lucide:file",size:12,className:fe[i.status]||"text-base-content/50"}),e.jsx("span",{className:"font-mono text-base-content/80 truncate",children:i.path}),e.jsxs("span",{className:"ml-auto flex items-center gap-1 flex-shrink-0",children:[i.additions>0&&e.jsxs("span",{className:"text-success",children:["+",i.additions]}),i.deletions>0&&e.jsxs("span",{className:"text-error",children:["-",i.deletions]})]})]},i.path))}),b&&e.jsx("div",{className:`mt-2 text-xs px-2 py-1 rounded ${b.includes("failed")?"bg-error/10 text-error":"bg-success/10 text-success"}`,children:b})]})})}const ge=n.lazy(()=>oe(()=>import("./PlanAnnotator.js"),__vite__mapDeps([0,1,2,3,4,5,6]),import.meta.url).then(t=>({default:t.PlanAnnotator}))),K={PENDING:"lucide:clock",COMPLETE:"lucide:check-circle",VERIFIED:"lucide:shield-check"},be=["Summary","Scope","Autonomous Decisions","Context for Implementer","Runtime Environment","Assumptions","Risks and Mitigations","Goal Verification","E2E Test Scenarios","E2E Results","Verification Scenario","Open Questions","Deferred Ideas"];function ve(t){const a=t.match(/^#\s+(.+)$/m),o=a?a[1].replace(" Implementation Plan",""):"Untitled",f=t.match(/\*\*Goal:\*\*\s*(.+?)(?:\n|$)/),l=f?f[1]:"",h=[],d=/^- \[(x| )\] Task (\d+):\s*(.+)$/gm;let u;for(;(u=d.exec(t))!==null;)h.push({number:parseInt(u[2],10),title:u[3],completed:u[1]==="x"});const g=t.match(/## Implementation Tasks\n([\s\S]*?)(?=\n## [^#]|$)/),S=g?g[1].trim():"",b=[],p=/^## (.+)$/gm,c=[];let j;for(;(j=p.exec(t))!==null;)c.push({heading:j[1],index:j.index,contentStart:j.index+j[0].length});for(let w=0;w{if(!a.path)return;const s=decodeURIComponent(a.path);h(x=>x===s?x:s)},[a.path]);const[d,u]=n.useState(null),[g,S]=n.useState(!0),[b,p]=n.useState(!1),[c,j]=n.useState(null),[w,C]=n.useState(!1),[y,i]=n.useState("view"),[m,v]=n.useState(!1),[D,F]=n.useState(!1),[Y,J]=n.useState(0),z=n.useRef(null),[X,Z]=n.useState(!1),ee=n.useCallback(s=>{const x=document.getElementById(`task-${s}`);x&&x.scrollIntoView({behavior:"smooth",block:"start"})},[]),se=n.useCallback(()=>{var s;(s=z.current)==null||s.scrollIntoView({behavior:"smooth",block:"start"})},[]);n.useEffect(()=>{const s=document.querySelector("main");if(!s)return;const x=()=>{if(!z.current)return;const N=z.current.getBoundingClientRect(),$=s.getBoundingClientRect().top;Z(N.bottom<$)};return s.addEventListener("scroll",x,{passive:!0}),()=>s.removeEventListener("scroll",x)},[]);const V=t?`?project=${encodeURIComponent(t)}`:"",B=n.useRef(t);B.current!==t&&(B.current=t,h(null),u(null),j(null),S(!0));const I=n.useCallback(async()=>{var s;try{const N=await(await fetch(`/api/plans/active${V}`)).json();if(f(N.specs||[]),((s=N.specs)==null?void 0:s.length)>0&&!l){const $=N.specs.find(G=>G.status==="PENDING"||G.status==="COMPLETE");h($?$.filePath:N.specs[0].filePath)}}catch(x){j("Failed to load specs"),console.error("Failed to load specs:",x)}finally{S(!1)}},[l,V]),T=n.useCallback(async(s,x=!1)=>{x||p(!0),j(null);try{const N=await fetch(`/api/plan/content?path=${encodeURIComponent(s)}${t?`&project=${encodeURIComponent(t)}`:""}`);if(!N.ok)throw new Error("Failed to load spec content");u(await N.json())}catch(N){j("Failed to load spec content"),console.error("Failed to load spec content:",N)}finally{x||p(!1)}},[t]),te=n.useCallback(async s=>{if(confirm(`Delete spec "${s.split("/").pop()}"? This cannot be undone.`)){C(!0);try{if(!(await fetch(`/api/plan?path=${encodeURIComponent(s)}${t?`&project=${encodeURIComponent(t)}`:""}`,{method:"DELETE"})).ok)throw new Error("Failed to delete spec");h(null),u(null),await I()}catch(x){j("Failed to delete spec"),console.error("Failed to delete spec:",x)}finally{C(!1)}}},[I,t]);n.useEffect(()=>{I();const s=setInterval(()=>{I(),l&&T(l,!0)},Q.SPEC_REFRESH_INTERVAL_MS);return()=>clearInterval(s)},[I,T,l]),n.useEffect(()=>{l&&T(l)},[l,T]);const O=n.useRef(l),U=n.useRef(!1);if(n.useEffect(()=>{if(O.current===l||(O.current=l,!l||!o.length)||U.current)return;U.current=!0;const s=o.find(x=>x.filePath===l);s&&s.status==="PENDING"&&!s.approved?i("annotate"):i("view")},[l,o]),g)return e.jsx(M,{});if(o.length===0)return e.jsxs("div",{className:"space-y-6",children:[e.jsxs("div",{className:"flex items-center gap-3 flex-wrap",children:[e.jsx("h1",{className:"text-2xl font-bold",children:"Specifications"}),e.jsx(H,{}),e.jsx("span",{className:"text-base-content/50 text-sm",children:"Spec-driven plans, tasks, and progress"})]}),e.jsx(P,{children:e.jsx(R,{children:e.jsxs("div",{className:"flex flex-col items-center justify-center py-12 text-center",children:[e.jsx(r,{icon:"lucide:file-text",size:48,className:"text-base-content/40 mb-4"}),e.jsx("h3",{className:"text-lg font-medium mb-2",children:"No Active Specs"}),e.jsxs("p",{className:"text-base-content/60 max-w-md",children:["Use"," ",e.jsx("code",{className:"text-primary bg-base-300 px-1 rounded",children:"/spec"})," ","in Pilot Shell to start a spec-driven development workflow."]})]})})})]});const k=o.find(s=>s.filePath===l),L=o.filter(s=>s.filePath!==l),E=d?ve(d.content):null;return e.jsxs("div",{className:"space-y-6",children:[e.jsxs("div",{className:"flex items-center gap-3 flex-wrap",children:[e.jsx("h1",{className:"text-2xl font-bold",children:"Specifications"}),e.jsx(H,{}),l&&d&&e.jsxs("div",{className:"flex items-center rounded-lg border border-base-300 overflow-hidden text-xs",children:[e.jsxs("button",{className:`px-2.5 py-1.5 flex items-center gap-1.5 transition-colors ${y==="view"?"bg-primary text-primary-content":"hover:bg-base-200"}`,onClick:()=>i("view"),title:"View plan",children:[e.jsx(r,{icon:"lucide:eye",size:13}),"View"]}),e.jsxs("button",{className:`px-2.5 py-1.5 flex items-center gap-1.5 transition-colors ${y==="annotate"?"bg-primary text-primary-content":"hover:bg-base-200"}`,onClick:()=>i("annotate"),title:"Review plan",children:[e.jsx(r,{icon:"lucide:pencil",size:13}),"Review"]})]}),k&&e.jsx("div",{role:"tablist",className:"flex items-center gap-1.5 min-w-0 overflow-hidden",children:e.jsxs("button",{role:"tab","aria-selected":!0,className:"px-2.5 py-1.5 rounded-lg text-xs font-medium border transition-colors cursor-pointer flex items-center gap-1.5 truncate bg-primary/10 border-primary/30 text-primary",children:[e.jsx(r,{icon:K[k.status]??K.PENDING,size:12,className:"text-warning flex-shrink-0"}),e.jsx("span",{className:"truncate max-w-40",children:k.name}),k.total>0&&e.jsxs("span",{className:"text-[10px] opacity-60 flex-shrink-0",children:[k.completed,"/",k.total]})]})}),e.jsx("span",{className:"flex-1"}),L.length>0&&e.jsxs("select",{className:"select select-bordered select-xs text-xs max-w-48",value:"",onChange:s=>h(s.target.value),children:[e.jsxs("option",{value:"",disabled:!0,children:["Previous (",L.length,")"]}),L.map(s=>e.jsx("option",{value:s.filePath,children:s.name},s.filePath))]}),l&&e.jsx(ie,{text:"Delete spec",position:"bottom",children:e.jsx(_,{variant:"ghost",size:"sm",onClick:()=>te(l),disabled:w,children:e.jsx(r,{icon:"lucide:trash-2",size:16,className:"text-error"})})})]}),b?e.jsx(M,{}):c?e.jsx(P,{children:e.jsx(R,{children:e.jsxs("div",{className:"flex flex-col items-center justify-center py-12 text-center",children:[e.jsx(r,{icon:"lucide:alert-circle",size:48,className:"text-error mb-4"}),e.jsx("p",{className:"text-error",children:c})]})})}):E&&k?e.jsxs(e.Fragment,{children:[y==="annotate"&&d&&e.jsx(n.Suspense,{fallback:e.jsx(M,{}),children:e.jsxs("div",{className:"rounded-xl border border-base-300 bg-base-100",style:{height:"calc(100vh - 180px)",minHeight:500,display:"flex",flexDirection:"column"},children:[e.jsxs("div",{className:"flex items-center gap-2 px-4 py-2 border-b border-base-300 bg-base-200/40 flex-shrink-0 text-xs text-base-content/60",children:[e.jsx(r,{icon:"lucide:pencil-line",size:13,className:"text-primary"}),e.jsx("span",{children:"Hover over a block and click the + button to add annotations. Review them in the sidebar."})]}),e.jsx("div",{style:{flex:1,minHeight:0,display:"flex"},children:e.jsx(ge,{planContent:d.content,planPath:d.filePath,projectParam:t?`&project=${encodeURIComponent(t)}`:"",onShare:()=>F(!0),onReceiveFeedback:()=>v(!0),reloadKey:Y})})]})}),y!=="annotate"&&e.jsxs(e.Fragment,{children:[e.jsx("div",{ref:z,children:e.jsx(ue,{parsed:E,spec:k,onTaskClick:ee,specContent:d==null?void 0:d.content,onImportFeedback:()=>v(!0)})}),e.jsx(je,{}),E.sections.length>0&&e.jsx("div",{className:"space-y-2",children:E.sections.map(s=>e.jsx(ce,{heading:s.heading,content:s.content,defaultOpen:s.heading==="Summary"||s.heading==="Scope"},s.heading))}),E.implementationSection&&e.jsx(P,{children:e.jsxs(R,{className:"p-6",children:[e.jsxs("h3",{className:"text-lg font-semibold mb-4 flex items-center gap-2",children:[e.jsx(r,{icon:"lucide:list-tree",size:18}),"Implementation Details"]}),e.jsx(le,{content:E.implementationSection})]})})]}),X&&y==="view"&&e.jsxs("button",{onClick:se,className:"fixed bottom-6 right-6 btn btn-primary btn-sm shadow-lg gap-1.5 z-50",children:[e.jsx(r,{icon:"lucide:arrow-up",size:14}),"Task List"]})]}):null,d&&m&&e.jsx(re,{isOpen:m,onClose:()=>v(!1),planPath:d.filePath,projectParam:t?`&project=${encodeURIComponent(t)}`:"",onAnnotationsImported:()=>{v(!1),i("annotate"),J(s=>s+1)}}),d&&D&&e.jsx(q,{isOpen:D,onClose:()=>F(!1),specContent:d.content,annotations:[],planPath:d.filePath,onCopied:()=>{F(!1),setTimeout(()=>v(!0),300)}})]})}export{ke as SpecView};
+const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./PlanAnnotator.js","./vendor-markdown.js","./vendor-charts.js","./vendor-diff.js","./viewer-bundle.js","./viewer.css"])))=>i.map(i=>d[i]);
+import{C as P,a as R,B as A,I as r,S as q,T as Q,g as V,b as ne,c as ae,V as M,P as H,h as ie,i as ce,j as le,k as re,_ as oe}from"./viewer-bundle.js";import{j as e,a as n}from"./vendor-markdown.js";import"./vendor-charts.js";import{S as W}from"./Spinner.js";import"./vendor-diff.js";const de={primary:"progress-primary",secondary:"progress-secondary",accent:"progress-accent",info:"progress-info",success:"progress-success",warning:"progress-warning",error:"progress-error"};function xe({value:t,max:a=100,variant:o="primary",className:f=""}){return e.jsx("progress",{className:`progress ${de[o]} ${f}`,value:t,max:a})}const me={PENDING:{color:"warning",icon:"lucide:clock",label:"In Progress"},COMPLETE:{color:"info",icon:"lucide:check-circle",label:"Complete"},VERIFIED:{color:"success",icon:"lucide:shield-check",label:"Verified"}},he={color:"neutral",icon:"lucide:circle-dot",label:""};function ue({parsed:t,spec:a,onTaskClick:o,specContent:f,annotations:l,onImportFeedback:h}){const[d,u]=n.useState(!1),g=me[a.status]??{...he,label:a.status},S=t.tasks.filter(c=>c.completed).length,b=t.tasks.length,p=b>0?S/b*100:0;return e.jsxs(e.Fragment,{children:[e.jsx(P,{children:e.jsxs(R,{className:"p-5",children:[e.jsxs("div",{className:"flex items-start justify-between mb-4",children:[e.jsxs("div",{children:[e.jsx("h2",{className:"text-xl font-semibold",children:t.title}),t.goal&&e.jsx("p",{className:"text-base-content/60 text-sm mt-1",children:t.goal})]}),e.jsxs(A,{variant:g.color,size:"sm",className:"whitespace-nowrap flex-shrink-0",children:[e.jsx(r,{icon:g.icon,size:12,className:"mr-1"}),g.label]})]}),e.jsxs("div",{className:"mb-4",children:[e.jsxs("div",{className:"flex justify-between text-sm mb-1.5",children:[e.jsx("span",{className:"text-base-content/70",children:"Progress"}),e.jsxs("span",{className:"font-medium",children:[S," / ",b," tasks"]})]}),e.jsx(xe,{value:p,max:100,variant:"primary"})]}),e.jsx("div",{className:"space-y-2",children:t.tasks.map(c=>e.jsxs("div",{className:`flex items-center gap-3 p-2 rounded-lg cursor-pointer transition-colors ${c.completed?"bg-success/10 hover:bg-success/15":"bg-base-200/50 hover:bg-base-200"}`,onClick:()=>o==null?void 0:o(c.number),children:[e.jsx("div",{className:`w-5 h-5 rounded-md flex items-center justify-center ${c.completed?"bg-success text-success-content":"bg-base-300"}`,children:c.completed?e.jsx(r,{icon:"lucide:check",size:14}):e.jsx("span",{className:"text-xs text-base-content/50",children:c.number})}),e.jsxs("span",{className:`text-sm ${c.completed?"text-base-content/70":"text-base-content"}`,children:["Task ",c.number,": ",c.title]})]},c.number))}),e.jsxs("div",{className:"flex items-center gap-4 mt-4 pt-4 border-t border-base-300/50 text-xs text-base-content/50",children:[e.jsx(A,{variant:a.specType==="Bugfix"?"warning":"info",size:"xs",children:a.specType==="Bugfix"?"Bugfix":"Feature"}),a.author&&e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(r,{icon:"lucide:user",size:12}),e.jsx("span",{children:a.author})]}),a.iterations>0&&e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(r,{icon:"lucide:repeat",size:12}),e.jsxs("span",{children:[a.iterations," iteration",a.iterations>1?"s":""]})]}),!a.approved&&a.status==="PENDING"&&e.jsx(A,{variant:"warning",size:"xs",children:"Awaiting Approval"}),a.worktree?e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(r,{icon:"lucide:git-branch",size:12}),e.jsx("span",{children:"Worktree"})]}):e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(r,{icon:"lucide:git-commit",size:12}),e.jsx("span",{children:"Direct"})]}),a.modifiedAt&&e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(r,{icon:"lucide:calendar",size:12}),e.jsx("span",{children:new Date(a.modifiedAt).toLocaleString(void 0,{year:"numeric",month:"short",day:"numeric",hour:"2-digit",minute:"2-digit"})})]}),f&&e.jsxs("div",{className:"flex items-center gap-1 ml-auto",children:[e.jsxs("button",{className:"btn btn-ghost btn-xs gap-1",onClick:()=>u(!0),title:"Share spec with a teammate",children:[e.jsx(r,{icon:"lucide:send",size:12}),e.jsx("span",{children:"Share with Teammate"})]}),h&&e.jsxs("button",{className:"btn btn-ghost btn-xs gap-1",onClick:h,title:"Receive feedback from a colleague",children:[e.jsx(r,{icon:"lucide:inbox",size:12}),e.jsx("span",{children:"Receive Feedback"})]})]}),!f&&e.jsxs("div",{className:"flex items-center gap-1 ml-auto",children:[e.jsx(r,{icon:"lucide:file",size:12}),e.jsx("span",{className:"font-mono",children:a.filePath.split("/").pop()})]})]})]})}),f&&e.jsx(q,{isOpen:d,onClose:()=>u(!1),specContent:f,annotations:l??[],planPath:a.filePath,onCopied:()=>{u(!1),setTimeout(()=>h==null?void 0:h(),300)}})]})}const pe={A:"lucide:file-plus",M:"lucide:file-edit",D:"lucide:file-minus"},fe={A:"text-success",M:"text-warning",D:"text-error"};function je(){const[t,a]=n.useState(null),[o,f]=n.useState([]),[l,h]=n.useState(!0),[d,u]=n.useState(!1),[g,S]=n.useState(!1),[b,p]=n.useState(null),c=n.useCallback(async()=>{try{const m=await(await fetch("/api/worktree/status")).json();if(a(m),m.active){const D=await(await fetch("/api/worktree/diff")).json();f(D.files||[])}else f([])}catch{a(null)}finally{h(!1)}},[]);n.useEffect(()=>{c();const i=setInterval(c,Q.SPEC_REFRESH_INTERVAL_MS);return()=>clearInterval(i)},[c]);const j=async()=>{var i;if(confirm("Sync worktree changes to the base branch via squash merge?")){u(!0),p(null);try{const v=await(await fetch("/api/worktree/sync",{method:"POST"})).json();v.success?(p(`Synced ${v.files_changed} files — commit ${(i=v.commit_hash)==null?void 0:i.slice(0,7)}`),await c()):p(`Sync failed: ${v.error}`)}catch{p("Sync failed")}finally{u(!1)}}},w=async()=>{if(confirm("Discard all worktree changes? This cannot be undone.")){S(!0),p(null);try{const m=await(await fetch("/api/worktree/discard",{method:"POST"})).json();m.success?(p("Worktree discarded"),await c()):p(`Discard failed: ${m.error}`)}catch{p("Discard failed")}finally{S(!1)}}};if(l||!(t!=null&&t.active))return null;const C=o.reduce((i,m)=>i+m.additions,0),y=o.reduce((i,m)=>i+m.deletions,0);return e.jsx(P,{children:e.jsxs(R,{className:"p-4",children:[e.jsxs("div",{className:"flex items-center justify-between mb-3",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(r,{icon:"lucide:git-branch",size:16,className:"text-primary"}),e.jsx("span",{className:"text-sm font-medium",children:"Worktree Isolation"}),e.jsx(A,{variant:"info",size:"xs",children:t.branch})]}),e.jsxs("div",{className:"flex items-center gap-1.5",children:[e.jsxs(V,{variant:"primary",size:"xs",onClick:j,disabled:d||g||o.length===0,children:[d?e.jsx(W,{size:"xs"}):e.jsx(r,{icon:"lucide:git-merge",size:12}),e.jsx("span",{className:"ml-1",children:"Sync"})]}),e.jsxs(V,{variant:"ghost",size:"xs",onClick:w,disabled:d||g,children:[g?e.jsx(W,{size:"xs"}):e.jsx(r,{icon:"lucide:trash-2",size:12,className:"text-error"}),e.jsx("span",{className:"ml-1",children:"Discard"})]})]})]}),e.jsxs("div",{className:"flex items-center gap-3 text-xs text-base-content/60 mb-2",children:[e.jsxs("span",{children:[o.length," file",o.length!==1?"s":""," changed"]}),C>0&&e.jsxs("span",{className:"text-success",children:["+",C]}),y>0&&e.jsxs("span",{className:"text-error",children:["-",y]}),e.jsxs("span",{className:"ml-auto",children:["base: ",e.jsx("span",{className:"font-mono text-base-content/80",children:t.baseBranch})]})]}),o.length>0&&e.jsx("div",{className:"space-y-0.5 max-h-40 overflow-y-auto",children:o.map(i=>e.jsxs("div",{className:"flex items-center gap-2 text-xs py-0.5",children:[e.jsx(r,{icon:pe[i.status]||"lucide:file",size:12,className:fe[i.status]||"text-base-content/50"}),e.jsx("span",{className:"font-mono text-base-content/80 truncate",children:i.path}),e.jsxs("span",{className:"ml-auto flex items-center gap-1 flex-shrink-0",children:[i.additions>0&&e.jsxs("span",{className:"text-success",children:["+",i.additions]}),i.deletions>0&&e.jsxs("span",{className:"text-error",children:["-",i.deletions]})]})]},i.path))}),b&&e.jsx("div",{className:`mt-2 text-xs px-2 py-1 rounded ${b.includes("failed")?"bg-error/10 text-error":"bg-success/10 text-success"}`,children:b})]})})}const ge=["Summary","Investigation","Behavior Contract","Fix Approach","Scope","Autonomous Decisions","Context for Implementer","Runtime Environment","Assumptions","Risks and Mitigations","Goal Verification","E2E Test Scenarios","E2E Results","Verification Scenario","Verification Scenarios","Open Questions","Deferred Ideas"];function be(t){const a=t.match(/^#\s+(.+)$/m),o=a?a[1].replace(" Implementation Plan",""):"Untitled",f=t.match(/\*\*Goal:\*\*\s*(.+?)(?:\n|$)/),l=f?f[1]:"",h=[],d=/^- \[(x| )\] Task (\d+):\s*(.+)$/gm;let u;for(;(u=d.exec(t))!==null;)h.push({number:parseInt(u[2],10),title:u[3],completed:u[1]==="x"});const g=t.match(/## (?:Implementation Tasks|Tasks)\n([\s\S]*?)(?=\n## [^#]|$)/),S=g?g[1].trim():"",b=[],p=/^## (.+)$/gm,c=[];let j;for(;(j=p.exec(t))!==null;)c.push({heading:j[1],index:j.index,contentStart:j.index+j[0].length});for(let w=0;woe(()=>import("./PlanAnnotator.js").then(t=>t.P),__vite__mapDeps([0,1,2,3,4,5]),import.meta.url).then(t=>({default:t.PlanAnnotator}))),K={PENDING:"lucide:clock",COMPLETE:"lucide:check-circle",VERIFIED:"lucide:shield-check"};function ke(){const{selectedProject:t}=ne(),{params:a}=ae(),[o,f]=n.useState([]),[l,h]=n.useState(a.path?decodeURIComponent(a.path):null);n.useEffect(()=>{if(!a.path)return;const s=decodeURIComponent(a.path);h(x=>x===s?x:s)},[a.path]);const[d,u]=n.useState(null),[g,S]=n.useState(!0),[b,p]=n.useState(!1),[c,j]=n.useState(null),[w,C]=n.useState(!1),[y,i]=n.useState("view"),[m,v]=n.useState(!1),[D,F]=n.useState(!1),[Y,J]=n.useState(0),z=n.useRef(null),[X,Z]=n.useState(!1),ee=n.useCallback(s=>{const x=document.getElementById(`task-${s}`);x&&x.scrollIntoView({behavior:"smooth",block:"start"})},[]),se=n.useCallback(()=>{var s;(s=z.current)==null||s.scrollIntoView({behavior:"smooth",block:"start"})},[]);n.useEffect(()=>{const s=document.querySelector("main");if(!s)return;const x=()=>{if(!z.current)return;const N=z.current.getBoundingClientRect(),$=s.getBoundingClientRect().top;Z(N.bottom<$)};return s.addEventListener("scroll",x,{passive:!0}),()=>s.removeEventListener("scroll",x)},[]);const _=t?`?project=${encodeURIComponent(t)}`:"",B=n.useRef(t);B.current!==t&&(B.current=t,h(null),u(null),j(null),S(!0));const E=n.useCallback(async()=>{var s;try{const N=await(await fetch(`/api/plans/active${_}`)).json();if(f(N.specs||[]),((s=N.specs)==null?void 0:s.length)>0&&!l){const $=N.specs.find(G=>G.status==="PENDING"||G.status==="COMPLETE");h($?$.filePath:N.specs[0].filePath)}}catch(x){j("Failed to load specs"),console.error("Failed to load specs:",x)}finally{S(!1)}},[l,_]),T=n.useCallback(async(s,x=!1)=>{x||p(!0),j(null);try{const N=await fetch(`/api/plan/content?path=${encodeURIComponent(s)}${t?`&project=${encodeURIComponent(t)}`:""}`);if(!N.ok)throw new Error("Failed to load spec content");u(await N.json())}catch(N){j("Failed to load spec content"),console.error("Failed to load spec content:",N)}finally{x||p(!1)}},[t]),te=n.useCallback(async s=>{if(confirm(`Delete spec "${s.split("/").pop()}"? This cannot be undone.`)){C(!0);try{if(!(await fetch(`/api/plan?path=${encodeURIComponent(s)}${t?`&project=${encodeURIComponent(t)}`:""}`,{method:"DELETE"})).ok)throw new Error("Failed to delete spec");h(null),u(null),await E()}catch(x){j("Failed to delete spec"),console.error("Failed to delete spec:",x)}finally{C(!1)}}},[E,t]);n.useEffect(()=>{E();const s=setInterval(()=>{E(),l&&T(l,!0)},Q.SPEC_REFRESH_INTERVAL_MS);return()=>clearInterval(s)},[E,T,l]),n.useEffect(()=>{l&&T(l)},[l,T]);const O=n.useRef(l),U=n.useRef(!1);if(n.useEffect(()=>{if(O.current===l||(O.current=l,!l||!o.length)||U.current)return;U.current=!0;const s=o.find(x=>x.filePath===l);s&&s.status==="PENDING"&&!s.approved?i("annotate"):i("view")},[l,o]),g)return e.jsx(M,{});if(o.length===0)return e.jsxs("div",{className:"space-y-6",children:[e.jsxs("div",{className:"flex items-center gap-3 flex-wrap",children:[e.jsx("h1",{className:"text-2xl font-bold",children:"Specifications"}),e.jsx(H,{}),e.jsx("span",{className:"text-base-content/50 text-sm",children:"Spec-driven plans, tasks, and progress"})]}),e.jsx(P,{children:e.jsx(R,{children:e.jsxs("div",{className:"flex flex-col items-center justify-center py-12 text-center",children:[e.jsx(r,{icon:"lucide:file-text",size:48,className:"text-base-content/40 mb-4"}),e.jsx("h3",{className:"text-lg font-medium mb-2",children:"No Active Specs"}),e.jsxs("p",{className:"text-base-content/60 max-w-md",children:["Use"," ",e.jsx("code",{className:"text-primary bg-base-300 px-1 rounded",children:"/spec"})," ","in Pilot Shell to start a spec-driven development workflow."]})]})})})]});const k=o.find(s=>s.filePath===l),L=o.filter(s=>s.filePath!==l),I=d?be(d.content):null;return e.jsxs("div",{className:"space-y-6",children:[e.jsxs("div",{className:"flex items-center gap-3 flex-wrap",children:[e.jsx("h1",{className:"text-2xl font-bold",children:"Specifications"}),e.jsx(H,{}),l&&d&&e.jsxs("div",{className:"flex items-center rounded-lg border border-base-300 overflow-hidden text-xs",children:[e.jsxs("button",{className:`px-2.5 py-1.5 flex items-center gap-1.5 transition-colors ${y==="view"?"bg-primary text-primary-content":"hover:bg-base-200"}`,onClick:()=>i("view"),title:"View plan",children:[e.jsx(r,{icon:"lucide:eye",size:13}),"View"]}),e.jsxs("button",{className:`px-2.5 py-1.5 flex items-center gap-1.5 transition-colors ${y==="annotate"?"bg-primary text-primary-content":"hover:bg-base-200"}`,onClick:()=>i("annotate"),title:"Review plan",children:[e.jsx(r,{icon:"lucide:pencil",size:13}),"Review"]})]}),k&&e.jsx("div",{role:"tablist",className:"flex items-center gap-1.5 min-w-0 overflow-hidden",children:e.jsxs("button",{role:"tab","aria-selected":!0,className:"px-2.5 py-1.5 rounded-lg text-xs font-medium border transition-colors cursor-pointer flex items-center gap-1.5 truncate bg-primary/10 border-primary/30 text-primary",children:[e.jsx(r,{icon:K[k.status]??K.PENDING,size:12,className:"text-warning flex-shrink-0"}),e.jsx("span",{className:"truncate max-w-40",children:k.name}),k.total>0&&e.jsxs("span",{className:"text-[10px] opacity-60 flex-shrink-0",children:[k.completed,"/",k.total]})]})}),e.jsx("span",{className:"flex-1"}),L.length>0&&e.jsxs("select",{className:"select select-bordered select-xs text-xs max-w-48",value:"",onChange:s=>h(s.target.value),children:[e.jsxs("option",{value:"",disabled:!0,children:["Previous (",L.length,")"]}),L.map(s=>e.jsx("option",{value:s.filePath,children:s.name},s.filePath))]}),l&&e.jsx(ie,{text:"Delete spec",position:"bottom",children:e.jsx(V,{variant:"ghost",size:"sm",onClick:()=>te(l),disabled:w,children:e.jsx(r,{icon:"lucide:trash-2",size:16,className:"text-error"})})})]}),b?e.jsx(M,{}):c?e.jsx(P,{children:e.jsx(R,{children:e.jsxs("div",{className:"flex flex-col items-center justify-center py-12 text-center",children:[e.jsx(r,{icon:"lucide:alert-circle",size:48,className:"text-error mb-4"}),e.jsx("p",{className:"text-error",children:c})]})})}):I&&k?e.jsxs(e.Fragment,{children:[y==="annotate"&&d&&e.jsx(n.Suspense,{fallback:e.jsx(M,{}),children:e.jsxs("div",{className:"rounded-xl border border-base-300 bg-base-100",style:{height:"calc(100vh - 180px)",minHeight:500,display:"flex",flexDirection:"column"},children:[e.jsxs("div",{className:"flex items-center gap-2 px-4 py-2 border-b border-base-300 bg-base-200/40 flex-shrink-0 text-xs text-base-content/60",children:[e.jsx(r,{icon:"lucide:pencil-line",size:13,className:"text-primary"}),e.jsx("span",{children:"Hover over a block and click the + button to add annotations. Review them in the sidebar."})]}),e.jsx("div",{style:{flex:1,minHeight:0,display:"flex"},children:e.jsx(ve,{planContent:d.content,planPath:d.filePath,projectParam:t?`&project=${encodeURIComponent(t)}`:"",onShare:()=>F(!0),onReceiveFeedback:()=>v(!0),reloadKey:Y})})]})}),y!=="annotate"&&e.jsxs(e.Fragment,{children:[e.jsx("div",{ref:z,children:e.jsx(ue,{parsed:I,spec:k,onTaskClick:ee,specContent:d==null?void 0:d.content,onImportFeedback:()=>v(!0)})}),e.jsx(je,{}),I.sections.length>0&&e.jsx("div",{className:"space-y-2",children:I.sections.map(s=>e.jsx(ce,{heading:s.heading,content:s.content,defaultOpen:s.heading==="Summary"||s.heading==="Scope"||s.heading==="Investigation"||s.heading==="Behavior Contract"},s.heading))}),I.implementationSection&&e.jsx(P,{children:e.jsxs(R,{className:"p-6",children:[e.jsxs("h3",{className:"text-lg font-semibold mb-4 flex items-center gap-2",children:[e.jsx(r,{icon:"lucide:list-tree",size:18}),"Implementation Details"]}),e.jsx(le,{content:I.implementationSection})]})})]}),X&&y==="view"&&e.jsxs("button",{onClick:se,className:"fixed bottom-6 right-6 btn btn-primary btn-sm shadow-lg gap-1.5 z-50",children:[e.jsx(r,{icon:"lucide:arrow-up",size:14}),"Task List"]})]}):null,d&&m&&e.jsx(re,{isOpen:m,onClose:()=>v(!1),planPath:d.filePath,projectParam:t?`&project=${encodeURIComponent(t)}`:"",onAnnotationsImported:()=>{v(!1),i("annotate"),J(s=>s+1)}}),d&&D&&e.jsx(q,{isOpen:D,onClose:()=>F(!1),specContent:d.content,annotations:[],planPath:d.filePath,onCopied:()=>{F(!1),setTimeout(()=>v(!0),300)}})]})}export{ke as SpecView};
diff --git a/pilot/ui/index5.js b/pilot/ui/index5.js
index c41ff50e..f872139e 100644
--- a/pilot/ui/index5.js
+++ b/pilot/ui/index5.js
@@ -1,2 +1,2 @@
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./viewer-bundle.js","./vendor-markdown.js","./vendor-charts.js","./vendor-diff.js","./viewer.css"])))=>i.map(i=>d[i]);
-import{I as l,n as L,_ as C,V as z,o as A,p as U,q as O}from"./viewer-bundle.js";import{a as r,j as e}from"./vendor-markdown.js";import"./vendor-charts.js";import{u as D,p as M,c as _,B as V}from"./useAnnotation.js";import"./vendor-diff.js";function $({sharerAnnotations:m,recipientAnnotations:i,onRemoveRecipientAnnotation:n,onUpdateRecipientAnnotation:o,onSendFeedback:g,isSending:j=!1}){const[d,c]=r.useState(!1),[f,b]=r.useState(null),[y,a]=r.useState("");return e.jsxs("div",{className:"flex flex-col h-full border-l-2 border-base-300 bg-base-200/50",children:[e.jsxs("div",{className:"px-3 py-2.5 border-b border-base-300 flex-shrink-0 space-y-2",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(l,{icon:"lucide:message-square-plus",size:14,className:"text-primary"}),e.jsx("span",{className:"text-sm font-semibold flex-1",children:"Feedback Mode"}),i.length>0&&e.jsx("span",{className:"badge badge-primary badge-sm",children:i.length})]}),e.jsxs("button",{className:"btn btn-primary btn-sm w-full gap-2",disabled:i.length===0||j,onClick:g,children:[j?e.jsx("span",{className:"loading loading-spinner loading-xs"}):e.jsx(l,{icon:"lucide:send",size:14}),"Send Feedback (",i.length,")"]})]}),e.jsxs("div",{className:"flex-1 overflow-y-auto p-2 space-y-3",children:[m.length>0&&e.jsxs("div",{children:[e.jsxs("button",{className:"flex items-center gap-2 w-full text-left py-1 px-1 text-xs text-base-content/50 hover:text-base-content/70 transition-colors",onClick:()=>c(!d),children:[e.jsx(l,{icon:d?"lucide:chevron-down":"lucide:chevron-right",size:12}),e.jsxs("span",{children:[m.length," sharer annotation",m.length!==1?"s":""]})]}),d&&e.jsx("div",{className:"space-y-1 mt-1 ml-2",children:m.map((t,s)=>e.jsxs("div",{className:"flex items-start gap-2 p-2 rounded-lg bg-base-200/80 border border-base-300/50",children:[e.jsx("span",{className:"inline-flex items-center justify-center text-[10px] font-bold rounded-full w-4 h-4 flex-shrink-0 mt-0.5 bg-base-300 text-base-content/50",children:s+1}),e.jsxs("div",{className:"flex-1 min-w-0",children:[t.originalText&&e.jsxs("p",{className:"text-[11px] text-base-content/40 italic break-words mb-0.5",children:["“",t.originalText.slice(0,50),t.originalText.length>50?"…":"","”"]}),e.jsx("p",{className:"text-xs text-base-content/60 break-words",children:t.text})]})]},t.id))})]}),e.jsxs("div",{children:[e.jsx("p",{className:"text-xs font-medium text-base-content/60 px-1 mb-1",children:"Your Feedback"}),i.length===0?e.jsxs("div",{className:"flex flex-col items-center justify-center py-8 text-center px-3",children:[e.jsx(l,{icon:"lucide:mouse-pointer",size:24,className:"text-base-content/15 mb-2"}),e.jsx("p",{className:"text-xs text-base-content/40",children:"Select text to add feedback"})]}):e.jsx("div",{className:"space-y-1",children:i.map((t,s)=>f===t.id?e.jsxs("div",{className:"p-2.5 rounded-lg border bg-base-200 border-base-300 space-y-2",children:[t.originalText&&e.jsxs("p",{className:"text-[11px] text-base-content/50 italic break-words",children:["“",t.originalText.slice(0,80),t.originalText.length>80?"…":"","”"]}),e.jsx("textarea",{value:y,onChange:p=>a(p.target.value),rows:2,autoFocus:!0,className:"textarea textarea-bordered textarea-xs w-full text-xs resize-none",placeholder:"Your feedback…"}),e.jsxs("div",{className:"flex gap-1 items-center",children:[e.jsx("button",{className:"btn btn-ghost btn-xs text-error",onClick:()=>{b(null),n(t.id)},children:e.jsx(l,{icon:"lucide:trash-2",size:11})}),e.jsxs("div",{className:"flex gap-1 ml-auto",children:[e.jsx("button",{className:"btn btn-ghost btn-xs",onClick:()=>b(null),children:"Cancel"}),e.jsx("button",{className:"btn btn-neutral btn-xs",disabled:y===t.text,onClick:()=>{o(t.id,y),b(null)},children:"Save"})]})]})]},t.id):e.jsxs("div",{className:"flex items-start gap-2 p-2 rounded-lg cursor-pointer group transition-colors border border-transparent hover:bg-base-200/60",onClick:()=>{b(t.id),a(t.text)},children:[e.jsx("span",{className:"inline-flex items-center justify-center text-[10px] font-bold rounded-full w-4 h-4 flex-shrink-0 mt-0.5 bg-primary/20 text-primary",children:s+1}),e.jsxs("div",{className:"flex-1 min-w-0",children:[t.originalText&&e.jsxs("p",{className:"text-[11px] text-base-content/50 italic break-words mb-0.5",children:["“",t.originalText.slice(0,50),t.originalText.length>50?"…":"","”"]}),e.jsxs("p",{className:"text-xs text-base-content/80 break-words",children:[t.text.slice(0,100),t.text.length>100?"…":""]})]}),e.jsx("button",{className:"btn btn-ghost btn-xs opacity-0 group-hover:opacity-100 transition-opacity flex-shrink-0 text-error",onClick:p=>{p.stopPropagation(),n(t.id)},children:e.jsx(l,{icon:"lucide:x",size:11})})]},t.id))})]})]})]})}function q({selection:m,onSubmit:i,onDismiss:n}){const o=r.useRef(null),g=r.useRef(null),[j,d]=r.useState("");r.useEffect(()=>{var a;(a=g.current)==null||a.focus()},[]),r.useEffect(()=>{const a=s=>{s.key==="Escape"&&n()},t=s=>{requestAnimationFrame(()=>{o.current&&!o.current.contains(s.target)&&n()})};return document.addEventListener("keydown",a),document.addEventListener("mousedown",t),()=>{document.removeEventListener("keydown",a),document.removeEventListener("mousedown",t)}},[n]);const c=()=>{const a=j.trim();a&&(i(a),d(""))},f=a=>{a.key==="Enter"&&!a.shiftKey&&(a.preventDefault(),c())},b=m.rect.top-100,y=m.rect.left+m.rect.width/2;return e.jsxs("div",{ref:o,style:{position:"fixed",top:Math.max(b,8),left:y,transform:"translateX(-50%)",zIndex:50,width:240},className:"bg-base-100 border border-base-300 rounded-lg shadow-lg p-2 space-y-2",onMouseDown:a=>a.stopPropagation(),children:[e.jsx("textarea",{ref:g,value:j,onChange:a=>d(a.target.value),onKeyDown:f,placeholder:"Add annotation… (Enter to save)",rows:2,className:"textarea textarea-bordered textarea-xs w-full text-xs resize-none"}),e.jsxs("div",{className:"flex gap-1 justify-end",children:[e.jsx("button",{className:"btn btn-ghost btn-xs",onClick:n,children:"Cancel"}),e.jsx("button",{className:"btn btn-primary btn-xs",disabled:!j.trim(),onClick:c,children:"Save"})]})]})}async function J(){try{const m=await fetch("/api/license");if(m.ok){const i=await m.json();if(i.email)return i.email}}catch{}return"Anonymous"}function W({data:m}){const i=m??"",[n,o]=r.useState({status:"loading"}),{success:g,error:j}=L(),d=r.useRef(null),{state:c,addAnnotation:f,removeAnnotation:b,updateAnnotation:y,handleMouseUp:a,clearPendingSelection:t}=D(d);r.useEffect(()=>{if(!i){o({status:"error",message:"No share data in URL."});return}let u=!1;async function N(){try{if(A(i)){const x=await fetch(`/api/share/${i}`);if(!x.ok){u||o({status:"error",message:x.status===404?"Shared spec not found — the link may have expired (3 day limit).":"Failed to fetch shared spec from paste service."});return}const{data:v}=await x.json(),{decompress:S}=await C(async()=>{const{decompress:T}=await import("./viewer-bundle.js").then(P=>P.r);return{decompress:T}},__vite__mapDeps([0,1,2,3,4]),import.meta.url),E=JSON.parse(await S(v));u||o({status:"ready",payload:E})}else{const x=await U(i);if(!x){u||o({status:"error",message:"Failed to decompress — the URL may be corrupted or truncated."});return}u||o({status:"ready",payload:x})}}catch(x){u||o({status:"error",message:x instanceof Error?x.message:"Failed to load shared spec."})}}return N(),()=>{u=!0}},[i]);const s=n.status==="ready"?n.payload:null,h=r.useMemo(()=>s?M(s.specContent):[],[s==null?void 0:s.specContent]),[p,w]=r.useState(!1),k=r.useCallback(u=>{var x;if(!c.pendingSelection)return;const N=_(c.pendingSelection.blockId,c.pendingSelection.selectedText,u);f(N),(x=window.getSelection())==null||x.removeAllRanges(),t()},[c.pendingSelection,f,t]),F=r.useCallback(async()=>{if(!(!s||c.annotations.length===0)){w(!0);try{const{generateFeedbackUrl:u}=await C(async()=>{const{generateFeedbackUrl:S}=await import("./viewer-bundle.js").then(E=>E.s);return{generateFeedbackUrl:S}},__vite__mapDeps([0,1,2,3,4]),import.meta.url),N={annotations:c.annotations,author:await J(),planPath:s.planPath,createdAt:Date.now()},x=`${window.location.protocol}//${window.location.host}`,v=await u(N,x);if(v)await navigator.clipboard.writeText(v.url),g("Feedback URL copied to clipboard — share it with the spec owner.");else{const{compress:S}=await C(async()=>{const{compress:P}=await import("./viewer-bundle.js").then(I=>I.r);return{compress:P}},__vite__mapDeps([0,1,2,3,4]),import.meta.url),E=await S(JSON.stringify(N)),T=await fetch("/api/share",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({data:E})});if(T.ok){const{id:P}=await T.json(),I=`${x}/#/feedback/${P}`;await navigator.clipboard.writeText(I),g("Feedback URL copied to clipboard — share it with the spec owner.")}else j("Failed to store feedback — please try again.")}}finally{w(!1)}}},[c.annotations,s==null?void 0:s.planPath,g,j]);if(n.status==="loading")return e.jsx("div",{className:"min-h-screen p-6",children:e.jsx(z,{})});if(n.status==="error")return e.jsx("div",{className:"flex items-center justify-center min-h-screen p-6",children:e.jsxs("div",{className:"max-w-md text-center space-y-4",children:[e.jsx("div",{className:"bg-error/10 rounded-full w-16 h-16 flex items-center justify-center mx-auto",children:e.jsx(l,{icon:"lucide:lock",size:28,className:"text-error"})}),e.jsx("h2",{className:"text-xl font-semibold",children:"Failed to load shared spec"}),e.jsx("p",{className:"text-sm text-base-content/60",children:n.message}),e.jsxs("button",{className:"btn btn-ghost btn-sm",onClick:()=>window.location.reload(),children:[e.jsx(l,{icon:"lucide:refresh-cw",size:14}),"Retry"]})]})});const R=new Date(s.createdAt).toLocaleString(void 0,{dateStyle:"medium",timeStyle:"short"});return e.jsxs("div",{style:{display:"flex",width:"100%",height:"100vh",minHeight:0},children:[e.jsx("div",{style:{flex:1,minWidth:0,overflowY:"auto"},children:e.jsxs("div",{className:"max-w-4xl mx-auto px-4 py-6 space-y-4",children:[e.jsx("div",{className:"card bg-base-200 border border-base-300",children:e.jsx("div",{className:"card-body p-4",children:e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("div",{className:"bg-primary/10 rounded-lg p-2",children:e.jsx(l,{icon:"lucide:share-2",size:18,className:"text-primary"})}),e.jsxs("div",{className:"flex-1",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"text-sm font-semibold",children:"Shared Specification"}),e.jsx("span",{className:"badge badge-primary badge-xs",children:"Annotatable"})]}),e.jsxs("div",{className:"flex items-center gap-3 text-xs text-base-content/50 mt-0.5",children:[(s==null?void 0:s.author)&&e.jsxs("span",{className:"flex items-center gap-1",children:[e.jsx(l,{icon:"lucide:user",size:11}),s==null?void 0:s.author]}),e.jsxs("span",{className:"flex items-center gap-1",children:[e.jsx(l,{icon:"lucide:calendar",size:11}),R]}),e.jsxs("span",{className:"flex items-center gap-1",children:[e.jsx(l,{icon:"lucide:minimize-2",size:11,className:"text-success"}),"Compressed"]})]})]})]})})}),e.jsx("div",{className:"card bg-base-100 border border-base-300",children:e.jsx("div",{className:"card-body p-5",children:e.jsx("div",{ref:d,children:e.jsx(V,{blocks:h,annotations:c.annotations,selectedAnnotationId:c.selectedAnnotationId,onBlockMouseUp:a,onSelectAnnotation:()=>{},onQuickAnnotate:(u,N,x)=>{const v=_(u,N,x);f(v)}})})})})]})}),e.jsx("div",{style:{width:272,flexShrink:0,position:"sticky",top:0,height:"100vh",overflow:"hidden"},children:e.jsx($,{sharerAnnotations:(s==null?void 0:s.annotations)??[],recipientAnnotations:c.annotations,onRemoveRecipientAnnotation:b,onUpdateRecipientAnnotation:(u,N)=>y(u,{text:N}),onSendFeedback:F,isSending:p})}),c.pendingSelection&&e.jsx(q,{selection:c.pendingSelection,onSubmit:k,onDismiss:t})]})}function X({data:m}){const i=m??"",[n,o]=r.useState({status:"loading"}),[g,j]=r.useState([]),[d,c]=r.useState(""),[f,b]=r.useState("idle");r.useEffect(()=>{if(!i){o({status:"error",message:"No feedback data in URL."});return}let t=!1;async function s(){try{let h=null;if(A(i)){const p=await fetch(`/api/share/${i}`);if(!p.ok){t||o({status:"error",message:p.status===404?"Feedback link expired (3 day limit).":"Failed to fetch feedback."});return}const{data:w}=await p.json(),{decompress:k}=await C(async()=>{const{decompress:F}=await import("./viewer-bundle.js").then(R=>R.r);return{decompress:F}},__vite__mapDeps([0,1,2,3,4]),import.meta.url);h=JSON.parse(await k(w))}else h=await O(i);if(!h){t||o({status:"error",message:"Failed to decompress — URL may be corrupted or truncated."});return}t||o({status:"ready",payload:h})}catch(h){t||o({status:"error",message:h instanceof Error?h.message:"Failed to load feedback."})}}return s(),()=>{t=!0}},[i]),r.useEffect(()=>{n.status==="ready"&&fetch("/api/plans").then(t=>t.json()).then(t=>{const s=t.plans??[];j(s);const h=n.payload;if(h.planPath){const p=s.find(w=>w.filePath===h.planPath);p&&c(p.filePath)}s.length>0&&!d&&c(s[0].filePath)}).catch(()=>{})},[n.status]);const y=r.useCallback(async()=>{if(!(n.status!=="ready"||!d)){b("importing");try{const{payload:t}=n,s=await fetch(`/api/annotations?path=${encodeURIComponent(d)}`),h=s.ok?(await s.json()).planAnnotations??[]:[],p=t.annotations.map(k=>({...k,feedbackStatus:"pending",importedAt:Date.now()})),w=[...h,...p];await fetch(`/api/annotations/plan?path=${encodeURIComponent(d)}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({annotations:w})}),b("done")}catch{b("error")}}},[n,d]);if(n.status==="loading")return e.jsx("div",{className:"min-h-screen p-6",children:e.jsx(z,{})});if(n.status==="error")return e.jsx("div",{className:"flex items-center justify-center min-h-screen p-6",children:e.jsxs("div",{className:"max-w-md text-center space-y-4",children:[e.jsx("div",{className:"bg-error/10 rounded-full w-16 h-16 flex items-center justify-center mx-auto",children:e.jsx(l,{icon:"lucide:message-square-x",size:28,className:"text-error"})}),e.jsx("h2",{className:"text-xl font-semibold",children:"Failed to load feedback"}),e.jsx("p",{className:"text-sm text-base-content/60",children:n.message})]})});const{payload:a}=n;return f==="done"?e.jsx("div",{className:"flex items-center justify-center min-h-screen p-6",children:e.jsxs("div",{className:"max-w-md text-center space-y-4",children:[e.jsx("div",{className:"bg-success/10 rounded-full w-16 h-16 flex items-center justify-center mx-auto",children:e.jsx(l,{icon:"lucide:check-circle",size:28,className:"text-success"})}),e.jsx("h2",{className:"text-xl font-semibold",children:"Feedback imported!"}),e.jsxs("p",{className:"text-sm text-base-content/60",children:[a.annotations.length," annotation",a.annotations.length!==1?"s":""," from"," ",e.jsx("strong",{children:a.author})," added to your spec."]}),e.jsx("p",{className:"text-xs text-base-content/40",children:"Open the Specifications tab to review and accept/reject each annotation."}),e.jsxs("a",{href:"/#/spec",className:"btn btn-primary btn-sm gap-2",children:[e.jsx(l,{icon:"lucide:file-text",size:14}),"Open Specifications"]})]})}):e.jsx("div",{className:"flex items-center justify-center min-h-screen p-6",children:e.jsxs("div",{className:"max-w-lg w-full space-y-6",children:[e.jsxs("div",{className:"text-center space-y-2",children:[e.jsx("div",{className:"bg-primary/10 rounded-full w-16 h-16 flex items-center justify-center mx-auto",children:e.jsx(l,{icon:"lucide:message-square-plus",size:28,className:"text-primary"})}),e.jsx("h2",{className:"text-xl font-semibold",children:"Incoming Feedback"}),e.jsxs("p",{className:"text-sm text-base-content/60",children:[e.jsx("strong",{children:a.author})," sent ",a.annotations.length," annotation",a.annotations.length!==1?"s":""]})]}),e.jsx("div",{className:"card bg-base-200 border border-base-300",children:e.jsxs("div",{className:"card-body p-4 space-y-2",children:[e.jsx("p",{className:"text-xs font-medium text-base-content/60 mb-1",children:"Preview"}),a.annotations.slice(0,3).map(t=>e.jsxs("div",{className:"flex items-start gap-2 p-2 rounded bg-base-100 border border-base-300/50 text-xs",children:[t.originalText&&e.jsxs("span",{className:"text-base-content/40 italic flex-shrink-0",children:["“",t.originalText.slice(0,40),"”"]}),e.jsx("span",{className:"text-base-content/70 flex-1",children:t.text.slice(0,80)})]},t.id)),a.annotations.length>3&&e.jsxs("p",{className:"text-xs text-base-content/40 text-center",children:["+",a.annotations.length-3," more…"]})]})}),e.jsxs("div",{className:"space-y-2",children:[e.jsx("label",{className:"text-sm font-medium",children:"Import into spec"}),g.length===0?e.jsx("p",{className:"text-xs text-base-content/50",children:"No specs found in this project."}):e.jsx("select",{className:"select select-bordered select-sm w-full",value:d,onChange:t=>c(t.target.value),children:g.map(t=>e.jsxs("option",{value:t.filePath,children:[t.name," (",t.status,")"]},t.filePath))})]}),f==="error"&&e.jsxs("div",{className:"alert alert-error py-2",children:[e.jsx(l,{icon:"lucide:alert-circle",size:14}),e.jsx("span",{className:"text-sm",children:"Import failed — please try again."})]}),e.jsxs("button",{className:"btn btn-primary w-full gap-2",disabled:!d||f==="importing",onClick:y,children:[f==="importing"?e.jsx("span",{className:"loading loading-spinner loading-sm"}):e.jsx(l,{icon:"lucide:download",size:16}),"Import ",a.annotations.length," Annotation",a.annotations.length!==1?"s":""]})]})})}export{X as FeedbackImportView,W as SharedSpecView};
+import{I as l,n as L,_ as C,V as z,o as A,p as U,q as O}from"./viewer-bundle.js";import{a as r,j as e}from"./vendor-markdown.js";import"./vendor-charts.js";import{u as D,p as M,c as _,B as V}from"./PlanAnnotator.js";import"./vendor-diff.js";function $({sharerAnnotations:m,recipientAnnotations:i,onRemoveRecipientAnnotation:n,onUpdateRecipientAnnotation:o,onSendFeedback:g,isSending:j=!1}){const[d,c]=r.useState(!1),[f,b]=r.useState(null),[y,a]=r.useState("");return e.jsxs("div",{className:"flex flex-col h-full border-l-2 border-base-300 bg-base-200/50",children:[e.jsxs("div",{className:"px-3 py-2.5 border-b border-base-300 flex-shrink-0 space-y-2",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(l,{icon:"lucide:message-square-plus",size:14,className:"text-primary"}),e.jsx("span",{className:"text-sm font-semibold flex-1",children:"Feedback Mode"}),i.length>0&&e.jsx("span",{className:"badge badge-primary badge-sm",children:i.length})]}),e.jsxs("button",{className:"btn btn-primary btn-sm w-full gap-2",disabled:i.length===0||j,onClick:g,children:[j?e.jsx("span",{className:"loading loading-spinner loading-xs"}):e.jsx(l,{icon:"lucide:send",size:14}),"Send Feedback (",i.length,")"]})]}),e.jsxs("div",{className:"flex-1 overflow-y-auto p-2 space-y-3",children:[m.length>0&&e.jsxs("div",{children:[e.jsxs("button",{className:"flex items-center gap-2 w-full text-left py-1 px-1 text-xs text-base-content/50 hover:text-base-content/70 transition-colors",onClick:()=>c(!d),children:[e.jsx(l,{icon:d?"lucide:chevron-down":"lucide:chevron-right",size:12}),e.jsxs("span",{children:[m.length," sharer annotation",m.length!==1?"s":""]})]}),d&&e.jsx("div",{className:"space-y-1 mt-1 ml-2",children:m.map((t,s)=>e.jsxs("div",{className:"flex items-start gap-2 p-2 rounded-lg bg-base-200/80 border border-base-300/50",children:[e.jsx("span",{className:"inline-flex items-center justify-center text-[10px] font-bold rounded-full w-4 h-4 flex-shrink-0 mt-0.5 bg-base-300 text-base-content/50",children:s+1}),e.jsxs("div",{className:"flex-1 min-w-0",children:[t.originalText&&e.jsxs("p",{className:"text-[11px] text-base-content/40 italic break-words mb-0.5",children:["“",t.originalText.slice(0,50),t.originalText.length>50?"…":"","”"]}),e.jsx("p",{className:"text-xs text-base-content/60 break-words",children:t.text})]})]},t.id))})]}),e.jsxs("div",{children:[e.jsx("p",{className:"text-xs font-medium text-base-content/60 px-1 mb-1",children:"Your Feedback"}),i.length===0?e.jsxs("div",{className:"flex flex-col items-center justify-center py-8 text-center px-3",children:[e.jsx(l,{icon:"lucide:mouse-pointer",size:24,className:"text-base-content/15 mb-2"}),e.jsx("p",{className:"text-xs text-base-content/40",children:"Select text to add feedback"})]}):e.jsx("div",{className:"space-y-1",children:i.map((t,s)=>f===t.id?e.jsxs("div",{className:"p-2.5 rounded-lg border bg-base-200 border-base-300 space-y-2",children:[t.originalText&&e.jsxs("p",{className:"text-[11px] text-base-content/50 italic break-words",children:["“",t.originalText.slice(0,80),t.originalText.length>80?"…":"","”"]}),e.jsx("textarea",{value:y,onChange:p=>a(p.target.value),rows:2,autoFocus:!0,className:"textarea textarea-bordered textarea-xs w-full text-xs resize-none",placeholder:"Your feedback…"}),e.jsxs("div",{className:"flex gap-1 items-center",children:[e.jsx("button",{className:"btn btn-ghost btn-xs text-error",onClick:()=>{b(null),n(t.id)},children:e.jsx(l,{icon:"lucide:trash-2",size:11})}),e.jsxs("div",{className:"flex gap-1 ml-auto",children:[e.jsx("button",{className:"btn btn-ghost btn-xs",onClick:()=>b(null),children:"Cancel"}),e.jsx("button",{className:"btn btn-neutral btn-xs",disabled:y===t.text,onClick:()=>{o(t.id,y),b(null)},children:"Save"})]})]})]},t.id):e.jsxs("div",{className:"flex items-start gap-2 p-2 rounded-lg cursor-pointer group transition-colors border border-transparent hover:bg-base-200/60",onClick:()=>{b(t.id),a(t.text)},children:[e.jsx("span",{className:"inline-flex items-center justify-center text-[10px] font-bold rounded-full w-4 h-4 flex-shrink-0 mt-0.5 bg-primary/20 text-primary",children:s+1}),e.jsxs("div",{className:"flex-1 min-w-0",children:[t.originalText&&e.jsxs("p",{className:"text-[11px] text-base-content/50 italic break-words mb-0.5",children:["“",t.originalText.slice(0,50),t.originalText.length>50?"…":"","”"]}),e.jsxs("p",{className:"text-xs text-base-content/80 break-words",children:[t.text.slice(0,100),t.text.length>100?"…":""]})]}),e.jsx("button",{className:"btn btn-ghost btn-xs opacity-0 group-hover:opacity-100 transition-opacity flex-shrink-0 text-error",onClick:p=>{p.stopPropagation(),n(t.id)},children:e.jsx(l,{icon:"lucide:x",size:11})})]},t.id))})]})]})]})}function q({selection:m,onSubmit:i,onDismiss:n}){const o=r.useRef(null),g=r.useRef(null),[j,d]=r.useState("");r.useEffect(()=>{var a;(a=g.current)==null||a.focus()},[]),r.useEffect(()=>{const a=s=>{s.key==="Escape"&&n()},t=s=>{requestAnimationFrame(()=>{o.current&&!o.current.contains(s.target)&&n()})};return document.addEventListener("keydown",a),document.addEventListener("mousedown",t),()=>{document.removeEventListener("keydown",a),document.removeEventListener("mousedown",t)}},[n]);const c=()=>{const a=j.trim();a&&(i(a),d(""))},f=a=>{a.key==="Enter"&&!a.shiftKey&&(a.preventDefault(),c())},b=m.rect.top-100,y=m.rect.left+m.rect.width/2;return e.jsxs("div",{ref:o,style:{position:"fixed",top:Math.max(b,8),left:y,transform:"translateX(-50%)",zIndex:50,width:240},className:"bg-base-100 border border-base-300 rounded-lg shadow-lg p-2 space-y-2",onMouseDown:a=>a.stopPropagation(),children:[e.jsx("textarea",{ref:g,value:j,onChange:a=>d(a.target.value),onKeyDown:f,placeholder:"Add annotation… (Enter to save)",rows:2,className:"textarea textarea-bordered textarea-xs w-full text-xs resize-none"}),e.jsxs("div",{className:"flex gap-1 justify-end",children:[e.jsx("button",{className:"btn btn-ghost btn-xs",onClick:n,children:"Cancel"}),e.jsx("button",{className:"btn btn-primary btn-xs",disabled:!j.trim(),onClick:c,children:"Save"})]})]})}async function J(){try{const m=await fetch("/api/license");if(m.ok){const i=await m.json();if(i.email)return i.email}}catch{}return"Anonymous"}function W({data:m}){const i=m??"",[n,o]=r.useState({status:"loading"}),{success:g,error:j}=L(),d=r.useRef(null),{state:c,addAnnotation:f,removeAnnotation:b,updateAnnotation:y,handleMouseUp:a,clearPendingSelection:t}=D(d);r.useEffect(()=>{if(!i){o({status:"error",message:"No share data in URL."});return}let u=!1;async function N(){try{if(A(i)){const x=await fetch(`/api/share/${i}`);if(!x.ok){u||o({status:"error",message:x.status===404?"Shared spec not found — the link may have expired (3 day limit).":"Failed to fetch shared spec from paste service."});return}const{data:v}=await x.json(),{decompress:S}=await C(async()=>{const{decompress:T}=await import("./viewer-bundle.js").then(P=>P.r);return{decompress:T}},__vite__mapDeps([0,1,2,3,4]),import.meta.url),E=JSON.parse(await S(v));u||o({status:"ready",payload:E})}else{const x=await U(i);if(!x){u||o({status:"error",message:"Failed to decompress — the URL may be corrupted or truncated."});return}u||o({status:"ready",payload:x})}}catch(x){u||o({status:"error",message:x instanceof Error?x.message:"Failed to load shared spec."})}}return N(),()=>{u=!0}},[i]);const s=n.status==="ready"?n.payload:null,h=r.useMemo(()=>s?M(s.specContent):[],[s==null?void 0:s.specContent]),[p,w]=r.useState(!1),k=r.useCallback(u=>{var x;if(!c.pendingSelection)return;const N=_(c.pendingSelection.blockId,c.pendingSelection.selectedText,u);f(N),(x=window.getSelection())==null||x.removeAllRanges(),t()},[c.pendingSelection,f,t]),F=r.useCallback(async()=>{if(!(!s||c.annotations.length===0)){w(!0);try{const{generateFeedbackUrl:u}=await C(async()=>{const{generateFeedbackUrl:S}=await import("./viewer-bundle.js").then(E=>E.s);return{generateFeedbackUrl:S}},__vite__mapDeps([0,1,2,3,4]),import.meta.url),N={annotations:c.annotations,author:await J(),planPath:s.planPath,createdAt:Date.now()},x=`${window.location.protocol}//${window.location.host}`,v=await u(N,x);if(v)await navigator.clipboard.writeText(v.url),g("Feedback URL copied to clipboard — share it with the spec owner.");else{const{compress:S}=await C(async()=>{const{compress:P}=await import("./viewer-bundle.js").then(I=>I.r);return{compress:P}},__vite__mapDeps([0,1,2,3,4]),import.meta.url),E=await S(JSON.stringify(N)),T=await fetch("/api/share",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({data:E})});if(T.ok){const{id:P}=await T.json(),I=`${x}/#/feedback/${P}`;await navigator.clipboard.writeText(I),g("Feedback URL copied to clipboard — share it with the spec owner.")}else j("Failed to store feedback — please try again.")}}finally{w(!1)}}},[c.annotations,s==null?void 0:s.planPath,g,j]);if(n.status==="loading")return e.jsx("div",{className:"min-h-screen p-6",children:e.jsx(z,{})});if(n.status==="error")return e.jsx("div",{className:"flex items-center justify-center min-h-screen p-6",children:e.jsxs("div",{className:"max-w-md text-center space-y-4",children:[e.jsx("div",{className:"bg-error/10 rounded-full w-16 h-16 flex items-center justify-center mx-auto",children:e.jsx(l,{icon:"lucide:lock",size:28,className:"text-error"})}),e.jsx("h2",{className:"text-xl font-semibold",children:"Failed to load shared spec"}),e.jsx("p",{className:"text-sm text-base-content/60",children:n.message}),e.jsxs("button",{className:"btn btn-ghost btn-sm",onClick:()=>window.location.reload(),children:[e.jsx(l,{icon:"lucide:refresh-cw",size:14}),"Retry"]})]})});const R=new Date(s.createdAt).toLocaleString(void 0,{dateStyle:"medium",timeStyle:"short"});return e.jsxs("div",{style:{display:"flex",width:"100%",height:"100vh",minHeight:0},children:[e.jsx("div",{style:{flex:1,minWidth:0,overflowY:"auto"},children:e.jsxs("div",{className:"max-w-4xl mx-auto px-4 py-6 space-y-4",children:[e.jsx("div",{className:"card bg-base-200 border border-base-300",children:e.jsx("div",{className:"card-body p-4",children:e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("div",{className:"bg-primary/10 rounded-lg p-2",children:e.jsx(l,{icon:"lucide:share-2",size:18,className:"text-primary"})}),e.jsxs("div",{className:"flex-1",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"text-sm font-semibold",children:"Shared Specification"}),e.jsx("span",{className:"badge badge-primary badge-xs",children:"Annotatable"})]}),e.jsxs("div",{className:"flex items-center gap-3 text-xs text-base-content/50 mt-0.5",children:[(s==null?void 0:s.author)&&e.jsxs("span",{className:"flex items-center gap-1",children:[e.jsx(l,{icon:"lucide:user",size:11}),s==null?void 0:s.author]}),e.jsxs("span",{className:"flex items-center gap-1",children:[e.jsx(l,{icon:"lucide:calendar",size:11}),R]}),e.jsxs("span",{className:"flex items-center gap-1",children:[e.jsx(l,{icon:"lucide:minimize-2",size:11,className:"text-success"}),"Compressed"]})]})]})]})})}),e.jsx("div",{className:"card bg-base-100 border border-base-300",children:e.jsx("div",{className:"card-body p-5",children:e.jsx("div",{ref:d,children:e.jsx(V,{blocks:h,annotations:c.annotations,selectedAnnotationId:c.selectedAnnotationId,onBlockMouseUp:a,onSelectAnnotation:()=>{},onQuickAnnotate:(u,N,x)=>{const v=_(u,N,x);f(v)}})})})})]})}),e.jsx("div",{style:{width:272,flexShrink:0,position:"sticky",top:0,height:"100vh",overflow:"hidden"},children:e.jsx($,{sharerAnnotations:(s==null?void 0:s.annotations)??[],recipientAnnotations:c.annotations,onRemoveRecipientAnnotation:b,onUpdateRecipientAnnotation:(u,N)=>y(u,{text:N}),onSendFeedback:F,isSending:p})}),c.pendingSelection&&e.jsx(q,{selection:c.pendingSelection,onSubmit:k,onDismiss:t})]})}function X({data:m}){const i=m??"",[n,o]=r.useState({status:"loading"}),[g,j]=r.useState([]),[d,c]=r.useState(""),[f,b]=r.useState("idle");r.useEffect(()=>{if(!i){o({status:"error",message:"No feedback data in URL."});return}let t=!1;async function s(){try{let h=null;if(A(i)){const p=await fetch(`/api/share/${i}`);if(!p.ok){t||o({status:"error",message:p.status===404?"Feedback link expired (3 day limit).":"Failed to fetch feedback."});return}const{data:w}=await p.json(),{decompress:k}=await C(async()=>{const{decompress:F}=await import("./viewer-bundle.js").then(R=>R.r);return{decompress:F}},__vite__mapDeps([0,1,2,3,4]),import.meta.url);h=JSON.parse(await k(w))}else h=await O(i);if(!h){t||o({status:"error",message:"Failed to decompress — URL may be corrupted or truncated."});return}t||o({status:"ready",payload:h})}catch(h){t||o({status:"error",message:h instanceof Error?h.message:"Failed to load feedback."})}}return s(),()=>{t=!0}},[i]),r.useEffect(()=>{n.status==="ready"&&fetch("/api/plans").then(t=>t.json()).then(t=>{const s=t.plans??[];j(s);const h=n.payload;if(h.planPath){const p=s.find(w=>w.filePath===h.planPath);p&&c(p.filePath)}s.length>0&&!d&&c(s[0].filePath)}).catch(()=>{})},[n.status]);const y=r.useCallback(async()=>{if(!(n.status!=="ready"||!d)){b("importing");try{const{payload:t}=n,s=await fetch(`/api/annotations?path=${encodeURIComponent(d)}`),h=s.ok?(await s.json()).planAnnotations??[]:[],p=t.annotations.map(k=>({...k,feedbackStatus:"pending",importedAt:Date.now()})),w=[...h,...p];await fetch(`/api/annotations/plan?path=${encodeURIComponent(d)}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({annotations:w})}),b("done")}catch{b("error")}}},[n,d]);if(n.status==="loading")return e.jsx("div",{className:"min-h-screen p-6",children:e.jsx(z,{})});if(n.status==="error")return e.jsx("div",{className:"flex items-center justify-center min-h-screen p-6",children:e.jsxs("div",{className:"max-w-md text-center space-y-4",children:[e.jsx("div",{className:"bg-error/10 rounded-full w-16 h-16 flex items-center justify-center mx-auto",children:e.jsx(l,{icon:"lucide:message-square-x",size:28,className:"text-error"})}),e.jsx("h2",{className:"text-xl font-semibold",children:"Failed to load feedback"}),e.jsx("p",{className:"text-sm text-base-content/60",children:n.message})]})});const{payload:a}=n;return f==="done"?e.jsx("div",{className:"flex items-center justify-center min-h-screen p-6",children:e.jsxs("div",{className:"max-w-md text-center space-y-4",children:[e.jsx("div",{className:"bg-success/10 rounded-full w-16 h-16 flex items-center justify-center mx-auto",children:e.jsx(l,{icon:"lucide:check-circle",size:28,className:"text-success"})}),e.jsx("h2",{className:"text-xl font-semibold",children:"Feedback imported!"}),e.jsxs("p",{className:"text-sm text-base-content/60",children:[a.annotations.length," annotation",a.annotations.length!==1?"s":""," from"," ",e.jsx("strong",{children:a.author})," added to your spec."]}),e.jsx("p",{className:"text-xs text-base-content/40",children:"Open the Specifications tab to review and accept/reject each annotation."}),e.jsxs("a",{href:"/#/spec",className:"btn btn-primary btn-sm gap-2",children:[e.jsx(l,{icon:"lucide:file-text",size:14}),"Open Specifications"]})]})}):e.jsx("div",{className:"flex items-center justify-center min-h-screen p-6",children:e.jsxs("div",{className:"max-w-lg w-full space-y-6",children:[e.jsxs("div",{className:"text-center space-y-2",children:[e.jsx("div",{className:"bg-primary/10 rounded-full w-16 h-16 flex items-center justify-center mx-auto",children:e.jsx(l,{icon:"lucide:message-square-plus",size:28,className:"text-primary"})}),e.jsx("h2",{className:"text-xl font-semibold",children:"Incoming Feedback"}),e.jsxs("p",{className:"text-sm text-base-content/60",children:[e.jsx("strong",{children:a.author})," sent ",a.annotations.length," annotation",a.annotations.length!==1?"s":""]})]}),e.jsx("div",{className:"card bg-base-200 border border-base-300",children:e.jsxs("div",{className:"card-body p-4 space-y-2",children:[e.jsx("p",{className:"text-xs font-medium text-base-content/60 mb-1",children:"Preview"}),a.annotations.slice(0,3).map(t=>e.jsxs("div",{className:"flex items-start gap-2 p-2 rounded bg-base-100 border border-base-300/50 text-xs",children:[t.originalText&&e.jsxs("span",{className:"text-base-content/40 italic flex-shrink-0",children:["“",t.originalText.slice(0,40),"”"]}),e.jsx("span",{className:"text-base-content/70 flex-1",children:t.text.slice(0,80)})]},t.id)),a.annotations.length>3&&e.jsxs("p",{className:"text-xs text-base-content/40 text-center",children:["+",a.annotations.length-3," more…"]})]})}),e.jsxs("div",{className:"space-y-2",children:[e.jsx("label",{className:"text-sm font-medium",children:"Import into spec"}),g.length===0?e.jsx("p",{className:"text-xs text-base-content/50",children:"No specs found in this project."}):e.jsx("select",{className:"select select-bordered select-sm w-full",value:d,onChange:t=>c(t.target.value),children:g.map(t=>e.jsxs("option",{value:t.filePath,children:[t.name," (",t.status,")"]},t.filePath))})]}),f==="error"&&e.jsxs("div",{className:"alert alert-error py-2",children:[e.jsx(l,{icon:"lucide:alert-circle",size:14}),e.jsx("span",{className:"text-sm",children:"Import failed — please try again."})]}),e.jsxs("button",{className:"btn btn-primary w-full gap-2",disabled:!d||f==="importing",onClick:y,children:[f==="importing"?e.jsx("span",{className:"loading loading-spinner loading-sm"}):e.jsx(l,{icon:"lucide:download",size:16}),"Import ",a.annotations.length," Annotation",a.annotations.length!==1?"s":""]})]})})}export{X as FeedbackImportView,W as SharedSpecView};
diff --git a/pilot/ui/viewer-bundle.js b/pilot/ui/viewer-bundle.js
index 3137a57e..28ab3ae3 100644
--- a/pilot/ui/viewer-bundle.js
+++ b/pilot/ui/viewer-bundle.js
@@ -1,5 +1,5 @@
-const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./PlanAnnotator.js","./vendor-markdown.js","./useAnnotation.js","./vendor-charts.js","./vendor-diff.js","./index.js","./index2.js","./Spinner.js","./viewer2.css","./index3.js","./index4.js","./ExtensionsView.js","./index5.js"])))=>i.map(i=>d[i]);
-import{j as e,a as o,M as Yt,b as Xt}from"./vendor-markdown.js";import{r as Zt,a as es}from"./vendor-charts.js";import"./vendor-diff.js";(function(){const s=document.createElement("link").relList;if(s&&s.supports&&s.supports("modulepreload"))return;for(const a of document.querySelectorAll('link[rel="modulepreload"]'))r(a);new MutationObserver(a=>{for(const i of a)if(i.type==="childList")for(const c of i.addedNodes)c.tagName==="LINK"&&c.rel==="modulepreload"&&r(c)}).observe(document,{childList:!0,subtree:!0});function n(a){const i={};return a.integrity&&(i.integrity=a.integrity),a.referrerPolicy&&(i.referrerPolicy=a.referrerPolicy),a.crossOrigin==="use-credentials"?i.credentials="include":a.crossOrigin==="anonymous"?i.credentials="omit":i.credentials="same-origin",i}function r(a){if(a.ep)return;a.ep=!0;const i=n(a);fetch(a.href,i)}})();var be={},Je;function ts(){if(Je)return be;Je=1;var t=Zt();return be.createRoot=t.createRoot,be.hydrateRoot=t.hydrateRoot,be}var ss=ts();const ns="modulepreload",as=function(t,s){return new URL(t,s).href},Qe={},B=function(s,n,r){let a=Promise.resolve();if(n&&n.length>0){let c=function(l){return Promise.all(l.map(m=>Promise.resolve(m).then(x=>({status:"fulfilled",value:x}),x=>({status:"rejected",reason:x}))))};const d=document.getElementsByTagName("link"),u=document.querySelector("meta[property=csp-nonce]"),h=(u==null?void 0:u.nonce)||(u==null?void 0:u.getAttribute("nonce"));a=c(n.map(l=>{if(l=as(l,r),l in Qe)return;Qe[l]=!0;const m=l.endsWith(".css"),x=m?'[rel="stylesheet"]':"";if(!!r)for(let f=d.length-1;f>=0;f--){const g=d[f];if(g.href===l&&(!m||g.rel==="stylesheet"))return}else if(document.querySelector(`link[href="${l}"]${x}`))return;const j=document.createElement("link");if(j.rel=m?"stylesheet":ns,m||(j.as="script"),j.crossOrigin="",j.href=l,h&&j.setAttribute("nonce",h),document.head.appendChild(j),m)return new Promise((f,g)=>{j.addEventListener("load",f),j.addEventListener("error",()=>g(new Error(`Unable to preload CSS for ${l}`)))})}))}function i(c){const d=new Event("vite:preloadError",{cancelable:!0});if(d.payload=c,window.dispatchEvent(d),!d.defaultPrevented)throw c}return a.then(c=>{for(const d of c||[])d.status==="rejected"&&i(d.reason);return s().catch(i)})};function rs(){return e.jsx("a",{href:"#/",className:"flex items-center",children:e.jsx("span",{className:"font-bold text-lg",children:"Pilot Shell Console"})})}const is={primary:"btn-primary",secondary:"btn-secondary",ghost:"btn-ghost",outline:"btn-outline",error:"btn-error"},os={xs:"btn-xs",sm:"btn-sm",md:"",lg:"btn-lg"};function W({variant:t="primary",size:s="md",loading:n=!1,className:r="",children:a,disabled:i,...c}){return e.jsxs("button",{className:`btn ${is[t]} ${os[s]} active:scale-[0.98] transition-transform ${r}`,disabled:i||n,...c,children:[n&&e.jsx("span",{className:"loading loading-spinner loading-sm"}),a]})}function H({children:t,className:s="",compact:n=!1,interactive:r,onClick:a}){const i=r??!!a;return e.jsx("div",{className:`card bg-base-100 shadow-sm border border-base-200 transition-all duration-150 ${i?"cursor-pointer hover:-translate-y-0.5 hover:shadow-md hover:border-base-content/15":""} ${n?"card-compact":""} ${s}`,onClick:a,children:t})}function V({children:t,className:s=""}){return e.jsx("div",{className:`card-body ${s}`,children:t})}function kr({children:t,className:s=""}){return e.jsx("h2",{className:`card-title ${s}`,children:t})}const cs={primary:"badge-primary",secondary:"badge-secondary",accent:"badge-accent",ghost:"badge-ghost",info:"badge-info",success:"badge-success",warning:"badge-warning",error:"badge-error"},ls={xs:"badge-xs",sm:"badge-sm",md:"",lg:"badge-lg"};function q({children:t,variant:s="ghost",size:n="md",outline:r=!1,className:a=""}){return e.jsx("span",{className:`badge ${cs[s]} ${ls[n]} ${r?"badge-outline":""} ${a}`,children:t})}const ds={default:"modal-box surface-elevated",wide:"modal-box surface-elevated max-w-4xl w-[90vw]"};function fe({open:t,onClose:s,title:n,children:r,actions:a,size:i="default"}){const c=e.jsxs("dialog",{className:`modal ${t?"modal-open":""}`,children:[e.jsxs("div",{className:ds[i],children:[e.jsxs("div",{className:"flex items-center justify-between",children:[n&&e.jsx("h3",{className:"font-bold text-lg",children:n}),e.jsx("button",{className:"btn btn-sm btn-circle btn-ghost",onClick:s,"aria-label":"Close",children:"✕"})]}),e.jsx("div",{className:"py-4",children:r}),a&&e.jsx("div",{className:"modal-action",children:a})]}),e.jsx("form",{method:"dialog",className:"modal-backdrop",children:e.jsx("button",{onClick:s,children:"close"})})]});return typeof document>"u"?c:es.createPortal(c,document.body)}const St=o.createContext(!1);function Cr(){return o.useContext(St)}function us({children:t}){const[s,n]=o.useState(()=>typeof window>"u"?!1:window.matchMedia("(prefers-reduced-motion: reduce)").matches);return o.useEffect(()=>{const r=window.matchMedia("(prefers-reduced-motion: reduce)"),a=i=>n(i.matches);return r.addEventListener("change",a),()=>r.removeEventListener("change",a)},[]),e.jsx(St.Provider,{value:s,children:t})}function ms(t,s){const n=t.icons,r=t.aliases||Object.create(null),a=Object.create(null);function i(c){if(n[c])return a[c]=[];if(!(c in a)){a[c]=null;const d=r[c]&&r[c].parent,u=d&&i(d);u&&(a[c]=[d].concat(u))}return a[c]}return Object.keys(n).concat(Object.keys(r)).forEach(i),a}const kt=Object.freeze({left:0,top:0,width:16,height:16}),ye=Object.freeze({rotate:0,vFlip:!1,hFlip:!1}),Me=Object.freeze({...kt,...ye}),De=Object.freeze({...Me,body:"",hidden:!1});function hs(t,s){const n={};!t.hFlip!=!s.hFlip&&(n.hFlip=!0),!t.vFlip!=!s.vFlip&&(n.vFlip=!0);const r=((t.rotate||0)+(s.rotate||0))%4;return r&&(n.rotate=r),n}function Ye(t,s){const n=hs(t,s);for(const r in De)r in ye?r in t&&!(r in n)&&(n[r]=ye[r]):r in s?n[r]=s[r]:r in t&&(n[r]=t[r]);return n}function fs(t,s,n){const r=t.icons,a=t.aliases||Object.create(null);let i={};function c(d){i=Ye(r[d]||a[d],i)}return c(s),n.forEach(c),Ye(t,i)}function Ct(t,s){const n=[];if(typeof t!="object"||typeof t.icons!="object")return n;t.not_found instanceof Array&&t.not_found.forEach(a=>{s(a,null),n.push(a)});const r=ms(t);for(const a in r){const i=r[a];i&&(s(a,fs(t,a,i)),n.push(a))}return n}const xs={provider:"",aliases:{},not_found:{},...kt};function Se(t,s){for(const n in s)if(n in t&&typeof t[n]!=typeof s[n])return!1;return!0}function Et(t){if(typeof t!="object"||t===null)return null;const s=t;if(typeof s.prefix!="string"||!t.icons||typeof t.icons!="object"||!Se(t,xs))return null;const n=s.icons;for(const a in n){const i=n[a];if(!a||typeof i.body!="string"||!Se(i,De))return null}const r=s.aliases||Object.create(null);for(const a in r){const i=r[a],c=i.parent;if(!a||typeof c!="string"||!n[c]&&!r[c]||!Se(i,De))return null}return s}const Xe=Object.create(null);function ps(t,s){return{provider:t,prefix:s,icons:Object.create(null),missing:new Set}}function re(t,s){const n=Xe[t]||(Xe[t]=Object.create(null));return n[s]||(n[s]=ps(t,s))}function Rt(t,s){return Et(s)?Ct(s,(n,r)=>{r?t.icons[n]=r:t.missing.add(n)}):[]}function bs(t,s,n){try{if(typeof n.body=="string")return t.icons[s]={...n},!0}catch{}return!1}const Pt=/^[a-z0-9]+(-[a-z0-9]+)*$/,Ne=(t,s,n,r="")=>{const a=t.split(":");if(t.slice(0,1)==="@"){if(a.length<2||a.length>3)return null;r=a.shift().slice(1)}if(a.length>3||!a.length)return null;if(a.length>1){const d=a.pop(),u=a.pop(),h={provider:a.length>0?a[0]:r,prefix:u,name:d};return s&&!je(h)?null:h}const i=a[0],c=i.split("-");if(c.length>1){const d={provider:r,prefix:c.shift(),name:c.join("-")};return s&&!je(d)?null:d}if(n&&r===""){const d={provider:r,prefix:"",name:i};return s&&!je(d,n)?null:d}return null},je=(t,s)=>t?!!((s&&t.prefix===""||t.prefix)&&t.name):!1;let xe=!1;function Tt(t){return typeof t=="boolean"&&(xe=t),xe}function Ze(t){const s=typeof t=="string"?Ne(t,!0,xe):t;if(s){const n=re(s.provider,s.prefix),r=s.name;return n.icons[r]||(n.missing.has(r)?null:void 0)}}function gs(t,s){const n=Ne(t,!0,xe);if(!n)return!1;const r=re(n.provider,n.prefix);return s?bs(r,n.name,s):(r.missing.add(n.name),!0)}function js(t,s){if(typeof t!="object")return!1;if(typeof s!="string"&&(s=t.provider||""),xe&&!s&&!t.prefix){let a=!1;return Et(t)&&(t.prefix="",Ct(t,(i,c)=>{gs(i,c)&&(a=!0)})),a}const n=t.prefix;if(!je({prefix:n,name:"a"}))return!1;const r=re(s,n);return!!Rt(r,t)}const It=Object.freeze({width:null,height:null}),Dt=Object.freeze({...It,...ye}),vs=/(-?[0-9.]*[0-9]+[0-9.]*)/g,ys=/^-?[0-9.]*[0-9]+[0-9.]*$/g;function et(t,s,n){if(s===1)return t;if(n=n||100,typeof t=="number")return Math.ceil(t*s*n)/n;if(typeof t!="string")return t;const r=t.split(vs);if(r===null||!r.length)return t;const a=[];let i=r.shift(),c=ys.test(i);for(;;){if(c){const d=parseFloat(i);isNaN(d)?a.push(i):a.push(Math.ceil(d*s*n)/n)}else a.push(i);if(i=r.shift(),i===void 0)return a.join("");c=!c}}function ws(t,s="defs"){let n="";const r=t.indexOf("<"+s);for(;r>=0;){const a=t.indexOf(">",r),i=t.indexOf(""+s);if(a===-1||i===-1)break;const c=t.indexOf(">",i);if(c===-1)break;n+=t.slice(a+1,i).trim(),t=t.slice(0,r).trim()+t.slice(c+1)}return{defs:n,content:t}}function Ns(t,s){return t?""+t+" "+s:s}function Ss(t,s,n){const r=ws(t);return Ns(r.defs,s+r.content+n)}const ks=t=>t==="unset"||t==="undefined"||t==="none";function Cs(t,s){const n={...Me,...t},r={...Dt,...s},a={left:n.left,top:n.top,width:n.width,height:n.height};let i=n.body;[n,r].forEach(f=>{const g=[],v=f.hFlip,p=f.vFlip;let y=f.rotate;v?p?y+=2:(g.push("translate("+(a.width+a.left).toString()+" "+(0-a.top).toString()+")"),g.push("scale(-1 1)"),a.top=a.left=0):p&&(g.push("translate("+(0-a.left).toString()+" "+(a.height+a.top).toString()+")"),g.push("scale(1 -1)"),a.top=a.left=0);let C;switch(y<0&&(y-=Math.floor(y/4)*4),y=y%4,y){case 1:C=a.height/2+a.top,g.unshift("rotate(90 "+C.toString()+" "+C.toString()+")");break;case 2:g.unshift("rotate(180 "+(a.width/2+a.left).toString()+" "+(a.height/2+a.top).toString()+")");break;case 3:C=a.width/2+a.left,g.unshift("rotate(-90 "+C.toString()+" "+C.toString()+")");break}y%2===1&&(a.left!==a.top&&(C=a.left,a.left=a.top,a.top=C),a.width!==a.height&&(C=a.width,a.width=a.height,a.height=C)),g.length&&(i=Ss(i,''," "))});const c=r.width,d=r.height,u=a.width,h=a.height;let l,m;c===null?(m=d===null?"1em":d==="auto"?h:d,l=et(m,u/h)):(l=c==="auto"?u:c,m=d===null?et(l,h/u):d==="auto"?h:d);const x={},b=(f,g)=>{ks(g)||(x[f]=g.toString())};b("width",l),b("height",m);const j=[a.left,a.top,u,h];return x.viewBox=j.join(" "),{attributes:x,viewBox:j,body:i}}const Es=/\sid="(\S+)"/g,Rs="IconifyId"+Date.now().toString(16)+(Math.random()*16777216|0).toString(16);let Ps=0;function Ts(t,s=Rs){const n=[];let r;for(;r=Es.exec(t);)n.push(r[1]);if(!n.length)return t;const a="suffix"+(Math.random()*16777216|Date.now()).toString(16);return n.forEach(i=>{const c=typeof s=="function"?s(i):s+(Ps++).toString(),d=i.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");t=t.replace(new RegExp('([#;"])('+d+')([")]|\\.[a-z])',"g"),"$1"+c+a+"$3")}),t=t.replace(new RegExp(a,"g"),""),t}const _e=Object.create(null);function Is(t,s){_e[t]=s}function Le(t){return _e[t]||_e[""]}function ze(t){let s;if(typeof t.resources=="string")s=[t.resources];else if(s=t.resources,!(s instanceof Array)||!s.length)return null;return{resources:s,path:t.path||"/",maxURL:t.maxURL||500,rotate:t.rotate||750,timeout:t.timeout||5e3,random:t.random===!0,index:t.index||0,dataAfterTimeout:t.dataAfterTimeout!==!1}}const Fe=Object.create(null),oe=["https://api.simplesvg.com","https://api.unisvg.com"],ve=[];for(;oe.length>0;)oe.length===1||Math.random()>.5?ve.push(oe.shift()):ve.push(oe.pop());Fe[""]=ze({resources:["https://api.iconify.design"].concat(ve)});function Ds(t,s){const n=ze(s);return n===null?!1:(Fe[t]=n,!0)}function Ue(t){return Fe[t]}const _s=()=>{let t;try{if(t=fetch,typeof t=="function")return t}catch{}};let tt=_s();function Ls(t,s){const n=Ue(t);if(!n)return 0;let r;if(!n.maxURL)r=0;else{let a=0;n.resources.forEach(c=>{a=Math.max(a,c.length)});const i=s+".json?icons=";r=n.maxURL-a-n.path.length-i.length}return r}function As(t){return t===404}const $s=(t,s,n)=>{const r=[],a=Ls(t,s),i="icons";let c={type:i,provider:t,prefix:s,icons:[]},d=0;return n.forEach((u,h)=>{d+=u.length+1,d>=a&&h>0&&(r.push(c),c={type:i,provider:t,prefix:s,icons:[]},d=u.length),c.icons.push(u)}),r.push(c),r};function Os(t){if(typeof t=="string"){const s=Ue(t);if(s)return s.path}return"/"}const Ms=(t,s,n)=>{if(!tt){n("abort",424);return}let r=Os(s.provider);switch(s.type){case"icons":{const i=s.prefix,d=s.icons.join(","),u=new URLSearchParams({icons:d});r+=i+".json?"+u.toString();break}case"custom":{const i=s.uri;r+=i.slice(0,1)==="/"?i.slice(1):i;break}default:n("abort",400);return}let a=503;tt(t+r).then(i=>{const c=i.status;if(c!==200){setTimeout(()=>{n(As(c)?"abort":"next",c)});return}return a=501,i.json()}).then(i=>{if(typeof i!="object"||i===null){setTimeout(()=>{i===404?n("abort",i):n("next",a)});return}setTimeout(()=>{n("success",i)})}).catch(()=>{n("next",a)})},zs={prepare:$s,send:Ms};function _t(t,s){t.forEach(n=>{const r=n.loaderCallbacks;r&&(n.loaderCallbacks=r.filter(a=>a.id!==s))})}function Fs(t){t.pendingCallbacksFlag||(t.pendingCallbacksFlag=!0,setTimeout(()=>{t.pendingCallbacksFlag=!1;const s=t.loaderCallbacks?t.loaderCallbacks.slice(0):[];if(!s.length)return;let n=!1;const r=t.provider,a=t.prefix;s.forEach(i=>{const c=i.icons,d=c.pending.length;c.pending=c.pending.filter(u=>{if(u.prefix!==a)return!0;const h=u.name;if(t.icons[h])c.loaded.push({provider:r,prefix:a,name:h});else if(t.missing.has(h))c.missing.push({provider:r,prefix:a,name:h});else return n=!0,!0;return!1}),c.pending.length!==d&&(n||_t([t],i.id),i.callback(c.loaded.slice(0),c.missing.slice(0),c.pending.slice(0),i.abort))})}))}let Us=0;function qs(t,s,n){const r=Us++,a=_t.bind(null,n,r);if(!s.pending.length)return a;const i={id:r,icons:s,callback:t,abort:a};return n.forEach(c=>{(c.loaderCallbacks||(c.loaderCallbacks=[])).push(i)}),a}function Gs(t){const s={loaded:[],missing:[],pending:[]},n=Object.create(null);t.sort((a,i)=>a.provider!==i.provider?a.provider.localeCompare(i.provider):a.prefix!==i.prefix?a.prefix.localeCompare(i.prefix):a.name.localeCompare(i.name));let r={provider:"",prefix:"",name:""};return t.forEach(a=>{if(r.name===a.name&&r.prefix===a.prefix&&r.provider===a.provider)return;r=a;const i=a.provider,c=a.prefix,d=a.name,u=n[i]||(n[i]=Object.create(null)),h=u[c]||(u[c]=re(i,c));let l;d in h.icons?l=s.loaded:c===""||h.missing.has(d)?l=s.missing:l=s.pending;const m={provider:i,prefix:c,name:d};l.push(m)}),s}function Hs(t,s=!0,n=!1){const r=[];return t.forEach(a=>{const i=typeof a=="string"?Ne(a,s,n):a;i&&r.push(i)}),r}const Vs={resources:[],index:0,timeout:2e3,rotate:750,random:!1,dataAfterTimeout:!1};function Bs(t,s,n,r){const a=t.resources.length,i=t.random?Math.floor(Math.random()*a):t.index;let c;if(t.random){let w=t.resources.slice(0);for(c=[];w.length>1;){const _=Math.floor(Math.random()*w.length);c.push(w[_]),w=w.slice(0,_).concat(w.slice(_+1))}c=c.concat(w)}else c=t.resources.slice(i).concat(t.resources.slice(0,i));const d=Date.now();let u="pending",h=0,l,m=null,x=[],b=[];typeof r=="function"&&b.push(r);function j(){m&&(clearTimeout(m),m=null)}function f(){u==="pending"&&(u="aborted"),j(),x.forEach(w=>{w.status==="pending"&&(w.status="aborted")}),x=[]}function g(w,_){_&&(b=[]),typeof w=="function"&&b.push(w)}function v(){return{startTime:d,payload:s,status:u,queriesSent:h,queriesPending:x.length,subscribe:g,abort:f}}function p(){u="failed",b.forEach(w=>{w(void 0,l)})}function y(){x.forEach(w=>{w.status==="pending"&&(w.status="aborted")}),x=[]}function C(w,_,L){const R=_!=="success";switch(x=x.filter(E=>E!==w),u){case"pending":break;case"failed":if(R||!t.dataAfterTimeout)return;break;default:return}if(_==="abort"){l=L,p();return}if(R){l=L,x.length||(c.length?I():p());return}if(j(),y(),!t.random){const E=t.resources.indexOf(w.resource);E!==-1&&E!==t.index&&(t.index=E)}u="completed",b.forEach(E=>{E(L)})}function I(){if(u!=="pending")return;j();const w=c.shift();if(w===void 0){if(x.length){m=setTimeout(()=>{j(),u==="pending"&&(y(),p())},t.timeout);return}p();return}const _={status:"pending",resource:w,callback:(L,R)=>{C(_,L,R)}};x.push(_),h++,m=setTimeout(I,t.rotate),n(w,s,_.callback)}return setTimeout(I),v}function Lt(t){const s={...Vs,...t};let n=[];function r(){n=n.filter(d=>d().status==="pending")}function a(d,u,h){const l=Bs(s,d,u,(m,x)=>{r(),h&&h(m,x)});return n.push(l),l}function i(d){return n.find(u=>d(u))||null}return{query:a,find:i,setIndex:d=>{s.index=d},getIndex:()=>s.index,cleanup:r}}function st(){}const ke=Object.create(null);function Ks(t){if(!ke[t]){const s=Ue(t);if(!s)return;const n=Lt(s),r={config:s,redundancy:n};ke[t]=r}return ke[t]}function Ws(t,s,n){let r,a;if(typeof t=="string"){const i=Le(t);if(!i)return n(void 0,424),st;a=i.send;const c=Ks(t);c&&(r=c.redundancy)}else{const i=ze(t);if(i){r=Lt(i);const c=t.resources?t.resources[0]:"",d=Le(c);d&&(a=d.send)}}return!r||!a?(n(void 0,424),st):r.query(s,a,n)().abort}function nt(){}function Js(t){t.iconsLoaderFlag||(t.iconsLoaderFlag=!0,setTimeout(()=>{t.iconsLoaderFlag=!1,Fs(t)}))}function Qs(t){const s=[],n=[];return t.forEach(r=>{(r.match(Pt)?s:n).push(r)}),{valid:s,invalid:n}}function ce(t,s,n){function r(){const a=t.pendingIcons;s.forEach(i=>{a&&a.delete(i),t.icons[i]||t.missing.add(i)})}if(n&&typeof n=="object")try{if(!Rt(t,n).length){r();return}}catch(a){console.error(a)}r(),Js(t)}function at(t,s){t instanceof Promise?t.then(n=>{s(n)}).catch(()=>{s(null)}):s(t)}function Ys(t,s){t.iconsToLoad?t.iconsToLoad=t.iconsToLoad.concat(s).sort():t.iconsToLoad=s,t.iconsQueueFlag||(t.iconsQueueFlag=!0,setTimeout(()=>{t.iconsQueueFlag=!1;const{provider:n,prefix:r}=t,a=t.iconsToLoad;if(delete t.iconsToLoad,!a||!a.length)return;const i=t.loadIcon;if(t.loadIcons&&(a.length>1||!i)){at(t.loadIcons(a,r,n),l=>{ce(t,a,l)});return}if(i){a.forEach(l=>{const m=i(l,r,n);at(m,x=>{const b=x?{prefix:r,icons:{[l]:x}}:null;ce(t,[l],b)})});return}const{valid:c,invalid:d}=Qs(a);if(d.length&&ce(t,d,null),!c.length)return;const u=r.match(Pt)?Le(n):null;if(!u){ce(t,c,null);return}u.prepare(n,r,c).forEach(l=>{Ws(n,l,m=>{ce(t,l.icons,m)})})}))}const Xs=(t,s)=>{const n=Hs(t,!0,Tt()),r=Gs(n);if(!r.pending.length){let u=!0;return s&&setTimeout(()=>{u&&s(r.loaded,r.missing,r.pending,nt)}),()=>{u=!1}}const a=Object.create(null),i=[];let c,d;return r.pending.forEach(u=>{const{provider:h,prefix:l}=u;if(l===d&&h===c)return;c=h,d=l,i.push(re(h,l));const m=a[h]||(a[h]=Object.create(null));m[l]||(m[l]=[])}),r.pending.forEach(u=>{const{provider:h,prefix:l,name:m}=u,x=re(h,l),b=x.pendingIcons||(x.pendingIcons=new Set);b.has(m)||(b.add(m),a[h][l].push(m))}),i.forEach(u=>{const h=a[u.provider][u.prefix];h.length&&Ys(u,h)}),s?qs(s,r,i):nt};function Zs(t,s){const n={...t};for(const r in s){const a=s[r],i=typeof a;r in It?(a===null||a&&(i==="string"||i==="number"))&&(n[r]=a):i===typeof n[r]&&(n[r]=r==="rotate"?a%4:a)}return n}const en=/[\s,]+/;function tn(t,s){s.split(en).forEach(n=>{switch(n.trim()){case"horizontal":t.hFlip=!0;break;case"vertical":t.vFlip=!0;break}})}function sn(t,s=0){const n=t.replace(/^-?[0-9.]*/,"");function r(a){for(;a<0;)a+=4;return a%4}if(n===""){const a=parseInt(t);return isNaN(a)?0:r(a)}else if(n!==t){let a=0;switch(n){case"%":a=25;break;case"deg":a=90}if(a){let i=parseFloat(t.slice(0,t.length-n.length));return isNaN(i)?0:(i=i/a,i%1===0?r(i):0)}}return s}function nn(t,s){let n=t.indexOf("xlink:")===-1?"":' xmlns:xlink="http://www.w3.org/1999/xlink"';for(const r in s)n+=" "+r+'="'+s[r]+'"';return'"+t+" "}function an(t){return t.replace(/"/g,"'").replace(/%/g,"%25").replace(/#/g,"%23").replace(//g,"%3E").replace(/\s+/g," ")}function rn(t){return"data:image/svg+xml,"+an(t)}function on(t){return'url("'+rn(t)+'")'}let me;function cn(){try{me=window.trustedTypes.createPolicy("iconify",{createHTML:t=>t})}catch{me=null}}function ln(t){return me===void 0&&cn(),me?me.createHTML(t):t}const At={...Dt,inline:!1},dn={xmlns:"http://www.w3.org/2000/svg",xmlnsXlink:"http://www.w3.org/1999/xlink","aria-hidden":!0,role:"img"},un={display:"inline-block"},Ae={backgroundColor:"currentColor"},$t={backgroundColor:"transparent"},rt={Image:"var(--svg)",Repeat:"no-repeat",Size:"100% 100%"},it={WebkitMask:Ae,mask:Ae,background:$t};for(const t in it){const s=it[t];for(const n in rt)s[t+n]=rt[n]}const mn={...At,inline:!0};function ot(t){return t+(t.match(/^[-0-9.]+$/)?"px":"")}const hn=(t,s,n)=>{const r=s.inline?mn:At,a=Zs(r,s),i=s.mode||"svg",c={},d=s.style||{},u={...i==="svg"?dn:{}};if(n){const g=Ne(n,!1,!0);if(g){const v=["iconify"],p=["provider","prefix"];for(const y of p)g[y]&&v.push("iconify--"+g[y]);u.className=v.join(" ")}}for(let g in s){const v=s[g];if(v!==void 0)switch(g){case"icon":case"style":case"children":case"onLoad":case"mode":case"ssr":case"fallback":break;case"_ref":u.ref=v;break;case"className":u[g]=(u[g]?u[g]+" ":"")+v;break;case"inline":case"hFlip":case"vFlip":a[g]=v===!0||v==="true"||v===1;break;case"flip":typeof v=="string"&&tn(a,v);break;case"color":c.color=v;break;case"rotate":typeof v=="string"?a[g]=sn(v):typeof v=="number"&&(a[g]=v);break;case"ariaHidden":case"aria-hidden":v!==!0&&v!=="true"&&delete u["aria-hidden"];break;default:r[g]===void 0&&(u[g]=v)}}const h=Cs(t,a),l=h.attributes;if(a.inline&&(c.verticalAlign="-0.125em"),i==="svg"){u.style={...c,...d},Object.assign(u,l);let g=0,v=s.id;return typeof v=="string"&&(v=v.replace(/-/g,"_")),u.dangerouslySetInnerHTML={__html:ln(Ts(h.body,v?()=>v+"ID"+g++:"iconifyReact"))},o.createElement("svg",u)}const{body:m,width:x,height:b}=t,j=i==="mask"||(i==="bg"?!1:m.indexOf("currentColor")!==-1),f=nn(m,{...l,width:x+"",height:b+""});return u.style={...c,"--svg":on(f),width:ot(l.width),height:ot(l.height),...un,...j?Ae:$t,...d},o.createElement("span",u)};Tt(!0);Is("",zs);if(typeof document<"u"&&typeof window<"u"){const t=window;if(t.IconifyPreload!==void 0){const s=t.IconifyPreload,n="Invalid IconifyPreload syntax.";typeof s=="object"&&s!==null&&(s instanceof Array?s:[s]).forEach(r=>{try{(typeof r!="object"||r===null||r instanceof Array||typeof r.icons!="object"||typeof r.prefix!="string"||!js(r))&&console.error(n)}catch{console.error(n)}})}if(t.IconifyProviders!==void 0){const s=t.IconifyProviders;if(typeof s=="object"&&s!==null)for(let n in s){const r="IconifyProviders["+n+"] is invalid.";try{const a=s[n];if(typeof a!="object"||!a||a.resources===void 0)continue;Ds(n,a)||console.error(r)}catch{console.error(r)}}}}function Ot(t){const[s,n]=o.useState(!!t.ssr),[r,a]=o.useState({});function i(b){if(b){const j=t.icon;if(typeof j=="object")return{name:"",data:j};const f=Ze(j);if(f)return{name:j,data:f}}return{name:""}}const[c,d]=o.useState(i(!!t.ssr));function u(){const b=r.callback;b&&(b(),a({}))}function h(b){if(JSON.stringify(c)!==JSON.stringify(b))return u(),d(b),!0}function l(){var b;const j=t.icon;if(typeof j=="object"){h({name:"",data:j});return}const f=Ze(j);if(h({name:j,data:f}))if(f===void 0){const g=Xs([j],l);a({callback:g})}else f&&((b=t.onLoad)===null||b===void 0||b.call(t,j))}o.useEffect(()=>(n(!0),u),[]),o.useEffect(()=>{s&&l()},[t.icon,s]);const{name:m,data:x}=c;return x?hn({...Me,...x},t,m):t.children?t.children:t.fallback?t.fallback:o.createElement("span",{})}const fn=o.forwardRef((t,s)=>Ot({...t,_ref:s}));o.forwardRef((t,s)=>Ot({inline:!0,...t,_ref:s}));function S({icon:t,size:s=20,className:n="",style:r}){return e.jsx(fn,{icon:t,width:s,height:s,className:n,style:r})}function $e({icon:t="lucide:inbox",title:s,description:n,command:r,action:a}){return e.jsxs("div",{className:"flex flex-col items-center justify-center py-12 text-center",children:[e.jsx(S,{icon:t,size:32,className:"text-base-content/30 mb-3"}),e.jsx("h3",{className:"text-heading text-base-content/70",children:s}),n&&e.jsx("p",{className:"text-muted text-sm mt-1 max-w-sm",children:n}),r&&e.jsx("div",{className:"mt-3 px-4 py-2 rounded-lg bg-base-100 border border-base-200",children:e.jsx("code",{className:"text-sm font-mono text-primary",children:r})}),a&&e.jsx("div",{className:"mt-4",children:a})]})}const xn={top:"tooltip-top",bottom:"tooltip-bottom",left:"tooltip-left",right:"tooltip-right"};function Y({text:t,children:s,position:n="top"}){return e.jsx("div",{className:`tooltip ${xn[n]} [&::before]:bg-base-300 [&::before]:text-base-content`,"data-tip":t,children:s})}const pn={success:{bg:"alert-success",icon:"lucide:check-circle",iconColor:"text-success-content"},error:{bg:"alert-error",icon:"lucide:x-circle",iconColor:"text-error-content"},info:{bg:"alert-info",icon:"lucide:info",iconColor:"text-info-content"},warning:{bg:"alert-warning",icon:"lucide:alert-triangle",iconColor:"text-warning-content"}};function bn({id:t,type:s,message:n,title:r,duration:a=5e3,dismissible:i=!0,onClick:c,onDismiss:d}){const[u,h]=o.useState(!1),{bg:l,icon:m,iconColor:x}=pn[s];o.useEffect(()=>{if(a>0){const j=setTimeout(()=>{h(!0),setTimeout(()=>d(t),300)},a);return()=>clearTimeout(j)}},[a,t,d]);const b=()=>{h(!0),setTimeout(()=>d(t),300)};return e.jsxs("div",{role:"alert",className:`alert ${l} shadow-lg transition-all duration-300 ${u?"opacity-0 translate-x-4":"opacity-100 translate-x-0"} ${c?"cursor-pointer hover:scale-[1.02]":""}`,onClick:c,children:[e.jsx(S,{icon:m,size:20,className:x}),e.jsxs("div",{className:"flex-1",children:[r&&e.jsx("h3",{className:"font-bold text-sm",children:r}),e.jsx("span",{className:"text-sm",children:n})]}),i&&e.jsx("button",{onClick:j=>{j.stopPropagation(),b()},className:"btn btn-ghost btn-sm btn-circle","aria-label":"Dismiss",children:e.jsx(S,{icon:"lucide:x",size:16})})]})}function gn({toasts:t,onDismiss:s}){return t.length===0?null:e.jsx("div",{className:"toast toast-end toast-bottom z-50",children:t.map(n=>e.jsx(bn,{...n,onDismiss:s},n.id))})}function pe({width:t="100%",height:s="1rem",className:n=""}){return e.jsx("div",{className:`animate-pulse bg-base-300/50 rounded ${n}`,style:{width:t,height:s}})}function jn({lines:t=3,className:s=""}){return e.jsx("div",{className:`space-y-2 ${s}`,children:Array.from({length:t}).map((n,r)=>e.jsx(pe,{width:r===t-1?"60%":"100%",height:"0.75rem"},r))})}function vn({className:t=""}){return e.jsx("div",{className:`card bg-base-100 border border-base-200 shadow-sm ${t}`,children:e.jsxs("div",{className:"card-body animate-pulse",children:[e.jsxs("div",{className:"flex items-center gap-3 mb-3",children:[e.jsx("div",{className:"w-10 h-10 bg-base-300/50 rounded-lg"}),e.jsxs("div",{className:"flex-1 space-y-2",children:[e.jsx(pe,{width:"40%",height:"0.75rem"}),e.jsx(pe,{width:"70%",height:"1.25rem"})]})]}),e.jsx(jn,{lines:2})]})})}function te(){return e.jsxs("div",{className:"space-y-6 animate-pulse",children:[e.jsxs("div",{children:[e.jsx(pe,{width:"12rem",height:"1.75rem"}),e.jsx(pe,{width:"20rem",height:"0.875rem",className:"mt-2"})]}),e.jsx("div",{className:"space-y-3",children:Array.from({length:5}).map((t,s)=>e.jsx(vn,{},s))})]})}function yn({icon:t,label:s,href:n,active:r=!1,badge:a,collapsed:i=!1}){const c=e.jsxs("a",{href:n,className:`nav-item flex items-center gap-3 px-3 py-2.5 rounded-lg transition-all ${r?"active":""} ${i?"justify-center":""}`,children:[e.jsx(S,{icon:t,size:20}),!i&&e.jsxs(e.Fragment,{children:[e.jsx("span",{className:"flex-1",children:s}),a!==void 0&&e.jsx("span",{className:`badge badge-sm ${r?"badge-primary-content":"badge-ghost"}`,children:a})]})]});return i?e.jsx(Y,{text:s,position:"right",children:c}):c}const wn=[{icon:"lucide:layout-dashboard",label:"Dashboard",href:"#/"},{icon:"lucide:history",label:"Sessions",href:"#/sessions"},{icon:"lucide:brain",label:"Memories",href:"#/memories"},{icon:"lucide:lightbulb",label:"Requirements",href:"#/requirements"},{icon:"lucide:scroll",label:"Specifications",href:"#/spec"},{icon:"lucide:puzzle",label:"Extensions",href:"#/extensions"},{icon:"lucide:git-compare",label:"Changes",href:"#/changes"},{icon:"lucide:bar-chart-3",label:"Usage",href:"#/usage"},{icon:"lucide:book-open",label:"Help",href:"#/help"},{icon:"lucide:settings",label:"Settings",href:"#/settings"}];function Nn(t,s){return t===s||t.startsWith(s+"/")}function Sn({currentPath:t,collapsed:s=!1}){return e.jsx("nav",{className:"py-4 space-y-1 px-2",children:wn.map(n=>e.jsx(yn,{icon:n.icon,label:n.label,href:n.href,active:Nn(t,n.href),collapsed:s},n.href))})}const kn={solo:{label:"Solo",variant:"primary"},team:{label:"Team",variant:"accent"},trial:{label:"Trial",variant:"warning"}};function ct(t){return t.isExpired||t.tier==="trial"}function Cn({license:t,isLoading:s,onClick:n}){if(s||!t||!t.tier)return null;const a=ct(t)&&!!n?{onClick:n,role:"button",className:"cursor-pointer"}:{};if(t.isExpired)return e.jsx("span",{...a,children:e.jsx(q,{variant:"error",size:"xs",children:"Expired"})});const i=kn[t.tier];if(!i)return null;let c=i.label;t.tier==="trial"&&t.daysRemaining!=null&&(c=`${i.label} · ${t.daysRemaining}d left`);const d=!ct(t)&&t.email;return e.jsxs("span",{...a,className:`${a.className??""} inline-flex items-center gap-1.5`,children:[e.jsx(q,{variant:i.variant,size:"xs",children:c}),d&&e.jsx("span",{className:"text-base-content/50",children:t.email})]})}function En({open:t,onClose:s,onActivated:n}){const[r,a]=o.useState(""),[i,c]=o.useState(null),[d,u]=o.useState(!1),h=o.useCallback(async()=>{const m=r.trim();if(m){c(null),u(!0);try{const b=await(await fetch("/api/license/activate",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({key:m})})).json();b.success?(a(""),n(),s()):c(b.error??"Activation failed")}catch{c("Connection failed")}finally{u(!1)}}},[r,n,s]),l=o.useCallback(m=>{m.key==="Enter"&&!d&&h()},[h,d]);return e.jsxs(fe,{open:t,onClose:s,title:"Activate License",children:[e.jsxs("div",{className:"flex flex-col gap-3",children:[e.jsx("input",{id:"license-key-input",type:"text",className:"input input-bordered w-full",placeholder:"Enter your license key",value:r,onChange:m=>{a(m.target.value),c(null)},onKeyDown:l,disabled:d,autoFocus:!0}),i&&e.jsx("p",{className:"text-error text-sm",children:i}),e.jsx("div",{className:"bg-base-200/50 rounded-lg p-3 space-y-1.5",children:e.jsxs("p",{className:"text-xs text-base-content/60",children:["Don't have a key? Get one at"," ",e.jsx("a",{href:"https://pilot-shell.com/#pricing",target:"_blank",rel:"noopener noreferrer",className:"text-primary hover:underline font-medium",children:"pilot-shell.com"})]})})]}),e.jsxs("div",{className:"modal-action",children:[e.jsx("button",{className:"btn btn-ghost btn-sm",onClick:s,disabled:d,children:"Cancel"}),e.jsx("button",{className:"btn btn-primary btn-sm",onClick:h,disabled:d||!r.trim(),children:d?"Activating...":"Activate"})]})]})}function Mt(){const[t,s]=o.useState(null),[n,r]=o.useState(!0),a=o.useCallback((c=!1)=>{fetch(c?"/api/license?refresh=1":"/api/license").then(u=>u.json()).then(u=>{s(u),r(!1)}).catch(()=>{r(!1)})},[]);o.useEffect(()=>{a();const c=setInterval(()=>a(!0),6e4),d=()=>{document.visibilityState==="visible"&&a(!0)};return document.addEventListener("visibilitychange",d),()=>{clearInterval(c),document.removeEventListener("visibilitychange",d)}},[a]);const i=o.useCallback(()=>a(!0),[a]);return{license:t,isLoading:n,refetch:i}}const Rn={online:{color:"bg-success",label:"Online"},processing:{color:"bg-warning animate-pulse",label:"Processing"},offline:{color:"bg-error",label:"Offline"}};function Pn({version:t,workerStatus:s="offline",queueDepth:n=0,collapsed:r=!1}){const a=Rn[s],{license:i,isLoading:c,refetch:d}=Mt(),[u,h]=o.useState(!1),l=t?`v${t}`:null;return r?e.jsx("div",{className:"p-3 border-t border-base-300/50 space-y-3",children:e.jsx(Y,{text:`Worker ${a.label}${n>0?` · ${n} queued`:""}`,position:"right",children:e.jsx("div",{className:"flex justify-center",children:e.jsx("span",{className:`inline-block w-2.5 h-2.5 rounded-full ${a.color}`})})})}):e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"p-4 border-t border-base-300/50 space-y-2",children:[e.jsxs("div",{className:"flex items-center justify-between text-xs",children:[e.jsxs("div",{className:"flex items-center gap-1.5",children:[e.jsx("span",{className:`inline-block w-2 h-2 rounded-full ${a.color}`}),e.jsxs("span",{className:"text-base-content/60",children:["Worker ",a.label]}),n>0&&e.jsxs("span",{className:"text-base-content/50",children:["· ",n," queued"]})]}),l&&e.jsx("span",{className:"text-base-content/40",children:l})]}),!c&&(i==null?void 0:i.tier)&&e.jsx("div",{className:"flex items-center gap-2 text-xs",children:e.jsx(Cn,{license:i,isLoading:c,onClick:()=>h(!0)})}),!c&&(!i||!i.tier||i.tier==="trial"||i.isExpired)&&e.jsxs("div",{className:"flex items-center gap-2 text-xs",children:[e.jsx("a",{href:"https://pilot-shell.com/#pricing",target:"_blank",rel:"noopener noreferrer",className:"text-primary/70 hover:text-primary transition-colors",children:"Get a license"}),e.jsxs("button",{onClick:()=>h(!0),className:"btn btn-primary btn-xs gap-1",children:[e.jsx(S,{icon:"lucide:key",size:10}),"Activate"]})]})]}),e.jsx(En,{open:u,onClose:()=>h(!1),onActivated:d})]})}function Tn({currentPath:t,version:s,workerStatus:n,queueDepth:r,collapsed:a,onToggleCollapse:i}){return e.jsxs("aside",{className:`dashboard-sidebar flex flex-col border-r border-base-300 transition-all duration-300 h-screen sticky top-0 ${a?"w-[72px]":"w-64"}`,children:[e.jsxs("div",{className:"flex-shrink-0 flex items-center justify-between p-4 border-b border-base-300/50",children:[!a&&e.jsx(rs,{}),e.jsx("button",{onClick:i,className:"btn btn-ghost btn-sm btn-square",title:a?"Expand sidebar":"Collapse sidebar",children:e.jsx(S,{icon:a?"lucide:panel-left-open":"lucide:panel-left-close",size:18})})]}),e.jsx("div",{className:"flex-1 overflow-y-auto",children:e.jsx(Sn,{currentPath:t,collapsed:a})}),e.jsx("div",{className:"flex-shrink-0",children:e.jsx(Pn,{version:s,workerStatus:n,queueDepth:r,collapsed:a})})]})}function In(t){const s=t.endsWith("Z")?t:t+"Z",n=Date.now()-new Date(s).getTime();return n<6e4?"just now":n<36e5?`${Math.floor(n/6e4)}m ago`:n<864e5?`${Math.floor(n/36e5)}h ago`:`${Math.floor(n/864e5)}d ago`}const Dn={plan_approval:"lucide:file-check",verification_complete:"lucide:check-circle",attention_needed:"lucide:alert-circle"};function _n(t){const s=t.indexOf("/docs/plans/");if(s===-1)return;const n=t.slice(0,s),r=n.lastIndexOf("/");return r>=0?n.slice(r+1):n}function Ln(t){const s=t.split("/").pop();if(!s)return;let n=s.replace(/\.md$/,"");return/^\d{4}-\d{2}-\d{2}-/.test(n)&&(n=n.slice(11)),n}function An({notifications:t,unreadCount:s,onMarkAsRead:n,onMarkAllAsRead:r,onClearAll:a,onNavigate:i}){const[c,d]=o.useState(!1),u=o.useRef(null),h=o.useCallback(m=>{u.current&&!u.current.contains(m.target)&&d(!1)},[]);o.useEffect(()=>{if(c)return document.addEventListener("mousedown",h),()=>document.removeEventListener("mousedown",h)},[c,h]);const l=o.useCallback(m=>{if(m.is_read===0&&n(m.id),d(!1),!!i)if(m.plan_path){const x=_n(m.plan_path);i("/spec",x)}else m.session_id&&i(`/sessions?selected=${m.session_id}`)},[n,i]);return e.jsxs("div",{className:"relative",ref:u,children:[e.jsx(Y,{text:"Notifications",position:"bottom",children:e.jsx(W,{variant:"ghost",size:"sm",onClick:()=>d(!c),children:e.jsxs("div",{className:"relative",children:[e.jsx(S,{icon:"lucide:bell",size:18}),s>0&&e.jsx("span",{className:"absolute -top-1.5 -right-1.5 bg-error text-error-content text-[10px] font-bold rounded-full min-w-[16px] h-4 flex items-center justify-center px-0.5",children:s>99?"99+":s})]})})}),c&&e.jsxs("div",{className:"absolute right-0 top-full mt-2 w-80 max-h-96 overflow-y-auto rounded-xl border border-base-300 bg-base-100 shadow-xl z-50",children:[e.jsxs("div",{className:"flex items-center justify-between px-4 py-3 border-b border-base-300",children:[e.jsx("span",{className:"text-sm font-semibold",children:"Notifications"}),e.jsxs("div",{className:"flex items-center gap-3",children:[s>0&&e.jsx("button",{className:"text-xs text-primary hover:underline",onClick:()=>r(),children:"Mark all read"}),t.length>0&&e.jsx("button",{className:"text-xs text-error/70 hover:text-error hover:underline",onClick:()=>{a(),d(!1)},children:"Clear all"})]})]}),t.length===0?e.jsx("div",{className:"px-4 py-8 text-center text-sm text-base-content/50",children:"No notifications"}):e.jsx("div",{className:"divide-y divide-base-300",children:t.map(m=>e.jsx("button",{className:`w-full text-left px-4 py-3 hover:bg-base-200/50 transition-colors ${m.is_read===0?"bg-primary/5":""}`,onClick:()=>l(m),children:e.jsxs("div",{className:"flex items-start gap-3",children:[e.jsx(S,{icon:Dn[m.type]||"lucide:info",size:16,className:`mt-0.5 flex-shrink-0 ${m.is_read===0?"text-primary":"text-base-content/40"}`}),e.jsxs("div",{className:"min-w-0 flex-1",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:`text-sm truncate ${m.is_read===0?"font-medium":""}`,children:m.plan_path?Ln(m.plan_path)??m.title:m.title}),m.is_read===0&&e.jsx("span",{className:"w-2 h-2 rounded-full bg-primary flex-shrink-0"})]}),e.jsx("p",{className:"text-xs text-base-content/60 mt-0.5 line-clamp-2",children:m.message}),e.jsx("span",{className:"text-[10px] text-base-content/40 mt-1 block",children:In(m.created_at)})]})]})},m.id))})]})]})}function $n(){const[t,s]=o.useState([]),[n,r]=o.useState(0),a=o.useRef(!0),i=o.useCallback(async()=>{try{const h=await fetch("/api/notifications?limit=50&include_read=true");if(!h.ok)return;const l=await h.json();a.current&&(s(l),r(l.filter(m=>m.is_read===0).length))}catch{}},[]),c=o.useCallback(async h=>{s(l=>l.map(m=>m.id===h?{...m,is_read:1}:m)),r(l=>Math.max(0,l-1));try{(await fetch(`/api/notifications/${h}/read`,{method:"PATCH"})).ok||(s(m=>m.map(x=>x.id===h?{...x,is_read:0}:x)),r(m=>m+1))}catch{s(l=>l.map(m=>m.id===h?{...m,is_read:0}:m)),r(l=>l+1)}},[]),d=o.useCallback(async()=>{const h=t,l=n;s(m=>m.map(x=>({...x,is_read:1}))),r(0);try{(await fetch("/api/notifications/read-all",{method:"POST"})).ok||(s(h),r(l))}catch{s(h),r(l)}},[t,n]);o.useEffect(()=>{a.current=!0,i();const h=new EventSource("/stream");return h.addEventListener("open",()=>{i()}),h.onmessage=l=>{try{const m=JSON.parse(l.data);if(m.type==="new_notification"&&m.notification&&a.current){const x=m.notification;s(b=>b.some(j=>j.id===x.id)?b:[x,...b]),r(b=>b+1)}}catch{}},()=>{a.current=!1,h.close()}},[i]);const u=o.useCallback(async()=>{s([]),r(0);try{await fetch("/api/notifications",{method:"DELETE"})}catch{i()}},[i]);return{notifications:t,unreadCount:n,markAsRead:c,markAllAsRead:d,clearAll:u,refresh:i}}const zt="pilot-memory-theme";function On(){return typeof window>"u"||window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light"}function lt(){try{const t=localStorage.getItem(zt);if(t==="system"||t==="light"||t==="dark")return t}catch(t){console.warn("Failed to read theme preference from localStorage:",t)}return"system"}function dt(t){return t==="system"?On():t}function ut(t){return t==="dark"?"pilot-shell":"pilot-shell-light"}function Ft(){const[t,s]=o.useState(lt),[n,r]=o.useState(()=>dt(lt()));return o.useEffect(()=>{const i=dt(t);r(i),document.documentElement.setAttribute("data-theme",ut(i))},[t]),o.useEffect(()=>{if(t!=="system")return;const i=window.matchMedia("(prefers-color-scheme: dark)"),c=d=>{const u=d.matches?"dark":"light";r(u),document.documentElement.setAttribute("data-theme",ut(u))};return i.addEventListener("change",c),()=>i.removeEventListener("change",c)},[t]),{preference:t,resolvedTheme:n,setThemePreference:i=>{try{localStorage.setItem(zt,i),s(i)}catch(c){console.warn("Failed to save theme preference to localStorage:",c),s(i)}}}}const Ut=o.createContext(null);let Mn=0;function zn({children:t}){const[s,n]=o.useState([]),r=o.useCallback(l=>{const m=`toast-${++Mn}`;return n(x=>[...x,{...l,id:m}]),m},[]),a=o.useCallback(l=>{n(m=>m.filter(x=>x.id!==l))},[]),i=o.useCallback(()=>{n([])},[]),c=o.useCallback((l,m)=>r({type:"success",message:l,title:m}),[r]),d=o.useCallback((l,m)=>r({type:"error",message:l,title:m,duration:8e3}),[r]),u=o.useCallback((l,m)=>r({type:"info",message:l,title:m}),[r]),h=o.useCallback((l,m)=>r({type:"warning",message:l,title:m,duration:7e3}),[r]);return e.jsxs(Ut.Provider,{value:{addToast:r,removeToast:a,clearAll:i,success:c,error:d,info:u,warning:h},children:[t,e.jsx(gn,{toasts:s,onDismiss:a})]})}function qt(){const t=o.useContext(Ut);if(!t)throw new Error("useToast must be used within a ToastProvider");return t}const le="pilot-memory-selected-project",Fn={selectedProject:null,projects:[],setSelectedProject:()=>{},setProjects:()=>{},refreshProjects:async()=>{}},Gt=o.createContext(Fn);function Un({children:t}){const[s,n]=o.useState(()=>{try{return localStorage.getItem(le)||null}catch{return null}}),[r,a]=o.useState([]),i=o.useCallback(u=>{n(u);try{u?localStorage.setItem(le,u):localStorage.removeItem(le)}catch{}},[]),c=o.useCallback(u=>{a(u)},[]),d=o.useCallback(async()=>{try{const h=await(await fetch("/api/projects")).json(),l=h.projects||[],m=h.workspaceProject;a(l),n(x=>{if(x&&l.includes(x))return x;if(m&&l.includes(m)){try{localStorage.setItem(le,m)}catch{}return m}if(l.length>0){try{localStorage.setItem(le,l[0])}catch{}return l[0]}return x})}catch{}},[]);return o.useEffect(()=>{d()},[d]),o.useEffect(()=>{if(s&&r.length>0&&!r.includes(s)){const u=r[0]||null;i(u)}},[r,s,i]),e.jsx(Gt.Provider,{value:{selectedProject:s,projects:r,setSelectedProject:i,setProjects:c,refreshProjects:d},children:t})}function X(){return o.useContext(Gt)}function se(){const[t,s]=o.useState(()=>typeof window<"u"?mt(window.location.hash):{path:"/",params:{}});o.useEffect(()=>{if(typeof window>"u")return;const r=()=>{s(mt(window.location.hash))};return window.addEventListener("hashchange",r),()=>window.removeEventListener("hashchange",r)},[]);const n=o.useCallback(r=>{window.location.hash=r},[]);return{path:t.path,params:t.params,navigate:n}}function mt(t){const s=t.replace(/^#/,"")||"/",n={},[r,a]=s.split("?");return a&&new URLSearchParams(a).forEach((c,d)=>{n[d]=c}),{path:r,params:n}}function qn({onToggleTheme:t,onToggleLogs:s}){const{resolvedTheme:n}=Ft(),[r,a]=o.useState(!1),[i,c]=o.useState(!1),{setSelectedProject:d,projects:u}=X(),{navigate:h}=se(),{notifications:l,unreadCount:m,markAsRead:x,markAllAsRead:b,clearAll:j}=$n(),f=o.useCallback((v,p)=>{p&&u.includes(p)&&d(p),h(v)},[h,d,u]);o.useEffect(()=>{fetch("/api/auth/status").then(v=>v.json()).then(v=>{a(v.authRequired)}).catch(()=>{a(!1)})},[]);const g=async()=>{c(!0);try{await fetch("/api/auth/logout",{method:"POST"}),window.location.href="/login"}catch{c(!1)}};return e.jsxs("div",{className:"flex items-center gap-2",children:[s&&e.jsx(Y,{text:"Toggle console logs",position:"bottom",children:e.jsx(W,{variant:"ghost",size:"sm",onClick:s,children:e.jsx(S,{icon:"lucide:terminal",size:18})})}),e.jsx(Y,{text:`Switch to ${n==="light"?"dark":"light"} mode`,position:"bottom",children:e.jsx(W,{variant:"ghost",size:"sm",onClick:t,children:e.jsx(S,{icon:n==="light"?"lucide:moon":"lucide:sun",size:18})})}),e.jsx(Y,{text:"Repository",position:"bottom",children:e.jsx("a",{href:"https://github.com/maxritter/pilot-shell",target:"_blank",rel:"noopener noreferrer",className:"btn btn-ghost btn-sm",children:e.jsx(S,{icon:"lucide:git-branch",size:18})})}),r&&e.jsx(Y,{text:"Logout",position:"bottom",children:e.jsx(W,{variant:"ghost",size:"sm",onClick:g,disabled:i,children:e.jsx(S,{icon:"lucide:log-out",size:18})})}),e.jsx(An,{notifications:l,unreadCount:m,onMarkAsRead:x,onMarkAllAsRead:b,onClearAll:j,onNavigate:f})]})}const Gn=10080*60*1e3,ht=3,Hn={plan:"Plan",implement:"Impl",verify:"Verify"},Vn={plan:"text-info",implement:"text-warning",verify:"text-accent"};function Bn(t){const s=[],n=/^- \[(x| )\] Task (\d+):\s*(.+)$/gm;let r;for(;(r=n.exec(t))!==null;)s.push({number:parseInt(r[2],10),title:r[3],completed:r[1]==="x"});return s}function Kn({spec:t,tasks:s,loading:n}){const r=s?s.findIndex(a=>!a.completed):-1;return e.jsxs("div",{className:"absolute top-full left-0 mt-1 z-50 w-72 rounded-lg border border-base-300 bg-base-100 shadow-xl p-3 text-xs invisible opacity-0 group-hover:visible group-hover:opacity-100 transition-opacity pointer-events-none",children:[e.jsxs("div",{className:"flex items-center gap-1.5 mb-2 pb-2 border-b border-base-300/50",children:[t.specType&&e.jsx(S,{icon:t.specType==="Bugfix"?"lucide:bug":"lucide:sparkles",size:12,className:t.specType==="Bugfix"?"text-error":"text-info"}),e.jsx("span",{className:"font-semibold truncate",children:t.name}),t.project&&e.jsxs("span",{className:"text-base-content/50 truncate",children:["· ",t.project]})]}),n&&!s&&e.jsx("div",{className:"text-base-content/50 italic",children:"Loading tasks…"}),s&&s.length===0&&e.jsx("div",{className:"text-base-content/50 italic",children:"No tasks yet"}),s&&s.length>0&&e.jsx("ul",{className:"space-y-1 max-h-60 overflow-y-auto",children:s.map((a,i)=>{const c=i===r;return e.jsxs("li",{className:`flex items-start gap-1.5 ${a.completed?"text-base-content/40 line-through":c?"text-primary font-medium":"text-base-content/80"}`,children:[e.jsx(S,{icon:a.completed?"lucide:check-circle":c?"lucide:play-circle":"lucide:circle",size:11,className:"flex-shrink-0 mt-0.5"}),e.jsxs("span",{className:"truncate",children:[a.number,". ",a.title]})]},a.number)})})]})}function Wn({spec:t,onClick:s,onRequestTasks:n,tasks:r,loadingTasks:a}){const i=t.status==="PENDING"&&!t.approved;return e.jsxs("div",{className:"relative group",onMouseEnter:n,onFocus:n,children:[e.jsxs("button",{onClick:s,className:`flex items-center gap-1.5 px-2.5 py-1 rounded-lg border border-base-300 bg-base-200/60 hover:bg-base-200 transition-colors text-xs cursor-pointer whitespace-nowrap ${i?"animate-pulse":""}`,"aria-label":`${t.name}${t.specType?` (${t.specType})`:""}`,children:[t.specType&&e.jsx(S,{icon:t.specType==="Bugfix"?"lucide:bug":"lucide:sparkles",size:12,className:t.specType==="Bugfix"?"text-error":"text-info","aria-label":t.specType}),t.project&&e.jsx("span",{className:"text-base-content/40 font-medium truncate max-w-20",children:t.project}),e.jsx("span",{className:"font-medium truncate max-w-28",children:t.name}),e.jsxs("span",{className:"text-base-content/50 font-mono",children:[t.completed,"/",t.total]}),e.jsx("span",{className:`font-medium ${Vn[t.phase]||""}`,children:Hn[t.phase]||t.phase})]}),e.jsx(Kn,{spec:t,tasks:r,loading:a})]})}function Jn({specs:t,onPick:s}){return e.jsxs("div",{className:"dropdown dropdown-end dropdown-bottom",children:[e.jsxs("div",{tabIndex:0,role:"button",className:"px-2 py-1 rounded-lg border border-base-300 bg-base-200/60 hover:bg-base-200 transition-colors text-xs font-medium cursor-pointer","aria-label":`${t.length} more specs`,children:["+",t.length]}),e.jsx("ul",{tabIndex:0,className:"dropdown-content menu bg-base-100 rounded-box z-50 w-72 p-2 shadow-lg border border-base-200 mt-1",children:t.map(n=>e.jsx("li",{children:e.jsxs("button",{onClick:()=>s(n),className:"flex items-center gap-2 text-xs",children:[n.specType&&e.jsx(S,{icon:n.specType==="Bugfix"?"lucide:bug":"lucide:sparkles",size:12,className:n.specType==="Bugfix"?"text-error":"text-info"}),n.project&&e.jsx("span",{className:"text-base-content/40 truncate max-w-20",children:n.project}),e.jsx("span",{className:"font-medium truncate flex-1",children:n.name}),e.jsxs("span",{className:"text-base-content/50 font-mono",children:[n.completed,"/",n.total]})]})},n.filePath))})]})}function Qn(){const[t,s]=o.useState([]),[n,r]=o.useState({}),[a,i]=o.useState({}),{setSelectedProject:c,projects:d}=X(),{navigate:u}=se(),h=o.useRef(),l=o.useCallback(async()=>{try{const f=await fetch("/api/plans/active/all");if(!f.ok)return;const v=(await f.json()).specs||[],p=Date.now();s(v.filter(y=>y.status!=="VERIFIED"&&p-new Date(y.modifiedAt).getTime()(l(),h.current=setInterval(l,1e4),()=>clearInterval(h.current)),[l]);const m=o.useCallback(async f=>{const g=n[f.filePath];if(!(g&&g.modifiedAt===f.modifiedAt)&&!a[f.filePath]){i(v=>({...v,[f.filePath]:!0}));try{const v=f.project?`&project=${encodeURIComponent(f.project)}`:"",p=await fetch(`/api/plan/content?path=${encodeURIComponent(f.filePath)}${v}`);if(!p.ok)return;const y=await p.json(),C=Bn(y.content||"");r(I=>({...I,[f.filePath]:{modifiedAt:f.modifiedAt,tasks:C}}))}catch{}finally{i(v=>({...v,[f.filePath]:!1}))}}},[n,a]),x=o.useCallback(f=>{f.project&&d.includes(f.project)&&c(f.project);const g=encodeURIComponent(f.filePath);u(`/spec?path=${g}`)},[u,c,d]);if(t.length===0)return null;const b=t.slice(0,ht),j=t.slice(ht);return e.jsxs("div",{className:"flex items-center gap-2 min-w-0",children:[b.map(f=>{var g;return e.jsx(Wn,{spec:f,onClick:()=>x(f),onRequestTasks:()=>m(f),tasks:((g=n[f.filePath])==null?void 0:g.tasks)||null,loadingTasks:!!a[f.filePath]},f.filePath)}),j.length>0&&e.jsx(Jn,{specs:j,onPick:x})]})}function Yn({onToggleTheme:t,onToggleLogs:s}){return e.jsxs("header",{className:"h-14 bg-base-100 border-b border-base-300/50 flex items-center px-6 gap-4",children:[e.jsx("div",{className:"flex-1 min-w-0",children:e.jsx(Qn,{})}),e.jsx(qn,{onToggleTheme:t,onToggleLogs:s})]})}function Xn({children:t,currentPath:s,version:n,workerStatus:r,queueDepth:a,onToggleTheme:i,onToggleLogs:c,sidebarCollapsed:d,onToggleSidebar:u}){return e.jsxs("div",{className:"dashboard-layout flex h-screen",children:[e.jsx(Tn,{currentPath:s,version:n,workerStatus:r,queueDepth:a,collapsed:d,onToggleCollapse:u}),e.jsxs("div",{className:"flex-1 flex flex-col min-w-0 min-h-0",children:[e.jsx(Yn,{onToggleTheme:i,onToggleLogs:c}),e.jsx("main",{className:"flex-1 p-6 overflow-y-auto min-h-0",children:t})]})]})}function Zn({routes:t,fallback:s}){const{path:n}=se();for(const r of t){const a=ea(r.path,n);if(a){const i=r.component;return e.jsx(i,{...a.params})}}return s?e.jsx(e.Fragment,{children:s}):null}function ea(t,s){if(t===s)return{params:{}};const n=t.split("/"),r=s.split("/");if(n.length!==r.length)return null;const a={};for(let i=0;i{const a=setTimeout(()=>{r.current||s(!0)},8e3);return()=>clearTimeout(a)},[]),e.jsxs("div",{className:"h-full flex flex-col",children:[e.jsxs("div",{className:"flex items-center justify-between mb-4",children:[e.jsxs("div",{className:"flex items-baseline gap-3",children:[e.jsx("h1",{className:"text-2xl font-bold",children:"Documentation"}),e.jsx("span",{className:"text-base-content/50 text-sm",children:"Pilot Shell technical reference"})]}),e.jsxs("a",{href:Ce,target:"_blank",rel:"noopener noreferrer",className:"btn btn-sm btn-ghost gap-1.5",children:[e.jsx("svg",{className:"w-4 h-4",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"})}),"Open in browser"]})]}),t?e.jsx("div",{className:"flex-1 flex items-center justify-center",children:e.jsxs("div",{className:"text-center space-y-3",children:[e.jsx("div",{className:"text-4xl",children:"📡"}),e.jsx("p",{className:"text-base-content/60 text-sm",children:"Could not load documentation."}),e.jsx("a",{href:Ce,target:"_blank",rel:"noopener noreferrer",className:"btn btn-primary btn-sm",children:"Open docs in browser"})]})}):e.jsx("iframe",{ref:n,src:Ce,title:"Pilot Shell Documentation",className:"flex-1 w-full rounded-xl border border-base-300 bg-base-100",style:{minHeight:"calc(100vh - 10rem)"},onLoad:()=>{var a;r.current=!0;try{const i=n.current;((a=i==null?void 0:i.contentDocument)==null?void 0:a.title)===""&&s(!0)}catch{}}})]})}const sa={observation:{icon:"lucide:brain",variant:"info",color:"text-info"},summary:{icon:"lucide:file-text",variant:"warning",color:"text-warning"},prompt:{icon:"lucide:message-square",variant:"secondary",color:"text-secondary"},bugfix:{icon:"lucide:bug",variant:"error",color:"text-error"},feature:{icon:"lucide:sparkles",variant:"ghost",color:"text-emerald-400"},refactor:{icon:"lucide:refresh-cw",variant:"accent",color:"text-accent"},discovery:{icon:"lucide:search",variant:"info",color:"text-info"},decision:{icon:"lucide:git-branch",variant:"warning",color:"text-warning"},change:{icon:"lucide:pencil",variant:"secondary",color:"text-secondary"}},na={icon:"lucide:circle",variant:"secondary",color:"text-secondary"};function aa(t,s=50){return t.length<=s?t:t.slice(0,s)+"…"}function ra({memory:t,viewMode:s,onView:n,selectionMode:r,isSelected:a,onToggleSelection:i}){const c=sa[t.type]||na,d=s==="grid",u=()=>{r?i==null||i(t.id):n==null||n(t.id)},h=l=>{l.stopPropagation(),t.sessionDbId&&(window.location.hash=`/sessions?selected=${t.sessionDbId}`)};return e.jsx(H,{className:`hover:shadow-md transition-shadow cursor-pointer ${d?"":"flex flex-row"} ${a?"ring-2 ring-primary":""}`,onClick:u,children:e.jsx(V,{className:d?"p-4":"flex flex-row items-start gap-4 flex-1 p-4",children:e.jsxs("div",{className:`flex items-start gap-3 ${d?"":"flex-1"}`,children:[r?e.jsx("div",{className:"flex items-center justify-center w-8 h-8 flex-shrink-0",children:e.jsx("input",{type:"checkbox",className:"checkbox checkbox-primary",checked:a,onChange:()=>i==null?void 0:i(t.id),onClick:l=>l.stopPropagation()})}):e.jsx("div",{className:`p-2 rounded-lg bg-base-200 ${c.color} shrink-0`,children:e.jsx(S,{icon:c.icon,size:16})}),e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsxs("div",{className:"flex items-center justify-between gap-2 mb-1",children:[e.jsx(q,{variant:c.variant,size:"xs",children:t.type}),e.jsx("span",{className:"text-xs text-base-content/40 shrink-0",children:t.timestamp})]}),e.jsx("h3",{className:"font-medium text-sm line-clamp-2",children:t.title}),e.jsx("div",{className:"mt-1.5",children:t.sessionPrompt&&t.sessionDbId?e.jsxs("button",{onClick:h,className:"text-xs text-primary/70 hover:text-primary hover:underline truncate max-w-full block text-left transition-colors",title:`Session: ${t.sessionPrompt}`,children:[e.jsx(S,{icon:"lucide:terminal",size:11,className:"inline mr-1 -mt-0.5"}),aa(t.sessionPrompt)]}):e.jsx("span",{className:"text-xs text-base-content/30",children:"no session"})})]})]})})})}const ia={observation:{icon:"lucide:brain",variant:"info"},summary:{icon:"lucide:file-text",variant:"warning"},prompt:{icon:"lucide:message-square",variant:"secondary"},bugfix:{icon:"lucide:bug",variant:"error"},feature:{icon:"lucide:sparkles",variant:"success"},refactor:{icon:"lucide:refresh-cw",variant:"accent"},discovery:{icon:"lucide:search",variant:"info"},decision:{icon:"lucide:git-branch",variant:"warning"},change:{icon:"lucide:pencil",variant:"secondary"}};function oa({memory:t,onClose:s}){const n=t?ia[t.type]||{icon:"lucide:circle",variant:"secondary"}:{icon:"lucide:circle",variant:"secondary"};return e.jsx(fe,{open:!!t,onClose:s,title:"Memory Details",children:t&&e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"flex items-start gap-3",children:[e.jsx("div",{className:`p-2.5 rounded-lg bg-base-200 text-${n.variant}`,children:e.jsx(S,{icon:n.icon,size:20})}),e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("h3",{className:"text-base font-semibold leading-tight",children:t.title}),e.jsxs("div",{className:"flex items-center gap-2 mt-1.5 flex-wrap",children:[e.jsx(q,{variant:n.variant,size:"sm",children:t.type}),e.jsxs("span",{className:"text-xs text-base-content/50 flex items-center gap-1",children:[e.jsx(S,{icon:"lucide:folder",size:11}),t.project]}),e.jsx("span",{className:"text-xs text-base-content/40",children:t.timestamp}),e.jsxs("span",{className:"text-xs text-base-content/40 font-mono",children:["#",t.id]})]}),t.concepts&&t.concepts.length>0&&e.jsx("div",{className:"flex flex-wrap gap-1 mt-2",children:t.concepts.map(r=>e.jsx(q,{variant:"ghost",size:"xs",children:r},r))})]})]}),e.jsx("div",{className:"bg-base-200 rounded-lg p-4 max-h-96 overflow-y-auto",children:t.facts&&t.facts.length>0?e.jsx("ul",{className:"text-sm space-y-2 list-disc list-inside",children:t.facts.map((r,a)=>e.jsx("li",{children:r},a))}):e.jsx("pre",{className:"text-sm whitespace-pre-wrap break-words",children:t.content||"No content available"})})]})})}function ca({onSearch:t,isSearching:s,placeholder:n="Search your memories semantically..."}){const[r,a]=o.useState(""),i=c=>{c.preventDefault(),r.trim()&&t(r.trim())};return e.jsxs("form",{onSubmit:i,className:"flex gap-2",children:[e.jsxs("div",{className:"relative flex-1",children:[e.jsx(S,{icon:"lucide:search",size:20,className:"absolute left-4 top-1/2 -translate-y-1/2 text-base-content/50"}),e.jsx("input",{type:"search",placeholder:n,value:r,onChange:c=>a(c.target.value),className:"input input-bordered w-full pl-12 pr-4"})]}),e.jsx(W,{type:"submit",loading:s,disabled:!r.trim(),children:"Search"})]})}const la={observation:{icon:"lucide:brain",variant:"info",label:"Observation"},summary:{icon:"lucide:file-text",variant:"warning",label:"Summary"},prompt:{icon:"lucide:message-square",variant:"secondary",label:"Prompt"},bugfix:{icon:"lucide:bug",variant:"error",label:"Bug Fix"},feature:{icon:"lucide:sparkles",variant:"success",label:"Feature"},refactor:{icon:"lucide:refresh-cw",variant:"accent",label:"Refactor"},discovery:{icon:"lucide:search",variant:"info",label:"Discovery"},decision:{icon:"lucide:git-branch",variant:"warning",label:"Decision"},change:{icon:"lucide:pencil",variant:"secondary",label:"Change"}},da={icon:"lucide:circle",variant:"secondary",label:"Unknown"};function ua(t){try{return new Date(t).toLocaleDateString("en-US",{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit"})}catch{return t}}function ma({result:t}){const s=t.obsType||t.type,n=la[s]||da,r=Math.round(t.score*100),a=i=>i>=.7?"text-success":i>=.4?"text-warning":"text-base-content/50";return e.jsx(H,{className:"hover:shadow-md transition-shadow",children:e.jsx(V,{children:e.jsxs("div",{className:"flex items-start gap-3",children:[e.jsx("div",{className:"p-2 rounded-lg bg-base-200 shrink-0",children:e.jsx(S,{icon:n.icon,size:18})}),e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsxs("div",{className:"flex items-center gap-2 mb-1 flex-wrap",children:[e.jsx(q,{variant:n.variant,size:"xs",children:n.label}),e.jsxs("span",{className:"text-xs text-base-content/50",children:["#",t.id]}),t.score>0&&e.jsxs("span",{className:`ml-auto text-xs font-mono ${a(t.score)}`,children:[r,"% match"]})]}),e.jsx("h3",{className:"font-medium truncate",children:t.title}),e.jsx("p",{className:"text-sm text-base-content/60 mt-1 line-clamp-2",children:t.content}),e.jsxs("div",{className:"flex items-center gap-4 mt-3 text-xs text-base-content/50",children:[t.project&&e.jsxs("span",{className:"flex items-center gap-1",children:[e.jsx(S,{icon:"lucide:folder",size:12}),t.project]}),e.jsxs("span",{className:"flex items-center gap-1",children:[e.jsx(S,{icon:"lucide:clock",size:12}),ua(t.timestamp)]})]})]}),t.score>0&&e.jsxs("div",{className:"w-16 shrink-0 hidden sm:block",children:[e.jsx("div",{className:"h-2 bg-base-200 rounded-full overflow-hidden",children:e.jsx("div",{className:`h-full rounded-full transition-all ${t.score>=.7?"bg-success":t.score>=.4?"bg-warning":"bg-base-content/30"}`,style:{width:`${r}%`}})}),e.jsx("div",{className:"text-[10px] text-center mt-1 text-base-content/50",children:"similarity"})]})]})})})}function we(){const{selectedProject:t,projects:s,setSelectedProject:n}=X();return e.jsxs("div",{className:"relative inline-flex items-center",children:[e.jsx("select",{value:t??s[0]??"",onChange:r=>n(r.target.value),className:"select select-bordered select-sm text-xs font-normal pl-7 pr-8 min-w-[140px] max-w-[200px]",children:s.map(r=>e.jsx("option",{value:r,children:r},r))}),e.jsx(S,{icon:"lucide:folder",size:13,className:"absolute left-2.5 pointer-events-none text-base-content/40"})]})}const ha=12e4;function fa(){const{selectedProject:t}=X(),[s,n]=o.useState(!1),[r,a]=o.useState([]),[i,c]=o.useState(!1),[d,u]=o.useState(null),[h,l]=o.useState(null),m=o.useRef(null),x=o.useRef(!1),b=o.useCallback(async f=>{var p;(p=m.current)==null||p.abort(),x.current=!1;const g=new AbortController;m.current=g;const v=setTimeout(()=>g.abort(),ha);c(!0),n(!0),u(null);try{const y=new URLSearchParams({query:f,limit:"30"});t&&y.set("project",t);const C=await fetch(`/api/search/semantic?${y}`,{signal:g.signal});if(!C.ok)throw new Error(`Search failed with status ${C.status}`);const I=await C.json();a(I.results||[]),l({usedSemantic:I.usedSemantic,vectorDbAvailable:I.vectorDbAvailable})}catch(y){if(x.current)return;y.name==="AbortError"?u("Search timed out. Please try again."):u("Search failed. Please try again."),a([]),l(null)}finally{clearTimeout(v),x.current||c(!1)}},[t]),j=o.useCallback(()=>{var f;x.current=!0,(f=m.current)==null||f.abort(),n(!1),a([]),l(null),u(null),c(!1)},[]);return o.useEffect(()=>()=>{var f;(f=m.current)==null||f.abort()},[]),{isSearchMode:s,searchResults:r,isSearching:i,searchError:d,searchMeta:h,handleSearch:b,handleClearSearch:j}}function ft(){var I;const{params:t}=se(),[s,n]=o.useState([]),[r,a]=o.useState(!0),[i,c]=o.useState(null),d=t.id?Number(t.id):null,u=o.useRef(!1),{selectedProject:h}=X(),{isSearchMode:l,searchResults:m,isSearching:x,searchError:b,searchMeta:j,handleSearch:f,handleClearSearch:g}=fa(),v=o.useCallback(async w=>{await f(w)},[f]),p=o.useCallback(async()=>{a(!0);try{const w=new URLSearchParams;h&&w.set("project",h),w.set("limit","50");const L=await(await fetch(`/api/observations?${w}`)).json(),R=L.items||L.observations||[];n(R.map(E=>({id:E.id,type:E.type||"observation",title:E.title||"Untitled",content:E.narrative||E.content||"",facts:E.facts?typeof E.facts=="string"?JSON.parse(E.facts):E.facts:[],project:E.project||"unknown",timestamp:y(E.created_at),concepts:E.concepts?typeof E.concepts=="string"?JSON.parse(E.concepts):E.concepts:[],sessionDbId:E.session_db_id??void 0,sessionPrompt:E.session_prompt??void 0})))}catch(w){console.error("Failed to fetch memories:",w)}finally{a(!1)}},[h]);function y(w){if(!w)return"";const _=new Date(w),R=new Date().getTime()-_.getTime();return R<6e4?"just now":R<36e5?`${Math.floor(R/6e4)}m ago`:R<864e5?`${Math.floor(R/36e5)}h ago`:_.toLocaleDateString()}o.useEffect(()=>{p()},[p]),o.useEffect(()=>{if(d&&!u.current&&!r&&s.length>0){const w=s.find(_=>_.id===d);w&&(u.current=!0,c(w))}},[d,r,s]);const C=w=>{const _=s.find(L=>L.id===w);_&&c(_)};return e.jsxs("div",{className:"space-y-6",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"flex items-center gap-3 flex-wrap",children:[e.jsx("h1",{className:"text-2xl font-bold",children:"Memories"}),e.jsx(we,{}),e.jsx("span",{className:"text-base-content/50 text-sm",children:"Decisions, discoveries, and patterns from past sessions"})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[l&&e.jsxs(W,{variant:"ghost",size:"sm",onClick:g,children:[e.jsx(S,{icon:"lucide:x",size:16,className:"mr-1"}),"Clear"]}),!l&&e.jsx(W,{variant:"ghost",size:"sm",onClick:p,children:e.jsx(S,{icon:"lucide:refresh-cw",size:16})})]})]}),!l&&e.jsxs("div",{className:"bg-base-200/40 rounded-xl p-4 space-y-2",children:[e.jsx("p",{className:"text-xs font-semibold text-base-content/50 uppercase tracking-wider",children:"How Memories Work"}),e.jsxs("div",{className:"grid sm:grid-cols-3 gap-3 text-sm text-base-content/60",children:[e.jsxs("div",{className:"flex items-start gap-2",children:[e.jsx(S,{icon:"lucide:scan",size:14,className:"text-violet-400 flex-shrink-0 mt-0.5"}),e.jsxs("p",{children:[e.jsx("span",{className:"font-medium text-base-content/70",children:"Capture"})," — hooks observe each session and send events to a background Haiku model that extracts decisions, discoveries, and patterns"]})]}),e.jsxs("div",{className:"flex items-start gap-2",children:[e.jsx(S,{icon:"lucide:database",size:14,className:"text-sky-400 flex-shrink-0 mt-0.5"}),e.jsxs("p",{children:[e.jsx("span",{className:"font-medium text-base-content/70",children:"Store"})," — observations are persisted in a local SQLite database with full-text and semantic search"]})]}),e.jsxs("div",{className:"flex items-start gap-2",children:[e.jsx(S,{icon:"lucide:rotate-cw",size:14,className:"text-emerald-400 flex-shrink-0 mt-0.5"}),e.jsxs("p",{children:[e.jsx("span",{className:"font-medium text-base-content/70",children:"Re-inject"})," — at session start, relevant memories are loaded back into context so Claude remembers your conventions and past decisions"]})]})]})]}),e.jsx(ca,{onSearch:v,isSearching:x,placeholder:"Search memories semantically..."}),b&&!x&&e.jsxs("div",{className:"alert alert-error",children:[e.jsx(S,{icon:"lucide:alert-circle",size:16}),e.jsx("span",{children:b})]}),l?x?e.jsx(te,{}):b?null:m.length===0?e.jsx($e,{icon:"lucide:search-x",title:"No results found",description:"Try a different query"}):e.jsxs("div",{className:"space-y-3",children:[e.jsxs("div",{className:"text-sm text-base-content/60",children:[m.length," results",(j==null?void 0:j.usedSemantic)&&((I=m[0])==null?void 0:I.score)>0&&e.jsxs("span",{className:"ml-2",children:["(best match: ",Math.round(m[0].score*100),"% similarity)"]})]}),m.map(w=>e.jsx(ma,{result:w},`${w.type}-${w.id}`))]}):r?e.jsx(te,{}):s.length===0?e.jsx($e,{icon:"lucide:brain",title:"No memories yet",description:"Memories are created automatically as you use Claude Code — decisions, discoveries, and patterns are captured in the background."}):e.jsx("div",{className:"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4",children:s.map(w=>e.jsx(ra,{memory:w,viewMode:"grid",onView:C,selectionMode:!1,isSelected:!1,onToggleSelection:()=>{}},w.id))}),e.jsx(oa,{memory:i,onClose:()=>c(null)})]})}const xt={active:{variant:"warning",icon:"lucide:play"},completed:{variant:"success",icon:"lucide:check"}};function xa(t){return new Date(t).toLocaleDateString("en-US",{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit"})}function pa({sessionId:t}){const[s,n]=o.useState(!1),r=a=>{a.stopPropagation(),navigator.clipboard.writeText(t).then(()=>{n(!0),setTimeout(()=>n(!1),2e3)})};return e.jsxs("button",{onClick:r,className:"flex items-center gap-1.5 px-2 py-0.5 rounded bg-base-200 hover:bg-base-300 transition-colors text-xs font-mono text-base-content/60 group",title:"Copy session ID for /resume",children:[e.jsx("span",{className:"truncate max-w-32",children:t}),e.jsx(S,{icon:s?"lucide:check":"lucide:copy",size:12,className:s?"text-success":"text-base-content/40 group-hover:text-base-content/70"})]})}function Ee({icon:t,value:s,label:n}){return e.jsxs("div",{className:"flex flex-col items-center min-w-[4.5rem]",children:[e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(S,{icon:t,size:13,className:"text-base-content/40"}),e.jsx("span",{className:"font-semibold text-sm tabular-nums",children:s})]}),e.jsx("span",{className:"text-[10px] text-base-content/40 uppercase tracking-wider",children:n})]})}function ba(t){return t<.01?"<$0.01":t<1?`$${t.toFixed(2)}`:`$${t.toFixed(2)}`}function ga({session:t,isExpanded:s,onToggle:n,isResumed:r,costUsd:a}){const i=xt[t.status]||xt.active;return e.jsx(H,{className:`cursor-pointer hover:shadow-md transition-shadow ${s?"ring-2 ring-primary":""} ${t.status==="active"?"border-l-4 border-l-warning":""}`,onClick:n,children:e.jsx(V,{children:e.jsxs("div",{className:"flex items-start gap-4",children:[e.jsx("div",{className:"p-2 rounded-lg bg-base-200 shrink-0",children:e.jsx(S,{icon:i.icon,size:20,className:`text-${i.variant}`})}),e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsxs("div",{className:"flex items-center gap-2 mb-1 flex-wrap",children:[e.jsx(q,{variant:i.variant,size:"sm",children:t.status}),r&&e.jsx(q,{variant:"info",size:"sm",children:"resumed"}),t.content_session_id&&e.jsx(pa,{sessionId:t.content_session_id})]}),e.jsx("h3",{className:"font-medium line-clamp-1",children:t.user_prompt||t.project||"Untitled Session"}),e.jsxs("div",{className:"flex items-center gap-4 mt-2 text-sm text-base-content/60",children:[e.jsxs("span",{className:"flex items-center gap-1",children:[e.jsx(S,{icon:"lucide:folder",size:14}),t.project]}),e.jsxs("span",{className:"flex items-center gap-1",children:[e.jsx(S,{icon:"lucide:calendar",size:14}),xa(t.started_at)]})]})]}),e.jsxs("div",{className:"flex items-center gap-3 shrink-0",children:[e.jsx(Ee,{icon:"lucide:dollar-sign",value:a!=null?ba(a):"—",label:"Cost"}),e.jsx(Ee,{icon:"lucide:messages-square",value:t.observation_count+t.prompt_count,label:"Messages"}),e.jsx(Ee,{icon:"lucide:message-square",value:t.prompt_count,label:"Prompts"}),e.jsx(S,{icon:s?"lucide:chevron-up":"lucide:chevron-down",size:20,className:"text-base-content/50 ml-1"})]})]})})})}const Re={prompt:{icon:"lucide:message-square",color:"text-primary"},observation:{icon:"lucide:brain",color:"text-info"},bugfix:{icon:"lucide:bug",color:"text-error"},feature:{icon:"lucide:sparkles",color:"text-emerald-400"},refactor:{icon:"lucide:refresh-cw",color:"text-accent"},discovery:{icon:"lucide:search",color:"text-info"},decision:{icon:"lucide:git-branch",color:"text-warning"},change:{icon:"lucide:pencil",color:"text-secondary"}};function ja(t){return new Date(t).toLocaleTimeString("en-US",{hour:"2-digit",minute:"2-digit"})}function va({sessionId:t,skipHeader:s}){const[n,r]=o.useState(null),[a,i]=o.useState(!0),[c,d]=o.useState(new Set);o.useEffect(()=>{async function l(){i(!0);try{const x=await(await fetch(`/api/sessions/${t}/timeline`)).json();r(x)}catch(m){console.error("Failed to fetch timeline:",m)}finally{i(!1)}}l()},[t]);const u=l=>{d(m=>{const x=new Set(m);return x.has(l)?x.delete(l):x.add(l),x})};if(a)return e.jsx("div",{className:"space-y-3 animate-pulse py-4",children:Array.from({length:3}).map((l,m)=>e.jsx("div",{className:"h-16 bg-base-300/50 rounded-lg"},m))});if(!n)return e.jsx("div",{className:"text-center py-8 text-base-content/50",children:"Failed to load timeline"});const h={active:"badge-success",completed:"badge-info",failed:"badge-error"};return e.jsxs("div",{className:"mt-4 space-y-4",children:[!s&&e.jsxs(e.Fragment,{children:[e.jsx(H,{className:"bg-base-200/50",children:e.jsxs(V,{className:"py-3",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-3 mb-2",children:[e.jsx(q,{variant:"ghost",size:"sm",className:h[n.session.status]||"",children:n.session.status}),e.jsx("span",{className:"text-sm text-base-content/60",children:new Date(n.session.started_at).toLocaleString()}),n.session.completed_at&&e.jsxs("span",{className:"text-sm text-base-content/60",children:["→ ",new Date(n.session.completed_at).toLocaleString()]})]}),e.jsxs("div",{className:"flex flex-wrap gap-4 text-sm",children:[e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(S,{icon:"lucide:message-square",size:14,className:"text-primary"}),e.jsx("span",{className:"font-medium",children:n.stats.prompts}),e.jsx("span",{className:"text-base-content/60",children:"prompts"})]}),e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(S,{icon:"lucide:brain",size:14,className:"text-info"}),e.jsx("span",{className:"font-medium",children:n.stats.observations}),e.jsx("span",{className:"text-base-content/60",children:"observations"})]})]})]})}),n.session.user_prompt&&e.jsx(H,{className:"bg-primary/10 border-primary/30",children:e.jsxs(V,{className:"py-3",children:[e.jsxs("div",{className:"flex items-center gap-2 mb-2",children:[e.jsx(S,{icon:"lucide:terminal",size:16,className:"text-primary"}),e.jsx("span",{className:"font-medium text-sm",children:"Prompt"})]}),e.jsx("p",{className:"text-sm text-base-content/80 whitespace-pre-wrap",children:n.session.user_prompt})]})}),n.summary&&e.jsx(H,{className:"bg-warning/10 border-warning/30",children:e.jsxs(V,{className:"py-3",children:[e.jsxs("div",{className:"flex items-center gap-2 mb-3",children:[e.jsx(S,{icon:"lucide:file-text",size:16,className:"text-warning"}),e.jsx("span",{className:"font-medium text-sm",children:"Session Summary"}),e.jsx("span",{className:"text-xs text-base-content/50",children:new Date(n.summary.created_at).toLocaleTimeString()})]}),e.jsxs("div",{className:"space-y-3 text-sm",children:[n.summary.request&&e.jsxs("div",{children:[e.jsx("div",{className:"font-medium text-warning mb-1",children:"Request"}),e.jsx("div",{className:"text-base-content/80",children:n.summary.request})]}),n.summary.investigated&&e.jsxs("div",{children:[e.jsx("div",{className:"font-medium text-info mb-1",children:"Investigated"}),e.jsx("div",{className:"text-base-content/80",children:n.summary.investigated})]}),n.summary.learned&&e.jsxs("div",{children:[e.jsx("div",{className:"font-medium text-success mb-1",children:"Learned"}),e.jsx("div",{className:"text-base-content/80",children:n.summary.learned})]}),n.summary.completed&&e.jsxs("div",{children:[e.jsx("div",{className:"font-medium text-primary mb-1",children:"Completed"}),e.jsx("div",{className:"text-base-content/80",children:n.summary.completed})]}),n.summary.next_steps&&e.jsxs("div",{children:[e.jsx("div",{className:"font-medium text-accent mb-1",children:"Next Steps"}),e.jsx("div",{className:"text-base-content/80",children:n.summary.next_steps})]})]})]})})]}),e.jsxs("div",{className:"ml-8 border-l-2 border-base-300 pl-6 space-y-4",children:[[...n.timeline].reverse().map((l,m)=>{var g,v;const x=`${l.type}-${l.id}`,b=c.has(x),j=l.type==="prompt"?Re.prompt:Re[l.data.type]||Re.observation;let f=[];if(l.type==="observation"&&l.data.concepts)try{f=JSON.parse(l.data.concepts)}catch{}return e.jsxs("div",{className:"relative",children:[e.jsx("div",{className:`absolute -left-9 top-3 w-4 h-4 rounded-full border-2 border-base-100 ${l.type==="prompt"?"bg-primary":"bg-info"}`}),e.jsx(H,{className:"cursor-pointer hover:shadow-sm transition-shadow",onClick:p=>{p.stopPropagation(),u(x)},children:e.jsx(V,{className:"py-3",children:e.jsxs("div",{className:"flex items-start gap-3",children:[e.jsx("div",{className:`p-1.5 rounded bg-base-200 ${j.color}`,children:e.jsx(S,{icon:j.icon,size:14})}),e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-2 mb-1",children:[e.jsx(q,{variant:l.type==="prompt"?"primary":"info",size:"xs",children:l.type==="prompt"?`prompt #${l.data.prompt_number||"?"}`:l.data.type||"observation"}),e.jsx("span",{className:"text-xs text-base-content/50",children:ja(l.timestamp)}),e.jsxs("span",{className:"text-xs text-base-content/40",children:["#",l.id]}),f.length>0&&f.map(p=>e.jsx(q,{variant:"ghost",size:"xs",className:"text-base-content/50",children:p},p))]}),e.jsx("p",{className:"text-sm font-medium",children:l.type==="prompt"?((g=l.data.prompt_text)==null?void 0:g.length)>100?l.data.prompt_text.substring(0,100)+"...":l.data.prompt_text:l.data.title||"Untitled"}),l.type==="observation"&&l.data.narrative&&e.jsx("p",{className:`text-sm text-base-content/70 mt-1 ${b?"":"line-clamp-3"}`,children:l.data.narrative}),l.type==="prompt"&&((v=l.data.prompt_text)==null?void 0:v.length)>100&&e.jsx("p",{className:`text-sm text-base-content/70 mt-1 ${b?"whitespace-pre-wrap":"line-clamp-3"}`,children:b?l.data.prompt_text:l.data.prompt_text.substring(100)}),l.type==="observation"&&(l.data.files_read||l.data.files_modified)&&e.jsxs("div",{className:"flex flex-wrap gap-2 mt-2",children:[l.data.files_read&&(()=>{try{const p=JSON.parse(l.data.files_read);if(p.length>0)return e.jsxs("span",{className:"text-xs text-base-content/50",children:[e.jsx(S,{icon:"lucide:file",size:12,className:"inline mr-1"}),p.length," read"]})}catch{return null}})(),l.data.files_modified&&(()=>{try{const p=JSON.parse(l.data.files_modified);if(p.length>0)return e.jsxs("span",{className:"text-xs text-base-content/50",children:[e.jsx(S,{icon:"lucide:pencil",size:12,className:"inline mr-1"}),p.length," modified"]})}catch{return null}})()]}),b&&l.type==="observation"&&l.data.text&&e.jsxs("div",{className:"mt-3 pt-3 border-t border-base-200",children:[e.jsx("p",{className:"text-sm text-base-content/70 whitespace-pre-wrap",children:l.data.text}),(l.data.files_read||l.data.files_modified)&&e.jsxs("div",{className:"mt-3 space-y-1",children:[l.data.files_read&&(()=>{try{const p=JSON.parse(l.data.files_read);if(p.length>0)return e.jsxs("div",{children:[e.jsx("span",{className:"text-xs font-medium",children:"Files Read:"}),e.jsx("div",{className:"text-xs text-base-content/50 mt-1",children:p.map((y,C)=>e.jsx("div",{className:"truncate",children:y},C))})]})}catch{return null}})(),l.data.files_modified&&(()=>{try{const p=JSON.parse(l.data.files_modified);if(p.length>0)return e.jsxs("div",{children:[e.jsx("span",{className:"text-xs font-medium",children:"Files Modified:"}),e.jsx("div",{className:"text-xs text-base-content/50 mt-1",children:p.map((y,C)=>e.jsx("div",{className:"truncate",children:y},C))})]})}catch{return null}})()]})]})]}),e.jsx(S,{icon:b?"lucide:chevron-up":"lucide:chevron-down",size:16,className:"text-base-content/40"})]})})})]},x)}),n.timeline.length===0&&e.jsx("div",{className:"text-center py-8 text-base-content/50",children:"No activity in this session"})]})]})}function ya(t){return t<.01?"<$0.01":`$${t.toFixed(2)}`}const wa={Read:"lucide:file",Write:"lucide:file-plus",Edit:"lucide:file-edit",Bash:"lucide:terminal",Glob:"lucide:folder-search",Grep:"lucide:search",Agent:"lucide:bot",WebSearch:"lucide:globe",WebFetch:"lucide:download",AskUserQuestion:"lucide:message-circle",TaskCreate:"lucide:list-plus",TaskUpdate:"lucide:list-checks"};function ge({label:t,value:s,icon:n}){return e.jsxs("div",{className:"bg-base-200/50 rounded-lg px-3 py-2.5 text-center",children:[e.jsxs("div",{className:"flex items-center justify-center gap-1.5 mb-0.5",children:[e.jsx(S,{icon:n,size:13,className:"text-base-content/40"}),e.jsx("span",{className:"text-[10px] text-base-content/50 uppercase tracking-wider",children:t})]}),e.jsx("div",{className:"text-base font-semibold tabular-nums",children:s})]})}function Na({tools:t}){const s=Object.entries(t);if(s.length===0)return e.jsx(e.Fragment,{});const n=Math.max(...s.map(([,u])=>u)),r=s.slice(0,20),a=Math.ceil(r.length/2),i=r.slice(0,a),c=r.slice(a),d=([u,h])=>e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(S,{icon:wa[u]||"lucide:wrench",size:13,className:"text-base-content/40 shrink-0"}),e.jsx("span",{className:"text-sm w-28 truncate",title:u,children:u}),e.jsx("div",{className:"flex-1 h-1.5 bg-base-300 rounded-full overflow-hidden",children:e.jsx("div",{className:"h-full bg-info rounded-full transition-all",style:{width:`${h/n*100}%`}})}),e.jsx("span",{className:"text-xs tabular-nums text-base-content/50 w-8 text-right",children:h})]},u);return e.jsxs("div",{className:"grid grid-cols-2 gap-x-6 gap-y-1.5",children:[e.jsx("div",{className:"space-y-1.5",children:i.map(d)}),e.jsx("div",{className:"space-y-1.5",children:c.map(d)}),s.length>20&&e.jsxs("span",{className:"col-span-2 text-xs text-base-content/40 mt-1",children:["+ ",s.length-20," more tools"]})]})}function Sa({session:t,open:s,onClose:n,onResumedDetected:r}){const[a,i]=o.useState(null),[c,d]=o.useState(null),[u,h]=o.useState(!0),[l,m]=o.useState(!0),x=o.useRef(r);x.current=r,o.useEffect(()=>{if(!s)return;let f=!1;async function g(){var v;h(!0);try{const[p,y]=await Promise.all([fetch(`/api/sessions/${t.id}/stats`),fetch(`/api/sessions/${t.id}/timeline`)]);if(!f){if(p.ok){const C=await p.json();C.stats?(i(C.stats),m(!0),(v=x.current)==null||v.call(x,C.stats.is_resumed)):m(!1)}else m(!1);if(y.ok){const C=await y.json();d(C.session??null)}}}catch{f||m(!1)}finally{f||h(!1)}}return g(),()=>{f=!0}},[t.id,s]);const b=a?Object.entries(a.models):[],j=(c==null?void 0:c.status)==="active"||t.status==="active";return e.jsx(fe,{open:s,onClose:n,title:"Session Details",size:"wide",children:e.jsxs("div",{className:"max-h-[70vh] overflow-y-auto space-y-4 pr-1",children:[e.jsxs("div",{className:"flex items-center gap-3 flex-wrap text-sm",children:[e.jsx(q,{variant:j?"warning":"success",size:"sm",children:j?"active":"completed"}),(a==null?void 0:a.is_resumed)&&e.jsx(q,{variant:"info",size:"sm",children:"resumed"}),e.jsx("span",{className:"text-base-content/50",children:c?new Date(c.started_at).toLocaleString():new Date(t.started_at).toLocaleString()}),(c==null?void 0:c.completed_at)&&e.jsxs("span",{className:"text-base-content/40",children:["→ ",new Date(c.completed_at).toLocaleString()]}),b.length>0&&e.jsxs(e.Fragment,{children:[e.jsx("span",{className:"text-base-content/20",children:"|"}),b.map(([f,g])=>e.jsxs(q,{variant:"ghost",size:"sm",children:[f.replace("claude-","").replace(/-\d{8}$/,"")," (",g,")"]},f))]})]}),u?e.jsx("div",{className:"grid grid-cols-4 gap-3 animate-pulse",children:Array.from({length:4}).map((f,g)=>e.jsx("div",{className:"bg-base-300/50 rounded-lg h-14"},g))}):a?e.jsxs("div",{className:"grid grid-cols-4 gap-3",children:[e.jsx(ge,{label:"Cost",value:ya(a.cost_usd),icon:"lucide:dollar-sign"}),e.jsx(ge,{label:"Messages",value:String(a.turns),icon:"lucide:messages-square"}),e.jsx(ge,{label:"Observations",value:String(t.observation_count),icon:"lucide:brain"}),e.jsx(ge,{label:"Prompts",value:String(t.prompt_count),icon:"lucide:message-square"})]}):l?null:e.jsxs("div",{className:"text-sm text-base-content/40 text-center py-2",children:[e.jsx(S,{icon:"lucide:file-x",size:16,className:"inline mr-2"}),"JSONL file not available — showing timeline data only"]}),t.user_prompt&&e.jsxs("div",{className:"border border-base-300 rounded-lg p-4",children:[e.jsxs("div",{className:"flex items-center gap-2 mb-2",children:[e.jsx(S,{icon:"lucide:terminal",size:14,className:"text-primary"}),e.jsx("span",{className:"text-xs text-base-content/50 uppercase tracking-wider",children:"Prompt"})]}),e.jsx("p",{className:"text-sm whitespace-pre-wrap break-words text-base-content/80",children:t.user_prompt})]}),a&&Object.keys(a.tools).length>0&&e.jsxs("div",{className:"border border-base-300 rounded-lg p-4",children:[e.jsxs("div",{className:"flex items-center gap-2 mb-3",children:[e.jsx(S,{icon:"lucide:wrench",size:14,className:"text-info"}),e.jsx("span",{className:"text-xs text-base-content/50 uppercase tracking-wider",children:"Tool Usage"})]}),e.jsx(Na,{tools:a.tools})]}),e.jsx(va,{sessionId:t.id,skipHeader:!0})]})})}const ka=[{key:"date",label:"Date",icon:"lucide:calendar"},{key:"cost",label:"Cost",icon:"lucide:dollar-sign"},{key:"messages",label:"Messages",icon:"lucide:messages-square"},{key:"prompts",label:"Prompts",icon:"lucide:message-square"}];function pt(t,s,n){switch(s){case"date":return t.started_at_epoch;case"cost":return n[t.id]??0;case"messages":return t.observation_count+t.prompt_count;case"prompts":return t.prompt_count}}function Ca(){const{params:t}=se(),[s,n]=o.useState([]),[r,a]=o.useState(!0),[i,c]=o.useState(null),[d,u]=o.useState(""),[h,l]=o.useState("date"),[m,x]=o.useState("desc"),[b,j]=o.useState({}),{selectedProject:f,setSelectedProject:g}=X(),v=o.useRef(null),[p,y]=o.useState(new Set),C=o.useCallback(async R=>{a(!0);try{const E=new URLSearchParams;E.set("limit","50"),f&&E.set("project",f),R&&E.set("search",R);const $=(await(await fetch(`/api/sessions?${E}`)).json()).items||[];if(n($),$.length>0){const D=$.map(P=>P.id);fetch("/api/sessions/costs",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({ids:D})}).then(P=>P.json()).then(P=>j(P.costs||{})).catch(()=>{})}}catch(E){console.error("Failed to fetch sessions:",E)}finally{a(!1)}},[f]);o.useEffect(()=>{C(d||void 0)},[C,d]),o.useEffect(()=>{if(!t.selected||r)return;const R=Number(t.selected),E=s.find(N=>N.id===R);E?(c(E),f&&E.project!==f&&g(E.project)):f&&s.length>0&&g(null)},[t.selected,r,s,f,g]);const I=R=>{v.current&&clearTimeout(v.current),v.current=setTimeout(()=>{u(R)},300)},w=o.useCallback(R=>{y(E=>{if(!i||E.has(i.id)||!R)return E;const N=new Set(E);return N.add(i.id),N})},[i]),_=R=>{h===R?x(E=>E==="desc"?"asc":"desc"):(l(R),x("desc"))},L=o.useMemo(()=>{const R=[],E=[];for(const $ of s)$.status==="active"?R.push($):E.push($);const N=m==="desc"?-1:1,A=($,D)=>N*(pt($,h,b)-pt(D,h,b));return R.sort(A),E.sort(A),[...R,...E]},[s,h,m,b]);return e.jsxs("div",{className:"space-y-6",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"flex items-center gap-3 flex-wrap",children:[e.jsx("h1",{className:"text-2xl font-bold",children:"Sessions"}),e.jsx(we,{}),e.jsxs("span",{className:"text-xs text-base-content/50",children:[s.length," session",s.length!==1?"s":""]}),e.jsx("span",{className:"text-base-content/50 text-sm",children:"Browse past sessions · copy session ID to resume"})]}),e.jsx("div",{className:"flex items-center gap-2",children:e.jsx(W,{variant:"ghost",size:"sm",onClick:()=>C(d||void 0),children:e.jsx(S,{icon:"lucide:refresh-cw",size:16})})})]}),e.jsxs("div",{className:"relative",children:[e.jsx(S,{icon:"lucide:search",size:20,className:"absolute left-4 top-1/2 -translate-y-1/2 text-base-content/50"}),e.jsx("input",{type:"search",placeholder:"Search sessions by prompt, project, or session ID...",onChange:R=>I(R.target.value),className:"input input-bordered w-full pl-12 pr-4"})]}),r?e.jsx(te,{}):s.length===0?e.jsx($e,{icon:"lucide:history",title:d?"No matching sessions":"No sessions found",description:d?"Try a different search query":"Sessions will appear here as you use Claude Code"}):e.jsxs("div",{className:"space-y-3",children:[e.jsxs("div",{className:"flex items-center justify-end gap-1 pr-2",children:[e.jsx("span",{className:"text-xs text-base-content/40 mr-2",children:"Sort by:"}),ka.map(({key:R,label:E,icon:N})=>{const A=h===R;return e.jsxs("button",{onClick:()=>_(R),className:`flex items-center gap-1 px-2.5 py-1 rounded text-xs transition-colors ${A?"bg-primary/10 text-primary font-medium":"text-base-content/50 hover:text-base-content/80 hover:bg-base-200"}`,children:[e.jsx(S,{icon:N,size:12}),E,A&&e.jsx(S,{icon:m==="desc"?"lucide:arrow-down":"lucide:arrow-up",size:12})]},R)})]}),L.map(R=>e.jsx("div",{id:`session-${R.id}`,children:e.jsx(ga,{session:R,isExpanded:(i==null?void 0:i.id)===R.id,onToggle:()=>c((i==null?void 0:i.id)===R.id?null:R),isResumed:p.has(R.id),costUsd:b[R.id]})},R.id))]}),i&&e.jsx(Sa,{session:i,open:!!i,onClose:()=>c(null),onResumedDetected:w})]})}const he=["sonnet","opus"],Ht={sonnet:"Sonnet 4.6",opus:"Opus 4.7"},Vt=/^claude-[a-z0-9][a-z0-9.\-]*$/;function bt(t){return typeof t!="string"||t.length===0?!1:he.includes(t)?!0:Vt.test(t)}function Ea(t){return!he.includes(t)&&Vt.test(t)}const G={model:"opus",extendedContext:!0,skills:{spec:"opus","spec-plan":"opus","spec-implement":"sonnet","spec-verify":"sonnet","setup-rules":"opus","create-skill":"opus",prd:"opus"},agents:{"spec-review":"sonnet","changes-review":"sonnet"},reviewerAgents:{specReview:!0,changesReview:!0},codexReviewers:{specReview:!1,changesReview:!1},codexAvailable:!1,specWorkflow:{worktreeSupport:!0,askQuestionsDuringPlanning:!0,planApproval:!0}};function Ra(){const[t,s]=o.useState(G),[n,r]=o.useState(!0),[a,i]=o.useState(null),[c,d]=o.useState(!1),[u,h]=o.useState(!1);o.useEffect(()=>{fetch("/api/settings").then(p=>{if(!p.ok)throw new Error(`API error: ${p.status}`);return p.json()}).then(p=>{s({...G,...p}),r(!1)}).catch(p=>{i(p.message||"Failed to load settings"),r(!1)})},[]);const l=o.useCallback(p=>{s(y=>({...y,model:p})),d(!0),h(!1)},[]),m=o.useCallback(p=>{s(y=>({...y,extendedContext:p})),d(!0),h(!1)},[]),x=o.useCallback((p,y)=>{s(C=>({...C,skills:{...C.skills,[p]:y}})),d(!0),h(!1)},[]),b=o.useCallback((p,y)=>{s(C=>({...C,agents:{...C.agents,[p]:y}})),d(!0),h(!1)},[]),j=o.useCallback((p,y)=>{s(C=>({...C,reviewerAgents:{...C.reviewerAgents,[p]:y}})),d(!0),h(!1)},[]),f=o.useCallback((p,y)=>{s(C=>({...C,codexReviewers:{...C.codexReviewers,[p]:y}})),d(!0),h(!1)},[]),g=o.useCallback((p,y)=>{s(C=>({...C,specWorkflow:{...C.specWorkflow,[p]:y}})),d(!0),h(!1)},[]),v=o.useCallback(async()=>{await fetch("/api/settings",{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)}).then(p=>{if(!p.ok)throw new Error(`Save failed: ${p.status}`);return p.json()}).then(p=>{s(p),d(!1),h(!0)})},[t]);return{settings:t,isLoading:n,error:a,isDirty:c,saved:u,updateModel:l,updateExtendedContext:m,updateSkill:x,updateAgent:b,updateReviewerAgent:j,updateCodexReviewer:f,updateSpecWorkflow:g,save:v}}const Pe="__custom__";function Te({value:t,choices:s,onChange:n,disabled:r=!1,id:a}){const i=Ea(t),[c,d]=o.useState(i),[u,h]=o.useState(i?t:""),l=c||i?Pe:t,m=b=>{if(b===Pe){d(!0);return}d(!1),h(""),n(b)},x=()=>{const b=u.trim();bt(b)&&n(b)};return e.jsxs("div",{className:"flex flex-col gap-1",children:[e.jsxs("select",{id:a,className:"select select-sm select-bordered w-full max-w-xs",value:l,onChange:b=>m(b.target.value),disabled:r,children:[s.map(b=>e.jsx("option",{value:b,children:Ht[b]??b},b)),e.jsx("option",{value:Pe,children:"Custom…"})]}),(c||i)&&e.jsx("input",{type:"text",className:`input input-xs input-bordered w-full max-w-xs ${u&&!bt(u.trim())?"input-error":""}`,placeholder:"claude-opus-4-6",value:u||(i?t:""),onChange:b=>h(b.target.value),onBlur:x,onKeyDown:b=>{b.key==="Enter"&&(b.preventDefault(),x())},disabled:r,"aria-label":"Custom model ID",spellCheck:!1,autoCapitalize:"off",autoCorrect:"off"})]})}const Pa=[{key:"main",label:"Main Session",sub:"Quick mode / direct chat"},{key:"prd",label:"PRD"},{key:"setup-rules",label:"Setup Rules"},{key:"create-skill",label:"Create Skill"}],Ta=[{key:"spec-plan",label:"Planning"},{key:"spec-implement",label:"Implementation"},{key:"spec-verify",label:"Verification"}],Ia=[{key:"spec-review",label:"Spec Review",toggleKey:"specReview",description:"Validates plans before implementation. Checks alignment with requirements and flags risky assumptions. Runs in a separate context window."},{key:"changes-review",label:"Changes Review",toggleKey:"changesReview",description:"Reviews code after implementation. Checks compliance, security, test coverage, and goal achievement. Reads all changed files in a separate context window."}],Da=[{key:"codex-spec-review",label:"Codex Spec Review",toggleKey:"specReview",description:"Adversarial plan review powered by OpenAI Codex. Provides an independent second opinion on plans."},{key:"codex-changes-review",label:"Codex Changes Review",toggleKey:"changesReview",description:"Adversarial code review powered by OpenAI Codex. Provides an independent second opinion on implementations."}],_a=[{key:"worktree-support",label:"Worktree Support",toggleKey:"worktreeSupport",description:"Ask whether to isolate changes in a git worktree. When off, worktree is always skipped."},{key:"ask-questions",label:"Ask Questions",toggleKey:"askQuestionsDuringPlanning",description:"Ask clarifying questions during planning. When off, planning runs fully autonomous."},{key:"plan-approval",label:"Plan Approval",toggleKey:"planApproval",description:"Require approval before implementation starts. When off, implementation begins automatically."}];function gt({children:t}){return e.jsx("h2",{className:"text-xs font-semibold uppercase tracking-wide text-base-content/50 mb-2",children:t})}function jt({children:t}){return e.jsx("tr",{children:e.jsx("td",{colSpan:3,className:"font-medium text-xs text-base-content/50 uppercase tracking-wide pt-4 pb-1 px-0 border-b border-base-300",children:t})})}function vt({model:t}){return e.jsx("span",{className:"text-xs text-base-content/40",children:Ht[t]??t})}function La(){const{settings:t,isLoading:s,error:n,isDirty:r,updateModel:a,updateExtendedContext:i,updateSkill:c,updateAgent:d,updateReviewerAgent:u,updateCodexReviewer:h,updateSpecWorkflow:l,save:m}=Ra(),[x,b]=o.useState(null),[j,f]=o.useState(!1),[g,v]=o.useState(!1),[p,y]=o.useState(!1),[C,I]=o.useState(null),w=o.useRef(!1),_=o.useRef(!1);o.useEffect(()=>{w.current=r},[r]);const L=async()=>{f(!0),b(null);try{await m(),v(!0)}catch(N){b(N instanceof Error?N.message:"Failed to save")}finally{f(!1)}};o.useEffect(()=>{const N=A=>{w.current&&A.preventDefault()};return window.addEventListener("beforeunload",N),()=>window.removeEventListener("beforeunload",N)},[]),o.useEffect(()=>{const N=()=>{if(_.current){_.current=!1;return}if(!w.current)return;const A=(window.location.hash.replace(/^#/,"")||"/").split("?")[0];A!=="/settings"&&(_.current=!0,history.replaceState(null,"","#/settings"),window.dispatchEvent(new HashChangeEvent("hashchange")),I("#"+A),y(!0))};return window.addEventListener("hashchange",N),()=>window.removeEventListener("hashchange",N)},[]);const R=()=>{y(!1),w.current=!1,C&&(window.location.hash=C)},E=()=>{y(!1),I(null)};return s?e.jsxs("div",{className:"space-y-4",children:[e.jsx("h1",{className:"text-2xl font-bold",children:"Settings"}),e.jsx("div",{className:"card bg-base-200 animate-pulse",children:e.jsxs("div",{className:"card-body p-4",children:[e.jsx("div",{className:"h-4 bg-base-300 rounded w-32 mb-3"}),e.jsx("div",{className:"h-8 bg-base-300 rounded w-48"})]})})]}):n?e.jsxs("div",{className:"space-y-4",children:[e.jsx("h1",{className:"text-2xl font-bold",children:"Settings"}),e.jsx("div",{className:"alert alert-error",children:e.jsxs("span",{children:["Failed to load settings: ",n]})})]}):e.jsxs("div",{className:"space-y-6",children:[e.jsxs("div",{className:"flex items-start justify-between gap-4",children:[e.jsxs("div",{className:"flex items-baseline gap-3",children:[e.jsx("h1",{className:"text-2xl font-bold",children:"Settings"}),e.jsx("span",{className:"text-base-content/50 text-sm",children:"Model preferences, workflow, and automation"})]}),e.jsx("button",{className:`btn btn-primary btn-sm flex-shrink-0 ${j?"loading":""}`,onClick:L,disabled:j||!r,children:j?"Saving...":r?"Save Changes":"Saved"})]}),x&&e.jsx("div",{className:"alert alert-error py-2",children:e.jsx("span",{children:x})}),e.jsxs("section",{children:[e.jsx(gt,{children:"Model Preferences"}),e.jsx("div",{className:"card bg-base-200",children:e.jsxs("div",{className:"card-body p-4",children:[e.jsxs("table",{className:"table table-sm",children:[e.jsxs("colgroup",{children:[e.jsx("col",{className:"w-[45%]"}),e.jsx("col",{className:"w-[35%]"}),e.jsx("col",{className:"w-[20%]"})]}),e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{className:"text-xs",children:"Setting"}),e.jsx("th",{className:"text-xs",children:"Model"}),e.jsx("th",{className:"text-xs text-base-content/40",children:"Default"})]})}),e.jsxs("tbody",{children:[e.jsx(jt,{children:"General"}),Pa.map(N=>{const A=N.key==="main",$=A?t.model:t.skills[N.key]??G.skills[N.key],D=A?G.model:G.skills[N.key];return e.jsxs("tr",{children:[e.jsxs("td",{children:[e.jsx("span",{className:"text-sm",children:N.label}),N.sub&&e.jsx("div",{className:"text-xs text-base-content/40",children:N.sub})]}),e.jsx("td",{children:e.jsx(Te,{value:$,choices:he,onChange:A?a:P=>c(N.key,P),id:A?"main-model":`cmd-${N.key}`})}),e.jsx("td",{children:e.jsx(vt,{model:D})})]},N.key)}),e.jsx(jt,{children:"Spec Phases"}),Ta.map(N=>e.jsxs("tr",{children:[e.jsx("td",{children:e.jsx("span",{className:"text-sm",children:N.label})}),e.jsx("td",{children:e.jsx(Te,{value:t.skills[N.key]??G.skills[N.key],choices:he,onChange:A=>c(N.key,A),id:`cmd-${N.key}`})}),e.jsx("td",{children:e.jsx(vt,{model:G.skills[N.key]})})]},N.key))]})]}),e.jsxs("div",{className:"grid grid-cols-1 md:grid-cols-2 gap-3 mt-3",children:[e.jsxs("div",{className:"flex items-center gap-3 px-3 py-2 rounded-lg bg-base-100/50 border border-base-300",children:[e.jsx("input",{type:"checkbox",className:"toggle toggle-sm toggle-primary flex-shrink-0",checked:t.extendedContext,onChange:N=>i(N.target.checked),id:"toggle-extended-context","aria-label":"Enable 1M extended context"}),e.jsxs("div",{className:"min-w-0",children:[e.jsx("div",{className:"text-sm font-semibold leading-tight",children:"Extended Context (1M)"}),e.jsx("div",{className:"text-xs text-base-content/50",children:"Use 1M Token Context Window. Sonnet 1M is not included in Max plan — Max users must set all models to Opus for 1M. Applies only to the Sonnet and Opus aliases; custom model IDs are sent verbatim."})]})]}),e.jsxs("div",{className:"px-3 py-2 rounded-lg bg-base-100/50 border border-base-300",children:[e.jsx("div",{className:"text-sm font-semibold leading-tight mb-1",children:"Pricing"}),e.jsxs("div",{className:"text-xs text-base-content/50 space-y-0.5",children:[e.jsx("div",{children:"Sonnet 4.6 — $3 / $15 per MTok (input / output)"}),e.jsx("div",{children:"Opus 4.7 — $5 / $25 per MTok (input / output)"})]})]})]})]})})]}),e.jsxs("section",{children:[e.jsx(gt,{children:"Spec Workflow"}),e.jsx("div",{className:"text-xs font-medium text-base-content/40 uppercase tracking-wide mb-1.5",children:"Review Agents"}),e.jsx("div",{className:"grid grid-cols-2 gap-2 mb-4",children:Ia.map(N=>{var $;const A=(($=t.reviewerAgents)==null?void 0:$[N.toggleKey])??G.reviewerAgents[N.toggleKey];return e.jsx("div",{className:`rounded-lg border px-3 py-2.5 transition-colors ${A?"border-base-300 bg-base-200":"border-base-300/50 bg-base-200/50 opacity-60"}`,children:e.jsxs("div",{className:"flex items-start gap-2.5",children:[e.jsx("input",{type:"checkbox",className:"toggle toggle-sm mt-0.5 flex-shrink-0",checked:A,onChange:D=>u(N.toggleKey,D.target.checked),id:`toggle-${N.key}`,"aria-label":`Enable ${N.label} agent`}),e.jsxs("div",{className:"min-w-0 flex-1",children:[e.jsxs("div",{className:"flex items-center justify-between gap-2",children:[e.jsx("div",{className:"text-sm font-semibold leading-tight",children:N.label}),e.jsx(Te,{value:t.agents[N.key]??G.agents[N.key],choices:he,onChange:D=>d(N.key,D),id:`agent-${N.key}`,disabled:!A})]}),e.jsx("div",{className:"text-xs text-base-content/50 mt-1",children:N.description})]})]})},N.key)})}),e.jsx("div",{className:"text-xs font-medium text-base-content/40 uppercase tracking-wide mb-1.5",children:"Codex Reviewers"}),e.jsx("div",{className:`grid grid-cols-2 gap-2 mb-4 ${t.codexAvailable?"":"opacity-50"}`,children:Da.map(N=>{var $;const A=t.codexAvailable&&((($=t.codexReviewers)==null?void 0:$[N.toggleKey])??G.codexReviewers[N.toggleKey]);return e.jsx("div",{className:`rounded-lg border px-3 py-2.5 transition-colors ${A?"border-base-300 bg-base-200":"border-base-300/50 bg-base-200/50 opacity-60"}`,children:e.jsxs("div",{className:"flex items-start gap-2.5",children:[e.jsx("input",{type:"checkbox",className:"toggle toggle-sm mt-0.5 flex-shrink-0",checked:A,onChange:D=>h(N.toggleKey,D.target.checked),disabled:!t.codexAvailable,id:`toggle-${N.key}`,"aria-label":`Enable ${N.label}`}),e.jsxs("div",{className:"min-w-0 flex-1",children:[e.jsx("div",{className:"text-sm font-semibold leading-tight",children:N.label}),e.jsx("div",{className:"text-xs text-base-content/50 mt-1",children:N.description})]})]})},N.key)})}),!t.codexAvailable&&e.jsxs("div",{className:"text-xs text-base-content/40 mb-4 pl-1",children:["Codex reviewers require the Codex plugin. Install:"," ",e.jsx("code",{className:"text-base-content/60",children:"claude plugin install @openai/codex"})," ","then run ",e.jsx("code",{className:"text-base-content/60",children:"/codex:setup"})," and restart Pilot."]}),e.jsx("div",{className:"text-xs font-medium text-base-content/40 uppercase tracking-wide mb-1.5",children:"Automation"}),e.jsx("div",{className:"grid grid-cols-3 gap-2",children:_a.map(N=>{var $;const A=(($=t.specWorkflow)==null?void 0:$[N.toggleKey])??G.specWorkflow[N.toggleKey];return e.jsxs("div",{className:"rounded-lg border border-base-300 bg-base-200 px-3 py-2.5 flex items-start gap-2.5",children:[e.jsx("input",{type:"checkbox",className:"toggle toggle-sm mt-0.5 flex-shrink-0",checked:A,onChange:D=>l(N.toggleKey,D.target.checked),id:`toggle-${N.key}`,"aria-label":N.label}),e.jsxs("div",{className:"min-w-0",children:[e.jsx("div",{className:"text-sm font-semibold leading-tight",children:N.label}),e.jsx("div",{className:"text-xs text-base-content/50 mt-0.5",children:N.description})]})]},N.key)})})]}),e.jsxs(fe,{open:g,onClose:()=>v(!1),title:"Settings Saved",actions:e.jsx("button",{className:"btn btn-primary btn-sm",onClick:()=>v(!1),children:"Got it"}),children:[e.jsx("p",{children:"Your settings have been saved successfully."}),e.jsx("p",{className:"mt-2 font-medium text-warning",children:"Please restart Claude Code for changes to take effect."})]}),e.jsx(fe,{open:p,onClose:E,title:"Unsaved Changes",actions:e.jsxs(e.Fragment,{children:[e.jsx("button",{className:"btn btn-ghost btn-sm",onClick:E,children:"Stay"}),e.jsx("button",{className:"btn btn-error btn-sm",onClick:R,children:"Leave"})]}),children:e.jsx("p",{children:"You have unsaved settings changes. Are you sure you want to leave this page?"})})]})}async function qe(t){const s=new TextEncoder().encode(t),n=new CompressionStream("deflate-raw"),r=n.writable.getWriter();r.write(s),r.close();const a=await new Response(n.readable).arrayBuffer();return new Uint8Array(a).toBase64({alphabet:"base64url",omitPadding:!0})}async function Ge(t){const s=Uint8Array.fromBase64(t,{alphabet:"base64url"}),n=new DecompressionStream("deflate-raw"),r=n.writable.getWriter();r.write(s),r.close();const a=await new Response(n.readable).arrayBuffer();return new TextDecoder().decode(a)}const He=Object.freeze(Object.defineProperty({__proto__:null,compress:qe,decompress:Ge},Symbol.toStringTag,{value:"Module"})),Bt=32768;async function Kt(t,s){try{const n=await qe(JSON.stringify(t));return n.length>Bt?null:{url:`${s}/#/shared/${n}`}}catch{return null}}async function Aa(t){if(!t)return null;try{return JSON.parse(await Ge(t))}catch{return null}}async function $a(t,s){try{const n=await qe(JSON.stringify(t));return n.length>Bt?null:{url:`${s}/#/feedback/${n}`}}catch{return null}}async function Wt(t){if(!t)return null;try{return JSON.parse(await Ge(t))}catch{return null}}function Jt(t){return/^[A-Za-z0-9]{8}$/.test(t)}const Er=Object.freeze(Object.defineProperty({__proto__:null,generateFeedbackUrl:$a,generateShareUrl:Kt,isPasteServiceId:Jt,parseFeedbackUrl:Wt,parseShareUrl:Aa},Symbol.toStringTag,{value:"Module"}));async function Oa(t){const s=t.indexOf("#");if(s===-1)return null;const n=t.slice(s+1),[r]=n.split("?");let a=r;if(a.startsWith("/feedback/")?a=a.slice(10):a.startsWith("/shared/")&&(a=a.slice(8)),!a)return null;if(Jt(a)){const i=await fetch(`/api/share/${a}`);if(!i.ok)return null;const{data:c}=await i.json(),{decompress:d}=await B(async()=>{const{decompress:u}=await Promise.resolve().then(()=>He);return{decompress:u}},void 0,import.meta.url);return JSON.parse(await d(c))}return Wt(a)}function Ma({isOpen:t,onClose:s,planPath:n,projectParam:r,onAnnotationsImported:a}){const{success:i,error:c}=qt(),[d,u]=o.useState(""),[h,l]=o.useState({status:"idle"}),m=o.useRef(null),x=o.useRef(null);o.useEffect(()=>{var g,v;const f=m.current;f&&(t?((g=f.showModal)==null||g.call(f),setTimeout(()=>{var p;return(p=x.current)==null?void 0:p.focus()},50)):((v=f.close)==null||v.call(f),u(""),l({status:"idle"})))},[t]);const b=async()=>{if(d.trim()){l({status:"loading"});try{const f=await Oa(d.trim());if(!f){l({status:"error",message:"Failed to decode feedback URL — check the URL is complete."});return}if("specContent"in f&&typeof f.specContent=="string"){l({status:"error",message:'This is a share URL, not a feedback URL. Feedback URLs are generated when a reviewer clicks "Send Feedback".'});return}if(f.planPath&&n&&f.planPath!==n){l({status:"error",message:`This feedback was created for a different spec (${f.planPath}). Open the correct spec first, then import.`});return}l({status:"preview",payload:f})}catch(f){l({status:"error",message:f instanceof Error?f.message:"Failed to decode feedback URL."})}}},j=async()=>{if(h.status!=="preview")return;const{payload:f}=h;try{const g=await fetch(`/api/annotations?path=${encodeURIComponent(n)}${r}`),v=g.ok?(await g.json()).planAnnotations??[]:[],y=f.annotations.map(w=>({id:w.id??crypto.randomUUID(),blockId:w.blockId??"",originalText:w.originalText??"",text:w.text??"",createdAt:w.createdAt??Date.now(),author:w.author??f.author,feedbackStatus:"pending",importedAt:Date.now()})).filter(w=>!v.some(_=>_.originalText===w.originalText&&_.text===w.text));if(y.length===0){l({status:"done",count:0,author:f.author}),i("All annotations already imported — nothing new to add.");return}const C=[...v,...y],I=await fetch(`/api/annotations/plan?path=${encodeURIComponent(n)}${r}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({annotations:C})});if(!I.ok){c("Failed to save annotations — please try again."),l({status:"error",message:`Server returned ${I.status}. Annotations were not saved.`});return}a(y),l({status:"done",count:y.length,author:f.author}),i(`Imported ${y.length} annotation${y.length!==1?"s":""} from ${f.author}`)}catch{c("Failed to import annotations.")}};return e.jsx("dialog",{ref:m,className:"modal",onClick:f=>{f.target===m.current&&s()},children:e.jsxs("div",{className:"modal-box w-full max-w-lg",children:[e.jsxs("div",{className:"flex items-center gap-2 mb-4",children:[e.jsx(S,{icon:"lucide:message-square-plus",size:18,className:"text-primary"}),e.jsx("h3",{className:"text-lg font-semibold",children:"Import Feedback"}),e.jsx("button",{className:"btn btn-ghost btn-xs ml-auto",onClick:s,"aria-label":"Close",children:e.jsx(S,{icon:"lucide:x",size:16})})]}),h.status==="done"?e.jsxs("div",{className:"text-center py-4 space-y-3",children:[e.jsx("div",{className:"bg-success/10 rounded-full w-12 h-12 flex items-center justify-center mx-auto",children:e.jsx(S,{icon:"lucide:check-circle",size:24,className:"text-success"})}),e.jsxs("p",{className:"text-sm",children:["Imported ",e.jsx("strong",{children:h.count})," annotation",h.count!==1?"s":""," from"," ",e.jsx("strong",{children:h.author}),"."]}),e.jsx("p",{className:"text-xs text-base-content/50",children:"Review them in the annotation panel — accept or reject each one."}),e.jsx("button",{className:"btn btn-primary btn-sm",onClick:s,children:"Done"})]}):e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"mb-4",children:[e.jsx("label",{className:"text-xs font-medium text-base-content/60 mb-1.5 block",children:"Paste feedback URL from colleague"}),e.jsxs("div",{className:"flex gap-2",children:[e.jsx("input",{ref:x,type:"text",value:d,onChange:f=>{u(f.target.value),l({status:"idle"})},onKeyDown:f=>{f.key==="Enter"&&b()},className:"input input-bordered input-sm flex-1 font-mono text-xs",placeholder:"Paste feedback URL (pilot-shell.com or localhost)...",disabled:h.status==="loading"}),e.jsx("button",{className:"btn btn-outline btn-sm",onClick:b,disabled:!d.trim()||h.status==="loading",children:h.status==="loading"?e.jsx("span",{className:"loading loading-spinner loading-xs"}):"Preview"})]})]}),h.status==="error"&&e.jsxs("div",{className:"alert alert-error py-2 mb-4",children:[e.jsx(S,{icon:"lucide:alert-circle",size:14}),e.jsx("span",{className:"text-xs",children:h.message})]}),h.status==="preview"&&e.jsxs("div",{className:"space-y-3",children:[e.jsx("div",{className:"card bg-base-200 border border-base-300",children:e.jsxs("div",{className:"card-body p-3 space-y-2",children:[e.jsxs("div",{className:"flex items-center gap-2 text-xs text-base-content/60",children:[e.jsx(S,{icon:"lucide:user",size:12}),e.jsxs("span",{children:["From: ",e.jsx("strong",{children:h.payload.author})]}),e.jsx("span",{children:"·"}),e.jsxs("span",{children:[h.payload.annotations.length," annotation",h.payload.annotations.length!==1?"s":""]})]}),h.payload.annotations.slice(0,3).map(f=>e.jsxs("div",{className:"flex items-start gap-2 p-2 rounded bg-base-100 border border-base-300/50 text-xs",children:[f.originalText&&e.jsxs("span",{className:"text-base-content/40 italic flex-shrink-0 max-w-[120px] truncate",children:["“",f.originalText,"”"]}),e.jsx("span",{className:"text-base-content/70",children:f.text.slice(0,60)})]},f.id)),h.payload.annotations.length>3&&e.jsxs("p",{className:"text-xs text-base-content/40 text-center",children:["+",h.payload.annotations.length-3," more…"]})]})}),e.jsxs("button",{className:"btn btn-primary btn-sm w-full gap-2",onClick:j,children:[e.jsx(S,{icon:"lucide:download",size:14}),"Import ",h.payload.annotations.length," Annotation",h.payload.annotations.length!==1?"s":""]})]})]})]})})}const za="https://pilot-shell.com/shared",Fa=32768;function Ie(t){return t<1024?`${t} B`:`${(t/1024).toFixed(1)} KB`}function Ua(){const[t,s]=o.useState(""),[n,r]=o.useState(""),[a,i]=o.useState(!1),[c,d]=o.useState(!1),[u,h]=o.useState(null),[l,m]=o.useState("local"),x=o.useRef(0),b=o.useCallback(v=>{m(v),s(""),r(""),h(null)},[]),j=o.useCallback(async(v,p,y,C,I)=>{const w=++x.current;d(!0),h(null),s(""),r(""),i(!1);try{if(typeof CompressionStream>"u"){h("Your browser does not support the required compression API. Please upgrade to Chrome 80+, Firefox 113+, or Safari 16.4+."),d(!1);return}let _=p;if(_.length===0&&C)try{const R=await fetch(`/api/annotations?path=${encodeURIComponent(C)}`);if(R.ok){const E=await R.json();Array.isArray(E.planAnnotations)&&(_=E.planAnnotations)}}catch{}const L={specContent:v,annotations:_.filter(R=>R.feedbackStatus!=="rejected").map(R=>({id:R.id,blockId:R.blockId,originalText:R.originalText,text:R.text,createdAt:R.createdAt})),author:y??await qa(),planPath:C,...I&&I!=="specification"?{contentType:I}:{},createdAt:Date.now()};if(w!==x.current)return;if(l==="web"){const{compress:R}=await B(async()=>{const{compress:A}=await Promise.resolve().then(()=>He);return{compress:A}},void 0,import.meta.url),E=await R(JSON.stringify(L));if(w!==x.current)return;if(E.length>Fa){h('This spec is too large for web sharing (exceeds 32 KB compressed). Switch to "Recipient has Pilot Shell" to use a local link instead.');return}const N=`${za}#${E}`;s(N),r(Ie(new Blob([N]).size)),i(!1)}else{const R=`${window.location.protocol}//${window.location.host}`,E=await Kt(L,R);if(w!==x.current)return;if(E)s(E.url),r(Ie(new Blob([E.url]).size)),i(!1);else{const N=await Ga(L,R);if(w!==x.current)return;N?(s(N.url),r(Ie(new Blob([N.url]).size)),i(!0)):h("Failed to generate share URL. The spec may be too large.")}}}catch(_){if(w!==x.current)return;h(_ instanceof Error?_.message:"Failed to generate share URL")}finally{w===x.current&&d(!1)}},[l]),f=o.useCallback(async()=>{if(!t||!navigator.clipboard)return!1;try{return await navigator.clipboard.writeText(t),!0}catch{return!1}},[t]),g=o.useCallback(()=>{s(""),r(""),i(!1),h(null)},[]);return{shareUrl:t,urlSize:n,isPasteServiceUsed:a,isGenerating:c,error:u,target:l,setTarget:b,generate:j,copyToClipboard:f,clear:g}}async function qa(){try{const t=await fetch("/api/license");if(t.ok){const s=await t.json();if(s.email)return s.email}}catch{}return"Anonymous"}async function Ga(t,s){try{const{compress:n}=await B(async()=>{const{compress:d}=await Promise.resolve().then(()=>He);return{compress:d}},void 0,import.meta.url),r=await n(JSON.stringify(t)),a=await fetch("/api/share",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({data:r})});if(!a.ok)return null;const{id:i}=await a.json();return{url:`${s}/#/shared/${i}`}}catch{return null}}function Ha({isOpen:t,onClose:s,specContent:n,annotations:r,planPath:a,contentType:i="specification",onCopied:c}){const{success:d,error:u}=qt(),{shareUrl:h,urlSize:l,isPasteServiceUsed:m,isGenerating:x,error:b,target:j,setTarget:f,generate:g,copyToClipboard:v,clear:p}=Ua(),y=o.useRef(null),C=o.useRef(null);o.useEffect(()=>{t&&g(n,r,void 0,a,i),t||p()},[t,j]),o.useEffect(()=>{var R,E;const L=y.current;L&&(t?(R=L.showModal)==null||R.call(L):(E=L.close)==null||E.call(L))},[t]);const I=async()=>{await v()?(d("Share link copied — now paste your colleague's feedback URL"),c?c():s()):u("Failed to copy to clipboard")},w=L=>{L!==j&&f(L)},_=L=>{L.key==="Escape"&&s()};return e.jsx("dialog",{ref:y,className:"modal",onKeyDown:_,onClick:L=>{L.target===y.current&&s()},children:e.jsxs("div",{className:"modal-box w-full max-w-lg",children:[e.jsxs("div",{className:"flex items-center gap-2 mb-4",children:[e.jsx(S,{icon:"lucide:share-2",size:18,className:"text-primary"}),e.jsxs("h3",{className:"text-lg font-semibold",children:["Share ",i==="requirement"?"Requirement":"Specification"]}),e.jsx("button",{className:"btn btn-ghost btn-xs ml-auto",onClick:s,"aria-label":"Close",children:e.jsx(S,{icon:"lucide:x",size:16})})]}),e.jsxs("div",{className:"mb-4",children:[e.jsx("label",{className:"text-xs font-medium text-base-content/60 mb-1.5 block",children:"Recipient"}),e.jsxs("div",{className:"flex rounded-lg border border-base-300 overflow-hidden text-xs",children:[e.jsxs("button",{className:`flex-1 flex items-center justify-center gap-1.5 px-3 py-2 transition-colors ${j==="local"?"bg-base-300 text-base-content font-medium":"text-base-content/50 hover:text-base-content/80"}`,onClick:()=>w("local"),children:[e.jsx(S,{icon:"lucide:monitor",size:13}),"Has Pilot Shell"]}),e.jsxs("button",{className:`flex-1 flex items-center justify-center gap-1.5 px-3 py-2 transition-colors ${j==="web"?"bg-base-300 text-base-content font-medium":"text-base-content/50 hover:text-base-content/80"}`,onClick:()=>w("web"),children:[e.jsx(S,{icon:"lucide:globe",size:13}),"Share via pilot-shell.com"]})]})]}),x&&e.jsxs("div",{className:"flex items-center gap-3 py-6 justify-center",children:[e.jsx("span",{className:"loading loading-spinner loading-sm text-primary"}),e.jsx("span",{className:"text-sm text-base-content/60",children:"Generating…"})]}),!x&&b&&e.jsxs("div",{className:"alert alert-error mb-4",children:[e.jsx(S,{icon:"lucide:alert-circle",size:16}),e.jsx("span",{className:"text-sm",children:b})]}),!x&&h&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"mb-4",children:[e.jsx("label",{className:"text-xs font-medium text-base-content/60 mb-1.5 block",children:"Share link"}),e.jsxs("div",{className:"flex gap-2",children:[e.jsx("input",{ref:C,type:"text",readOnly:!0,value:h,className:"input input-bordered input-sm flex-1 font-mono text-xs",onClick:()=>{var L;return(L=C.current)==null?void 0:L.select()}}),e.jsxs("button",{className:"btn btn-primary btn-sm gap-1",onClick:I,children:[e.jsx(S,{icon:"lucide:copy",size:14}),"Copy"]})]})]}),e.jsxs("div",{className:"flex items-center gap-3 text-xs text-base-content/50 mb-4 flex-wrap",children:[e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(S,{icon:"lucide:minimize-2",size:12,className:"text-success"}),e.jsx("span",{children:"Compressed"})]}),e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(S,{icon:"lucide:database",size:12}),e.jsx("span",{children:l})]}),m&&e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(S,{icon:"lucide:cloud",size:12,className:"text-info"}),e.jsx("span",{children:"Stored locally · 3 day expiry"})]})]}),j==="web"?e.jsxs("div",{className:"alert alert-info py-2 px-3",children:[e.jsx(S,{icon:"lucide:info",size:14}),e.jsx("span",{className:"text-xs",children:"Zero data sent to pilot-shell.com — the spec is embedded in the URL fragment, which is never transmitted to any server."})]}):e.jsxs("div",{className:"alert alert-info py-2 px-3",children:[e.jsx(S,{icon:"lucide:info",size:14}),e.jsx("span",{className:"text-xs",children:"Recipient must have Pilot Console running to open this link."})]})]})]})})}function Va({content:t}){return e.jsx("div",{className:"spec-markdown",children:e.jsx(Yt,{remarkPlugins:[Xt],components:{h3:({children:s})=>{const r=String(s??"").match(/Task\s+(\d+)/),a=r?`task-${r[1]}`:void 0;return e.jsx("h3",{id:a,className:"text-lg font-semibold mt-6 mb-3 pb-2 border-b border-base-300/50 first:mt-0 scroll-mt-4",children:s})},h4:({children:s})=>e.jsx("h4",{className:"text-base font-medium mt-4 mb-2 text-base-content/90",children:s}),p:({children:s})=>e.jsx("p",{className:"text-sm text-base-content/80 mb-3 leading-relaxed",children:s}),ul:({children:s})=>e.jsx("ul",{className:"text-sm space-y-1.5 mb-4 ml-1",children:s}),ol:({children:s})=>e.jsx("ol",{className:"text-sm space-y-1.5 mb-4 ml-1 list-decimal list-inside",children:s}),li:({children:s})=>e.jsxs("li",{className:"text-base-content/80 flex items-start gap-2",children:[e.jsx("span",{className:"text-primary mt-0.5 text-xs select-none",children:"▸"}),e.jsx("span",{className:"flex-1",children:s})]}),code:({className:s,children:n})=>s?e.jsx("code",{className:"block bg-base-300 p-3 rounded-lg text-xs font-mono overflow-x-auto mb-4 border border-base-content/10",children:n}):e.jsx("code",{className:"bg-base-300 text-primary px-1.5 py-0.5 rounded text-xs font-mono",children:n}),pre:({children:s})=>e.jsx("pre",{className:"bg-base-300 p-3 rounded-lg text-xs font-mono overflow-x-auto mb-4 border border-base-content/10",children:s}),strong:({children:s})=>e.jsx("strong",{className:"font-semibold text-base-content",children:s}),table:({children:s})=>e.jsx("div",{className:"overflow-x-auto mb-4",children:e.jsx("table",{className:"table table-sm w-full",children:s})}),thead:({children:s})=>e.jsx("thead",{className:"bg-base-200",children:s}),th:({children:s})=>e.jsx("th",{className:"text-left text-xs font-medium text-base-content/70 p-2",children:s}),td:({children:s})=>e.jsx("td",{className:"text-sm p-2 border-t border-base-300/50",children:s}),blockquote:({children:s})=>e.jsx("blockquote",{className:"border-l-4 border-primary/50 pl-4 py-1 my-3 text-sm text-base-content/70 italic",children:s}),hr:()=>e.jsx("hr",{className:"my-6 border-base-300"})},children:t})})}const Ba={Summary:"lucide:text",Scope:"lucide:target","Autonomous Decisions":"lucide:brain","Context for Implementer":"lucide:book-open","Runtime Environment":"lucide:terminal",Assumptions:"lucide:lightbulb","Risks and Mitigations":"lucide:alert-triangle","Goal Verification":"lucide:check-square","E2E Test Scenarios":"lucide:monitor-check","E2E Results":"lucide:clipboard-check","Verification Scenario":"lucide:mouse-pointer-click","Open Questions":"lucide:help-circle","Deferred Ideas":"lucide:bookmark","Problem Statement":"lucide:crosshair","Core User Flows":"lucide:route","Technical Context":"lucide:cpu","Key Decisions":"lucide:scale"};function Ka({heading:t,content:s,defaultOpen:n=!1}){const[r,a]=o.useState(n),i=Ba[t]||"lucide:file-text";return e.jsx(H,{children:e.jsxs(V,{className:"p-0",children:[e.jsxs("button",{className:"w-full flex items-center gap-2.5 p-4 text-left cursor-pointer hover:bg-base-200/50 transition-colors",onClick:()=>a(!r),children:[e.jsx(S,{icon:i,size:16,className:"text-primary flex-shrink-0"}),e.jsx("span",{className:"text-sm font-semibold flex-1",children:t}),e.jsx(S,{icon:"lucide:chevron-down",size:14,className:`text-base-content/40 transition-transform duration-200 ${r?"rotate-180":""}`})]}),r&&e.jsx("div",{className:"px-4 pb-4 pt-0 border-t border-base-300/50",children:e.jsx("div",{className:"pt-3",children:e.jsx(Va,{content:s})})})]})})}const Wa={SPEC_REFRESH_INTERVAL_MS:5e3,GIT_REFRESH_INTERVAL_MS:1e4},Ja=o.lazy(()=>B(()=>import("./PlanAnnotator.js"),__vite__mapDeps([0,1,2,3,4]),import.meta.url).then(t=>({default:t.PlanAnnotator}))),Qa=["Problem Statement","Core User Flows","Scope","Technical Context","Key Decisions","Research Findings"],Ya={Feature:"info",Infrastructure:"warning",UX:"info",API:"info",Performance:"success",Security:"warning",Documentation:"info",Integration:"info"};function Xa(t){const s=t.match(/^#\s+(.+)$/m),n=s?s[1]:"Untitled PRD",r={},a=t.match(/^Author:\s*(.+)$/m);a&&(r.author=a[1].trim());const i=t.match(/^Category:\s*(.+)$/m);i&&(r.category=i[1].trim());const c=t.match(/^Status:\s*(.+)$/m);c&&(r.status=c[1].trim());const d=t.match(/^Research:\s*(.+)$/m);d&&(r.research=d[1].trim());const u=t.match(/^Created:\s*(.+)$/m);u&&(r.createdAt=u[1].trim());const h=[],l=/^## (.+)$/gm,m=[];let x;for(;(x=l.exec(t))!==null;)m.push({heading:x[1],index:x.index,contentStart:x.index+x[0].length});for(let b=0;b{if(!s.path)return;const T=decodeURIComponent(s.path);i(O=>O===T?O:T)},[s.path]);const[c,d]=o.useState(null),[u,h]=o.useState(!0),[l,m]=o.useState(!1),[x,b]=o.useState(null),[j,f]=o.useState("view"),[g,v]=o.useState(!1),[p,y]=o.useState(!1),[C,I]=o.useState(0),[w,_]=o.useState(!1),L=t?`?project=${encodeURIComponent(t)}`:"",R=o.useRef(t);R.current!==t&&(R.current=t,i(null),d(null),b(null),h(!0));const E=o.useCallback(async()=>{var T;try{const z=await(await fetch(`/api/prd${L}`)).json();r(z.prds||[]),((T=z.prds)==null?void 0:T.length)>0&&!a&&i(z.prds[0].filePath)}catch(O){b("Failed to load PRDs"),console.error("Failed to load PRDs:",O)}finally{h(!1)}},[a,L]),N=o.useCallback(async(T,O=!1)=>{O||m(!0),b(null);try{const z=await fetch(`/api/prd/content?path=${encodeURIComponent(T)}${t?`&project=${encodeURIComponent(t)}`:""}`);if(!z.ok)throw new Error("Failed to load PRD content");d(await z.json())}catch(z){b("Failed to load PRD content"),console.error("Failed to load PRD content:",z)}finally{O||m(!1)}},[t]),A=o.useCallback(async T=>{if(confirm(`Delete "${T.split("/").pop()}"? This cannot be undone.`)){_(!0);try{if(!(await fetch(`/api/prd?path=${encodeURIComponent(T)}${t?`&project=${encodeURIComponent(t)}`:""}`,{method:"DELETE"})).ok)throw new Error("Failed to delete PRD");i(null),d(null),await E()}catch(O){b("Failed to delete PRD"),console.error("Failed to delete PRD:",O)}finally{_(!1)}}},[E,t]);if(o.useEffect(()=>{E();const T=setInterval(()=>{E(),a&&N(a,!0)},Wa.SPEC_REFRESH_INTERVAL_MS);return()=>clearInterval(T)},[E,N,a]),o.useEffect(()=>{a&&N(a)},[a,N]),u)return e.jsx(te,{});if(n.length===0)return e.jsxs("div",{className:"space-y-6",children:[e.jsxs("div",{className:"flex items-center gap-3 flex-wrap",children:[e.jsx("h1",{className:"text-2xl font-bold",children:"Requirements"}),e.jsx(we,{})," "]}),e.jsx(H,{children:e.jsx(V,{children:e.jsxs("div",{className:"flex flex-col items-center justify-center py-12 text-center",children:[e.jsx(S,{icon:"lucide:lightbulb",size:48,className:"text-base-content/40 mb-4"}),e.jsx("h3",{className:"text-lg font-medium mb-2",children:"No Requirements"}),e.jsxs("p",{className:"text-base-content/60 max-w-md",children:["Use"," ",e.jsx("code",{className:"text-primary bg-base-300 px-1 rounded",children:"/prd"})," ","in Pilot Shell to brainstorm vague ideas into Product Requirements Documents through back-and-forth conversation, with optional research."]})]})})})]});const $=n.find(T=>T.filePath===a),D=n.filter(T=>T.filePath!==a),P=c?Xa(c.content):null;return e.jsxs("div",{className:"space-y-6",children:[e.jsxs("div",{className:"flex items-center gap-3 flex-wrap",children:[e.jsx("h1",{className:"text-2xl font-bold",children:"Requirements"}),e.jsx(we,{}),a&&c&&e.jsxs("div",{className:"flex items-center rounded-lg border border-base-300 overflow-hidden text-xs",children:[e.jsxs("button",{className:`px-2.5 py-1.5 flex items-center gap-1.5 transition-colors ${j==="view"?"bg-primary text-primary-content":"hover:bg-base-200"}`,onClick:()=>f("view"),title:"View PRD",children:[e.jsx(S,{icon:"lucide:eye",size:13}),"View"]}),e.jsxs("button",{className:`px-2.5 py-1.5 flex items-center gap-1.5 transition-colors ${j==="annotate"?"bg-primary text-primary-content":"hover:bg-base-200"}`,onClick:()=>f("annotate"),title:"Review PRD",children:[e.jsx(S,{icon:"lucide:pencil",size:13}),"Review"]})]}),$&&e.jsx("div",{role:"tablist",className:"flex items-center gap-1.5 min-w-0 overflow-hidden",children:e.jsxs("button",{role:"tab","aria-selected":!0,className:"px-2.5 py-1.5 rounded-lg text-xs font-medium border transition-colors cursor-pointer flex items-center gap-1.5 truncate bg-primary/10 border-primary/30 text-primary",children:[e.jsx(S,{icon:"lucide:lightbulb",size:12,className:"text-warning flex-shrink-0"}),e.jsx("span",{className:"truncate max-w-40",children:$.name}),e.jsx("span",{className:"text-[10px] opacity-60 flex-shrink-0",children:Za($.modifiedAt)})]})}),e.jsx("span",{className:"flex-1"}),D.length>0&&e.jsxs("select",{className:"select select-bordered select-xs text-xs max-w-48",value:"",onChange:T=>i(T.target.value),children:[e.jsxs("option",{value:"",disabled:!0,children:["Previous (",D.length,")"]}),D.map(T=>e.jsx("option",{value:T.filePath,children:T.name},T.filePath))]}),a&&e.jsx(Y,{text:"Delete PRD",position:"bottom",children:e.jsx(W,{variant:"ghost",size:"sm",onClick:()=>A(a),disabled:w,children:e.jsx(S,{icon:"lucide:trash-2",size:16,className:"text-error"})})})]}),l?e.jsx(te,{}):x?e.jsx(H,{children:e.jsx(V,{children:e.jsxs("div",{className:"flex flex-col items-center justify-center py-12 text-center",children:[e.jsx(S,{icon:"lucide:alert-circle",size:48,className:"text-error mb-4"}),e.jsx("p",{className:"text-error",children:x})]})})}):P&&c?e.jsxs(e.Fragment,{children:[j==="annotate"&&e.jsx(o.Suspense,{fallback:e.jsx(te,{}),children:e.jsxs("div",{className:"rounded-xl border border-base-300 bg-base-100",style:{height:"calc(100vh - 180px)",minHeight:500,display:"flex",flexDirection:"column"},children:[e.jsxs("div",{className:"flex items-center gap-2 px-4 py-2 border-b border-base-300 bg-base-200/40 flex-shrink-0 text-xs text-base-content/60",children:[e.jsx(S,{icon:"lucide:pencil-line",size:13,className:"text-primary"}),e.jsx("span",{children:"Hover over a block and click the + button to add annotations. Review them in the sidebar."})]}),e.jsx("div",{style:{flex:1,minHeight:0,display:"flex"},children:e.jsx(Ja,{planContent:c.content,planPath:c.filePath,projectParam:t?`&project=${encodeURIComponent(t)}`:"",onShare:()=>y(!0),onReceiveFeedback:()=>v(!0),reloadKey:C})})]})}),j!=="annotate"&&e.jsxs(e.Fragment,{children:[e.jsx(H,{children:e.jsxs(V,{className:"p-6",children:[e.jsxs("div",{className:"flex items-start gap-3",children:[e.jsx("div",{className:"w-10 h-10 bg-warning/20 rounded-xl flex items-center justify-center flex-shrink-0",children:e.jsx(S,{icon:"lucide:lightbulb",size:20,className:"text-warning"})}),e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("h2",{className:"text-xl font-bold",children:P.title}),e.jsxs("p",{className:"text-xs text-base-content/50 mt-1",children:[P.sections.length," sections"]})]})]}),e.jsxs("div",{className:"flex items-center gap-4 mt-4 pt-4 border-t border-base-300/50 text-xs text-base-content/50 flex-wrap",children:[P.metadata.category&&e.jsx(q,{variant:Ya[P.metadata.category]??"info",size:"xs",children:P.metadata.category}),P.metadata.status&&e.jsx(q,{variant:P.metadata.status==="Final"?"success":"warning",size:"xs",children:P.metadata.status}),P.metadata.author&&e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(S,{icon:"lucide:user",size:12}),e.jsx("span",{children:P.metadata.author})]}),P.metadata.createdAt&&e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(S,{icon:"lucide:calendar",size:12}),e.jsx("span",{children:P.metadata.createdAt})]}),P.metadata.research&&P.metadata.research!=="None"&&e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(S,{icon:"lucide:search",size:12}),e.jsxs("span",{children:[P.metadata.research," research"]})]}),c&&e.jsxs("div",{className:"flex items-center gap-1 ml-auto",children:[e.jsxs("button",{className:"btn btn-ghost btn-xs gap-1",onClick:()=>y(!0),title:"Share PRD with a teammate",children:[e.jsx(S,{icon:"lucide:send",size:12}),e.jsx("span",{children:"Share with Teammate"})]}),e.jsxs("button",{className:"btn btn-ghost btn-xs gap-1",onClick:()=>v(!0),title:"Receive feedback from a colleague",children:[e.jsx(S,{icon:"lucide:inbox",size:12}),e.jsx("span",{children:"Receive Feedback"})]})]})]})]})}),P.sections.length>0&&e.jsx("div",{className:"space-y-2",children:P.sections.map(T=>e.jsx(Ka,{heading:T.heading,content:T.content,defaultOpen:T.heading==="Problem Statement"||T.heading==="Scope"},T.heading))})]})]}):null,c&&g&&e.jsx(Ma,{isOpen:g,onClose:()=>v(!1),planPath:c.filePath,projectParam:t?`&project=${encodeURIComponent(t)}`:"",onAnnotationsImported:()=>{v(!1),f("annotate"),I(T=>T+1)}}),c&&p&&e.jsx(Ha,{isOpen:p,onClose:()=>y(!1),specContent:c.content,annotations:[],planPath:c.filePath,contentType:"requirement",onCopied:()=>{y(!1),setTimeout(()=>v(!0),300)}})]})}const de=[{key:"DEBUG",label:"Debug",icon:"🔍",color:"text-base-content/50"},{key:"INFO",label:"Info",icon:"ℹ️",color:"text-info"},{key:"WARN",label:"Warn",icon:"⚠️",color:"text-warning"},{key:"ERROR",label:"Error",icon:"❌",color:"text-error"}],ue=[{key:"HOOK",label:"Hook",icon:"🪝",color:"text-purple-500"},{key:"WORKER",label:"Worker",icon:"⚙️",color:"text-info"},{key:"SDK",label:"SDK",icon:"📦",color:"text-success"},{key:"PARSER",label:"Parser",icon:"📄",color:"text-sky-500"},{key:"DB",label:"DB",icon:"🗄️",color:"text-orange-500"},{key:"SYSTEM",label:"System",icon:"💻",color:"text-base-content/50"},{key:"HTTP",label:"HTTP",icon:"🌐",color:"text-cyan-500"},{key:"SESSION",label:"Session",icon:"📋",color:"text-pink-500"},{key:"CHROMA",label:"Chroma",icon:"🔮",color:"text-violet-500"}];function tr(t){const s=/^\[([^\]]+)\]\s+\[(\w+)\s*\]\s+\[(\w+)\s*\]\s+(?:\[([^\]]+)\]\s+)?(.*)$/,n=t.match(s);if(!n)return{raw:t};const[,r,a,i,c,d]=n;let u;return d.startsWith("→")?u="dataIn":d.startsWith("←")?u="dataOut":d.startsWith("✓")?u="success":d.startsWith("✗")?u="failure":d.startsWith("⏱")?u="timing":d.includes("[HAPPY-PATH]")&&(u="happyPath"),{raw:t,timestamp:r,level:a==null?void 0:a.trim(),component:i==null?void 0:i.trim(),correlationId:c||void 0,message:d,isSpecial:u}}function sr({isOpen:t,onClose:s}){const[n,r]=o.useState(""),[a,i]=o.useState(!1),[c,d]=o.useState(null),[u,h]=o.useState(!1),[l,m]=o.useState(350),[x,b]=o.useState(!1),j=o.useRef(0),f=o.useRef(0),g=o.useRef(null),v=o.useRef(!0),[p,y]=o.useState(new Set(["DEBUG","INFO","WARN","ERROR"])),[C,I]=o.useState(new Set(["HOOK","WORKER","SDK","PARSER","DB","SYSTEM","HTTP","SESSION","CHROMA"])),[w,_]=o.useState(!1),L=o.useMemo(()=>n?n.split(`
-`).map(tr):[],[n]),R=o.useMemo(()=>L.filter(k=>w?k.raw.includes("[ALIGNMENT]"):!k.level||!k.component?!0:p.has(k.level)&&C.has(k.component)),[L,p,C,w]),E=o.useCallback(()=>{if(!g.current)return!0;const{scrollTop:k,scrollHeight:M,clientHeight:F}=g.current;return M-k-F<50},[]),N=o.useCallback(()=>{g.current&&v.current&&(g.current.scrollTop=g.current.scrollHeight)},[]),A=o.useCallback(async()=>{v.current=E(),i(!0),d(null);try{const k=await fetch("/api/logs");if(!k.ok)throw new Error(`Failed to fetch logs: ${k.statusText}`);const M=await k.json();r(M.logs||"")}catch(k){d(k instanceof Error?k.message:"Unknown error")}finally{i(!1)}},[E]);o.useEffect(()=>{N()},[n,N]);const $=o.useCallback(async()=>{if(confirm("Are you sure you want to clear all logs?")){i(!0),d(null);try{const k=await fetch("/api/logs/clear",{method:"POST"});if(!k.ok)throw new Error(`Failed to clear logs: ${k.statusText}`);r("")}catch(k){d(k instanceof Error?k.message:"Unknown error")}finally{i(!1)}}},[]),D=o.useCallback(k=>{k.preventDefault(),b(!0),j.current=k.clientY,f.current=l},[l]);o.useEffect(()=>{if(!x)return;const k=F=>{const Q=j.current-F.clientY,Z=Math.min(Math.max(150,f.current+Q),window.innerHeight-100);m(Z)},M=()=>{b(!1)};return document.addEventListener("mousemove",k),document.addEventListener("mouseup",M),()=>{document.removeEventListener("mousemove",k),document.removeEventListener("mouseup",M)}},[x]),o.useEffect(()=>{t&&(v.current=!0,A())},[t,A]),o.useEffect(()=>{if(!t||!u)return;const k=setInterval(A,2e3);return()=>clearInterval(k)},[t,u,A]);const P=o.useCallback(k=>{y(M=>{const F=new Set(M);return F.has(k)?F.delete(k):F.add(k),F})},[]),T=o.useCallback(k=>{I(M=>{const F=new Set(M);return F.has(k)?F.delete(k):F.add(k),F})},[]),O=o.useCallback(k=>{y(k?new Set(["DEBUG","INFO","WARN","ERROR"]):new Set)},[]),z=o.useCallback(k=>{I(k?new Set(["HOOK","WORKER","SDK","PARSER","DB","SYSTEM","HTTP","SESSION","CHROMA"]):new Set)},[]);if(!t)return null;const K=k=>{const M=de.find(F=>F.key===k);return(M==null?void 0:M.color)||"text-base-content"},J=k=>{const M=ue.find(F=>F.key===k);return(M==null?void 0:M.color)||"text-base-content"},ne=k=>k.level==="ERROR"?"bg-error/10":k.level==="WARN"?"bg-warning/5":"",U=(k,M)=>{var Z,ie;if(!k.timestamp)return e.jsx("div",{className:"whitespace-pre-wrap break-all text-base-content/60",children:k.raw},M);const F=de.find(ae=>ae.key===k.level),Q=ue.find(ae=>ae.key===k.component);return e.jsxs("div",{className:`whitespace-pre-wrap break-all py-0.5 px-1 rounded ${ne(k)}`,children:[e.jsxs("span",{className:"text-base-content/40",children:["[",k.timestamp,"]"]})," ",e.jsxs("span",{className:`font-medium ${K(k.level)}`,title:k.level,children:["[",(F==null?void 0:F.icon)||""," ",(Z=k.level)==null?void 0:Z.padEnd(5),"]"]})," ",e.jsxs("span",{className:`font-medium ${J(k.component)}`,title:k.component,children:["[",(Q==null?void 0:Q.icon)||""," ",(ie=k.component)==null?void 0:ie.padEnd(7),"]"]})," ",k.correlationId&&e.jsxs(e.Fragment,{children:[e.jsxs("span",{className:"text-base-content/50",children:["[",k.correlationId,"]"]})," "]}),e.jsx("span",{className:k.isSpecial==="success"?"text-success":k.isSpecial==="failure"?"text-error":"text-base-content",children:k.message})]},M)};return e.jsxs("div",{className:"fixed bottom-0 left-0 right-0 bg-base-100 border-t border-base-300 flex flex-col z-50 shadow-2xl",style:{height:`${l}px`},children:[e.jsx("div",{className:"h-1.5 cursor-ns-resize flex items-center justify-center bg-base-200 hover:bg-base-300 transition-colors",onMouseDown:D,children:e.jsx("div",{className:"w-12 h-1 bg-base-300 rounded-full"})}),e.jsxs("div",{className:"flex justify-between items-center px-3 h-9 bg-base-200 border-b border-base-300",children:[e.jsx("div",{className:"flex gap-1",children:e.jsx("div",{className:"px-3 py-1 text-xs font-medium bg-base-100 text-base-content rounded",children:"Console"})}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsxs("label",{className:"flex items-center gap-1.5 text-xs text-base-content/60 cursor-pointer",children:[e.jsx("input",{type:"checkbox",className:"checkbox checkbox-xs",checked:u,onChange:k=>h(k.target.checked)}),"Auto-refresh"]}),e.jsx("button",{className:"btn btn-ghost btn-xs btn-square",onClick:A,disabled:a,title:"Refresh logs",children:e.jsx(S,{icon:"lucide:refresh-cw",size:14,className:a?"animate-spin":""})}),e.jsx("button",{className:"btn btn-ghost btn-xs btn-square",onClick:()=>{v.current=!0,N()},title:"Scroll to bottom",children:e.jsx(S,{icon:"lucide:arrow-down",size:14})}),e.jsx("button",{className:"btn btn-ghost btn-xs btn-square hover:text-error",onClick:$,disabled:a,title:"Clear logs",children:e.jsx(S,{icon:"lucide:trash-2",size:14})}),e.jsx("button",{className:"btn btn-ghost btn-xs btn-square",onClick:s,title:"Close console",children:e.jsx(S,{icon:"lucide:x",size:14})})]})]}),e.jsxs("div",{className:"flex flex-wrap gap-3 px-3 py-2 bg-base-200/50 border-b border-base-300 text-xs",children:[e.jsxs("div",{className:"flex items-center gap-1.5",children:[e.jsx("span",{className:"font-medium text-base-content/50 uppercase text-[10px]",children:"Quick:"}),e.jsx("button",{className:`badge badge-sm cursor-pointer ${w?"badge-warning":"badge-ghost opacity-50"}`,onClick:()=>_(!w),title:"Show only session alignment logs",children:"🔗 Alignment"})]}),e.jsxs("div",{className:"flex items-center gap-1.5",children:[e.jsx("span",{className:"font-medium text-base-content/50 uppercase text-[10px]",children:"Levels:"}),e.jsxs("div",{className:"flex flex-wrap gap-1",children:[de.map(k=>e.jsxs("button",{className:`badge badge-sm cursor-pointer ${p.has(k.key)?"badge-primary":"badge-ghost opacity-40"}`,onClick:()=>P(k.key),title:k.label,children:[k.icon," ",k.label]},k.key)),e.jsx("button",{className:"badge badge-sm badge-ghost cursor-pointer",onClick:()=>O(p.size===0),title:p.size===de.length?"Select none":"Select all",children:p.size===de.length?"○":"●"})]})]}),e.jsxs("div",{className:"flex items-center gap-1.5",children:[e.jsx("span",{className:"font-medium text-base-content/50 uppercase text-[10px]",children:"Components:"}),e.jsxs("div",{className:"flex flex-wrap gap-1",children:[ue.map(k=>e.jsxs("button",{className:`badge badge-sm cursor-pointer ${C.has(k.key)?"badge-secondary":"badge-ghost opacity-40"}`,onClick:()=>T(k.key),title:k.label,children:[k.icon," ",k.label]},k.key)),e.jsx("button",{className:"badge badge-sm badge-ghost cursor-pointer",onClick:()=>z(C.size===0),title:C.size===ue.length?"Select none":"Select all",children:C.size===ue.length?"○":"●"})]})]})]}),c&&e.jsxs("div",{className:"px-3 py-2 bg-error/10 text-error text-xs",children:["⚠ ",c]}),e.jsx("div",{className:"flex-1 overflow-y-auto px-3 py-2",ref:g,children:e.jsx("div",{className:"font-mono text-xs leading-relaxed",children:R.length===0?e.jsx("div",{className:"text-base-content/40 italic",children:"No logs available"}):R.map((k,M)=>U(k,M))})})]})}const Oe={COMMAND_PALETTE:{key:"k",modifiers:["ctrl","meta"],description:"Open command palette",action:"openCommandPalette"},SEARCH:{key:"/",modifiers:["ctrl","meta"],description:"Focus search",action:"focusSearch"},ESCAPE:{key:"Escape",description:"Close modal/palette",action:"escape"},TOGGLE_THEME:{key:"t",modifiers:["ctrl","meta"],description:"Toggle theme",action:"toggleTheme"},TOGGLE_SIDEBAR:{key:"b",modifiers:["ctrl","meta"],description:"Toggle sidebar",action:"toggleSidebar"}},nr=[{sequence:["g","d"],description:"Go to Dashboard",action:"navigate:/"},{sequence:["g","c"],description:"Go to Changes",action:"navigate:/changes"},{sequence:["g","m"],description:"Go to Memories",action:"navigate:/memories"},{sequence:["g","v"],description:"Go to Extensions",action:"navigate:/extensions"},{sequence:["g","h"],description:"Go to Help",action:"navigate:/help"}];function yt(t){var r,a,i,c;const s=typeof navigator<"u"&&navigator.platform.includes("Mac"),n=[];return((r=t.modifiers)!=null&&r.includes("ctrl")||(a=t.modifiers)!=null&&a.includes("meta"))&&n.push(s?"⌘":"Ctrl"),(i=t.modifiers)!=null&&i.includes("shift")&&n.push(s?"⇧":"Shift"),(c=t.modifiers)!=null&&c.includes("alt")&&n.push(s?"⌥":"Alt"),n.push(t.key.toUpperCase()),n.join(s?"":"+")}function ar({open:t,onClose:s,onNavigate:n,onToggleTheme:r,onToggleSidebar:a}){const[i,c]=o.useState(""),[d,u]=o.useState(0),h=o.useRef(null),l=o.useRef(null),m=o.useMemo(()=>[{id:"nav-dashboard",label:"Go to Dashboard",shortcut:"G D",category:"navigation",icon:"lucide:layout-dashboard",action:()=>n("/")},{id:"nav-changes",label:"Go to Changes",shortcut:"G C",category:"navigation",icon:"lucide:git-compare",action:()=>n("/changes")},{id:"nav-memories",label:"Go to Memories",shortcut:"G M",category:"navigation",icon:"lucide:brain",action:()=>n("/memories")},{id:"nav-usage",label:"Go to Usage",shortcut:"G U",category:"navigation",icon:"lucide:bar-chart-3",action:()=>n("/usage")},{id:"nav-extensions",label:"Go to Extensions",shortcut:"G V",category:"navigation",icon:"lucide:puzzle",action:()=>n("/extensions")},{id:"nav-help",label:"Go to Help",shortcut:"G H",category:"navigation",icon:"lucide:book-open",action:()=>n("/help")},{id:"action-theme",label:"Toggle Theme",shortcut:yt(Oe.TOGGLE_THEME),category:"action",icon:"lucide:sun-moon",action:r},{id:"action-sidebar",label:"Toggle Sidebar",shortcut:yt(Oe.TOGGLE_SIDEBAR),category:"action",icon:"lucide:panel-left",action:a}],[n,r,a]),x=o.useMemo(()=>{if(!i)return m;const p=i.toLowerCase();return m.filter(y=>y.label.toLowerCase().includes(p)||y.category.toLowerCase().includes(p))},[m,i]);o.useEffect(()=>{u(0)},[i]),o.useEffect(()=>{t&&(c(""),u(0),setTimeout(()=>{var p;return(p=h.current)==null?void 0:p.focus()},50))},[t]),o.useEffect(()=>{if(!l.current)return;const p=l.current.querySelector('[data-selected="true"]');p==null||p.scrollIntoView({block:"nearest"})},[d]);const b=p=>{p.action(),s()},j=p=>{switch(p.key){case"ArrowDown":p.preventDefault(),u(y=>(y+1)%x.length);break;case"ArrowUp":p.preventDefault(),u(y=>(y-1+x.length)%x.length);break;case"Enter":p.preventDefault(),x[d]&&b(x[d]);break;case"Escape":p.preventDefault(),s();break}};if(!t)return null;const f=x.reduce((p,y)=>(p[y.category]||(p[y.category]=[]),p[y.category].push(y),p),{}),g={navigation:"Navigation",action:"Actions",theme:"Theme"};let v=0;return e.jsxs("dialog",{className:"modal modal-open",children:[e.jsxs("div",{className:"modal-box max-w-xl p-0 overflow-hidden",children:[e.jsxs("div",{className:"flex items-center gap-2 p-3 border-b border-base-300",children:[e.jsx(S,{icon:"lucide:search",size:18,className:"text-base-content/50"}),e.jsx("input",{ref:h,type:"text",placeholder:"Type a command or search...",value:i,onChange:p=>c(p.target.value),onKeyDown:j,className:"flex-1 bg-transparent outline-none text-base"}),e.jsx("kbd",{className:"kbd kbd-sm",children:"ESC"})]}),e.jsx("div",{ref:l,className:"max-h-80 overflow-y-auto p-2",children:x.length===0?e.jsx("div",{className:"text-center py-8 text-base-content/50",children:"No commands found"}):Object.entries(f).map(([p,y])=>e.jsxs("div",{children:[e.jsx("div",{className:"text-xs font-medium text-base-content/50 px-2 py-1 mt-2 first:mt-0",children:g[p]||p}),y.map(C=>{const I=v===d,w=v;return v++,e.jsxs("button",{"data-selected":I,className:`w-full flex items-center gap-3 px-3 py-2 rounded-lg text-left transition-colors ${I?"bg-primary text-primary-content":"hover:bg-base-200"}`,onClick:()=>b(C),onMouseEnter:()=>u(w),children:[e.jsx(S,{icon:C.icon,size:16,className:I?"text-primary-content":"text-base-content/60"}),e.jsx("span",{className:"flex-1",children:C.label}),C.shortcut&&e.jsx("kbd",{className:`kbd kbd-sm ${I?"bg-primary-content/20 text-primary-content":""}`,children:C.shortcut})]},C.id)})]},p))}),e.jsxs("div",{className:"border-t border-base-300 px-3 py-2 text-xs text-base-content/50 flex gap-4",children:[e.jsxs("span",{children:[e.jsx("kbd",{className:"kbd kbd-xs",children:"↑↓"})," Navigate"]}),e.jsxs("span",{children:[e.jsx("kbd",{className:"kbd kbd-xs",children:"↵"})," Select"]}),e.jsxs("span",{children:[e.jsx("kbd",{className:"kbd kbd-xs",children:"ESC"})," Close"]})]})]}),e.jsx("form",{method:"dialog",className:"modal-backdrop bg-black/50",children:e.jsx("button",{onClick:s,children:"close"})})]})}function rr({license:t,onActivated:s}){const[n,r]=o.useState(""),[a,i]=o.useState(null),[c,d]=o.useState(!1),u=o.useCallback(async()=>{const b=n.trim();if(b){i(null),d(!0);try{const f=await(await fetch("/api/license/activate",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({key:b})})).json();f.success?(r(""),i(null),s()):i(f.error??"Activation failed")}catch{i("Connection failed. Is the Pilot worker running?")}finally{d(!1)}}},[n,s]),h=o.useCallback(b=>{b.key==="Enter"&&!c&&u()},[u,c]),l=(t==null?void 0:t.isExpired)===!0,m=l?"License Expired":"License Required",x=l?"Your Pilot Shell license has expired. Please activate a new license to continue using the Console.":"Pilot Shell Console requires an active license or trial. Activate your license key below to get started.";return e.jsx("div",{className:"min-h-screen flex items-center justify-center bg-base-200 p-4",children:e.jsx("div",{className:"card bg-base-100 shadow-xl w-full max-w-md",children:e.jsxs("div",{className:"card-body items-center text-center gap-4",children:[e.jsx("div",{className:"text-5xl mb-2",children:l?"🚫":"🔒"}),e.jsx("h1",{className:"card-title text-2xl",children:m}),e.jsx("p",{className:"text-base-content/60 text-sm",children:x}),e.jsxs("div",{className:"w-full space-y-3 mt-2",children:[e.jsx("input",{type:"text",className:"input input-bordered w-full",placeholder:"Enter your license key",value:n,onChange:b=>{r(b.target.value),i(null)},onKeyDown:h,disabled:c,autoFocus:!0}),a&&e.jsx("p",{className:"text-error text-sm text-left",children:a}),e.jsx("button",{className:"btn btn-primary w-full",onClick:u,disabled:c||!n.trim(),children:c?"Activating...":"Activate License"})]}),e.jsx("div",{className:"divider text-base-content/40 text-xs my-1",children:"or"}),e.jsx("a",{href:"https://pilot-shell.com/#pricing",target:"_blank",rel:"noopener noreferrer",className:"btn btn-outline btn-sm w-full",children:"Get a License"}),e.jsxs("p",{className:"text-base-content/40 text-xs mt-2",children:["Visit"," ",e.jsx("a",{href:"https://pilot-shell.com",target:"_blank",rel:"noopener noreferrer",className:"text-primary hover:underline",children:"pilot-shell.com"})," ","to learn more about Pilot Shell."]})]})})})}const ir={totalGlobal:0,totalProject:0,totalPlugin:0,totalRemote:0};function or(){try{const t=localStorage.getItem("pilot-extensions-status");if(t)return JSON.parse(t)}catch{}return ir}function cr(){const{selectedProject:t,setProjects:s}=X(),[n,r]=o.useState({observations:0,summaries:0,sessions:0,lastObservationAt:null,projects:0}),[a,i]=o.useState({status:"offline"}),[c,d]=o.useState([]),[u,h]=o.useState({active:!1,plans:[]}),[l,m]=o.useState({branch:null,staged:0,unstaged:0,untracked:0,totalFiles:0}),[x,b]=o.useState({totalSpecs:0,verified:0,inProgress:0,pending:0,avgIterations:0,totalTasksCompleted:0,totalTasks:0,completionTimeline:[],recentlyVerified:[]}),[j,f]=o.useState(0),[g,v]=o.useState(0),[p,y]=o.useState(0),[C,I]=o.useState([]),[w,_]=o.useState(or),[L,R]=o.useState(!0),E=o.useCallback(async()=>{var $;try{const D=await fetch("/api/extensions?all=true").catch(()=>null);if(!(D!=null&&D.ok))return;const T=(await D.json()).extensions??[],O=T.filter(U=>U.scope==="global"&&!U.pluginName),z=T.filter(U=>U.scope==="project"),K=T.filter(U=>U.pluginName!=null);let J=0;try{const U=await fetch("/api/team-remote/extensions").catch(()=>null);U!=null&&U.ok&&(J=(($=(await U.json()).extensions)==null?void 0:$.length)??0)}catch{}const ne={totalGlobal:O.length,totalProject:z.length,totalPlugin:K.length,totalRemote:J};_(ne);try{localStorage.setItem("pilot-extensions-status",JSON.stringify(ne))}catch{}}catch{}},[]),N=o.useCallback(async()=>{const $=t?`?project=${encodeURIComponent(t)}`:"";Promise.all([fetch(`/api/stats${$}`),fetch("/health"),fetch(`/api/observations?limit=6${t?`&project=${encodeURIComponent(t)}`:""}`),fetch("/api/projects")]).then(async([D,P,T,O])=>{var Q,Z,ie,ae,Ve,Be,Ke;const z=await D.json(),K=await P.json(),J=await T.json(),ne=await O.json(),U=J.items||J.observations||J||[],k=Array.isArray(U)?U:[],M=k.length>0&&((Q=k[0])==null?void 0:Q.created_at)||null,F=ne.projects||[];s(F),r({observations:((Z=z.database)==null?void 0:Z.observations)||0,summaries:((ie=z.database)==null?void 0:ie.summaries)||0,sessions:((ae=z.database)==null?void 0:ae.sessions)||0,lastObservationAt:M?wt(M):null,projects:F.length}),i({status:K.status==="ok"?K.isProcessing?"processing":"online":"offline",version:(Ve=z.worker)==null?void 0:Ve.version,uptime:(Be=z.worker)!=null&&Be.uptime?lr(z.worker.uptime):void 0,queueDepth:K.queueDepth||0,workspaceProject:(Ke=z.worker)==null?void 0:Ke.workspaceProject}),d(k.slice(0,2).map(ee=>{var We;return{id:ee.id,type:ee.obs_type||ee.type||"observation",title:ee.title||((We=ee.content)==null?void 0:We.slice(0,100))||"Untitled",project:ee.project||"unknown",timestamp:wt(ee.created_at)}})),R(!1)}).catch(D=>{console.error("Failed to load core stats:",D),i({status:"offline"}),R(!1)}),fetch(`/api/plan${$}`).then(async D=>{const P=await D.json(),T=P.plans||(P.plan?[P.plan]:[]);h({active:T.length>0,plans:T})}).catch(()=>{}),fetch(`/api/git${$}`).then(async D=>{const P=await D.json();m({branch:P.branch||null,staged:P.staged||0,unstaged:P.unstaged||0,untracked:P.untracked||0,totalFiles:P.totalFiles||0})}).catch(()=>{}),fetch("/api/plans/active/all").then(async D=>{if(!D.ok)return;const T=(await D.json()).specs||[];b({totalSpecs:T.length,verified:T.filter(O=>O.status==="VERIFIED").length,inProgress:T.filter(O=>O.status==="COMPLETE"||O.status==="PENDING").length,pending:T.filter(O=>O.status==="PENDING").length,avgIterations:0,totalTasksCompleted:0,totalTasks:0,completionTimeline:[],recentlyVerified:[]})}).catch(()=>{}),fetch("/api/prd/all").then(async D=>{if(!D.ok)return;const P=await D.json();f((P.prds||[]).length)}).catch(()=>{}),fetch("/api/usage/daily").then(async D=>{if(!D.ok)return;const T=(await D.json()).daily||[],O=new Date().toISOString().slice(0,10),z=T.find(K=>K.date===O);v((z==null?void 0:z.totalCost)??0)}).catch(()=>{}),fetch("/api/sessions?limit=50").then(async D=>{if(!D.ok)return;const T=(await D.json()).items||[];y(T.filter(O=>O.status==="active").length)}).catch(()=>{}),fetch(`/api/analytics/timeline?range=30d${t?`&project=${encodeURIComponent(t)}`:""}`).then(async D=>{if(!D.ok)return;const P=await D.json();I(P.data||[])}).catch(()=>{})},[t,s]),A=o.useRef(N);return o.useEffect(()=>{A.current=N},[N]),o.useEffect(()=>{N()},[N]),o.useEffect(()=>{E();const $=new EventSource("/stream");return $.onmessage=D=>{try{const P=JSON.parse(D.data);P.type==="processing_status"&&i(T=>({...T,status:P.isProcessing?"processing":"online",queueDepth:P.queueDepth??T.queueDepth})),(P.type==="new_observation"||P.type==="new_summary"||P.type==="plan_association_changed")&&A.current()}catch{}},()=>{$.close()}},[E]),{stats:n,workerStatus:a,extensionsStatus:w,recentActivity:c,planStatus:u,gitInfo:l,specStats:x,prdCount:j,todayCost:g,activeSessions:p,observationTimeline:C,isLoading:L,refreshStats:N}}function wt(t){if(!t)return"";const s=new Date(t),r=new Date().getTime()-s.getTime();return r<6e4?"just now":r<36e5?`${Math.floor(r/6e4)}m ago`:r<864e5?`${Math.floor(r/36e5)}h ago`:s.toLocaleDateString()}function lr(t){return t<60?`${t}s`:t<3600?`${Math.floor(t/60)}m`:t<86400?`${Math.floor(t/3600)}h`:`${Math.floor(t/86400)}d`}function dr(t,s={}){const{enabled:n=!0}=s,r=o.useRef([]),a=o.useRef(null),i=o.useCallback(()=>{r.current=[],a.current&&(clearTimeout(a.current),a.current=null)},[]);o.useEffect(()=>{if(!n)return;const c=d=>{const u=d.target;if(u.tagName==="INPUT"||u.tagName==="TEXTAREA"||u.isContentEditable){d.key==="Escape"&&t("escape");return}navigator.platform.includes("Mac");const h=d.ctrlKey||d.metaKey;for(const l of Object.values(Oe)){const m=!l.modifiers||l.modifiers.some(j=>j==="ctrl"?d.ctrlKey:j==="meta"?d.metaKey:j==="shift"?d.shiftKey:j==="alt"?d.altKey:!1),x=d.key.toLowerCase()===l.key.toLowerCase(),b=l.modifiers&&l.modifiers.length>0;if(x&&m&&(b?h:!h)){d.preventDefault(),t(l.action),i();return}}if(!h&&!d.shiftKey&&!d.altKey){a.current&&clearTimeout(a.current),r.current.push(d.key.toLowerCase()),a.current=setTimeout(i,1e3);for(const l of nr){const m=r.current,x=l.sequence;if(x.slice(0,m.length).every((j,f)=>j===m[f])){if(m.length===x.length){d.preventDefault(),t(l.action),i();return}return}}i()}};return document.addEventListener("keydown",c),()=>{document.removeEventListener("keydown",c),i()}},[n,t,i])}const ur=o.lazy(()=>B(()=>import("./index.js"),__vite__mapDeps([5,1,3,4]),import.meta.url).then(t=>({default:t.DashboardView}))),mr=o.lazy(()=>B(()=>import("./index2.js"),__vite__mapDeps([6,1,3,4,7,8]),import.meta.url).then(t=>({default:t.ChangesView}))),hr=o.lazy(()=>B(()=>import("./index3.js"),__vite__mapDeps([9,1,3,4,7]),import.meta.url).then(t=>({default:t.SpecView}))),fr=o.lazy(()=>B(()=>import("./index4.js"),__vite__mapDeps([10,1,3,4]),import.meta.url).then(t=>({default:t.UsageView}))),xr=o.lazy(()=>B(()=>import("./ExtensionsView.js"),__vite__mapDeps([11,1,3,4]),import.meta.url).then(t=>({default:t.ExtensionsView}))),pr=o.lazy(()=>B(()=>import("./index5.js"),__vite__mapDeps([12,1,3,4,2]),import.meta.url).then(t=>({default:t.SharedSpecView}))),br=o.lazy(()=>B(()=>import("./index5.js"),__vite__mapDeps([12,1,3,4,2]),import.meta.url).then(t=>({default:t.FeedbackImportView}))),gr=[{path:"/",component:ur},{path:"/requirements",component:er},{path:"/spec",component:hr},{path:"/changes",component:mr},{path:"/memories",component:ft},{path:"/memories/:type",component:ft},{path:"/sessions",component:Ca},{path:"/usage",component:fr},{path:"/extensions",component:xr},{path:"/settings",component:La},{path:"/help",component:ta},{path:"/shared/:data",component:pr},{path:"/feedback/:data",component:br}],Nt="pilot-memory-sidebar-collapsed";function jr(){const{path:t,navigate:s}=se(),{resolvedTheme:n,setThemePreference:r}=Ft(),{workerStatus:a}=cr(),i=a.version,{license:c,isLoading:d,refetch:u}=Mt(),[h,l]=o.useState(()=>{if(typeof window<"u"&&window.innerWidth<1024)return!0;try{return localStorage.getItem(Nt)==="true"}catch{return!1}}),[m,x]=o.useState(!1),[b,j]=o.useState(!1),f=o.useCallback(()=>{r(n==="light"?"dark":"light")},[n,r]),g=o.useCallback(()=>{l(I=>{const w=!I;try{localStorage.setItem(Nt,String(w))}catch{}return w})},[]),v=o.useCallback(()=>{x(I=>!I)},[]),p=o.useCallback(I=>{if(I==="openCommandPalette")j(!0);else if(I==="escape")j(!1),x(!1);else if(I==="toggleTheme")r(n==="light"?"dark":"light");else if(I==="toggleSidebar")g();else if(I==="focusSearch"){const w=document.querySelector('input[type="search"]');w==null||w.focus()}else I.startsWith("navigate:")&&s(I.replace("navigate:",""))},[n,r,s,g]);dr(p);const y=!d&&(c==null?void 0:c.valid)===!0&&!c.isExpired,C=n==="dark"?"pilot-shell":"pilot-shell-light";return d?e.jsx("div",{className:"min-h-screen flex items-center justify-center bg-base-200","data-theme":C,children:e.jsxs("div",{className:"animate-pulse space-y-3 w-64",children:[e.jsx("div",{className:"h-8 bg-base-300/50 rounded w-3/4 mx-auto"}),e.jsx("div",{className:"h-4 bg-base-300/50 rounded w-1/2 mx-auto"})]})}):y?e.jsx("div",{"data-theme":C,children:e.jsx(us,{children:e.jsx(Un,{children:e.jsxs(zn,{children:[e.jsx(Xn,{currentPath:`#${t}`,version:i,workerStatus:a.status,queueDepth:a.queueDepth??0,onToggleTheme:f,onToggleLogs:v,sidebarCollapsed:h,onToggleSidebar:g,children:e.jsx(o.Suspense,{fallback:e.jsx(te,{}),children:e.jsx(Zn,{routes:gr})})}),e.jsx(sr,{isOpen:m,onClose:()=>x(!1)}),e.jsx(ar,{open:b,onClose:()=>j(!1),onNavigate:s,onToggleTheme:f,onToggleSidebar:g})]})})})}):e.jsx("div",{"data-theme":C,children:e.jsx(rr,{license:c,onActivated:u})})}class vr extends o.Component{constructor(s){super(s),this.state={hasError:!1,error:null,errorInfo:null}}static getDerivedStateFromError(s){return{hasError:!0,error:s}}componentDidCatch(s,n){console.error("[ErrorBoundary] Caught error:",s,n),this.setState({error:s,errorInfo:n})}render(){return this.state.hasError?e.jsxs("div",{className:"p-5 min-h-screen bg-base-200 text-error",children:[e.jsx("h1",{className:"text-2xl font-bold mb-2.5",children:"Something went wrong"}),e.jsx("p",{className:"mb-2.5 text-base-content/60",children:"The application encountered an error. Please refresh the page to try again."}),this.state.error&&e.jsxs("details",{className:"mt-5 text-base-content/60",children:[e.jsx("summary",{className:"cursor-pointer mb-2.5",children:"Error details"}),e.jsxs("pre",{className:"bg-base-300 p-2.5 rounded-lg overflow-auto text-sm",children:[this.state.error.toString(),this.state.errorInfo&&`
+const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./PlanAnnotator.js","./vendor-markdown.js","./vendor-charts.js","./vendor-diff.js","./index.js","./index2.js","./Spinner.js","./viewer2.css","./index3.js","./index4.js","./ExtensionsView.js","./index5.js"])))=>i.map(i=>d[i]);
+import{j as e,a as o,M as Yt,b as Xt}from"./vendor-markdown.js";import{r as Zt,a as es}from"./vendor-charts.js";import"./vendor-diff.js";(function(){const s=document.createElement("link").relList;if(s&&s.supports&&s.supports("modulepreload"))return;for(const a of document.querySelectorAll('link[rel="modulepreload"]'))r(a);new MutationObserver(a=>{for(const i of a)if(i.type==="childList")for(const c of i.addedNodes)c.tagName==="LINK"&&c.rel==="modulepreload"&&r(c)}).observe(document,{childList:!0,subtree:!0});function n(a){const i={};return a.integrity&&(i.integrity=a.integrity),a.referrerPolicy&&(i.referrerPolicy=a.referrerPolicy),a.crossOrigin==="use-credentials"?i.credentials="include":a.crossOrigin==="anonymous"?i.credentials="omit":i.credentials="same-origin",i}function r(a){if(a.ep)return;a.ep=!0;const i=n(a);fetch(a.href,i)}})();var be={},Je;function ts(){if(Je)return be;Je=1;var t=Zt();return be.createRoot=t.createRoot,be.hydrateRoot=t.hydrateRoot,be}var ss=ts();const ns="modulepreload",as=function(t,s){return new URL(t,s).href},Qe={},V=function(s,n,r){let a=Promise.resolve();if(n&&n.length>0){let c=function(l){return Promise.all(l.map(m=>Promise.resolve(m).then(x=>({status:"fulfilled",value:x}),x=>({status:"rejected",reason:x}))))};const d=document.getElementsByTagName("link"),u=document.querySelector("meta[property=csp-nonce]"),h=(u==null?void 0:u.nonce)||(u==null?void 0:u.getAttribute("nonce"));a=c(n.map(l=>{if(l=as(l,r),l in Qe)return;Qe[l]=!0;const m=l.endsWith(".css"),x=m?'[rel="stylesheet"]':"";if(!!r)for(let f=d.length-1;f>=0;f--){const g=d[f];if(g.href===l&&(!m||g.rel==="stylesheet"))return}else if(document.querySelector(`link[href="${l}"]${x}`))return;const j=document.createElement("link");if(j.rel=m?"stylesheet":ns,m||(j.as="script"),j.crossOrigin="",j.href=l,h&&j.setAttribute("nonce",h),document.head.appendChild(j),m)return new Promise((f,g)=>{j.addEventListener("load",f),j.addEventListener("error",()=>g(new Error(`Unable to preload CSS for ${l}`)))})}))}function i(c){const d=new Event("vite:preloadError",{cancelable:!0});if(d.payload=c,window.dispatchEvent(d),!d.defaultPrevented)throw c}return a.then(c=>{for(const d of c||[])d.status==="rejected"&&i(d.reason);return s().catch(i)})};function rs(){return e.jsx("a",{href:"#/",className:"flex items-center",children:e.jsx("span",{className:"font-bold text-lg",children:"Pilot Shell Console"})})}const is={primary:"btn-primary",secondary:"btn-secondary",ghost:"btn-ghost",outline:"btn-outline",error:"btn-error"},os={xs:"btn-xs",sm:"btn-sm",md:"",lg:"btn-lg"};function W({variant:t="primary",size:s="md",loading:n=!1,className:r="",children:a,disabled:i,...c}){return e.jsxs("button",{className:`btn ${is[t]} ${os[s]} active:scale-[0.98] transition-transform ${r}`,disabled:i||n,...c,children:[n&&e.jsx("span",{className:"loading loading-spinner loading-sm"}),a]})}function B({children:t,className:s="",compact:n=!1,interactive:r,onClick:a}){const i=r??!!a;return e.jsx("div",{className:`card bg-base-100 shadow-sm border border-base-200 transition-all duration-150 ${i?"cursor-pointer hover:-translate-y-0.5 hover:shadow-md hover:border-base-content/15":""} ${n?"card-compact":""} ${s}`,onClick:a,children:t})}function H({children:t,className:s=""}){return e.jsx("div",{className:`card-body ${s}`,children:t})}function kr({children:t,className:s=""}){return e.jsx("h2",{className:`card-title ${s}`,children:t})}const cs={primary:"badge-primary",secondary:"badge-secondary",accent:"badge-accent",ghost:"badge-ghost",info:"badge-info",success:"badge-success",warning:"badge-warning",error:"badge-error"},ls={xs:"badge-xs",sm:"badge-sm",md:"",lg:"badge-lg"};function q({children:t,variant:s="ghost",size:n="md",outline:r=!1,className:a=""}){return e.jsx("span",{className:`badge ${cs[s]} ${ls[n]} ${r?"badge-outline":""} ${a}`,children:t})}const ds={default:"modal-box surface-elevated",wide:"modal-box surface-elevated max-w-4xl w-[90vw]"};function fe({open:t,onClose:s,title:n,children:r,actions:a,size:i="default"}){const c=e.jsxs("dialog",{className:`modal ${t?"modal-open":""}`,children:[e.jsxs("div",{className:ds[i],children:[e.jsxs("div",{className:"flex items-center justify-between",children:[n&&e.jsx("h3",{className:"font-bold text-lg",children:n}),e.jsx("button",{className:"btn btn-sm btn-circle btn-ghost",onClick:s,"aria-label":"Close",children:"✕"})]}),e.jsx("div",{className:"py-4",children:r}),a&&e.jsx("div",{className:"modal-action",children:a})]}),e.jsx("form",{method:"dialog",className:"modal-backdrop",children:e.jsx("button",{onClick:s,children:"close"})})]});return typeof document>"u"?c:es.createPortal(c,document.body)}const St=o.createContext(!1);function Cr(){return o.useContext(St)}function us({children:t}){const[s,n]=o.useState(()=>typeof window>"u"?!1:window.matchMedia("(prefers-reduced-motion: reduce)").matches);return o.useEffect(()=>{const r=window.matchMedia("(prefers-reduced-motion: reduce)"),a=i=>n(i.matches);return r.addEventListener("change",a),()=>r.removeEventListener("change",a)},[]),e.jsx(St.Provider,{value:s,children:t})}function ms(t,s){const n=t.icons,r=t.aliases||Object.create(null),a=Object.create(null);function i(c){if(n[c])return a[c]=[];if(!(c in a)){a[c]=null;const d=r[c]&&r[c].parent,u=d&&i(d);u&&(a[c]=[d].concat(u))}return a[c]}return Object.keys(n).concat(Object.keys(r)).forEach(i),a}const kt=Object.freeze({left:0,top:0,width:16,height:16}),ye=Object.freeze({rotate:0,vFlip:!1,hFlip:!1}),Me=Object.freeze({...kt,...ye}),De=Object.freeze({...Me,body:"",hidden:!1});function hs(t,s){const n={};!t.hFlip!=!s.hFlip&&(n.hFlip=!0),!t.vFlip!=!s.vFlip&&(n.vFlip=!0);const r=((t.rotate||0)+(s.rotate||0))%4;return r&&(n.rotate=r),n}function Ye(t,s){const n=hs(t,s);for(const r in De)r in ye?r in t&&!(r in n)&&(n[r]=ye[r]):r in s?n[r]=s[r]:r in t&&(n[r]=t[r]);return n}function fs(t,s,n){const r=t.icons,a=t.aliases||Object.create(null);let i={};function c(d){i=Ye(r[d]||a[d],i)}return c(s),n.forEach(c),Ye(t,i)}function Ct(t,s){const n=[];if(typeof t!="object"||typeof t.icons!="object")return n;t.not_found instanceof Array&&t.not_found.forEach(a=>{s(a,null),n.push(a)});const r=ms(t);for(const a in r){const i=r[a];i&&(s(a,fs(t,a,i)),n.push(a))}return n}const xs={provider:"",aliases:{},not_found:{},...kt};function Se(t,s){for(const n in s)if(n in t&&typeof t[n]!=typeof s[n])return!1;return!0}function Et(t){if(typeof t!="object"||t===null)return null;const s=t;if(typeof s.prefix!="string"||!t.icons||typeof t.icons!="object"||!Se(t,xs))return null;const n=s.icons;for(const a in n){const i=n[a];if(!a||typeof i.body!="string"||!Se(i,De))return null}const r=s.aliases||Object.create(null);for(const a in r){const i=r[a],c=i.parent;if(!a||typeof c!="string"||!n[c]&&!r[c]||!Se(i,De))return null}return s}const Xe=Object.create(null);function ps(t,s){return{provider:t,prefix:s,icons:Object.create(null),missing:new Set}}function re(t,s){const n=Xe[t]||(Xe[t]=Object.create(null));return n[s]||(n[s]=ps(t,s))}function Rt(t,s){return Et(s)?Ct(s,(n,r)=>{r?t.icons[n]=r:t.missing.add(n)}):[]}function bs(t,s,n){try{if(typeof n.body=="string")return t.icons[s]={...n},!0}catch{}return!1}const Pt=/^[a-z0-9]+(-[a-z0-9]+)*$/,Ne=(t,s,n,r="")=>{const a=t.split(":");if(t.slice(0,1)==="@"){if(a.length<2||a.length>3)return null;r=a.shift().slice(1)}if(a.length>3||!a.length)return null;if(a.length>1){const d=a.pop(),u=a.pop(),h={provider:a.length>0?a[0]:r,prefix:u,name:d};return s&&!je(h)?null:h}const i=a[0],c=i.split("-");if(c.length>1){const d={provider:r,prefix:c.shift(),name:c.join("-")};return s&&!je(d)?null:d}if(n&&r===""){const d={provider:r,prefix:"",name:i};return s&&!je(d,n)?null:d}return null},je=(t,s)=>t?!!((s&&t.prefix===""||t.prefix)&&t.name):!1;let xe=!1;function Tt(t){return typeof t=="boolean"&&(xe=t),xe}function Ze(t){const s=typeof t=="string"?Ne(t,!0,xe):t;if(s){const n=re(s.provider,s.prefix),r=s.name;return n.icons[r]||(n.missing.has(r)?null:void 0)}}function gs(t,s){const n=Ne(t,!0,xe);if(!n)return!1;const r=re(n.provider,n.prefix);return s?bs(r,n.name,s):(r.missing.add(n.name),!0)}function js(t,s){if(typeof t!="object")return!1;if(typeof s!="string"&&(s=t.provider||""),xe&&!s&&!t.prefix){let a=!1;return Et(t)&&(t.prefix="",Ct(t,(i,c)=>{gs(i,c)&&(a=!0)})),a}const n=t.prefix;if(!je({prefix:n,name:"a"}))return!1;const r=re(s,n);return!!Rt(r,t)}const It=Object.freeze({width:null,height:null}),Dt=Object.freeze({...It,...ye}),vs=/(-?[0-9.]*[0-9]+[0-9.]*)/g,ys=/^-?[0-9.]*[0-9]+[0-9.]*$/g;function et(t,s,n){if(s===1)return t;if(n=n||100,typeof t=="number")return Math.ceil(t*s*n)/n;if(typeof t!="string")return t;const r=t.split(vs);if(r===null||!r.length)return t;const a=[];let i=r.shift(),c=ys.test(i);for(;;){if(c){const d=parseFloat(i);isNaN(d)?a.push(i):a.push(Math.ceil(d*s*n)/n)}else a.push(i);if(i=r.shift(),i===void 0)return a.join("");c=!c}}function ws(t,s="defs"){let n="";const r=t.indexOf("<"+s);for(;r>=0;){const a=t.indexOf(">",r),i=t.indexOf(""+s);if(a===-1||i===-1)break;const c=t.indexOf(">",i);if(c===-1)break;n+=t.slice(a+1,i).trim(),t=t.slice(0,r).trim()+t.slice(c+1)}return{defs:n,content:t}}function Ns(t,s){return t?""+t+" "+s:s}function Ss(t,s,n){const r=ws(t);return Ns(r.defs,s+r.content+n)}const ks=t=>t==="unset"||t==="undefined"||t==="none";function Cs(t,s){const n={...Me,...t},r={...Dt,...s},a={left:n.left,top:n.top,width:n.width,height:n.height};let i=n.body;[n,r].forEach(f=>{const g=[],v=f.hFlip,p=f.vFlip;let w=f.rotate;v?p?w+=2:(g.push("translate("+(a.width+a.left).toString()+" "+(0-a.top).toString()+")"),g.push("scale(-1 1)"),a.top=a.left=0):p&&(g.push("translate("+(0-a.left).toString()+" "+(a.height+a.top).toString()+")"),g.push("scale(1 -1)"),a.top=a.left=0);let C;switch(w<0&&(w-=Math.floor(w/4)*4),w=w%4,w){case 1:C=a.height/2+a.top,g.unshift("rotate(90 "+C.toString()+" "+C.toString()+")");break;case 2:g.unshift("rotate(180 "+(a.width/2+a.left).toString()+" "+(a.height/2+a.top).toString()+")");break;case 3:C=a.width/2+a.left,g.unshift("rotate(-90 "+C.toString()+" "+C.toString()+")");break}w%2===1&&(a.left!==a.top&&(C=a.left,a.left=a.top,a.top=C),a.width!==a.height&&(C=a.width,a.width=a.height,a.height=C)),g.length&&(i=Ss(i,''," "))});const c=r.width,d=r.height,u=a.width,h=a.height;let l,m;c===null?(m=d===null?"1em":d==="auto"?h:d,l=et(m,u/h)):(l=c==="auto"?u:c,m=d===null?et(l,h/u):d==="auto"?h:d);const x={},b=(f,g)=>{ks(g)||(x[f]=g.toString())};b("width",l),b("height",m);const j=[a.left,a.top,u,h];return x.viewBox=j.join(" "),{attributes:x,viewBox:j,body:i}}const Es=/\sid="(\S+)"/g,Rs="IconifyId"+Date.now().toString(16)+(Math.random()*16777216|0).toString(16);let Ps=0;function Ts(t,s=Rs){const n=[];let r;for(;r=Es.exec(t);)n.push(r[1]);if(!n.length)return t;const a="suffix"+(Math.random()*16777216|Date.now()).toString(16);return n.forEach(i=>{const c=typeof s=="function"?s(i):s+(Ps++).toString(),d=i.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");t=t.replace(new RegExp('([#;"])('+d+')([")]|\\.[a-z])',"g"),"$1"+c+a+"$3")}),t=t.replace(new RegExp(a,"g"),""),t}const _e=Object.create(null);function Is(t,s){_e[t]=s}function Le(t){return _e[t]||_e[""]}function ze(t){let s;if(typeof t.resources=="string")s=[t.resources];else if(s=t.resources,!(s instanceof Array)||!s.length)return null;return{resources:s,path:t.path||"/",maxURL:t.maxURL||500,rotate:t.rotate||750,timeout:t.timeout||5e3,random:t.random===!0,index:t.index||0,dataAfterTimeout:t.dataAfterTimeout!==!1}}const Fe=Object.create(null),oe=["https://api.simplesvg.com","https://api.unisvg.com"],ve=[];for(;oe.length>0;)oe.length===1||Math.random()>.5?ve.push(oe.shift()):ve.push(oe.pop());Fe[""]=ze({resources:["https://api.iconify.design"].concat(ve)});function Ds(t,s){const n=ze(s);return n===null?!1:(Fe[t]=n,!0)}function Ue(t){return Fe[t]}const _s=()=>{let t;try{if(t=fetch,typeof t=="function")return t}catch{}};let tt=_s();function Ls(t,s){const n=Ue(t);if(!n)return 0;let r;if(!n.maxURL)r=0;else{let a=0;n.resources.forEach(c=>{a=Math.max(a,c.length)});const i=s+".json?icons=";r=n.maxURL-a-n.path.length-i.length}return r}function As(t){return t===404}const $s=(t,s,n)=>{const r=[],a=Ls(t,s),i="icons";let c={type:i,provider:t,prefix:s,icons:[]},d=0;return n.forEach((u,h)=>{d+=u.length+1,d>=a&&h>0&&(r.push(c),c={type:i,provider:t,prefix:s,icons:[]},d=u.length),c.icons.push(u)}),r.push(c),r};function Os(t){if(typeof t=="string"){const s=Ue(t);if(s)return s.path}return"/"}const Ms=(t,s,n)=>{if(!tt){n("abort",424);return}let r=Os(s.provider);switch(s.type){case"icons":{const i=s.prefix,d=s.icons.join(","),u=new URLSearchParams({icons:d});r+=i+".json?"+u.toString();break}case"custom":{const i=s.uri;r+=i.slice(0,1)==="/"?i.slice(1):i;break}default:n("abort",400);return}let a=503;tt(t+r).then(i=>{const c=i.status;if(c!==200){setTimeout(()=>{n(As(c)?"abort":"next",c)});return}return a=501,i.json()}).then(i=>{if(typeof i!="object"||i===null){setTimeout(()=>{i===404?n("abort",i):n("next",a)});return}setTimeout(()=>{n("success",i)})}).catch(()=>{n("next",a)})},zs={prepare:$s,send:Ms};function _t(t,s){t.forEach(n=>{const r=n.loaderCallbacks;r&&(n.loaderCallbacks=r.filter(a=>a.id!==s))})}function Fs(t){t.pendingCallbacksFlag||(t.pendingCallbacksFlag=!0,setTimeout(()=>{t.pendingCallbacksFlag=!1;const s=t.loaderCallbacks?t.loaderCallbacks.slice(0):[];if(!s.length)return;let n=!1;const r=t.provider,a=t.prefix;s.forEach(i=>{const c=i.icons,d=c.pending.length;c.pending=c.pending.filter(u=>{if(u.prefix!==a)return!0;const h=u.name;if(t.icons[h])c.loaded.push({provider:r,prefix:a,name:h});else if(t.missing.has(h))c.missing.push({provider:r,prefix:a,name:h});else return n=!0,!0;return!1}),c.pending.length!==d&&(n||_t([t],i.id),i.callback(c.loaded.slice(0),c.missing.slice(0),c.pending.slice(0),i.abort))})}))}let Us=0;function qs(t,s,n){const r=Us++,a=_t.bind(null,n,r);if(!s.pending.length)return a;const i={id:r,icons:s,callback:t,abort:a};return n.forEach(c=>{(c.loaderCallbacks||(c.loaderCallbacks=[])).push(i)}),a}function Gs(t){const s={loaded:[],missing:[],pending:[]},n=Object.create(null);t.sort((a,i)=>a.provider!==i.provider?a.provider.localeCompare(i.provider):a.prefix!==i.prefix?a.prefix.localeCompare(i.prefix):a.name.localeCompare(i.name));let r={provider:"",prefix:"",name:""};return t.forEach(a=>{if(r.name===a.name&&r.prefix===a.prefix&&r.provider===a.provider)return;r=a;const i=a.provider,c=a.prefix,d=a.name,u=n[i]||(n[i]=Object.create(null)),h=u[c]||(u[c]=re(i,c));let l;d in h.icons?l=s.loaded:c===""||h.missing.has(d)?l=s.missing:l=s.pending;const m={provider:i,prefix:c,name:d};l.push(m)}),s}function Bs(t,s=!0,n=!1){const r=[];return t.forEach(a=>{const i=typeof a=="string"?Ne(a,s,n):a;i&&r.push(i)}),r}const Hs={resources:[],index:0,timeout:2e3,rotate:750,random:!1,dataAfterTimeout:!1};function Vs(t,s,n,r){const a=t.resources.length,i=t.random?Math.floor(Math.random()*a):t.index;let c;if(t.random){let N=t.resources.slice(0);for(c=[];N.length>1;){const _=Math.floor(Math.random()*N.length);c.push(N[_]),N=N.slice(0,_).concat(N.slice(_+1))}c=c.concat(N)}else c=t.resources.slice(i).concat(t.resources.slice(0,i));const d=Date.now();let u="pending",h=0,l,m=null,x=[],b=[];typeof r=="function"&&b.push(r);function j(){m&&(clearTimeout(m),m=null)}function f(){u==="pending"&&(u="aborted"),j(),x.forEach(N=>{N.status==="pending"&&(N.status="aborted")}),x=[]}function g(N,_){_&&(b=[]),typeof N=="function"&&b.push(N)}function v(){return{startTime:d,payload:s,status:u,queriesSent:h,queriesPending:x.length,subscribe:g,abort:f}}function p(){u="failed",b.forEach(N=>{N(void 0,l)})}function w(){x.forEach(N=>{N.status==="pending"&&(N.status="aborted")}),x=[]}function C(N,_,L){const R=_!=="success";switch(x=x.filter(E=>E!==N),u){case"pending":break;case"failed":if(R||!t.dataAfterTimeout)return;break;default:return}if(_==="abort"){l=L,p();return}if(R){l=L,x.length||(c.length?I():p());return}if(j(),w(),!t.random){const E=t.resources.indexOf(N.resource);E!==-1&&E!==t.index&&(t.index=E)}u="completed",b.forEach(E=>{E(L)})}function I(){if(u!=="pending")return;j();const N=c.shift();if(N===void 0){if(x.length){m=setTimeout(()=>{j(),u==="pending"&&(w(),p())},t.timeout);return}p();return}const _={status:"pending",resource:N,callback:(L,R)=>{C(_,L,R)}};x.push(_),h++,m=setTimeout(I,t.rotate),n(N,s,_.callback)}return setTimeout(I),v}function Lt(t){const s={...Hs,...t};let n=[];function r(){n=n.filter(d=>d().status==="pending")}function a(d,u,h){const l=Vs(s,d,u,(m,x)=>{r(),h&&h(m,x)});return n.push(l),l}function i(d){return n.find(u=>d(u))||null}return{query:a,find:i,setIndex:d=>{s.index=d},getIndex:()=>s.index,cleanup:r}}function st(){}const ke=Object.create(null);function Ks(t){if(!ke[t]){const s=Ue(t);if(!s)return;const n=Lt(s),r={config:s,redundancy:n};ke[t]=r}return ke[t]}function Ws(t,s,n){let r,a;if(typeof t=="string"){const i=Le(t);if(!i)return n(void 0,424),st;a=i.send;const c=Ks(t);c&&(r=c.redundancy)}else{const i=ze(t);if(i){r=Lt(i);const c=t.resources?t.resources[0]:"",d=Le(c);d&&(a=d.send)}}return!r||!a?(n(void 0,424),st):r.query(s,a,n)().abort}function nt(){}function Js(t){t.iconsLoaderFlag||(t.iconsLoaderFlag=!0,setTimeout(()=>{t.iconsLoaderFlag=!1,Fs(t)}))}function Qs(t){const s=[],n=[];return t.forEach(r=>{(r.match(Pt)?s:n).push(r)}),{valid:s,invalid:n}}function ce(t,s,n){function r(){const a=t.pendingIcons;s.forEach(i=>{a&&a.delete(i),t.icons[i]||t.missing.add(i)})}if(n&&typeof n=="object")try{if(!Rt(t,n).length){r();return}}catch(a){console.error(a)}r(),Js(t)}function at(t,s){t instanceof Promise?t.then(n=>{s(n)}).catch(()=>{s(null)}):s(t)}function Ys(t,s){t.iconsToLoad?t.iconsToLoad=t.iconsToLoad.concat(s).sort():t.iconsToLoad=s,t.iconsQueueFlag||(t.iconsQueueFlag=!0,setTimeout(()=>{t.iconsQueueFlag=!1;const{provider:n,prefix:r}=t,a=t.iconsToLoad;if(delete t.iconsToLoad,!a||!a.length)return;const i=t.loadIcon;if(t.loadIcons&&(a.length>1||!i)){at(t.loadIcons(a,r,n),l=>{ce(t,a,l)});return}if(i){a.forEach(l=>{const m=i(l,r,n);at(m,x=>{const b=x?{prefix:r,icons:{[l]:x}}:null;ce(t,[l],b)})});return}const{valid:c,invalid:d}=Qs(a);if(d.length&&ce(t,d,null),!c.length)return;const u=r.match(Pt)?Le(n):null;if(!u){ce(t,c,null);return}u.prepare(n,r,c).forEach(l=>{Ws(n,l,m=>{ce(t,l.icons,m)})})}))}const Xs=(t,s)=>{const n=Bs(t,!0,Tt()),r=Gs(n);if(!r.pending.length){let u=!0;return s&&setTimeout(()=>{u&&s(r.loaded,r.missing,r.pending,nt)}),()=>{u=!1}}const a=Object.create(null),i=[];let c,d;return r.pending.forEach(u=>{const{provider:h,prefix:l}=u;if(l===d&&h===c)return;c=h,d=l,i.push(re(h,l));const m=a[h]||(a[h]=Object.create(null));m[l]||(m[l]=[])}),r.pending.forEach(u=>{const{provider:h,prefix:l,name:m}=u,x=re(h,l),b=x.pendingIcons||(x.pendingIcons=new Set);b.has(m)||(b.add(m),a[h][l].push(m))}),i.forEach(u=>{const h=a[u.provider][u.prefix];h.length&&Ys(u,h)}),s?qs(s,r,i):nt};function Zs(t,s){const n={...t};for(const r in s){const a=s[r],i=typeof a;r in It?(a===null||a&&(i==="string"||i==="number"))&&(n[r]=a):i===typeof n[r]&&(n[r]=r==="rotate"?a%4:a)}return n}const en=/[\s,]+/;function tn(t,s){s.split(en).forEach(n=>{switch(n.trim()){case"horizontal":t.hFlip=!0;break;case"vertical":t.vFlip=!0;break}})}function sn(t,s=0){const n=t.replace(/^-?[0-9.]*/,"");function r(a){for(;a<0;)a+=4;return a%4}if(n===""){const a=parseInt(t);return isNaN(a)?0:r(a)}else if(n!==t){let a=0;switch(n){case"%":a=25;break;case"deg":a=90}if(a){let i=parseFloat(t.slice(0,t.length-n.length));return isNaN(i)?0:(i=i/a,i%1===0?r(i):0)}}return s}function nn(t,s){let n=t.indexOf("xlink:")===-1?"":' xmlns:xlink="http://www.w3.org/1999/xlink"';for(const r in s)n+=" "+r+'="'+s[r]+'"';return'"+t+" "}function an(t){return t.replace(/"/g,"'").replace(/%/g,"%25").replace(/#/g,"%23").replace(//g,"%3E").replace(/\s+/g," ")}function rn(t){return"data:image/svg+xml,"+an(t)}function on(t){return'url("'+rn(t)+'")'}let me;function cn(){try{me=window.trustedTypes.createPolicy("iconify",{createHTML:t=>t})}catch{me=null}}function ln(t){return me===void 0&&cn(),me?me.createHTML(t):t}const At={...Dt,inline:!1},dn={xmlns:"http://www.w3.org/2000/svg",xmlnsXlink:"http://www.w3.org/1999/xlink","aria-hidden":!0,role:"img"},un={display:"inline-block"},Ae={backgroundColor:"currentColor"},$t={backgroundColor:"transparent"},rt={Image:"var(--svg)",Repeat:"no-repeat",Size:"100% 100%"},it={WebkitMask:Ae,mask:Ae,background:$t};for(const t in it){const s=it[t];for(const n in rt)s[t+n]=rt[n]}const mn={...At,inline:!0};function ot(t){return t+(t.match(/^[-0-9.]+$/)?"px":"")}const hn=(t,s,n)=>{const r=s.inline?mn:At,a=Zs(r,s),i=s.mode||"svg",c={},d=s.style||{},u={...i==="svg"?dn:{}};if(n){const g=Ne(n,!1,!0);if(g){const v=["iconify"],p=["provider","prefix"];for(const w of p)g[w]&&v.push("iconify--"+g[w]);u.className=v.join(" ")}}for(let g in s){const v=s[g];if(v!==void 0)switch(g){case"icon":case"style":case"children":case"onLoad":case"mode":case"ssr":case"fallback":break;case"_ref":u.ref=v;break;case"className":u[g]=(u[g]?u[g]+" ":"")+v;break;case"inline":case"hFlip":case"vFlip":a[g]=v===!0||v==="true"||v===1;break;case"flip":typeof v=="string"&&tn(a,v);break;case"color":c.color=v;break;case"rotate":typeof v=="string"?a[g]=sn(v):typeof v=="number"&&(a[g]=v);break;case"ariaHidden":case"aria-hidden":v!==!0&&v!=="true"&&delete u["aria-hidden"];break;default:r[g]===void 0&&(u[g]=v)}}const h=Cs(t,a),l=h.attributes;if(a.inline&&(c.verticalAlign="-0.125em"),i==="svg"){u.style={...c,...d},Object.assign(u,l);let g=0,v=s.id;return typeof v=="string"&&(v=v.replace(/-/g,"_")),u.dangerouslySetInnerHTML={__html:ln(Ts(h.body,v?()=>v+"ID"+g++:"iconifyReact"))},o.createElement("svg",u)}const{body:m,width:x,height:b}=t,j=i==="mask"||(i==="bg"?!1:m.indexOf("currentColor")!==-1),f=nn(m,{...l,width:x+"",height:b+""});return u.style={...c,"--svg":on(f),width:ot(l.width),height:ot(l.height),...un,...j?Ae:$t,...d},o.createElement("span",u)};Tt(!0);Is("",zs);if(typeof document<"u"&&typeof window<"u"){const t=window;if(t.IconifyPreload!==void 0){const s=t.IconifyPreload,n="Invalid IconifyPreload syntax.";typeof s=="object"&&s!==null&&(s instanceof Array?s:[s]).forEach(r=>{try{(typeof r!="object"||r===null||r instanceof Array||typeof r.icons!="object"||typeof r.prefix!="string"||!js(r))&&console.error(n)}catch{console.error(n)}})}if(t.IconifyProviders!==void 0){const s=t.IconifyProviders;if(typeof s=="object"&&s!==null)for(let n in s){const r="IconifyProviders["+n+"] is invalid.";try{const a=s[n];if(typeof a!="object"||!a||a.resources===void 0)continue;Ds(n,a)||console.error(r)}catch{console.error(r)}}}}function Ot(t){const[s,n]=o.useState(!!t.ssr),[r,a]=o.useState({});function i(b){if(b){const j=t.icon;if(typeof j=="object")return{name:"",data:j};const f=Ze(j);if(f)return{name:j,data:f}}return{name:""}}const[c,d]=o.useState(i(!!t.ssr));function u(){const b=r.callback;b&&(b(),a({}))}function h(b){if(JSON.stringify(c)!==JSON.stringify(b))return u(),d(b),!0}function l(){var b;const j=t.icon;if(typeof j=="object"){h({name:"",data:j});return}const f=Ze(j);if(h({name:j,data:f}))if(f===void 0){const g=Xs([j],l);a({callback:g})}else f&&((b=t.onLoad)===null||b===void 0||b.call(t,j))}o.useEffect(()=>(n(!0),u),[]),o.useEffect(()=>{s&&l()},[t.icon,s]);const{name:m,data:x}=c;return x?hn({...Me,...x},t,m):t.children?t.children:t.fallback?t.fallback:o.createElement("span",{})}const fn=o.forwardRef((t,s)=>Ot({...t,_ref:s}));o.forwardRef((t,s)=>Ot({inline:!0,...t,_ref:s}));function S({icon:t,size:s=20,className:n="",style:r}){return e.jsx(fn,{icon:t,width:s,height:s,className:n,style:r})}function $e({icon:t="lucide:inbox",title:s,description:n,command:r,action:a}){return e.jsxs("div",{className:"flex flex-col items-center justify-center py-12 text-center",children:[e.jsx(S,{icon:t,size:32,className:"text-base-content/30 mb-3"}),e.jsx("h3",{className:"text-heading text-base-content/70",children:s}),n&&e.jsx("p",{className:"text-muted text-sm mt-1 max-w-sm",children:n}),r&&e.jsx("div",{className:"mt-3 px-4 py-2 rounded-lg bg-base-100 border border-base-200",children:e.jsx("code",{className:"text-sm font-mono text-primary",children:r})}),a&&e.jsx("div",{className:"mt-4",children:a})]})}const xn={top:"tooltip-top",bottom:"tooltip-bottom",left:"tooltip-left",right:"tooltip-right"};function Y({text:t,children:s,position:n="top"}){return e.jsx("div",{className:`tooltip ${xn[n]} [&::before]:bg-base-300 [&::before]:text-base-content`,"data-tip":t,children:s})}const pn={success:{bg:"alert-success",icon:"lucide:check-circle",iconColor:"text-success-content"},error:{bg:"alert-error",icon:"lucide:x-circle",iconColor:"text-error-content"},info:{bg:"alert-info",icon:"lucide:info",iconColor:"text-info-content"},warning:{bg:"alert-warning",icon:"lucide:alert-triangle",iconColor:"text-warning-content"}};function bn({id:t,type:s,message:n,title:r,duration:a=5e3,dismissible:i=!0,onClick:c,onDismiss:d}){const[u,h]=o.useState(!1),{bg:l,icon:m,iconColor:x}=pn[s];o.useEffect(()=>{if(a>0){const j=setTimeout(()=>{h(!0),setTimeout(()=>d(t),300)},a);return()=>clearTimeout(j)}},[a,t,d]);const b=()=>{h(!0),setTimeout(()=>d(t),300)};return e.jsxs("div",{role:"alert",className:`alert ${l} shadow-lg transition-all duration-300 ${u?"opacity-0 translate-x-4":"opacity-100 translate-x-0"} ${c?"cursor-pointer hover:scale-[1.02]":""}`,onClick:c,children:[e.jsx(S,{icon:m,size:20,className:x}),e.jsxs("div",{className:"flex-1",children:[r&&e.jsx("h3",{className:"font-bold text-sm",children:r}),e.jsx("span",{className:"text-sm",children:n})]}),i&&e.jsx("button",{onClick:j=>{j.stopPropagation(),b()},className:"btn btn-ghost btn-sm btn-circle","aria-label":"Dismiss",children:e.jsx(S,{icon:"lucide:x",size:16})})]})}function gn({toasts:t,onDismiss:s}){return t.length===0?null:e.jsx("div",{className:"toast toast-end toast-bottom z-50",children:t.map(n=>e.jsx(bn,{...n,onDismiss:s},n.id))})}function pe({width:t="100%",height:s="1rem",className:n=""}){return e.jsx("div",{className:`animate-pulse bg-base-300/50 rounded ${n}`,style:{width:t,height:s}})}function jn({lines:t=3,className:s=""}){return e.jsx("div",{className:`space-y-2 ${s}`,children:Array.from({length:t}).map((n,r)=>e.jsx(pe,{width:r===t-1?"60%":"100%",height:"0.75rem"},r))})}function vn({className:t=""}){return e.jsx("div",{className:`card bg-base-100 border border-base-200 shadow-sm ${t}`,children:e.jsxs("div",{className:"card-body animate-pulse",children:[e.jsxs("div",{className:"flex items-center gap-3 mb-3",children:[e.jsx("div",{className:"w-10 h-10 bg-base-300/50 rounded-lg"}),e.jsxs("div",{className:"flex-1 space-y-2",children:[e.jsx(pe,{width:"40%",height:"0.75rem"}),e.jsx(pe,{width:"70%",height:"1.25rem"})]})]}),e.jsx(jn,{lines:2})]})})}function te(){return e.jsxs("div",{className:"space-y-6 animate-pulse",children:[e.jsxs("div",{children:[e.jsx(pe,{width:"12rem",height:"1.75rem"}),e.jsx(pe,{width:"20rem",height:"0.875rem",className:"mt-2"})]}),e.jsx("div",{className:"space-y-3",children:Array.from({length:5}).map((t,s)=>e.jsx(vn,{},s))})]})}function yn({icon:t,label:s,href:n,active:r=!1,badge:a,collapsed:i=!1}){const c=e.jsxs("a",{href:n,className:`nav-item flex items-center gap-3 px-3 py-2.5 rounded-lg transition-all ${r?"active":""} ${i?"justify-center":""}`,children:[e.jsx(S,{icon:t,size:20}),!i&&e.jsxs(e.Fragment,{children:[e.jsx("span",{className:"flex-1",children:s}),a!==void 0&&e.jsx("span",{className:`badge badge-sm ${r?"badge-primary-content":"badge-ghost"}`,children:a})]})]});return i?e.jsx(Y,{text:s,position:"right",children:c}):c}const wn=[{icon:"lucide:layout-dashboard",label:"Dashboard",href:"#/"},{icon:"lucide:history",label:"Sessions",href:"#/sessions"},{icon:"lucide:brain",label:"Memories",href:"#/memories"},{icon:"lucide:lightbulb",label:"Requirements",href:"#/requirements"},{icon:"lucide:scroll",label:"Specifications",href:"#/spec"},{icon:"lucide:puzzle",label:"Extensions",href:"#/extensions"},{icon:"lucide:git-compare",label:"Changes",href:"#/changes"},{icon:"lucide:bar-chart-3",label:"Usage",href:"#/usage"},{icon:"lucide:book-open",label:"Help",href:"#/help"},{icon:"lucide:settings",label:"Settings",href:"#/settings"}];function Nn(t,s){return t===s||t.startsWith(s+"/")}function Sn({currentPath:t,collapsed:s=!1}){return e.jsx("nav",{className:"py-4 space-y-1 px-2",children:wn.map(n=>e.jsx(yn,{icon:n.icon,label:n.label,href:n.href,active:Nn(t,n.href),collapsed:s},n.href))})}const kn={solo:{label:"Solo",variant:"primary"},team:{label:"Team",variant:"accent"},trial:{label:"Trial",variant:"warning"}};function ct(t){return t.isExpired||t.tier==="trial"}function Cn({license:t,isLoading:s,onClick:n}){if(s||!t||!t.tier)return null;const a=ct(t)&&!!n?{onClick:n,role:"button",className:"cursor-pointer"}:{};if(t.isExpired)return e.jsx("span",{...a,children:e.jsx(q,{variant:"error",size:"xs",children:"Expired"})});const i=kn[t.tier];if(!i)return null;let c=i.label;t.tier==="trial"&&t.daysRemaining!=null&&(c=`${i.label} · ${t.daysRemaining}d left`);const d=!ct(t)&&t.email;return e.jsxs("span",{...a,className:`${a.className??""} inline-flex items-center gap-1.5`,children:[e.jsx(q,{variant:i.variant,size:"xs",children:c}),d&&e.jsx("span",{className:"text-base-content/50",children:t.email})]})}function En({open:t,onClose:s,onActivated:n}){const[r,a]=o.useState(""),[i,c]=o.useState(null),[d,u]=o.useState(!1),h=o.useCallback(async()=>{const m=r.trim();if(m){c(null),u(!0);try{const b=await(await fetch("/api/license/activate",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({key:m})})).json();b.success?(a(""),n(),s()):c(b.error??"Activation failed")}catch{c("Connection failed")}finally{u(!1)}}},[r,n,s]),l=o.useCallback(m=>{m.key==="Enter"&&!d&&h()},[h,d]);return e.jsxs(fe,{open:t,onClose:s,title:"Activate License",children:[e.jsxs("div",{className:"flex flex-col gap-3",children:[e.jsx("input",{id:"license-key-input",type:"text",className:"input input-bordered w-full",placeholder:"Enter your license key",value:r,onChange:m=>{a(m.target.value),c(null)},onKeyDown:l,disabled:d,autoFocus:!0}),i&&e.jsx("p",{className:"text-error text-sm",children:i}),e.jsx("div",{className:"bg-base-200/50 rounded-lg p-3 space-y-1.5",children:e.jsxs("p",{className:"text-xs text-base-content/60",children:["Don't have a key? Get one at"," ",e.jsx("a",{href:"https://pilot-shell.com/#pricing",target:"_blank",rel:"noopener noreferrer",className:"text-primary hover:underline font-medium",children:"pilot-shell.com"})]})})]}),e.jsxs("div",{className:"modal-action",children:[e.jsx("button",{className:"btn btn-ghost btn-sm",onClick:s,disabled:d,children:"Cancel"}),e.jsx("button",{className:"btn btn-primary btn-sm",onClick:h,disabled:d||!r.trim(),children:d?"Activating...":"Activate"})]})]})}function Mt(){const[t,s]=o.useState(null),[n,r]=o.useState(!0),a=o.useCallback((c=!1)=>{fetch(c?"/api/license?refresh=1":"/api/license").then(u=>u.json()).then(u=>{s(u),r(!1)}).catch(()=>{r(!1)})},[]);o.useEffect(()=>{a();const c=setInterval(()=>a(!0),6e4),d=()=>{document.visibilityState==="visible"&&a(!0)};return document.addEventListener("visibilitychange",d),()=>{clearInterval(c),document.removeEventListener("visibilitychange",d)}},[a]);const i=o.useCallback(()=>a(!0),[a]);return{license:t,isLoading:n,refetch:i}}const Rn={online:{color:"bg-success",label:"Online"},processing:{color:"bg-warning animate-pulse",label:"Processing"},offline:{color:"bg-error",label:"Offline"}};function Pn({version:t,workerStatus:s="offline",queueDepth:n=0,collapsed:r=!1}){const a=Rn[s],{license:i,isLoading:c,refetch:d}=Mt(),[u,h]=o.useState(!1),l=t?`v${t}`:null;return r?e.jsx("div",{className:"p-3 border-t border-base-300/50 space-y-3",children:e.jsx(Y,{text:`Worker ${a.label}${n>0?` · ${n} queued`:""}`,position:"right",children:e.jsx("div",{className:"flex justify-center",children:e.jsx("span",{className:`inline-block w-2.5 h-2.5 rounded-full ${a.color}`})})})}):e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"p-4 border-t border-base-300/50 space-y-2",children:[e.jsxs("div",{className:"flex items-center justify-between text-xs",children:[e.jsxs("div",{className:"flex items-center gap-1.5",children:[e.jsx("span",{className:`inline-block w-2 h-2 rounded-full ${a.color}`}),e.jsxs("span",{className:"text-base-content/60",children:["Worker ",a.label]}),n>0&&e.jsxs("span",{className:"text-base-content/50",children:["· ",n," queued"]})]}),l&&e.jsx("span",{className:"text-base-content/40",children:l})]}),!c&&(i==null?void 0:i.tier)&&e.jsx("div",{className:"flex items-center gap-2 text-xs",children:e.jsx(Cn,{license:i,isLoading:c,onClick:()=>h(!0)})}),!c&&(!i||!i.tier||i.tier==="trial"||i.isExpired)&&e.jsxs("div",{className:"flex items-center gap-2 text-xs",children:[e.jsx("a",{href:"https://pilot-shell.com/#pricing",target:"_blank",rel:"noopener noreferrer",className:"text-primary/70 hover:text-primary transition-colors",children:"Get a license"}),e.jsxs("button",{onClick:()=>h(!0),className:"btn btn-primary btn-xs gap-1",children:[e.jsx(S,{icon:"lucide:key",size:10}),"Activate"]})]})]}),e.jsx(En,{open:u,onClose:()=>h(!1),onActivated:d})]})}function Tn({currentPath:t,version:s,workerStatus:n,queueDepth:r,collapsed:a,onToggleCollapse:i}){return e.jsxs("aside",{className:`dashboard-sidebar flex flex-col border-r border-base-300 transition-all duration-300 h-screen sticky top-0 ${a?"w-[72px]":"w-64"}`,children:[e.jsxs("div",{className:"flex-shrink-0 flex items-center justify-between p-4 border-b border-base-300/50",children:[!a&&e.jsx(rs,{}),e.jsx("button",{onClick:i,className:"btn btn-ghost btn-sm btn-square",title:a?"Expand sidebar":"Collapse sidebar",children:e.jsx(S,{icon:a?"lucide:panel-left-open":"lucide:panel-left-close",size:18})})]}),e.jsx("div",{className:"flex-1 overflow-y-auto",children:e.jsx(Sn,{currentPath:t,collapsed:a})}),e.jsx("div",{className:"flex-shrink-0",children:e.jsx(Pn,{version:s,workerStatus:n,queueDepth:r,collapsed:a})})]})}function In(t){const s=t.endsWith("Z")?t:t+"Z",n=Date.now()-new Date(s).getTime();return n<6e4?"just now":n<36e5?`${Math.floor(n/6e4)}m ago`:n<864e5?`${Math.floor(n/36e5)}h ago`:`${Math.floor(n/864e5)}d ago`}const Dn={plan_approval:"lucide:file-check",verification_complete:"lucide:check-circle",attention_needed:"lucide:alert-circle"};function _n(t){const s=t.indexOf("/docs/plans/");if(s===-1)return;const n=t.slice(0,s),r=n.lastIndexOf("/");return r>=0?n.slice(r+1):n}function Ln(t){const s=t.split("/").pop();if(!s)return;let n=s.replace(/\.md$/,"");return/^\d{4}-\d{2}-\d{2}-/.test(n)&&(n=n.slice(11)),n}function An({notifications:t,unreadCount:s,onMarkAsRead:n,onMarkAllAsRead:r,onClearAll:a,onNavigate:i}){const[c,d]=o.useState(!1),u=o.useRef(null),h=o.useCallback(m=>{u.current&&!u.current.contains(m.target)&&d(!1)},[]);o.useEffect(()=>{if(c)return document.addEventListener("mousedown",h),()=>document.removeEventListener("mousedown",h)},[c,h]);const l=o.useCallback(m=>{if(m.is_read===0&&n(m.id),d(!1),!!i)if(m.plan_path){const x=_n(m.plan_path);i("/spec",x)}else m.session_id&&i(`/sessions?selected=${m.session_id}`)},[n,i]);return e.jsxs("div",{className:"relative",ref:u,children:[e.jsx(Y,{text:"Notifications",position:"bottom",children:e.jsx(W,{variant:"ghost",size:"sm",onClick:()=>d(!c),children:e.jsxs("div",{className:"relative",children:[e.jsx(S,{icon:"lucide:bell",size:18}),s>0&&e.jsx("span",{className:"absolute -top-1.5 -right-1.5 bg-error text-error-content text-[10px] font-bold rounded-full min-w-[16px] h-4 flex items-center justify-center px-0.5",children:s>99?"99+":s})]})})}),c&&e.jsxs("div",{className:"absolute right-0 top-full mt-2 w-80 max-h-96 overflow-y-auto rounded-xl border border-base-300 bg-base-100 shadow-xl z-50",children:[e.jsxs("div",{className:"flex items-center justify-between px-4 py-3 border-b border-base-300",children:[e.jsx("span",{className:"text-sm font-semibold",children:"Notifications"}),e.jsxs("div",{className:"flex items-center gap-3",children:[s>0&&e.jsx("button",{className:"text-xs text-primary hover:underline",onClick:()=>r(),children:"Mark all read"}),t.length>0&&e.jsx("button",{className:"text-xs text-error/70 hover:text-error hover:underline",onClick:()=>{a(),d(!1)},children:"Clear all"})]})]}),t.length===0?e.jsx("div",{className:"px-4 py-8 text-center text-sm text-base-content/50",children:"No notifications"}):e.jsx("div",{className:"divide-y divide-base-300",children:t.map(m=>e.jsx("button",{className:`w-full text-left px-4 py-3 hover:bg-base-200/50 transition-colors ${m.is_read===0?"bg-primary/5":""}`,onClick:()=>l(m),children:e.jsxs("div",{className:"flex items-start gap-3",children:[e.jsx(S,{icon:Dn[m.type]||"lucide:info",size:16,className:`mt-0.5 flex-shrink-0 ${m.is_read===0?"text-primary":"text-base-content/40"}`}),e.jsxs("div",{className:"min-w-0 flex-1",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:`text-sm truncate ${m.is_read===0?"font-medium":""}`,children:m.plan_path?Ln(m.plan_path)??m.title:m.title}),m.is_read===0&&e.jsx("span",{className:"w-2 h-2 rounded-full bg-primary flex-shrink-0"})]}),e.jsx("p",{className:"text-xs text-base-content/60 mt-0.5 line-clamp-2",children:m.message}),e.jsx("span",{className:"text-[10px] text-base-content/40 mt-1 block",children:In(m.created_at)})]})]})},m.id))})]})]})}function $n(){const[t,s]=o.useState([]),[n,r]=o.useState(0),a=o.useRef(!0),i=o.useCallback(async()=>{try{const h=await fetch("/api/notifications?limit=50&include_read=true");if(!h.ok)return;const l=await h.json();a.current&&(s(l),r(l.filter(m=>m.is_read===0).length))}catch{}},[]),c=o.useCallback(async h=>{s(l=>l.map(m=>m.id===h?{...m,is_read:1}:m)),r(l=>Math.max(0,l-1));try{(await fetch(`/api/notifications/${h}/read`,{method:"PATCH"})).ok||(s(m=>m.map(x=>x.id===h?{...x,is_read:0}:x)),r(m=>m+1))}catch{s(l=>l.map(m=>m.id===h?{...m,is_read:0}:m)),r(l=>l+1)}},[]),d=o.useCallback(async()=>{const h=t,l=n;s(m=>m.map(x=>({...x,is_read:1}))),r(0);try{(await fetch("/api/notifications/read-all",{method:"POST"})).ok||(s(h),r(l))}catch{s(h),r(l)}},[t,n]);o.useEffect(()=>{a.current=!0,i();const h=new EventSource("/stream");return h.addEventListener("open",()=>{i()}),h.onmessage=l=>{try{const m=JSON.parse(l.data);if(m.type==="new_notification"&&m.notification&&a.current){const x=m.notification;s(b=>b.some(j=>j.id===x.id)?b:[x,...b]),r(b=>b+1)}}catch{}},()=>{a.current=!1,h.close()}},[i]);const u=o.useCallback(async()=>{s([]),r(0);try{await fetch("/api/notifications",{method:"DELETE"})}catch{i()}},[i]);return{notifications:t,unreadCount:n,markAsRead:c,markAllAsRead:d,clearAll:u,refresh:i}}const zt="pilot-memory-theme";function On(){return typeof window>"u"||window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light"}function lt(){try{const t=localStorage.getItem(zt);if(t==="system"||t==="light"||t==="dark")return t}catch(t){console.warn("Failed to read theme preference from localStorage:",t)}return"system"}function dt(t){return t==="system"?On():t}function ut(t){return t==="dark"?"pilot-shell":"pilot-shell-light"}function Ft(){const[t,s]=o.useState(lt),[n,r]=o.useState(()=>dt(lt()));return o.useEffect(()=>{const i=dt(t);r(i),document.documentElement.setAttribute("data-theme",ut(i))},[t]),o.useEffect(()=>{if(t!=="system")return;const i=window.matchMedia("(prefers-color-scheme: dark)"),c=d=>{const u=d.matches?"dark":"light";r(u),document.documentElement.setAttribute("data-theme",ut(u))};return i.addEventListener("change",c),()=>i.removeEventListener("change",c)},[t]),{preference:t,resolvedTheme:n,setThemePreference:i=>{try{localStorage.setItem(zt,i),s(i)}catch(c){console.warn("Failed to save theme preference to localStorage:",c),s(i)}}}}const Ut=o.createContext(null);let Mn=0;function zn({children:t}){const[s,n]=o.useState([]),r=o.useCallback(l=>{const m=`toast-${++Mn}`;return n(x=>[...x,{...l,id:m}]),m},[]),a=o.useCallback(l=>{n(m=>m.filter(x=>x.id!==l))},[]),i=o.useCallback(()=>{n([])},[]),c=o.useCallback((l,m)=>r({type:"success",message:l,title:m}),[r]),d=o.useCallback((l,m)=>r({type:"error",message:l,title:m,duration:8e3}),[r]),u=o.useCallback((l,m)=>r({type:"info",message:l,title:m}),[r]),h=o.useCallback((l,m)=>r({type:"warning",message:l,title:m,duration:7e3}),[r]);return e.jsxs(Ut.Provider,{value:{addToast:r,removeToast:a,clearAll:i,success:c,error:d,info:u,warning:h},children:[t,e.jsx(gn,{toasts:s,onDismiss:a})]})}function qt(){const t=o.useContext(Ut);if(!t)throw new Error("useToast must be used within a ToastProvider");return t}const le="pilot-memory-selected-project",Fn={selectedProject:null,projects:[],setSelectedProject:()=>{},setProjects:()=>{},refreshProjects:async()=>{}},Gt=o.createContext(Fn);function Un({children:t}){const[s,n]=o.useState(()=>{try{return localStorage.getItem(le)||null}catch{return null}}),[r,a]=o.useState([]),i=o.useCallback(u=>{n(u);try{u?localStorage.setItem(le,u):localStorage.removeItem(le)}catch{}},[]),c=o.useCallback(u=>{a(u)},[]),d=o.useCallback(async()=>{try{const h=await(await fetch("/api/projects")).json(),l=h.projects||[],m=h.workspaceProject;a(l),n(x=>{if(x&&l.includes(x))return x;if(m&&l.includes(m)){try{localStorage.setItem(le,m)}catch{}return m}if(l.length>0){try{localStorage.setItem(le,l[0])}catch{}return l[0]}return x})}catch{}},[]);return o.useEffect(()=>{d()},[d]),o.useEffect(()=>{if(s&&r.length>0&&!r.includes(s)){const u=r[0]||null;i(u)}},[r,s,i]),e.jsx(Gt.Provider,{value:{selectedProject:s,projects:r,setSelectedProject:i,setProjects:c,refreshProjects:d},children:t})}function X(){return o.useContext(Gt)}function se(){const[t,s]=o.useState(()=>typeof window<"u"?mt(window.location.hash):{path:"/",params:{}});o.useEffect(()=>{if(typeof window>"u")return;const r=()=>{s(mt(window.location.hash))};return window.addEventListener("hashchange",r),()=>window.removeEventListener("hashchange",r)},[]);const n=o.useCallback(r=>{window.location.hash=r},[]);return{path:t.path,params:t.params,navigate:n}}function mt(t){const s=t.replace(/^#/,"")||"/",n={},[r,a]=s.split("?");return a&&new URLSearchParams(a).forEach((c,d)=>{n[d]=c}),{path:r,params:n}}function qn({onToggleTheme:t,onToggleLogs:s}){const{resolvedTheme:n}=Ft(),[r,a]=o.useState(!1),[i,c]=o.useState(!1),{setSelectedProject:d,projects:u}=X(),{navigate:h}=se(),{notifications:l,unreadCount:m,markAsRead:x,markAllAsRead:b,clearAll:j}=$n(),f=o.useCallback((v,p)=>{p&&u.includes(p)&&d(p),h(v)},[h,d,u]);o.useEffect(()=>{fetch("/api/auth/status").then(v=>v.json()).then(v=>{a(v.authRequired)}).catch(()=>{a(!1)})},[]);const g=async()=>{c(!0);try{await fetch("/api/auth/logout",{method:"POST"}),window.location.href="/login"}catch{c(!1)}};return e.jsxs("div",{className:"flex items-center gap-2",children:[s&&e.jsx(Y,{text:"Toggle console logs",position:"bottom",children:e.jsx(W,{variant:"ghost",size:"sm",onClick:s,children:e.jsx(S,{icon:"lucide:terminal",size:18})})}),e.jsx(Y,{text:`Switch to ${n==="light"?"dark":"light"} mode`,position:"bottom",children:e.jsx(W,{variant:"ghost",size:"sm",onClick:t,children:e.jsx(S,{icon:n==="light"?"lucide:moon":"lucide:sun",size:18})})}),e.jsx(Y,{text:"Repository",position:"bottom",children:e.jsx("a",{href:"https://github.com/maxritter/pilot-shell",target:"_blank",rel:"noopener noreferrer",className:"btn btn-ghost btn-sm",children:e.jsx(S,{icon:"lucide:git-branch",size:18})})}),r&&e.jsx(Y,{text:"Logout",position:"bottom",children:e.jsx(W,{variant:"ghost",size:"sm",onClick:g,disabled:i,children:e.jsx(S,{icon:"lucide:log-out",size:18})})}),e.jsx(An,{notifications:l,unreadCount:m,onMarkAsRead:x,onMarkAllAsRead:b,onClearAll:j,onNavigate:f})]})}const Gn=10080*60*1e3,ht=3,Bn={plan:"Plan",implement:"Impl",verify:"Verify"},Hn={plan:"text-info",implement:"text-warning",verify:"text-accent"};function Vn(t){const s=[],n=/^- \[(x| )\] Task (\d+):\s*(.+)$/gm;let r;for(;(r=n.exec(t))!==null;)s.push({number:parseInt(r[2],10),title:r[3],completed:r[1]==="x"});return s}function Kn({spec:t,tasks:s,loading:n}){const r=s?s.findIndex(a=>!a.completed):-1;return e.jsxs("div",{className:"absolute top-full left-0 mt-1 z-50 w-72 rounded-lg border border-base-300 bg-base-100 shadow-xl p-3 text-xs invisible opacity-0 group-hover:visible group-hover:opacity-100 transition-opacity pointer-events-none",children:[e.jsxs("div",{className:"flex items-center gap-1.5 mb-2 pb-2 border-b border-base-300/50",children:[t.specType&&e.jsx(S,{icon:t.specType==="Bugfix"?"lucide:bug":"lucide:sparkles",size:12,className:t.specType==="Bugfix"?"text-error":"text-info"}),e.jsx("span",{className:"font-semibold truncate",children:t.name}),t.project&&e.jsxs("span",{className:"text-base-content/50 truncate",children:["· ",t.project]})]}),n&&!s&&e.jsx("div",{className:"text-base-content/50 italic",children:"Loading tasks…"}),s&&s.length===0&&e.jsx("div",{className:"text-base-content/50 italic",children:"No tasks yet"}),s&&s.length>0&&e.jsx("ul",{className:"space-y-1 max-h-60 overflow-y-auto",children:s.map((a,i)=>{const c=i===r;return e.jsxs("li",{className:`flex items-start gap-1.5 ${a.completed?"text-base-content/40 line-through":c?"text-primary font-medium":"text-base-content/80"}`,children:[e.jsx(S,{icon:a.completed?"lucide:check-circle":c?"lucide:play-circle":"lucide:circle",size:11,className:"flex-shrink-0 mt-0.5"}),e.jsxs("span",{className:"truncate",children:[a.number,". ",a.title]})]},a.number)})})]})}function Wn({spec:t,onClick:s,onRequestTasks:n,tasks:r,loadingTasks:a}){const i=t.status==="PENDING"&&!t.approved;return e.jsxs("div",{className:"relative group",onMouseEnter:n,onFocus:n,children:[e.jsxs("button",{onClick:s,className:`flex items-center gap-1.5 px-2.5 py-1 rounded-lg border border-base-300 bg-base-200/60 hover:bg-base-200 transition-colors text-xs cursor-pointer whitespace-nowrap ${i?"animate-pulse":""}`,"aria-label":`${t.name}${t.specType?` (${t.specType})`:""}`,children:[t.specType&&e.jsx(S,{icon:t.specType==="Bugfix"?"lucide:bug":"lucide:sparkles",size:12,className:t.specType==="Bugfix"?"text-error":"text-info","aria-label":t.specType}),t.project&&e.jsx("span",{className:"text-base-content/40 font-medium truncate max-w-20",children:t.project}),e.jsx("span",{className:"font-medium truncate max-w-28",children:t.name}),e.jsxs("span",{className:"text-base-content/50 font-mono",children:[t.completed,"/",t.total]}),e.jsx("span",{className:`font-medium ${Hn[t.phase]||""}`,children:Bn[t.phase]||t.phase})]}),e.jsx(Kn,{spec:t,tasks:r,loading:a})]})}function Jn({specs:t,onPick:s}){return e.jsxs("div",{className:"dropdown dropdown-end dropdown-bottom",children:[e.jsxs("div",{tabIndex:0,role:"button",className:"px-2 py-1 rounded-lg border border-base-300 bg-base-200/60 hover:bg-base-200 transition-colors text-xs font-medium cursor-pointer","aria-label":`${t.length} more specs`,children:["+",t.length]}),e.jsx("ul",{tabIndex:0,className:"dropdown-content menu bg-base-100 rounded-box z-50 w-72 p-2 shadow-lg border border-base-200 mt-1",children:t.map(n=>e.jsx("li",{children:e.jsxs("button",{onClick:()=>s(n),className:"flex items-center gap-2 text-xs",children:[n.specType&&e.jsx(S,{icon:n.specType==="Bugfix"?"lucide:bug":"lucide:sparkles",size:12,className:n.specType==="Bugfix"?"text-error":"text-info"}),n.project&&e.jsx("span",{className:"text-base-content/40 truncate max-w-20",children:n.project}),e.jsx("span",{className:"font-medium truncate flex-1",children:n.name}),e.jsxs("span",{className:"text-base-content/50 font-mono",children:[n.completed,"/",n.total]})]})},n.filePath))})]})}function Qn(){const[t,s]=o.useState([]),[n,r]=o.useState({}),[a,i]=o.useState({}),{setSelectedProject:c,projects:d}=X(),{navigate:u}=se(),h=o.useRef(),l=o.useCallback(async()=>{try{const f=await fetch("/api/plans/active/all");if(!f.ok)return;const v=(await f.json()).specs||[],p=Date.now();s(v.filter(w=>w.status!=="VERIFIED"&&p-new Date(w.modifiedAt).getTime()(l(),h.current=setInterval(l,1e4),()=>clearInterval(h.current)),[l]);const m=o.useCallback(async f=>{const g=n[f.filePath];if(!(g&&g.modifiedAt===f.modifiedAt)&&!a[f.filePath]){i(v=>({...v,[f.filePath]:!0}));try{const v=f.project?`&project=${encodeURIComponent(f.project)}`:"",p=await fetch(`/api/plan/content?path=${encodeURIComponent(f.filePath)}${v}`);if(!p.ok)return;const w=await p.json(),C=Vn(w.content||"");r(I=>({...I,[f.filePath]:{modifiedAt:f.modifiedAt,tasks:C}}))}catch{}finally{i(v=>({...v,[f.filePath]:!1}))}}},[n,a]),x=o.useCallback(f=>{f.project&&d.includes(f.project)&&c(f.project);const g=encodeURIComponent(f.filePath);u(`/spec?path=${g}`)},[u,c,d]);if(t.length===0)return null;const b=t.slice(0,ht),j=t.slice(ht);return e.jsxs("div",{className:"flex items-center gap-2 min-w-0",children:[b.map(f=>{var g;return e.jsx(Wn,{spec:f,onClick:()=>x(f),onRequestTasks:()=>m(f),tasks:((g=n[f.filePath])==null?void 0:g.tasks)||null,loadingTasks:!!a[f.filePath]},f.filePath)}),j.length>0&&e.jsx(Jn,{specs:j,onPick:x})]})}function Yn({onToggleTheme:t,onToggleLogs:s}){return e.jsxs("header",{className:"h-14 bg-base-100 border-b border-base-300/50 flex items-center px-6 gap-4",children:[e.jsx("div",{className:"flex-1 min-w-0",children:e.jsx(Qn,{})}),e.jsx(qn,{onToggleTheme:t,onToggleLogs:s})]})}function Xn({children:t,currentPath:s,version:n,workerStatus:r,queueDepth:a,onToggleTheme:i,onToggleLogs:c,sidebarCollapsed:d,onToggleSidebar:u}){return e.jsxs("div",{className:"dashboard-layout flex h-screen",children:[e.jsx(Tn,{currentPath:s,version:n,workerStatus:r,queueDepth:a,collapsed:d,onToggleCollapse:u}),e.jsxs("div",{className:"flex-1 flex flex-col min-w-0 min-h-0",children:[e.jsx(Yn,{onToggleTheme:i,onToggleLogs:c}),e.jsx("main",{className:"flex-1 p-6 overflow-y-auto min-h-0",children:t})]})]})}function Zn({routes:t,fallback:s}){const{path:n}=se();for(const r of t){const a=ea(r.path,n);if(a){const i=r.component;return e.jsx(i,{...a.params})}}return s?e.jsx(e.Fragment,{children:s}):null}function ea(t,s){if(t===s)return{params:{}};const n=t.split("/"),r=s.split("/");if(n.length!==r.length)return null;const a={};for(let i=0;i{const a=setTimeout(()=>{r.current||s(!0)},8e3);return()=>clearTimeout(a)},[]),e.jsxs("div",{className:"h-full flex flex-col",children:[e.jsxs("div",{className:"flex items-center justify-between mb-4",children:[e.jsxs("div",{className:"flex items-baseline gap-3",children:[e.jsx("h1",{className:"text-2xl font-bold",children:"Documentation"}),e.jsx("span",{className:"text-base-content/50 text-sm",children:"Pilot Shell technical reference"})]}),e.jsxs("a",{href:Ce,target:"_blank",rel:"noopener noreferrer",className:"btn btn-sm btn-ghost gap-1.5",children:[e.jsx("svg",{className:"w-4 h-4",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"})}),"Open in browser"]})]}),t?e.jsx("div",{className:"flex-1 flex items-center justify-center",children:e.jsxs("div",{className:"text-center space-y-3",children:[e.jsx("div",{className:"text-4xl",children:"📡"}),e.jsx("p",{className:"text-base-content/60 text-sm",children:"Could not load documentation."}),e.jsx("a",{href:Ce,target:"_blank",rel:"noopener noreferrer",className:"btn btn-primary btn-sm",children:"Open docs in browser"})]})}):e.jsx("iframe",{ref:n,src:Ce,title:"Pilot Shell Documentation",className:"flex-1 w-full rounded-xl border border-base-300 bg-base-100",style:{minHeight:"calc(100vh - 10rem)"},onLoad:()=>{var a;r.current=!0;try{const i=n.current;((a=i==null?void 0:i.contentDocument)==null?void 0:a.title)===""&&s(!0)}catch{}}})]})}const sa={observation:{icon:"lucide:brain",variant:"info",color:"text-info"},summary:{icon:"lucide:file-text",variant:"warning",color:"text-warning"},prompt:{icon:"lucide:message-square",variant:"secondary",color:"text-secondary"},bugfix:{icon:"lucide:bug",variant:"error",color:"text-error"},feature:{icon:"lucide:sparkles",variant:"ghost",color:"text-emerald-400"},refactor:{icon:"lucide:refresh-cw",variant:"accent",color:"text-accent"},discovery:{icon:"lucide:search",variant:"info",color:"text-info"},decision:{icon:"lucide:git-branch",variant:"warning",color:"text-warning"},change:{icon:"lucide:pencil",variant:"secondary",color:"text-secondary"}},na={icon:"lucide:circle",variant:"secondary",color:"text-secondary"};function aa(t,s=50){return t.length<=s?t:t.slice(0,s)+"…"}function ra({memory:t,viewMode:s,onView:n,selectionMode:r,isSelected:a,onToggleSelection:i}){const c=sa[t.type]||na,d=s==="grid",u=()=>{r?i==null||i(t.id):n==null||n(t.id)},h=l=>{l.stopPropagation(),t.sessionDbId&&(window.location.hash=`/sessions?selected=${t.sessionDbId}`)};return e.jsx(B,{className:`hover:shadow-md transition-shadow cursor-pointer ${d?"":"flex flex-row"} ${a?"ring-2 ring-primary":""}`,onClick:u,children:e.jsx(H,{className:d?"p-4":"flex flex-row items-start gap-4 flex-1 p-4",children:e.jsxs("div",{className:`flex items-start gap-3 ${d?"":"flex-1"}`,children:[r?e.jsx("div",{className:"flex items-center justify-center w-8 h-8 flex-shrink-0",children:e.jsx("input",{type:"checkbox",className:"checkbox checkbox-primary",checked:a,onChange:()=>i==null?void 0:i(t.id),onClick:l=>l.stopPropagation()})}):e.jsx("div",{className:`p-2 rounded-lg bg-base-200 ${c.color} shrink-0`,children:e.jsx(S,{icon:c.icon,size:16})}),e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsxs("div",{className:"flex items-center justify-between gap-2 mb-1",children:[e.jsx(q,{variant:c.variant,size:"xs",children:t.type}),e.jsx("span",{className:"text-xs text-base-content/40 shrink-0",children:t.timestamp})]}),e.jsx("h3",{className:"font-medium text-sm line-clamp-2",children:t.title}),e.jsx("div",{className:"mt-1.5",children:t.sessionPrompt&&t.sessionDbId?e.jsxs("button",{onClick:h,className:"text-xs text-primary/70 hover:text-primary hover:underline truncate max-w-full block text-left transition-colors",title:`Session: ${t.sessionPrompt}`,children:[e.jsx(S,{icon:"lucide:terminal",size:11,className:"inline mr-1 -mt-0.5"}),aa(t.sessionPrompt)]}):e.jsx("span",{className:"text-xs text-base-content/30",children:"no session"})})]})]})})})}const ia={observation:{icon:"lucide:brain",variant:"info"},summary:{icon:"lucide:file-text",variant:"warning"},prompt:{icon:"lucide:message-square",variant:"secondary"},bugfix:{icon:"lucide:bug",variant:"error"},feature:{icon:"lucide:sparkles",variant:"success"},refactor:{icon:"lucide:refresh-cw",variant:"accent"},discovery:{icon:"lucide:search",variant:"info"},decision:{icon:"lucide:git-branch",variant:"warning"},change:{icon:"lucide:pencil",variant:"secondary"}};function oa({memory:t,onClose:s}){const n=t?ia[t.type]||{icon:"lucide:circle",variant:"secondary"}:{icon:"lucide:circle",variant:"secondary"};return e.jsx(fe,{open:!!t,onClose:s,title:"Memory Details",children:t&&e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"flex items-start gap-3",children:[e.jsx("div",{className:`p-2.5 rounded-lg bg-base-200 text-${n.variant}`,children:e.jsx(S,{icon:n.icon,size:20})}),e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("h3",{className:"text-base font-semibold leading-tight",children:t.title}),e.jsxs("div",{className:"flex items-center gap-2 mt-1.5 flex-wrap",children:[e.jsx(q,{variant:n.variant,size:"sm",children:t.type}),e.jsxs("span",{className:"text-xs text-base-content/50 flex items-center gap-1",children:[e.jsx(S,{icon:"lucide:folder",size:11}),t.project]}),e.jsx("span",{className:"text-xs text-base-content/40",children:t.timestamp}),e.jsxs("span",{className:"text-xs text-base-content/40 font-mono",children:["#",t.id]})]}),t.concepts&&t.concepts.length>0&&e.jsx("div",{className:"flex flex-wrap gap-1 mt-2",children:t.concepts.map(r=>e.jsx(q,{variant:"ghost",size:"xs",children:r},r))})]})]}),e.jsx("div",{className:"bg-base-200 rounded-lg p-4 max-h-96 overflow-y-auto",children:t.facts&&t.facts.length>0?e.jsx("ul",{className:"text-sm space-y-2 list-disc list-inside",children:t.facts.map((r,a)=>e.jsx("li",{children:r},a))}):e.jsx("pre",{className:"text-sm whitespace-pre-wrap break-words",children:t.content||"No content available"})})]})})}function ca({onSearch:t,isSearching:s,placeholder:n="Search your memories semantically..."}){const[r,a]=o.useState(""),i=c=>{c.preventDefault(),r.trim()&&t(r.trim())};return e.jsxs("form",{onSubmit:i,className:"flex gap-2",children:[e.jsxs("div",{className:"relative flex-1",children:[e.jsx(S,{icon:"lucide:search",size:20,className:"absolute left-4 top-1/2 -translate-y-1/2 text-base-content/50"}),e.jsx("input",{type:"search",placeholder:n,value:r,onChange:c=>a(c.target.value),className:"input input-bordered w-full pl-12 pr-4"})]}),e.jsx(W,{type:"submit",loading:s,disabled:!r.trim(),children:"Search"})]})}const la={observation:{icon:"lucide:brain",variant:"info",label:"Observation"},summary:{icon:"lucide:file-text",variant:"warning",label:"Summary"},prompt:{icon:"lucide:message-square",variant:"secondary",label:"Prompt"},bugfix:{icon:"lucide:bug",variant:"error",label:"Bug Fix"},feature:{icon:"lucide:sparkles",variant:"success",label:"Feature"},refactor:{icon:"lucide:refresh-cw",variant:"accent",label:"Refactor"},discovery:{icon:"lucide:search",variant:"info",label:"Discovery"},decision:{icon:"lucide:git-branch",variant:"warning",label:"Decision"},change:{icon:"lucide:pencil",variant:"secondary",label:"Change"}},da={icon:"lucide:circle",variant:"secondary",label:"Unknown"};function ua(t){try{return new Date(t).toLocaleDateString("en-US",{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit"})}catch{return t}}function ma({result:t}){const s=t.obsType||t.type,n=la[s]||da,r=Math.round(t.score*100),a=i=>i>=.7?"text-success":i>=.4?"text-warning":"text-base-content/50";return e.jsx(B,{className:"hover:shadow-md transition-shadow",children:e.jsx(H,{children:e.jsxs("div",{className:"flex items-start gap-3",children:[e.jsx("div",{className:"p-2 rounded-lg bg-base-200 shrink-0",children:e.jsx(S,{icon:n.icon,size:18})}),e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsxs("div",{className:"flex items-center gap-2 mb-1 flex-wrap",children:[e.jsx(q,{variant:n.variant,size:"xs",children:n.label}),e.jsxs("span",{className:"text-xs text-base-content/50",children:["#",t.id]}),t.score>0&&e.jsxs("span",{className:`ml-auto text-xs font-mono ${a(t.score)}`,children:[r,"% match"]})]}),e.jsx("h3",{className:"font-medium truncate",children:t.title}),e.jsx("p",{className:"text-sm text-base-content/60 mt-1 line-clamp-2",children:t.content}),e.jsxs("div",{className:"flex items-center gap-4 mt-3 text-xs text-base-content/50",children:[t.project&&e.jsxs("span",{className:"flex items-center gap-1",children:[e.jsx(S,{icon:"lucide:folder",size:12}),t.project]}),e.jsxs("span",{className:"flex items-center gap-1",children:[e.jsx(S,{icon:"lucide:clock",size:12}),ua(t.timestamp)]})]})]}),t.score>0&&e.jsxs("div",{className:"w-16 shrink-0 hidden sm:block",children:[e.jsx("div",{className:"h-2 bg-base-200 rounded-full overflow-hidden",children:e.jsx("div",{className:`h-full rounded-full transition-all ${t.score>=.7?"bg-success":t.score>=.4?"bg-warning":"bg-base-content/30"}`,style:{width:`${r}%`}})}),e.jsx("div",{className:"text-[10px] text-center mt-1 text-base-content/50",children:"similarity"})]})]})})})}function we(){const{selectedProject:t,projects:s,setSelectedProject:n}=X();return e.jsxs("div",{className:"relative inline-flex items-center",children:[e.jsx("select",{value:t??s[0]??"",onChange:r=>n(r.target.value),className:"select select-bordered select-sm text-xs font-normal pl-7 pr-8 min-w-[140px] max-w-[200px]",children:s.map(r=>e.jsx("option",{value:r,children:r},r))}),e.jsx(S,{icon:"lucide:folder",size:13,className:"absolute left-2.5 pointer-events-none text-base-content/40"})]})}const ha=12e4;function fa(){const{selectedProject:t}=X(),[s,n]=o.useState(!1),[r,a]=o.useState([]),[i,c]=o.useState(!1),[d,u]=o.useState(null),[h,l]=o.useState(null),m=o.useRef(null),x=o.useRef(!1),b=o.useCallback(async f=>{var p;(p=m.current)==null||p.abort(),x.current=!1;const g=new AbortController;m.current=g;const v=setTimeout(()=>g.abort(),ha);c(!0),n(!0),u(null);try{const w=new URLSearchParams({query:f,limit:"30"});t&&w.set("project",t);const C=await fetch(`/api/search/semantic?${w}`,{signal:g.signal});if(!C.ok)throw new Error(`Search failed with status ${C.status}`);const I=await C.json();a(I.results||[]),l({usedSemantic:I.usedSemantic,vectorDbAvailable:I.vectorDbAvailable})}catch(w){if(x.current)return;w.name==="AbortError"?u("Search timed out. Please try again."):u("Search failed. Please try again."),a([]),l(null)}finally{clearTimeout(v),x.current||c(!1)}},[t]),j=o.useCallback(()=>{var f;x.current=!0,(f=m.current)==null||f.abort(),n(!1),a([]),l(null),u(null),c(!1)},[]);return o.useEffect(()=>()=>{var f;(f=m.current)==null||f.abort()},[]),{isSearchMode:s,searchResults:r,isSearching:i,searchError:d,searchMeta:h,handleSearch:b,handleClearSearch:j}}function ft(){var I;const{params:t}=se(),[s,n]=o.useState([]),[r,a]=o.useState(!0),[i,c]=o.useState(null),d=t.id?Number(t.id):null,u=o.useRef(!1),{selectedProject:h}=X(),{isSearchMode:l,searchResults:m,isSearching:x,searchError:b,searchMeta:j,handleSearch:f,handleClearSearch:g}=fa(),v=o.useCallback(async N=>{await f(N)},[f]),p=o.useCallback(async()=>{a(!0);try{const N=new URLSearchParams;h&&N.set("project",h),N.set("limit","50");const L=await(await fetch(`/api/observations?${N}`)).json(),R=L.items||L.observations||[];n(R.map(E=>({id:E.id,type:E.type||"observation",title:E.title||"Untitled",content:E.narrative||E.content||"",facts:E.facts?typeof E.facts=="string"?JSON.parse(E.facts):E.facts:[],project:E.project||"unknown",timestamp:w(E.created_at),concepts:E.concepts?typeof E.concepts=="string"?JSON.parse(E.concepts):E.concepts:[],sessionDbId:E.session_db_id??void 0,sessionPrompt:E.session_prompt??void 0})))}catch(N){console.error("Failed to fetch memories:",N)}finally{a(!1)}},[h]);function w(N){if(!N)return"";const _=new Date(N),R=new Date().getTime()-_.getTime();return R<6e4?"just now":R<36e5?`${Math.floor(R/6e4)}m ago`:R<864e5?`${Math.floor(R/36e5)}h ago`:_.toLocaleDateString()}o.useEffect(()=>{p()},[p]),o.useEffect(()=>{if(d&&!u.current&&!r&&s.length>0){const N=s.find(_=>_.id===d);N&&(u.current=!0,c(N))}},[d,r,s]);const C=N=>{const _=s.find(L=>L.id===N);_&&c(_)};return e.jsxs("div",{className:"space-y-6",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"flex items-center gap-3 flex-wrap",children:[e.jsx("h1",{className:"text-2xl font-bold",children:"Memories"}),e.jsx(we,{}),e.jsx("span",{className:"text-base-content/50 text-sm",children:"Decisions, discoveries, and patterns from past sessions"})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[l&&e.jsxs(W,{variant:"ghost",size:"sm",onClick:g,children:[e.jsx(S,{icon:"lucide:x",size:16,className:"mr-1"}),"Clear"]}),!l&&e.jsx(W,{variant:"ghost",size:"sm",onClick:p,children:e.jsx(S,{icon:"lucide:refresh-cw",size:16})})]})]}),!l&&e.jsxs("div",{className:"bg-base-200/40 rounded-xl p-4 space-y-2",children:[e.jsx("p",{className:"text-xs font-semibold text-base-content/50 uppercase tracking-wider",children:"How Memories Work"}),e.jsxs("div",{className:"grid sm:grid-cols-3 gap-3 text-sm text-base-content/60",children:[e.jsxs("div",{className:"flex items-start gap-2",children:[e.jsx(S,{icon:"lucide:scan",size:14,className:"text-violet-400 flex-shrink-0 mt-0.5"}),e.jsxs("p",{children:[e.jsx("span",{className:"font-medium text-base-content/70",children:"Capture"})," — hooks observe each session and send events to a background Haiku model that extracts decisions, discoveries, and patterns"]})]}),e.jsxs("div",{className:"flex items-start gap-2",children:[e.jsx(S,{icon:"lucide:database",size:14,className:"text-sky-400 flex-shrink-0 mt-0.5"}),e.jsxs("p",{children:[e.jsx("span",{className:"font-medium text-base-content/70",children:"Store"})," — observations are persisted in a local SQLite database with full-text and semantic search"]})]}),e.jsxs("div",{className:"flex items-start gap-2",children:[e.jsx(S,{icon:"lucide:rotate-cw",size:14,className:"text-emerald-400 flex-shrink-0 mt-0.5"}),e.jsxs("p",{children:[e.jsx("span",{className:"font-medium text-base-content/70",children:"Re-inject"})," — at session start, relevant memories are loaded back into context so Claude remembers your conventions and past decisions"]})]})]})]}),e.jsx(ca,{onSearch:v,isSearching:x,placeholder:"Search memories semantically..."}),b&&!x&&e.jsxs("div",{className:"alert alert-error",children:[e.jsx(S,{icon:"lucide:alert-circle",size:16}),e.jsx("span",{children:b})]}),l?x?e.jsx(te,{}):b?null:m.length===0?e.jsx($e,{icon:"lucide:search-x",title:"No results found",description:"Try a different query"}):e.jsxs("div",{className:"space-y-3",children:[e.jsxs("div",{className:"text-sm text-base-content/60",children:[m.length," results",(j==null?void 0:j.usedSemantic)&&((I=m[0])==null?void 0:I.score)>0&&e.jsxs("span",{className:"ml-2",children:["(best match: ",Math.round(m[0].score*100),"% similarity)"]})]}),m.map(N=>e.jsx(ma,{result:N},`${N.type}-${N.id}`))]}):r?e.jsx(te,{}):s.length===0?e.jsx($e,{icon:"lucide:brain",title:"No memories yet",description:"Memories are created automatically as you use Claude Code — decisions, discoveries, and patterns are captured in the background."}):e.jsx("div",{className:"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4",children:s.map(N=>e.jsx(ra,{memory:N,viewMode:"grid",onView:C,selectionMode:!1,isSelected:!1,onToggleSelection:()=>{}},N.id))}),e.jsx(oa,{memory:i,onClose:()=>c(null)})]})}const xt={active:{variant:"warning",icon:"lucide:play"},completed:{variant:"success",icon:"lucide:check"}};function xa(t){return new Date(t).toLocaleDateString("en-US",{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit"})}function pa({sessionId:t}){const[s,n]=o.useState(!1),r=a=>{a.stopPropagation(),navigator.clipboard.writeText(t).then(()=>{n(!0),setTimeout(()=>n(!1),2e3)})};return e.jsxs("button",{onClick:r,className:"flex items-center gap-1.5 px-2 py-0.5 rounded bg-base-200 hover:bg-base-300 transition-colors text-xs font-mono text-base-content/60 group",title:"Copy session ID for /resume",children:[e.jsx("span",{className:"truncate max-w-32",children:t}),e.jsx(S,{icon:s?"lucide:check":"lucide:copy",size:12,className:s?"text-success":"text-base-content/40 group-hover:text-base-content/70"})]})}function Ee({icon:t,value:s,label:n}){return e.jsxs("div",{className:"flex flex-col items-center min-w-[4.5rem]",children:[e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(S,{icon:t,size:13,className:"text-base-content/40"}),e.jsx("span",{className:"font-semibold text-sm tabular-nums",children:s})]}),e.jsx("span",{className:"text-[10px] text-base-content/40 uppercase tracking-wider",children:n})]})}function ba(t){return t<.01?"<$0.01":t<1?`$${t.toFixed(2)}`:`$${t.toFixed(2)}`}function ga({session:t,isExpanded:s,onToggle:n,isResumed:r,costUsd:a}){const i=xt[t.status]||xt.active;return e.jsx(B,{className:`cursor-pointer hover:shadow-md transition-shadow ${s?"ring-2 ring-primary":""} ${t.status==="active"?"border-l-4 border-l-warning":""}`,onClick:n,children:e.jsx(H,{children:e.jsxs("div",{className:"flex items-start gap-4",children:[e.jsx("div",{className:"p-2 rounded-lg bg-base-200 shrink-0",children:e.jsx(S,{icon:i.icon,size:20,className:`text-${i.variant}`})}),e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsxs("div",{className:"flex items-center gap-2 mb-1 flex-wrap",children:[e.jsx(q,{variant:i.variant,size:"sm",children:t.status}),r&&e.jsx(q,{variant:"info",size:"sm",children:"resumed"}),t.content_session_id&&e.jsx(pa,{sessionId:t.content_session_id})]}),e.jsx("h3",{className:"font-medium line-clamp-1",children:t.user_prompt||t.project||"Untitled Session"}),e.jsxs("div",{className:"flex items-center gap-4 mt-2 text-sm text-base-content/60",children:[e.jsxs("span",{className:"flex items-center gap-1",children:[e.jsx(S,{icon:"lucide:folder",size:14}),t.project]}),e.jsxs("span",{className:"flex items-center gap-1",children:[e.jsx(S,{icon:"lucide:calendar",size:14}),xa(t.started_at)]})]})]}),e.jsxs("div",{className:"flex items-center gap-3 shrink-0",children:[e.jsx(Ee,{icon:"lucide:dollar-sign",value:a!=null?ba(a):"—",label:"Cost"}),e.jsx(Ee,{icon:"lucide:messages-square",value:t.observation_count+t.prompt_count,label:"Messages"}),e.jsx(Ee,{icon:"lucide:message-square",value:t.prompt_count,label:"Prompts"}),e.jsx(S,{icon:s?"lucide:chevron-up":"lucide:chevron-down",size:20,className:"text-base-content/50 ml-1"})]})]})})})}const Re={prompt:{icon:"lucide:message-square",color:"text-primary"},observation:{icon:"lucide:brain",color:"text-info"},bugfix:{icon:"lucide:bug",color:"text-error"},feature:{icon:"lucide:sparkles",color:"text-emerald-400"},refactor:{icon:"lucide:refresh-cw",color:"text-accent"},discovery:{icon:"lucide:search",color:"text-info"},decision:{icon:"lucide:git-branch",color:"text-warning"},change:{icon:"lucide:pencil",color:"text-secondary"}};function ja(t){return new Date(t).toLocaleTimeString("en-US",{hour:"2-digit",minute:"2-digit"})}function va({sessionId:t,skipHeader:s}){const[n,r]=o.useState(null),[a,i]=o.useState(!0),[c,d]=o.useState(new Set);o.useEffect(()=>{async function l(){i(!0);try{const x=await(await fetch(`/api/sessions/${t}/timeline`)).json();r(x)}catch(m){console.error("Failed to fetch timeline:",m)}finally{i(!1)}}l()},[t]);const u=l=>{d(m=>{const x=new Set(m);return x.has(l)?x.delete(l):x.add(l),x})};if(a)return e.jsx("div",{className:"space-y-3 animate-pulse py-4",children:Array.from({length:3}).map((l,m)=>e.jsx("div",{className:"h-16 bg-base-300/50 rounded-lg"},m))});if(!n)return e.jsx("div",{className:"text-center py-8 text-base-content/50",children:"Failed to load timeline"});const h={active:"badge-success",completed:"badge-info",failed:"badge-error"};return e.jsxs("div",{className:"mt-4 space-y-4",children:[!s&&e.jsxs(e.Fragment,{children:[e.jsx(B,{className:"bg-base-200/50",children:e.jsxs(H,{className:"py-3",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-3 mb-2",children:[e.jsx(q,{variant:"ghost",size:"sm",className:h[n.session.status]||"",children:n.session.status}),e.jsx("span",{className:"text-sm text-base-content/60",children:new Date(n.session.started_at).toLocaleString()}),n.session.completed_at&&e.jsxs("span",{className:"text-sm text-base-content/60",children:["→ ",new Date(n.session.completed_at).toLocaleString()]})]}),e.jsxs("div",{className:"flex flex-wrap gap-4 text-sm",children:[e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(S,{icon:"lucide:message-square",size:14,className:"text-primary"}),e.jsx("span",{className:"font-medium",children:n.stats.prompts}),e.jsx("span",{className:"text-base-content/60",children:"prompts"})]}),e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(S,{icon:"lucide:brain",size:14,className:"text-info"}),e.jsx("span",{className:"font-medium",children:n.stats.observations}),e.jsx("span",{className:"text-base-content/60",children:"observations"})]})]})]})}),n.session.user_prompt&&e.jsx(B,{className:"bg-primary/10 border-primary/30",children:e.jsxs(H,{className:"py-3",children:[e.jsxs("div",{className:"flex items-center gap-2 mb-2",children:[e.jsx(S,{icon:"lucide:terminal",size:16,className:"text-primary"}),e.jsx("span",{className:"font-medium text-sm",children:"Prompt"})]}),e.jsx("p",{className:"text-sm text-base-content/80 whitespace-pre-wrap",children:n.session.user_prompt})]})}),n.summary&&e.jsx(B,{className:"bg-warning/10 border-warning/30",children:e.jsxs(H,{className:"py-3",children:[e.jsxs("div",{className:"flex items-center gap-2 mb-3",children:[e.jsx(S,{icon:"lucide:file-text",size:16,className:"text-warning"}),e.jsx("span",{className:"font-medium text-sm",children:"Session Summary"}),e.jsx("span",{className:"text-xs text-base-content/50",children:new Date(n.summary.created_at).toLocaleTimeString()})]}),e.jsxs("div",{className:"space-y-3 text-sm",children:[n.summary.request&&e.jsxs("div",{children:[e.jsx("div",{className:"font-medium text-warning mb-1",children:"Request"}),e.jsx("div",{className:"text-base-content/80",children:n.summary.request})]}),n.summary.investigated&&e.jsxs("div",{children:[e.jsx("div",{className:"font-medium text-info mb-1",children:"Investigated"}),e.jsx("div",{className:"text-base-content/80",children:n.summary.investigated})]}),n.summary.learned&&e.jsxs("div",{children:[e.jsx("div",{className:"font-medium text-success mb-1",children:"Learned"}),e.jsx("div",{className:"text-base-content/80",children:n.summary.learned})]}),n.summary.completed&&e.jsxs("div",{children:[e.jsx("div",{className:"font-medium text-primary mb-1",children:"Completed"}),e.jsx("div",{className:"text-base-content/80",children:n.summary.completed})]}),n.summary.next_steps&&e.jsxs("div",{children:[e.jsx("div",{className:"font-medium text-accent mb-1",children:"Next Steps"}),e.jsx("div",{className:"text-base-content/80",children:n.summary.next_steps})]})]})]})})]}),e.jsxs("div",{className:"ml-8 border-l-2 border-base-300 pl-6 space-y-4",children:[[...n.timeline].reverse().map((l,m)=>{var g,v;const x=`${l.type}-${l.id}`,b=c.has(x),j=l.type==="prompt"?Re.prompt:Re[l.data.type]||Re.observation;let f=[];if(l.type==="observation"&&l.data.concepts)try{f=JSON.parse(l.data.concepts)}catch{}return e.jsxs("div",{className:"relative",children:[e.jsx("div",{className:`absolute -left-9 top-3 w-4 h-4 rounded-full border-2 border-base-100 ${l.type==="prompt"?"bg-primary":"bg-info"}`}),e.jsx(B,{className:"cursor-pointer hover:shadow-sm transition-shadow",onClick:p=>{p.stopPropagation(),u(x)},children:e.jsx(H,{className:"py-3",children:e.jsxs("div",{className:"flex items-start gap-3",children:[e.jsx("div",{className:`p-1.5 rounded bg-base-200 ${j.color}`,children:e.jsx(S,{icon:j.icon,size:14})}),e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-2 mb-1",children:[e.jsx(q,{variant:l.type==="prompt"?"primary":"info",size:"xs",children:l.type==="prompt"?`prompt #${l.data.prompt_number||"?"}`:l.data.type||"observation"}),e.jsx("span",{className:"text-xs text-base-content/50",children:ja(l.timestamp)}),e.jsxs("span",{className:"text-xs text-base-content/40",children:["#",l.id]}),f.length>0&&f.map(p=>e.jsx(q,{variant:"ghost",size:"xs",className:"text-base-content/50",children:p},p))]}),e.jsx("p",{className:"text-sm font-medium",children:l.type==="prompt"?((g=l.data.prompt_text)==null?void 0:g.length)>100?l.data.prompt_text.substring(0,100)+"...":l.data.prompt_text:l.data.title||"Untitled"}),l.type==="observation"&&l.data.narrative&&e.jsx("p",{className:`text-sm text-base-content/70 mt-1 ${b?"":"line-clamp-3"}`,children:l.data.narrative}),l.type==="prompt"&&((v=l.data.prompt_text)==null?void 0:v.length)>100&&e.jsx("p",{className:`text-sm text-base-content/70 mt-1 ${b?"whitespace-pre-wrap":"line-clamp-3"}`,children:b?l.data.prompt_text:l.data.prompt_text.substring(100)}),l.type==="observation"&&(l.data.files_read||l.data.files_modified)&&e.jsxs("div",{className:"flex flex-wrap gap-2 mt-2",children:[l.data.files_read&&(()=>{try{const p=JSON.parse(l.data.files_read);if(p.length>0)return e.jsxs("span",{className:"text-xs text-base-content/50",children:[e.jsx(S,{icon:"lucide:file",size:12,className:"inline mr-1"}),p.length," read"]})}catch{return null}})(),l.data.files_modified&&(()=>{try{const p=JSON.parse(l.data.files_modified);if(p.length>0)return e.jsxs("span",{className:"text-xs text-base-content/50",children:[e.jsx(S,{icon:"lucide:pencil",size:12,className:"inline mr-1"}),p.length," modified"]})}catch{return null}})()]}),b&&l.type==="observation"&&l.data.text&&e.jsxs("div",{className:"mt-3 pt-3 border-t border-base-200",children:[e.jsx("p",{className:"text-sm text-base-content/70 whitespace-pre-wrap",children:l.data.text}),(l.data.files_read||l.data.files_modified)&&e.jsxs("div",{className:"mt-3 space-y-1",children:[l.data.files_read&&(()=>{try{const p=JSON.parse(l.data.files_read);if(p.length>0)return e.jsxs("div",{children:[e.jsx("span",{className:"text-xs font-medium",children:"Files Read:"}),e.jsx("div",{className:"text-xs text-base-content/50 mt-1",children:p.map((w,C)=>e.jsx("div",{className:"truncate",children:w},C))})]})}catch{return null}})(),l.data.files_modified&&(()=>{try{const p=JSON.parse(l.data.files_modified);if(p.length>0)return e.jsxs("div",{children:[e.jsx("span",{className:"text-xs font-medium",children:"Files Modified:"}),e.jsx("div",{className:"text-xs text-base-content/50 mt-1",children:p.map((w,C)=>e.jsx("div",{className:"truncate",children:w},C))})]})}catch{return null}})()]})]})]}),e.jsx(S,{icon:b?"lucide:chevron-up":"lucide:chevron-down",size:16,className:"text-base-content/40"})]})})})]},x)}),n.timeline.length===0&&e.jsx("div",{className:"text-center py-8 text-base-content/50",children:"No activity in this session"})]})]})}function ya(t){return t<.01?"<$0.01":`$${t.toFixed(2)}`}const wa={Read:"lucide:file",Write:"lucide:file-plus",Edit:"lucide:file-edit",Bash:"lucide:terminal",Glob:"lucide:folder-search",Grep:"lucide:search",Agent:"lucide:bot",WebSearch:"lucide:globe",WebFetch:"lucide:download",AskUserQuestion:"lucide:message-circle",TaskCreate:"lucide:list-plus",TaskUpdate:"lucide:list-checks"};function ge({label:t,value:s,icon:n}){return e.jsxs("div",{className:"bg-base-200/50 rounded-lg px-3 py-2.5 text-center",children:[e.jsxs("div",{className:"flex items-center justify-center gap-1.5 mb-0.5",children:[e.jsx(S,{icon:n,size:13,className:"text-base-content/40"}),e.jsx("span",{className:"text-[10px] text-base-content/50 uppercase tracking-wider",children:t})]}),e.jsx("div",{className:"text-base font-semibold tabular-nums",children:s})]})}function Na({tools:t}){const s=Object.entries(t);if(s.length===0)return e.jsx(e.Fragment,{});const n=Math.max(...s.map(([,u])=>u)),r=s.slice(0,20),a=Math.ceil(r.length/2),i=r.slice(0,a),c=r.slice(a),d=([u,h])=>e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(S,{icon:wa[u]||"lucide:wrench",size:13,className:"text-base-content/40 shrink-0"}),e.jsx("span",{className:"text-sm w-28 truncate",title:u,children:u}),e.jsx("div",{className:"flex-1 h-1.5 bg-base-300 rounded-full overflow-hidden",children:e.jsx("div",{className:"h-full bg-info rounded-full transition-all",style:{width:`${h/n*100}%`}})}),e.jsx("span",{className:"text-xs tabular-nums text-base-content/50 w-8 text-right",children:h})]},u);return e.jsxs("div",{className:"grid grid-cols-2 gap-x-6 gap-y-1.5",children:[e.jsx("div",{className:"space-y-1.5",children:i.map(d)}),e.jsx("div",{className:"space-y-1.5",children:c.map(d)}),s.length>20&&e.jsxs("span",{className:"col-span-2 text-xs text-base-content/40 mt-1",children:["+ ",s.length-20," more tools"]})]})}function Sa({session:t,open:s,onClose:n,onResumedDetected:r}){const[a,i]=o.useState(null),[c,d]=o.useState(null),[u,h]=o.useState(!0),[l,m]=o.useState(!0),x=o.useRef(r);x.current=r,o.useEffect(()=>{if(!s)return;let f=!1;async function g(){var v;h(!0);try{const[p,w]=await Promise.all([fetch(`/api/sessions/${t.id}/stats`),fetch(`/api/sessions/${t.id}/timeline`)]);if(!f){if(p.ok){const C=await p.json();C.stats?(i(C.stats),m(!0),(v=x.current)==null||v.call(x,C.stats.is_resumed)):m(!1)}else m(!1);if(w.ok){const C=await w.json();d(C.session??null)}}}catch{f||m(!1)}finally{f||h(!1)}}return g(),()=>{f=!0}},[t.id,s]);const b=a?Object.entries(a.models):[],j=(c==null?void 0:c.status)==="active"||t.status==="active";return e.jsx(fe,{open:s,onClose:n,title:"Session Details",size:"wide",children:e.jsxs("div",{className:"max-h-[70vh] overflow-y-auto space-y-4 pr-1",children:[e.jsxs("div",{className:"flex items-center gap-3 flex-wrap text-sm",children:[e.jsx(q,{variant:j?"warning":"success",size:"sm",children:j?"active":"completed"}),(a==null?void 0:a.is_resumed)&&e.jsx(q,{variant:"info",size:"sm",children:"resumed"}),e.jsx("span",{className:"text-base-content/50",children:c?new Date(c.started_at).toLocaleString():new Date(t.started_at).toLocaleString()}),(c==null?void 0:c.completed_at)&&e.jsxs("span",{className:"text-base-content/40",children:["→ ",new Date(c.completed_at).toLocaleString()]}),b.length>0&&e.jsxs(e.Fragment,{children:[e.jsx("span",{className:"text-base-content/20",children:"|"}),b.map(([f,g])=>e.jsxs(q,{variant:"ghost",size:"sm",children:[f.replace("claude-","").replace(/-\d{8}$/,"")," (",g,")"]},f))]})]}),u?e.jsx("div",{className:"grid grid-cols-4 gap-3 animate-pulse",children:Array.from({length:4}).map((f,g)=>e.jsx("div",{className:"bg-base-300/50 rounded-lg h-14"},g))}):a?e.jsxs("div",{className:"grid grid-cols-4 gap-3",children:[e.jsx(ge,{label:"Cost",value:ya(a.cost_usd),icon:"lucide:dollar-sign"}),e.jsx(ge,{label:"Messages",value:String(a.turns),icon:"lucide:messages-square"}),e.jsx(ge,{label:"Observations",value:String(t.observation_count),icon:"lucide:brain"}),e.jsx(ge,{label:"Prompts",value:String(t.prompt_count),icon:"lucide:message-square"})]}):l?null:e.jsxs("div",{className:"text-sm text-base-content/40 text-center py-2",children:[e.jsx(S,{icon:"lucide:file-x",size:16,className:"inline mr-2"}),"JSONL file not available — showing timeline data only"]}),t.user_prompt&&e.jsxs("div",{className:"border border-base-300 rounded-lg p-4",children:[e.jsxs("div",{className:"flex items-center gap-2 mb-2",children:[e.jsx(S,{icon:"lucide:terminal",size:14,className:"text-primary"}),e.jsx("span",{className:"text-xs text-base-content/50 uppercase tracking-wider",children:"Prompt"})]}),e.jsx("p",{className:"text-sm whitespace-pre-wrap break-words text-base-content/80",children:t.user_prompt})]}),a&&Object.keys(a.tools).length>0&&e.jsxs("div",{className:"border border-base-300 rounded-lg p-4",children:[e.jsxs("div",{className:"flex items-center gap-2 mb-3",children:[e.jsx(S,{icon:"lucide:wrench",size:14,className:"text-info"}),e.jsx("span",{className:"text-xs text-base-content/50 uppercase tracking-wider",children:"Tool Usage"})]}),e.jsx(Na,{tools:a.tools})]}),e.jsx(va,{sessionId:t.id,skipHeader:!0})]})})}const ka=[{key:"date",label:"Date",icon:"lucide:calendar"},{key:"cost",label:"Cost",icon:"lucide:dollar-sign"},{key:"messages",label:"Messages",icon:"lucide:messages-square"},{key:"prompts",label:"Prompts",icon:"lucide:message-square"}];function pt(t,s,n){switch(s){case"date":return t.started_at_epoch;case"cost":return n[t.id]??0;case"messages":return t.observation_count+t.prompt_count;case"prompts":return t.prompt_count}}function Ca(){const{params:t}=se(),[s,n]=o.useState([]),[r,a]=o.useState(!0),[i,c]=o.useState(null),[d,u]=o.useState(""),[h,l]=o.useState("date"),[m,x]=o.useState("desc"),[b,j]=o.useState({}),{selectedProject:f,setSelectedProject:g}=X(),v=o.useRef(null),[p,w]=o.useState(new Set),C=o.useCallback(async R=>{a(!0);try{const E=new URLSearchParams;E.set("limit","50"),f&&E.set("project",f),R&&E.set("search",R);const $=(await(await fetch(`/api/sessions?${E}`)).json()).items||[];if(n($),$.length>0){const D=$.map(P=>P.id);fetch("/api/sessions/costs",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({ids:D})}).then(P=>P.json()).then(P=>j(P.costs||{})).catch(()=>{})}}catch(E){console.error("Failed to fetch sessions:",E)}finally{a(!1)}},[f]);o.useEffect(()=>{C(d||void 0)},[C,d]),o.useEffect(()=>{if(!t.selected||r)return;const R=Number(t.selected),E=s.find(y=>y.id===R);E?(c(E),f&&E.project!==f&&g(E.project)):f&&s.length>0&&g(null)},[t.selected,r,s,f,g]);const I=R=>{v.current&&clearTimeout(v.current),v.current=setTimeout(()=>{u(R)},300)},N=o.useCallback(R=>{w(E=>{if(!i||E.has(i.id)||!R)return E;const y=new Set(E);return y.add(i.id),y})},[i]),_=R=>{h===R?x(E=>E==="desc"?"asc":"desc"):(l(R),x("desc"))},L=o.useMemo(()=>{const R=[],E=[];for(const $ of s)$.status==="active"?R.push($):E.push($);const y=m==="desc"?-1:1,A=($,D)=>y*(pt($,h,b)-pt(D,h,b));return R.sort(A),E.sort(A),[...R,...E]},[s,h,m,b]);return e.jsxs("div",{className:"space-y-6",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"flex items-center gap-3 flex-wrap",children:[e.jsx("h1",{className:"text-2xl font-bold",children:"Sessions"}),e.jsx(we,{}),e.jsxs("span",{className:"text-xs text-base-content/50",children:[s.length," session",s.length!==1?"s":""]}),e.jsx("span",{className:"text-base-content/50 text-sm",children:"Browse past sessions · copy session ID to resume"})]}),e.jsx("div",{className:"flex items-center gap-2",children:e.jsx(W,{variant:"ghost",size:"sm",onClick:()=>C(d||void 0),children:e.jsx(S,{icon:"lucide:refresh-cw",size:16})})})]}),e.jsxs("div",{className:"relative",children:[e.jsx(S,{icon:"lucide:search",size:20,className:"absolute left-4 top-1/2 -translate-y-1/2 text-base-content/50"}),e.jsx("input",{type:"search",placeholder:"Search sessions by prompt, project, or session ID...",onChange:R=>I(R.target.value),className:"input input-bordered w-full pl-12 pr-4"})]}),r?e.jsx(te,{}):s.length===0?e.jsx($e,{icon:"lucide:history",title:d?"No matching sessions":"No sessions found",description:d?"Try a different search query":"Sessions will appear here as you use Claude Code"}):e.jsxs("div",{className:"space-y-3",children:[e.jsxs("div",{className:"flex items-center justify-end gap-1 pr-2",children:[e.jsx("span",{className:"text-xs text-base-content/40 mr-2",children:"Sort by:"}),ka.map(({key:R,label:E,icon:y})=>{const A=h===R;return e.jsxs("button",{onClick:()=>_(R),className:`flex items-center gap-1 px-2.5 py-1 rounded text-xs transition-colors ${A?"bg-primary/10 text-primary font-medium":"text-base-content/50 hover:text-base-content/80 hover:bg-base-200"}`,children:[e.jsx(S,{icon:y,size:12}),E,A&&e.jsx(S,{icon:m==="desc"?"lucide:arrow-down":"lucide:arrow-up",size:12})]},R)})]}),L.map(R=>e.jsx("div",{id:`session-${R.id}`,children:e.jsx(ga,{session:R,isExpanded:(i==null?void 0:i.id)===R.id,onToggle:()=>c((i==null?void 0:i.id)===R.id?null:R),isResumed:p.has(R.id),costUsd:b[R.id]})},R.id))]}),i&&e.jsx(Sa,{session:i,open:!!i,onClose:()=>c(null),onResumedDetected:N})]})}const he=["sonnet","opus"],Bt={sonnet:"Sonnet 4.6",opus:"Opus 4.7"},Ht=/^claude-[a-z0-9][a-z0-9.\-]*$/;function bt(t){return typeof t!="string"||t.length===0?!1:he.includes(t)?!0:Ht.test(t)}function Ea(t){return!he.includes(t)&&Ht.test(t)}const G={model:"opus",extendedContext:!0,skills:{spec:"opus","spec-plan":"opus","spec-implement":"sonnet","spec-verify":"sonnet",fix:"opus","setup-rules":"opus","create-skill":"opus",prd:"opus",benchmark:"opus"},agents:{"spec-review":"sonnet","changes-review":"sonnet"},reviewerAgents:{specReview:!0,changesReview:!0},codexReviewers:{specReview:!1,changesReview:!1},codexAvailable:!1,specWorkflow:{worktreeSupport:!0,askQuestionsDuringPlanning:!0,planApproval:!0}};function Ra(){const[t,s]=o.useState(G),[n,r]=o.useState(!0),[a,i]=o.useState(null),[c,d]=o.useState(!1),[u,h]=o.useState(!1);o.useEffect(()=>{fetch("/api/settings").then(p=>{if(!p.ok)throw new Error(`API error: ${p.status}`);return p.json()}).then(p=>{s({...G,...p}),r(!1)}).catch(p=>{i(p.message||"Failed to load settings"),r(!1)})},[]);const l=o.useCallback(p=>{s(w=>({...w,model:p})),d(!0),h(!1)},[]),m=o.useCallback(p=>{s(w=>({...w,extendedContext:p})),d(!0),h(!1)},[]),x=o.useCallback((p,w)=>{s(C=>({...C,skills:{...C.skills,[p]:w}})),d(!0),h(!1)},[]),b=o.useCallback((p,w)=>{s(C=>({...C,agents:{...C.agents,[p]:w}})),d(!0),h(!1)},[]),j=o.useCallback((p,w)=>{s(C=>({...C,reviewerAgents:{...C.reviewerAgents,[p]:w}})),d(!0),h(!1)},[]),f=o.useCallback((p,w)=>{s(C=>({...C,codexReviewers:{...C.codexReviewers,[p]:w}})),d(!0),h(!1)},[]),g=o.useCallback((p,w)=>{s(C=>({...C,specWorkflow:{...C.specWorkflow,[p]:w}})),d(!0),h(!1)},[]),v=o.useCallback(async()=>{await fetch("/api/settings",{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)}).then(p=>{if(!p.ok)throw new Error(`Save failed: ${p.status}`);return p.json()}).then(p=>{s(p),d(!1),h(!0)})},[t]);return{settings:t,isLoading:n,error:a,isDirty:c,saved:u,updateModel:l,updateExtendedContext:m,updateSkill:x,updateAgent:b,updateReviewerAgent:j,updateCodexReviewer:f,updateSpecWorkflow:g,save:v}}const Pe="__custom__";function Te({value:t,choices:s,onChange:n,disabled:r=!1,id:a}){const i=Ea(t),[c,d]=o.useState(i),[u,h]=o.useState(i?t:""),l=c||i?Pe:t,m=b=>{if(b===Pe){d(!0);return}d(!1),h(""),n(b)},x=()=>{const b=u.trim();bt(b)&&n(b)};return e.jsxs("div",{className:"flex flex-col gap-1",children:[e.jsxs("select",{id:a,className:"select select-sm select-bordered w-full max-w-xs",value:l,onChange:b=>m(b.target.value),disabled:r,children:[s.map(b=>e.jsx("option",{value:b,children:Bt[b]??b},b)),e.jsx("option",{value:Pe,children:"Custom…"})]}),(c||i)&&e.jsx("input",{type:"text",className:`input input-xs input-bordered w-full max-w-xs ${u&&!bt(u.trim())?"input-error":""}`,placeholder:"claude-opus-4-6",value:u||(i?t:""),onChange:b=>h(b.target.value),onBlur:x,onKeyDown:b=>{b.key==="Enter"&&(b.preventDefault(),x())},disabled:r,"aria-label":"Custom model ID",spellCheck:!1,autoCapitalize:"off",autoCorrect:"off"})]})}const Pa=[{key:"main",label:"Main Session",sub:"Quick mode / direct chat — used for any prompt outside a workflow command"},{key:"fix",label:"Bugfix (/fix)",sub:"Investigate, write a failing test, fix at the root cause, audit — no plan file"},{key:"prd",label:"Product Requirements (/prd)",sub:"Brainstorm a vague idea into a concrete PRD with optional deep research"},{key:"setup-rules",label:"Project Rules (/setup-rules)",sub:"Auto-generate modular Claude rules from your codebase"},{key:"create-skill",label:"Create Skill (/create-skill)",sub:"Build a new reusable skill from a topic or capture one from this session"},{key:"benchmark",label:"Benchmark (/benchmark)",sub:"Quantitative before/after evals for rules, skills, and workflows"}],Ta=[{key:"spec-plan",label:"Planning Phase",sub:"Explore codebase, design plan, ask clarifying questions, get approval"},{key:"spec-implement",label:"Implementation Phase",sub:"TDD loop for each task — RED, GREEN, REFACTOR with quality hooks on every edit"},{key:"spec-verify",label:"Verification Phase",sub:"Full suite, type checks, code review agent, structured E2E browser scenarios"}],Ia=[{key:"spec-review",label:"Spec Review",toggleKey:"specReview",description:"Validates plans before implementation. Checks alignment with requirements and flags risky assumptions. Runs in a separate context window."},{key:"changes-review",label:"Changes Review",toggleKey:"changesReview",description:"Reviews code after implementation. Checks compliance, security, test coverage, and goal achievement. Reads all changed files in a separate context window."}],Da=[{key:"codex-spec-review",label:"Codex Spec Review",toggleKey:"specReview",description:"Adversarial plan review powered by OpenAI Codex. Provides an independent second opinion on plans."},{key:"codex-changes-review",label:"Codex Changes Review",toggleKey:"changesReview",description:"Adversarial code review powered by OpenAI Codex. Provides an independent second opinion on implementations."}],_a=[{key:"worktree-support",label:"Worktree Support",toggleKey:"worktreeSupport",description:"Ask whether to isolate changes in a git worktree. When off, worktree is always skipped."},{key:"ask-questions",label:"Ask Questions",toggleKey:"askQuestionsDuringPlanning",description:"Ask clarifying questions during planning. When off, planning runs fully autonomous."},{key:"plan-approval",label:"Plan Approval",toggleKey:"planApproval",description:"Require approval before implementation starts. When off, implementation begins automatically."}];function gt({children:t}){return e.jsx("h2",{className:"text-xs font-semibold uppercase tracking-wide text-base-content/50 mb-2",children:t})}function jt({children:t}){return e.jsx("tr",{children:e.jsx("td",{colSpan:3,className:"font-medium text-xs text-base-content/50 uppercase tracking-wide pt-4 pb-1 px-0 border-b border-base-300",children:t})})}function vt({model:t}){return e.jsx("span",{className:"text-xs text-base-content/40",children:Bt[t]??t})}function La(){const{settings:t,isLoading:s,error:n,isDirty:r,updateModel:a,updateExtendedContext:i,updateSkill:c,updateAgent:d,updateReviewerAgent:u,updateCodexReviewer:h,updateSpecWorkflow:l,save:m}=Ra(),[x,b]=o.useState(null),[j,f]=o.useState(!1),[g,v]=o.useState(!1),[p,w]=o.useState(!1),[C,I]=o.useState(null),N=o.useRef(!1),_=o.useRef(!1);o.useEffect(()=>{N.current=r},[r]);const L=async()=>{f(!0),b(null);try{await m(),v(!0)}catch(y){b(y instanceof Error?y.message:"Failed to save")}finally{f(!1)}};o.useEffect(()=>{const y=A=>{N.current&&A.preventDefault()};return window.addEventListener("beforeunload",y),()=>window.removeEventListener("beforeunload",y)},[]),o.useEffect(()=>{const y=()=>{if(_.current){_.current=!1;return}if(!N.current)return;const A=(window.location.hash.replace(/^#/,"")||"/").split("?")[0];A!=="/settings"&&(_.current=!0,history.replaceState(null,"","#/settings"),window.dispatchEvent(new HashChangeEvent("hashchange")),I("#"+A),w(!0))};return window.addEventListener("hashchange",y),()=>window.removeEventListener("hashchange",y)},[]);const R=()=>{w(!1),N.current=!1,C&&(window.location.hash=C)},E=()=>{w(!1),I(null)};return s?e.jsxs("div",{className:"space-y-4",children:[e.jsx("h1",{className:"text-2xl font-bold",children:"Settings"}),e.jsx("div",{className:"card bg-base-200 animate-pulse",children:e.jsxs("div",{className:"card-body p-4",children:[e.jsx("div",{className:"h-4 bg-base-300 rounded w-32 mb-3"}),e.jsx("div",{className:"h-8 bg-base-300 rounded w-48"})]})})]}):n?e.jsxs("div",{className:"space-y-4",children:[e.jsx("h1",{className:"text-2xl font-bold",children:"Settings"}),e.jsx("div",{className:"alert alert-error",children:e.jsxs("span",{children:["Failed to load settings: ",n]})})]}):e.jsxs("div",{className:"space-y-6",children:[e.jsxs("div",{className:"flex items-start justify-between gap-4",children:[e.jsxs("div",{className:"flex items-baseline gap-3",children:[e.jsx("h1",{className:"text-2xl font-bold",children:"Settings"}),e.jsx("span",{className:"text-base-content/50 text-sm",children:"Model preferences, workflow, and automation"})]}),e.jsx("button",{className:`btn btn-primary btn-sm flex-shrink-0 ${j?"loading":""}`,onClick:L,disabled:j||!r,children:j?"Saving...":r?"Save Changes":"Saved"})]}),x&&e.jsx("div",{className:"alert alert-error py-2",children:e.jsx("span",{children:x})}),e.jsxs("section",{children:[e.jsx(gt,{children:"Model Preferences"}),e.jsx("div",{className:"card bg-base-200",children:e.jsxs("div",{className:"card-body p-4",children:[e.jsxs("table",{className:"table table-sm",children:[e.jsxs("colgroup",{children:[e.jsx("col",{className:"w-[45%]"}),e.jsx("col",{className:"w-[35%]"}),e.jsx("col",{className:"w-[20%]"})]}),e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{className:"text-xs",children:"Setting"}),e.jsx("th",{className:"text-xs",children:"Model"}),e.jsx("th",{className:"text-xs text-base-content/40",children:"Default"})]})}),e.jsxs("tbody",{children:[e.jsx(jt,{children:"General"}),Pa.map(y=>{const A=y.key==="main",$=A?t.model:t.skills[y.key]??G.skills[y.key],D=A?G.model:G.skills[y.key];return e.jsxs("tr",{children:[e.jsxs("td",{children:[e.jsx("span",{className:"text-sm",children:y.label}),y.sub&&e.jsx("div",{className:"text-xs text-base-content/40",children:y.sub})]}),e.jsx("td",{children:e.jsx(Te,{value:$,choices:he,onChange:A?a:P=>c(y.key,P),id:A?"main-model":`cmd-${y.key}`})}),e.jsx("td",{children:e.jsx(vt,{model:D})})]},y.key)}),e.jsx(jt,{children:"Spec Phases"}),Ta.map(y=>e.jsxs("tr",{children:[e.jsxs("td",{children:[e.jsx("span",{className:"text-sm",children:y.label}),y.sub&&e.jsx("div",{className:"text-xs text-base-content/40",children:y.sub})]}),e.jsx("td",{children:e.jsx(Te,{value:t.skills[y.key]??G.skills[y.key],choices:he,onChange:A=>c(y.key,A),id:`cmd-${y.key}`})}),e.jsx("td",{children:e.jsx(vt,{model:G.skills[y.key]})})]},y.key))]})]}),e.jsxs("div",{className:"grid grid-cols-1 md:grid-cols-2 gap-3 mt-3",children:[e.jsxs("div",{className:"flex items-center gap-3 px-3 py-2 rounded-lg bg-base-100/50 border border-base-300",children:[e.jsx("input",{type:"checkbox",className:"toggle toggle-sm toggle-primary flex-shrink-0",checked:t.extendedContext,onChange:y=>i(y.target.checked),id:"toggle-extended-context","aria-label":"Enable 1M extended context"}),e.jsxs("div",{className:"min-w-0",children:[e.jsx("div",{className:"text-sm font-semibold leading-tight",children:"Extended Context (1M)"}),e.jsx("div",{className:"text-xs text-base-content/50",children:"Use 1M Token Context Window. Sonnet 1M is not included in Max plan — Max users must set all models to Opus for 1M. Applies only to the Sonnet and Opus aliases; custom model IDs are sent verbatim."})]})]}),e.jsxs("div",{className:"px-3 py-2 rounded-lg bg-base-100/50 border border-base-300",children:[e.jsx("div",{className:"text-sm font-semibold leading-tight mb-1",children:"Pricing"}),e.jsxs("div",{className:"text-xs text-base-content/50 space-y-0.5",children:[e.jsx("div",{children:"Sonnet 4.6 — $3 / $15 per MTok (input / output)"}),e.jsx("div",{children:"Opus 4.7 — $5 / $25 per MTok (input / output)"})]})]})]})]})})]}),e.jsxs("section",{children:[e.jsx(gt,{children:"Spec Workflow"}),e.jsx("div",{className:"text-xs font-medium text-base-content/40 uppercase tracking-wide mb-1.5",children:"Review Agents"}),e.jsx("div",{className:"grid grid-cols-2 gap-2 mb-4",children:Ia.map(y=>{var $;const A=(($=t.reviewerAgents)==null?void 0:$[y.toggleKey])??G.reviewerAgents[y.toggleKey];return e.jsx("div",{className:`rounded-lg border px-3 py-2.5 transition-colors ${A?"border-base-300 bg-base-200":"border-base-300/50 bg-base-200/50 opacity-60"}`,children:e.jsxs("div",{className:"flex items-start gap-2.5",children:[e.jsx("input",{type:"checkbox",className:"toggle toggle-sm mt-0.5 flex-shrink-0",checked:A,onChange:D=>u(y.toggleKey,D.target.checked),id:`toggle-${y.key}`,"aria-label":`Enable ${y.label} agent`}),e.jsxs("div",{className:"min-w-0 flex-1",children:[e.jsxs("div",{className:"flex items-center justify-between gap-2",children:[e.jsx("div",{className:"text-sm font-semibold leading-tight",children:y.label}),e.jsx(Te,{value:t.agents[y.key]??G.agents[y.key],choices:he,onChange:D=>d(y.key,D),id:`agent-${y.key}`,disabled:!A})]}),e.jsx("div",{className:"text-xs text-base-content/50 mt-1",children:y.description})]})]})},y.key)})}),e.jsx("div",{className:"text-xs font-medium text-base-content/40 uppercase tracking-wide mb-1.5",children:"Codex Reviewers"}),e.jsx("div",{className:`grid grid-cols-2 gap-2 mb-4 ${t.codexAvailable?"":"opacity-50"}`,children:Da.map(y=>{var $;const A=t.codexAvailable&&((($=t.codexReviewers)==null?void 0:$[y.toggleKey])??G.codexReviewers[y.toggleKey]);return e.jsx("div",{className:`rounded-lg border px-3 py-2.5 transition-colors ${A?"border-base-300 bg-base-200":"border-base-300/50 bg-base-200/50 opacity-60"}`,children:e.jsxs("div",{className:"flex items-start gap-2.5",children:[e.jsx("input",{type:"checkbox",className:"toggle toggle-sm mt-0.5 flex-shrink-0",checked:A,onChange:D=>h(y.toggleKey,D.target.checked),disabled:!t.codexAvailable,id:`toggle-${y.key}`,"aria-label":`Enable ${y.label}`}),e.jsxs("div",{className:"min-w-0 flex-1",children:[e.jsx("div",{className:"text-sm font-semibold leading-tight",children:y.label}),e.jsx("div",{className:"text-xs text-base-content/50 mt-1",children:y.description})]})]})},y.key)})}),!t.codexAvailable&&e.jsxs("div",{className:"text-xs text-base-content/40 mb-4 pl-1",children:["Codex reviewers require the Codex plugin. Install:"," ",e.jsx("code",{className:"text-base-content/60",children:"claude plugin install @openai/codex"})," ","then run ",e.jsx("code",{className:"text-base-content/60",children:"/codex:setup"})," and restart Pilot."]}),e.jsx("div",{className:"text-xs font-medium text-base-content/40 uppercase tracking-wide mb-1.5",children:"Automation"}),e.jsx("div",{className:"grid grid-cols-3 gap-2",children:_a.map(y=>{var $;const A=(($=t.specWorkflow)==null?void 0:$[y.toggleKey])??G.specWorkflow[y.toggleKey];return e.jsxs("div",{className:"rounded-lg border border-base-300 bg-base-200 px-3 py-2.5 flex items-start gap-2.5",children:[e.jsx("input",{type:"checkbox",className:"toggle toggle-sm mt-0.5 flex-shrink-0",checked:A,onChange:D=>l(y.toggleKey,D.target.checked),id:`toggle-${y.key}`,"aria-label":y.label}),e.jsxs("div",{className:"min-w-0",children:[e.jsx("div",{className:"text-sm font-semibold leading-tight",children:y.label}),e.jsx("div",{className:"text-xs text-base-content/50 mt-0.5",children:y.description})]})]},y.key)})})]}),e.jsxs(fe,{open:g,onClose:()=>v(!1),title:"Settings Saved",actions:e.jsx("button",{className:"btn btn-primary btn-sm",onClick:()=>v(!1),children:"Got it"}),children:[e.jsx("p",{children:"Your settings have been saved successfully."}),e.jsx("p",{className:"mt-2 font-medium text-warning",children:"Please restart Claude Code for changes to take effect."})]}),e.jsx(fe,{open:p,onClose:E,title:"Unsaved Changes",actions:e.jsxs(e.Fragment,{children:[e.jsx("button",{className:"btn btn-ghost btn-sm",onClick:E,children:"Stay"}),e.jsx("button",{className:"btn btn-error btn-sm",onClick:R,children:"Leave"})]}),children:e.jsx("p",{children:"You have unsaved settings changes. Are you sure you want to leave this page?"})})]})}async function qe(t){const s=new TextEncoder().encode(t),n=new CompressionStream("deflate-raw"),r=n.writable.getWriter();r.write(s),r.close();const a=await new Response(n.readable).arrayBuffer();return new Uint8Array(a).toBase64({alphabet:"base64url",omitPadding:!0})}async function Ge(t){const s=Uint8Array.fromBase64(t,{alphabet:"base64url"}),n=new DecompressionStream("deflate-raw"),r=n.writable.getWriter();r.write(s),r.close();const a=await new Response(n.readable).arrayBuffer();return new TextDecoder().decode(a)}const Be=Object.freeze(Object.defineProperty({__proto__:null,compress:qe,decompress:Ge},Symbol.toStringTag,{value:"Module"})),Vt=32768;async function Kt(t,s){try{const n=await qe(JSON.stringify(t));return n.length>Vt?null:{url:`${s}/#/shared/${n}`}}catch{return null}}async function Aa(t){if(!t)return null;try{return JSON.parse(await Ge(t))}catch{return null}}async function $a(t,s){try{const n=await qe(JSON.stringify(t));return n.length>Vt?null:{url:`${s}/#/feedback/${n}`}}catch{return null}}async function Wt(t){if(!t)return null;try{return JSON.parse(await Ge(t))}catch{return null}}function Jt(t){return/^[A-Za-z0-9]{8}$/.test(t)}const Er=Object.freeze(Object.defineProperty({__proto__:null,generateFeedbackUrl:$a,generateShareUrl:Kt,isPasteServiceId:Jt,parseFeedbackUrl:Wt,parseShareUrl:Aa},Symbol.toStringTag,{value:"Module"}));async function Oa(t){const s=t.indexOf("#");if(s===-1)return null;const n=t.slice(s+1),[r]=n.split("?");let a=r;if(a.startsWith("/feedback/")?a=a.slice(10):a.startsWith("/shared/")&&(a=a.slice(8)),!a)return null;if(Jt(a)){const i=await fetch(`/api/share/${a}`);if(!i.ok)return null;const{data:c}=await i.json(),{decompress:d}=await V(async()=>{const{decompress:u}=await Promise.resolve().then(()=>Be);return{decompress:u}},void 0,import.meta.url);return JSON.parse(await d(c))}return Wt(a)}function Ma({isOpen:t,onClose:s,planPath:n,projectParam:r,onAnnotationsImported:a}){const{success:i,error:c}=qt(),[d,u]=o.useState(""),[h,l]=o.useState({status:"idle"}),m=o.useRef(null),x=o.useRef(null);o.useEffect(()=>{var g,v;const f=m.current;f&&(t?((g=f.showModal)==null||g.call(f),setTimeout(()=>{var p;return(p=x.current)==null?void 0:p.focus()},50)):((v=f.close)==null||v.call(f),u(""),l({status:"idle"})))},[t]);const b=async()=>{if(d.trim()){l({status:"loading"});try{const f=await Oa(d.trim());if(!f){l({status:"error",message:"Failed to decode feedback URL — check the URL is complete."});return}if("specContent"in f&&typeof f.specContent=="string"){l({status:"error",message:'This is a share URL, not a feedback URL. Feedback URLs are generated when a reviewer clicks "Send Feedback".'});return}if(f.planPath&&n&&f.planPath!==n){l({status:"error",message:`This feedback was created for a different spec (${f.planPath}). Open the correct spec first, then import.`});return}l({status:"preview",payload:f})}catch(f){l({status:"error",message:f instanceof Error?f.message:"Failed to decode feedback URL."})}}},j=async()=>{if(h.status!=="preview")return;const{payload:f}=h;try{const g=await fetch(`/api/annotations?path=${encodeURIComponent(n)}${r}`),v=g.ok?(await g.json()).planAnnotations??[]:[],w=f.annotations.map(N=>({id:N.id??crypto.randomUUID(),blockId:N.blockId??"",originalText:N.originalText??"",text:N.text??"",createdAt:N.createdAt??Date.now(),author:N.author??f.author,feedbackStatus:"pending",importedAt:Date.now()})).filter(N=>!v.some(_=>_.originalText===N.originalText&&_.text===N.text));if(w.length===0){l({status:"done",count:0,author:f.author}),i("All annotations already imported — nothing new to add.");return}const C=[...v,...w],I=await fetch(`/api/annotations/plan?path=${encodeURIComponent(n)}${r}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({annotations:C})});if(!I.ok){c("Failed to save annotations — please try again."),l({status:"error",message:`Server returned ${I.status}. Annotations were not saved.`});return}a(w),l({status:"done",count:w.length,author:f.author}),i(`Imported ${w.length} annotation${w.length!==1?"s":""} from ${f.author}`)}catch{c("Failed to import annotations.")}};return e.jsx("dialog",{ref:m,className:"modal",onClick:f=>{f.target===m.current&&s()},children:e.jsxs("div",{className:"modal-box w-full max-w-lg",children:[e.jsxs("div",{className:"flex items-center gap-2 mb-4",children:[e.jsx(S,{icon:"lucide:message-square-plus",size:18,className:"text-primary"}),e.jsx("h3",{className:"text-lg font-semibold",children:"Import Feedback"}),e.jsx("button",{className:"btn btn-ghost btn-xs ml-auto",onClick:s,"aria-label":"Close",children:e.jsx(S,{icon:"lucide:x",size:16})})]}),h.status==="done"?e.jsxs("div",{className:"text-center py-4 space-y-3",children:[e.jsx("div",{className:"bg-success/10 rounded-full w-12 h-12 flex items-center justify-center mx-auto",children:e.jsx(S,{icon:"lucide:check-circle",size:24,className:"text-success"})}),e.jsxs("p",{className:"text-sm",children:["Imported ",e.jsx("strong",{children:h.count})," annotation",h.count!==1?"s":""," from"," ",e.jsx("strong",{children:h.author}),"."]}),e.jsx("p",{className:"text-xs text-base-content/50",children:"Review them in the annotation panel — accept or reject each one."}),e.jsx("button",{className:"btn btn-primary btn-sm",onClick:s,children:"Done"})]}):e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"mb-4",children:[e.jsx("label",{className:"text-xs font-medium text-base-content/60 mb-1.5 block",children:"Paste feedback URL from colleague"}),e.jsxs("div",{className:"flex gap-2",children:[e.jsx("input",{ref:x,type:"text",value:d,onChange:f=>{u(f.target.value),l({status:"idle"})},onKeyDown:f=>{f.key==="Enter"&&b()},className:"input input-bordered input-sm flex-1 font-mono text-xs",placeholder:"Paste feedback URL (pilot-shell.com or localhost)...",disabled:h.status==="loading"}),e.jsx("button",{className:"btn btn-outline btn-sm",onClick:b,disabled:!d.trim()||h.status==="loading",children:h.status==="loading"?e.jsx("span",{className:"loading loading-spinner loading-xs"}):"Preview"})]})]}),h.status==="error"&&e.jsxs("div",{className:"alert alert-error py-2 mb-4",children:[e.jsx(S,{icon:"lucide:alert-circle",size:14}),e.jsx("span",{className:"text-xs",children:h.message})]}),h.status==="preview"&&e.jsxs("div",{className:"space-y-3",children:[e.jsx("div",{className:"card bg-base-200 border border-base-300",children:e.jsxs("div",{className:"card-body p-3 space-y-2",children:[e.jsxs("div",{className:"flex items-center gap-2 text-xs text-base-content/60",children:[e.jsx(S,{icon:"lucide:user",size:12}),e.jsxs("span",{children:["From: ",e.jsx("strong",{children:h.payload.author})]}),e.jsx("span",{children:"·"}),e.jsxs("span",{children:[h.payload.annotations.length," annotation",h.payload.annotations.length!==1?"s":""]})]}),h.payload.annotations.slice(0,3).map(f=>e.jsxs("div",{className:"flex items-start gap-2 p-2 rounded bg-base-100 border border-base-300/50 text-xs",children:[f.originalText&&e.jsxs("span",{className:"text-base-content/40 italic flex-shrink-0 max-w-[120px] truncate",children:["“",f.originalText,"”"]}),e.jsx("span",{className:"text-base-content/70",children:f.text.slice(0,60)})]},f.id)),h.payload.annotations.length>3&&e.jsxs("p",{className:"text-xs text-base-content/40 text-center",children:["+",h.payload.annotations.length-3," more…"]})]})}),e.jsxs("button",{className:"btn btn-primary btn-sm w-full gap-2",onClick:j,children:[e.jsx(S,{icon:"lucide:download",size:14}),"Import ",h.payload.annotations.length," Annotation",h.payload.annotations.length!==1?"s":""]})]})]})]})})}const za="https://pilot-shell.com/shared",Fa=32768;function Ie(t){return t<1024?`${t} B`:`${(t/1024).toFixed(1)} KB`}function Ua(){const[t,s]=o.useState(""),[n,r]=o.useState(""),[a,i]=o.useState(!1),[c,d]=o.useState(!1),[u,h]=o.useState(null),[l,m]=o.useState("local"),x=o.useRef(0),b=o.useCallback(v=>{m(v),s(""),r(""),h(null)},[]),j=o.useCallback(async(v,p,w,C,I)=>{const N=++x.current;d(!0),h(null),s(""),r(""),i(!1);try{if(typeof CompressionStream>"u"){h("Your browser does not support the required compression API. Please upgrade to Chrome 80+, Firefox 113+, or Safari 16.4+."),d(!1);return}let _=p;if(_.length===0&&C)try{const R=await fetch(`/api/annotations?path=${encodeURIComponent(C)}`);if(R.ok){const E=await R.json();Array.isArray(E.planAnnotations)&&(_=E.planAnnotations)}}catch{}const L={specContent:v,annotations:_.filter(R=>R.feedbackStatus!=="rejected").map(R=>({id:R.id,blockId:R.blockId,originalText:R.originalText,text:R.text,createdAt:R.createdAt})),author:w??await qa(),planPath:C,...I&&I!=="specification"?{contentType:I}:{},createdAt:Date.now()};if(N!==x.current)return;if(l==="web"){const{compress:R}=await V(async()=>{const{compress:A}=await Promise.resolve().then(()=>Be);return{compress:A}},void 0,import.meta.url),E=await R(JSON.stringify(L));if(N!==x.current)return;if(E.length>Fa){h('This spec is too large for web sharing (exceeds 32 KB compressed). Switch to "Recipient has Pilot Shell" to use a local link instead.');return}const y=`${za}#${E}`;s(y),r(Ie(new Blob([y]).size)),i(!1)}else{const R=`${window.location.protocol}//${window.location.host}`,E=await Kt(L,R);if(N!==x.current)return;if(E)s(E.url),r(Ie(new Blob([E.url]).size)),i(!1);else{const y=await Ga(L,R);if(N!==x.current)return;y?(s(y.url),r(Ie(new Blob([y.url]).size)),i(!0)):h("Failed to generate share URL. The spec may be too large.")}}}catch(_){if(N!==x.current)return;h(_ instanceof Error?_.message:"Failed to generate share URL")}finally{N===x.current&&d(!1)}},[l]),f=o.useCallback(async()=>{if(!t||!navigator.clipboard)return!1;try{return await navigator.clipboard.writeText(t),!0}catch{return!1}},[t]),g=o.useCallback(()=>{s(""),r(""),i(!1),h(null)},[]);return{shareUrl:t,urlSize:n,isPasteServiceUsed:a,isGenerating:c,error:u,target:l,setTarget:b,generate:j,copyToClipboard:f,clear:g}}async function qa(){try{const t=await fetch("/api/license");if(t.ok){const s=await t.json();if(s.email)return s.email}}catch{}return"Anonymous"}async function Ga(t,s){try{const{compress:n}=await V(async()=>{const{compress:d}=await Promise.resolve().then(()=>Be);return{compress:d}},void 0,import.meta.url),r=await n(JSON.stringify(t)),a=await fetch("/api/share",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({data:r})});if(!a.ok)return null;const{id:i}=await a.json();return{url:`${s}/#/shared/${i}`}}catch{return null}}function Ba({isOpen:t,onClose:s,specContent:n,annotations:r,planPath:a,contentType:i="specification",onCopied:c}){const{success:d,error:u}=qt(),{shareUrl:h,urlSize:l,isPasteServiceUsed:m,isGenerating:x,error:b,target:j,setTarget:f,generate:g,copyToClipboard:v,clear:p}=Ua(),w=o.useRef(null),C=o.useRef(null);o.useEffect(()=>{t&&g(n,r,void 0,a,i),t||p()},[t,j]),o.useEffect(()=>{var R,E;const L=w.current;L&&(t?(R=L.showModal)==null||R.call(L):(E=L.close)==null||E.call(L))},[t]);const I=async()=>{await v()?(d("Share link copied — now paste your colleague's feedback URL"),c?c():s()):u("Failed to copy to clipboard")},N=L=>{L!==j&&f(L)},_=L=>{L.key==="Escape"&&s()};return e.jsx("dialog",{ref:w,className:"modal",onKeyDown:_,onClick:L=>{L.target===w.current&&s()},children:e.jsxs("div",{className:"modal-box w-full max-w-lg",children:[e.jsxs("div",{className:"flex items-center gap-2 mb-4",children:[e.jsx(S,{icon:"lucide:share-2",size:18,className:"text-primary"}),e.jsxs("h3",{className:"text-lg font-semibold",children:["Share ",i==="requirement"?"Requirement":"Specification"]}),e.jsx("button",{className:"btn btn-ghost btn-xs ml-auto",onClick:s,"aria-label":"Close",children:e.jsx(S,{icon:"lucide:x",size:16})})]}),e.jsxs("div",{className:"mb-4",children:[e.jsx("label",{className:"text-xs font-medium text-base-content/60 mb-1.5 block",children:"Recipient"}),e.jsxs("div",{className:"flex rounded-lg border border-base-300 overflow-hidden text-xs",children:[e.jsxs("button",{className:`flex-1 flex items-center justify-center gap-1.5 px-3 py-2 transition-colors ${j==="local"?"bg-base-300 text-base-content font-medium":"text-base-content/50 hover:text-base-content/80"}`,onClick:()=>N("local"),children:[e.jsx(S,{icon:"lucide:monitor",size:13}),"Has Pilot Shell"]}),e.jsxs("button",{className:`flex-1 flex items-center justify-center gap-1.5 px-3 py-2 transition-colors ${j==="web"?"bg-base-300 text-base-content font-medium":"text-base-content/50 hover:text-base-content/80"}`,onClick:()=>N("web"),children:[e.jsx(S,{icon:"lucide:globe",size:13}),"Share via pilot-shell.com"]})]})]}),x&&e.jsxs("div",{className:"flex items-center gap-3 py-6 justify-center",children:[e.jsx("span",{className:"loading loading-spinner loading-sm text-primary"}),e.jsx("span",{className:"text-sm text-base-content/60",children:"Generating…"})]}),!x&&b&&e.jsxs("div",{className:"alert alert-error mb-4",children:[e.jsx(S,{icon:"lucide:alert-circle",size:16}),e.jsx("span",{className:"text-sm",children:b})]}),!x&&h&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"mb-4",children:[e.jsx("label",{className:"text-xs font-medium text-base-content/60 mb-1.5 block",children:"Share link"}),e.jsxs("div",{className:"flex gap-2",children:[e.jsx("input",{ref:C,type:"text",readOnly:!0,value:h,className:"input input-bordered input-sm flex-1 font-mono text-xs",onClick:()=>{var L;return(L=C.current)==null?void 0:L.select()}}),e.jsxs("button",{className:"btn btn-primary btn-sm gap-1",onClick:I,children:[e.jsx(S,{icon:"lucide:copy",size:14}),"Copy"]})]})]}),e.jsxs("div",{className:"flex items-center gap-3 text-xs text-base-content/50 mb-4 flex-wrap",children:[e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(S,{icon:"lucide:minimize-2",size:12,className:"text-success"}),e.jsx("span",{children:"Compressed"})]}),e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(S,{icon:"lucide:database",size:12}),e.jsx("span",{children:l})]}),m&&e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(S,{icon:"lucide:cloud",size:12,className:"text-info"}),e.jsx("span",{children:"Stored locally · 3 day expiry"})]})]}),j==="web"?e.jsxs("div",{className:"alert alert-info py-2 px-3",children:[e.jsx(S,{icon:"lucide:info",size:14}),e.jsx("span",{className:"text-xs",children:"Zero data sent to pilot-shell.com — the spec is embedded in the URL fragment, which is never transmitted to any server."})]}):e.jsxs("div",{className:"alert alert-info py-2 px-3",children:[e.jsx(S,{icon:"lucide:info",size:14}),e.jsx("span",{className:"text-xs",children:"Recipient must have Pilot Console running to open this link."})]})]})]})})}function Ha({content:t}){return e.jsx("div",{className:"spec-markdown",children:e.jsx(Yt,{remarkPlugins:[Xt],components:{h3:({children:s})=>{const r=String(s??"").match(/Task\s+(\d+)/),a=r?`task-${r[1]}`:void 0;return e.jsx("h3",{id:a,className:"text-lg font-semibold mt-6 mb-3 pb-2 border-b border-base-300/50 first:mt-0 scroll-mt-4",children:s})},h4:({children:s})=>e.jsx("h4",{className:"text-base font-medium mt-4 mb-2 text-base-content/90",children:s}),p:({children:s})=>e.jsx("p",{className:"text-sm text-base-content/80 mb-3 leading-relaxed",children:s}),ul:({children:s})=>e.jsx("ul",{className:"text-sm space-y-1.5 mb-4 ml-1",children:s}),ol:({children:s})=>e.jsx("ol",{className:"text-sm space-y-1.5 mb-4 ml-1 list-decimal list-inside",children:s}),li:({children:s})=>e.jsxs("li",{className:"text-base-content/80 flex items-start gap-2",children:[e.jsx("span",{className:"text-primary mt-0.5 text-xs select-none",children:"▸"}),e.jsx("span",{className:"flex-1",children:s})]}),code:({className:s,children:n})=>s?e.jsx("code",{className:"block bg-base-300 p-3 rounded-lg text-xs font-mono overflow-x-auto mb-4 border border-base-content/10",children:n}):e.jsx("code",{className:"bg-base-300 text-primary px-1.5 py-0.5 rounded text-xs font-mono",children:n}),pre:({children:s})=>e.jsx("pre",{className:"bg-base-300 p-3 rounded-lg text-xs font-mono overflow-x-auto mb-4 border border-base-content/10",children:s}),strong:({children:s})=>e.jsx("strong",{className:"font-semibold text-base-content",children:s}),table:({children:s})=>e.jsx("div",{className:"overflow-x-auto mb-4",children:e.jsx("table",{className:"table table-sm w-full",children:s})}),thead:({children:s})=>e.jsx("thead",{className:"bg-base-200",children:s}),th:({children:s})=>e.jsx("th",{className:"text-left text-xs font-medium text-base-content/70 p-2",children:s}),td:({children:s})=>e.jsx("td",{className:"text-sm p-2 border-t border-base-300/50",children:s}),blockquote:({children:s})=>e.jsx("blockquote",{className:"border-l-4 border-primary/50 pl-4 py-1 my-3 text-sm text-base-content/70 italic",children:s}),hr:()=>e.jsx("hr",{className:"my-6 border-base-300"})},children:t})})}const Va={Summary:"lucide:text",Scope:"lucide:target","Autonomous Decisions":"lucide:brain","Context for Implementer":"lucide:book-open","Runtime Environment":"lucide:terminal",Assumptions:"lucide:lightbulb","Risks and Mitigations":"lucide:alert-triangle","Goal Verification":"lucide:check-square","E2E Test Scenarios":"lucide:monitor-check","E2E Results":"lucide:clipboard-check","Verification Scenario":"lucide:mouse-pointer-click","Open Questions":"lucide:help-circle","Deferred Ideas":"lucide:bookmark","Problem Statement":"lucide:crosshair","Core User Flows":"lucide:route","Technical Context":"lucide:cpu","Key Decisions":"lucide:scale"};function Ka({heading:t,content:s,defaultOpen:n=!1}){const[r,a]=o.useState(n),i=Va[t]||"lucide:file-text";return e.jsx(B,{children:e.jsxs(H,{className:"p-0",children:[e.jsxs("button",{className:"w-full flex items-center gap-2.5 p-4 text-left cursor-pointer hover:bg-base-200/50 transition-colors",onClick:()=>a(!r),children:[e.jsx(S,{icon:i,size:16,className:"text-primary flex-shrink-0"}),e.jsx("span",{className:"text-sm font-semibold flex-1",children:t}),e.jsx(S,{icon:"lucide:chevron-down",size:14,className:`text-base-content/40 transition-transform duration-200 ${r?"rotate-180":""}`})]}),r&&e.jsx("div",{className:"px-4 pb-4 pt-0 border-t border-base-300/50",children:e.jsx("div",{className:"pt-3",children:e.jsx(Ha,{content:s})})})]})})}const Wa={SPEC_REFRESH_INTERVAL_MS:5e3,GIT_REFRESH_INTERVAL_MS:1e4},Ja=o.lazy(()=>V(()=>import("./PlanAnnotator.js").then(t=>t.P),__vite__mapDeps([0,1,2,3]),import.meta.url).then(t=>({default:t.PlanAnnotator}))),Qa=["Problem Statement","Core User Flows","Scope","Technical Context","Key Decisions","Research Findings"],Ya={Feature:"info",Infrastructure:"warning",UX:"info",API:"info",Performance:"success",Security:"warning",Documentation:"info",Integration:"info"};function Xa(t){const s=t.match(/^#\s+(.+)$/m),n=s?s[1]:"Untitled PRD",r={},a=t.match(/^Author:\s*(.+)$/m);a&&(r.author=a[1].trim());const i=t.match(/^Category:\s*(.+)$/m);i&&(r.category=i[1].trim());const c=t.match(/^Status:\s*(.+)$/m);c&&(r.status=c[1].trim());const d=t.match(/^Research:\s*(.+)$/m);d&&(r.research=d[1].trim());const u=t.match(/^Created:\s*(.+)$/m);u&&(r.createdAt=u[1].trim());const h=[],l=/^## (.+)$/gm,m=[];let x;for(;(x=l.exec(t))!==null;)m.push({heading:x[1],index:x.index,contentStart:x.index+x[0].length});for(let b=0;b{if(!s.path)return;const T=decodeURIComponent(s.path);i(O=>O===T?O:T)},[s.path]);const[c,d]=o.useState(null),[u,h]=o.useState(!0),[l,m]=o.useState(!1),[x,b]=o.useState(null),[j,f]=o.useState("view"),[g,v]=o.useState(!1),[p,w]=o.useState(!1),[C,I]=o.useState(0),[N,_]=o.useState(!1),L=t?`?project=${encodeURIComponent(t)}`:"",R=o.useRef(t);R.current!==t&&(R.current=t,i(null),d(null),b(null),h(!0));const E=o.useCallback(async()=>{var T;try{const z=await(await fetch(`/api/prd${L}`)).json();r(z.prds||[]),((T=z.prds)==null?void 0:T.length)>0&&!a&&i(z.prds[0].filePath)}catch(O){b("Failed to load PRDs"),console.error("Failed to load PRDs:",O)}finally{h(!1)}},[a,L]),y=o.useCallback(async(T,O=!1)=>{O||m(!0),b(null);try{const z=await fetch(`/api/prd/content?path=${encodeURIComponent(T)}${t?`&project=${encodeURIComponent(t)}`:""}`);if(!z.ok)throw new Error("Failed to load PRD content");d(await z.json())}catch(z){b("Failed to load PRD content"),console.error("Failed to load PRD content:",z)}finally{O||m(!1)}},[t]),A=o.useCallback(async T=>{if(confirm(`Delete "${T.split("/").pop()}"? This cannot be undone.`)){_(!0);try{if(!(await fetch(`/api/prd?path=${encodeURIComponent(T)}${t?`&project=${encodeURIComponent(t)}`:""}`,{method:"DELETE"})).ok)throw new Error("Failed to delete PRD");i(null),d(null),await E()}catch(O){b("Failed to delete PRD"),console.error("Failed to delete PRD:",O)}finally{_(!1)}}},[E,t]);if(o.useEffect(()=>{E();const T=setInterval(()=>{E(),a&&y(a,!0)},Wa.SPEC_REFRESH_INTERVAL_MS);return()=>clearInterval(T)},[E,y,a]),o.useEffect(()=>{a&&y(a)},[a,y]),u)return e.jsx(te,{});if(n.length===0)return e.jsxs("div",{className:"space-y-6",children:[e.jsxs("div",{className:"flex items-center gap-3 flex-wrap",children:[e.jsx("h1",{className:"text-2xl font-bold",children:"Requirements"}),e.jsx(we,{})," "]}),e.jsx(B,{children:e.jsx(H,{children:e.jsxs("div",{className:"flex flex-col items-center justify-center py-12 text-center",children:[e.jsx(S,{icon:"lucide:lightbulb",size:48,className:"text-base-content/40 mb-4"}),e.jsx("h3",{className:"text-lg font-medium mb-2",children:"No Requirements"}),e.jsxs("p",{className:"text-base-content/60 max-w-md",children:["Use"," ",e.jsx("code",{className:"text-primary bg-base-300 px-1 rounded",children:"/prd"})," ","in Pilot Shell to brainstorm vague ideas into Product Requirements Documents through back-and-forth conversation, with optional research."]})]})})})]});const $=n.find(T=>T.filePath===a),D=n.filter(T=>T.filePath!==a),P=c?Xa(c.content):null;return e.jsxs("div",{className:"space-y-6",children:[e.jsxs("div",{className:"flex items-center gap-3 flex-wrap",children:[e.jsx("h1",{className:"text-2xl font-bold",children:"Requirements"}),e.jsx(we,{}),a&&c&&e.jsxs("div",{className:"flex items-center rounded-lg border border-base-300 overflow-hidden text-xs",children:[e.jsxs("button",{className:`px-2.5 py-1.5 flex items-center gap-1.5 transition-colors ${j==="view"?"bg-primary text-primary-content":"hover:bg-base-200"}`,onClick:()=>f("view"),title:"View PRD",children:[e.jsx(S,{icon:"lucide:eye",size:13}),"View"]}),e.jsxs("button",{className:`px-2.5 py-1.5 flex items-center gap-1.5 transition-colors ${j==="annotate"?"bg-primary text-primary-content":"hover:bg-base-200"}`,onClick:()=>f("annotate"),title:"Review PRD",children:[e.jsx(S,{icon:"lucide:pencil",size:13}),"Review"]})]}),$&&e.jsx("div",{role:"tablist",className:"flex items-center gap-1.5 min-w-0 overflow-hidden",children:e.jsxs("button",{role:"tab","aria-selected":!0,className:"px-2.5 py-1.5 rounded-lg text-xs font-medium border transition-colors cursor-pointer flex items-center gap-1.5 truncate bg-primary/10 border-primary/30 text-primary",children:[e.jsx(S,{icon:"lucide:lightbulb",size:12,className:"text-warning flex-shrink-0"}),e.jsx("span",{className:"truncate max-w-40",children:$.name}),e.jsx("span",{className:"text-[10px] opacity-60 flex-shrink-0",children:Za($.modifiedAt)})]})}),e.jsx("span",{className:"flex-1"}),D.length>0&&e.jsxs("select",{className:"select select-bordered select-xs text-xs max-w-48",value:"",onChange:T=>i(T.target.value),children:[e.jsxs("option",{value:"",disabled:!0,children:["Previous (",D.length,")"]}),D.map(T=>e.jsx("option",{value:T.filePath,children:T.name},T.filePath))]}),a&&e.jsx(Y,{text:"Delete PRD",position:"bottom",children:e.jsx(W,{variant:"ghost",size:"sm",onClick:()=>A(a),disabled:N,children:e.jsx(S,{icon:"lucide:trash-2",size:16,className:"text-error"})})})]}),l?e.jsx(te,{}):x?e.jsx(B,{children:e.jsx(H,{children:e.jsxs("div",{className:"flex flex-col items-center justify-center py-12 text-center",children:[e.jsx(S,{icon:"lucide:alert-circle",size:48,className:"text-error mb-4"}),e.jsx("p",{className:"text-error",children:x})]})})}):P&&c?e.jsxs(e.Fragment,{children:[j==="annotate"&&e.jsx(o.Suspense,{fallback:e.jsx(te,{}),children:e.jsxs("div",{className:"rounded-xl border border-base-300 bg-base-100",style:{height:"calc(100vh - 180px)",minHeight:500,display:"flex",flexDirection:"column"},children:[e.jsxs("div",{className:"flex items-center gap-2 px-4 py-2 border-b border-base-300 bg-base-200/40 flex-shrink-0 text-xs text-base-content/60",children:[e.jsx(S,{icon:"lucide:pencil-line",size:13,className:"text-primary"}),e.jsx("span",{children:"Hover over a block and click the + button to add annotations. Review them in the sidebar."})]}),e.jsx("div",{style:{flex:1,minHeight:0,display:"flex"},children:e.jsx(Ja,{planContent:c.content,planPath:c.filePath,projectParam:t?`&project=${encodeURIComponent(t)}`:"",onShare:()=>w(!0),onReceiveFeedback:()=>v(!0),reloadKey:C})})]})}),j!=="annotate"&&e.jsxs(e.Fragment,{children:[e.jsx(B,{children:e.jsxs(H,{className:"p-6",children:[e.jsxs("div",{className:"flex items-start gap-3",children:[e.jsx("div",{className:"w-10 h-10 bg-warning/20 rounded-xl flex items-center justify-center flex-shrink-0",children:e.jsx(S,{icon:"lucide:lightbulb",size:20,className:"text-warning"})}),e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("h2",{className:"text-xl font-bold",children:P.title}),e.jsxs("p",{className:"text-xs text-base-content/50 mt-1",children:[P.sections.length," sections"]})]})]}),e.jsxs("div",{className:"flex items-center gap-4 mt-4 pt-4 border-t border-base-300/50 text-xs text-base-content/50 flex-wrap",children:[P.metadata.category&&e.jsx(q,{variant:Ya[P.metadata.category]??"info",size:"xs",children:P.metadata.category}),P.metadata.status&&e.jsx(q,{variant:P.metadata.status==="Final"?"success":"warning",size:"xs",children:P.metadata.status}),P.metadata.author&&e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(S,{icon:"lucide:user",size:12}),e.jsx("span",{children:P.metadata.author})]}),P.metadata.createdAt&&e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(S,{icon:"lucide:calendar",size:12}),e.jsx("span",{children:P.metadata.createdAt})]}),P.metadata.research&&P.metadata.research!=="None"&&e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(S,{icon:"lucide:search",size:12}),e.jsxs("span",{children:[P.metadata.research," research"]})]}),c&&e.jsxs("div",{className:"flex items-center gap-1 ml-auto",children:[e.jsxs("button",{className:"btn btn-ghost btn-xs gap-1",onClick:()=>w(!0),title:"Share PRD with a teammate",children:[e.jsx(S,{icon:"lucide:send",size:12}),e.jsx("span",{children:"Share with Teammate"})]}),e.jsxs("button",{className:"btn btn-ghost btn-xs gap-1",onClick:()=>v(!0),title:"Receive feedback from a colleague",children:[e.jsx(S,{icon:"lucide:inbox",size:12}),e.jsx("span",{children:"Receive Feedback"})]})]})]})]})}),P.sections.length>0&&e.jsx("div",{className:"space-y-2",children:P.sections.map(T=>e.jsx(Ka,{heading:T.heading,content:T.content,defaultOpen:T.heading==="Problem Statement"||T.heading==="Scope"},T.heading))})]})]}):null,c&&g&&e.jsx(Ma,{isOpen:g,onClose:()=>v(!1),planPath:c.filePath,projectParam:t?`&project=${encodeURIComponent(t)}`:"",onAnnotationsImported:()=>{v(!1),f("annotate"),I(T=>T+1)}}),c&&p&&e.jsx(Ba,{isOpen:p,onClose:()=>w(!1),specContent:c.content,annotations:[],planPath:c.filePath,contentType:"requirement",onCopied:()=>{w(!1),setTimeout(()=>v(!0),300)}})]})}const de=[{key:"DEBUG",label:"Debug",icon:"🔍",color:"text-base-content/50"},{key:"INFO",label:"Info",icon:"ℹ️",color:"text-info"},{key:"WARN",label:"Warn",icon:"⚠️",color:"text-warning"},{key:"ERROR",label:"Error",icon:"❌",color:"text-error"}],ue=[{key:"HOOK",label:"Hook",icon:"🪝",color:"text-purple-500"},{key:"WORKER",label:"Worker",icon:"⚙️",color:"text-info"},{key:"SDK",label:"SDK",icon:"📦",color:"text-success"},{key:"PARSER",label:"Parser",icon:"📄",color:"text-sky-500"},{key:"DB",label:"DB",icon:"🗄️",color:"text-orange-500"},{key:"SYSTEM",label:"System",icon:"💻",color:"text-base-content/50"},{key:"HTTP",label:"HTTP",icon:"🌐",color:"text-cyan-500"},{key:"SESSION",label:"Session",icon:"📋",color:"text-pink-500"},{key:"CHROMA",label:"Chroma",icon:"🔮",color:"text-violet-500"}];function tr(t){const s=/^\[([^\]]+)\]\s+\[(\w+)\s*\]\s+\[(\w+)\s*\]\s+(?:\[([^\]]+)\]\s+)?(.*)$/,n=t.match(s);if(!n)return{raw:t};const[,r,a,i,c,d]=n;let u;return d.startsWith("→")?u="dataIn":d.startsWith("←")?u="dataOut":d.startsWith("✓")?u="success":d.startsWith("✗")?u="failure":d.startsWith("⏱")?u="timing":d.includes("[HAPPY-PATH]")&&(u="happyPath"),{raw:t,timestamp:r,level:a==null?void 0:a.trim(),component:i==null?void 0:i.trim(),correlationId:c||void 0,message:d,isSpecial:u}}function sr({isOpen:t,onClose:s}){const[n,r]=o.useState(""),[a,i]=o.useState(!1),[c,d]=o.useState(null),[u,h]=o.useState(!1),[l,m]=o.useState(350),[x,b]=o.useState(!1),j=o.useRef(0),f=o.useRef(0),g=o.useRef(null),v=o.useRef(!0),[p,w]=o.useState(new Set(["DEBUG","INFO","WARN","ERROR"])),[C,I]=o.useState(new Set(["HOOK","WORKER","SDK","PARSER","DB","SYSTEM","HTTP","SESSION","CHROMA"])),[N,_]=o.useState(!1),L=o.useMemo(()=>n?n.split(`
+`).map(tr):[],[n]),R=o.useMemo(()=>L.filter(k=>N?k.raw.includes("[ALIGNMENT]"):!k.level||!k.component?!0:p.has(k.level)&&C.has(k.component)),[L,p,C,N]),E=o.useCallback(()=>{if(!g.current)return!0;const{scrollTop:k,scrollHeight:M,clientHeight:F}=g.current;return M-k-F<50},[]),y=o.useCallback(()=>{g.current&&v.current&&(g.current.scrollTop=g.current.scrollHeight)},[]),A=o.useCallback(async()=>{v.current=E(),i(!0),d(null);try{const k=await fetch("/api/logs");if(!k.ok)throw new Error(`Failed to fetch logs: ${k.statusText}`);const M=await k.json();r(M.logs||"")}catch(k){d(k instanceof Error?k.message:"Unknown error")}finally{i(!1)}},[E]);o.useEffect(()=>{y()},[n,y]);const $=o.useCallback(async()=>{if(confirm("Are you sure you want to clear all logs?")){i(!0),d(null);try{const k=await fetch("/api/logs/clear",{method:"POST"});if(!k.ok)throw new Error(`Failed to clear logs: ${k.statusText}`);r("")}catch(k){d(k instanceof Error?k.message:"Unknown error")}finally{i(!1)}}},[]),D=o.useCallback(k=>{k.preventDefault(),b(!0),j.current=k.clientY,f.current=l},[l]);o.useEffect(()=>{if(!x)return;const k=F=>{const Q=j.current-F.clientY,Z=Math.min(Math.max(150,f.current+Q),window.innerHeight-100);m(Z)},M=()=>{b(!1)};return document.addEventListener("mousemove",k),document.addEventListener("mouseup",M),()=>{document.removeEventListener("mousemove",k),document.removeEventListener("mouseup",M)}},[x]),o.useEffect(()=>{t&&(v.current=!0,A())},[t,A]),o.useEffect(()=>{if(!t||!u)return;const k=setInterval(A,2e3);return()=>clearInterval(k)},[t,u,A]);const P=o.useCallback(k=>{w(M=>{const F=new Set(M);return F.has(k)?F.delete(k):F.add(k),F})},[]),T=o.useCallback(k=>{I(M=>{const F=new Set(M);return F.has(k)?F.delete(k):F.add(k),F})},[]),O=o.useCallback(k=>{w(k?new Set(["DEBUG","INFO","WARN","ERROR"]):new Set)},[]),z=o.useCallback(k=>{I(k?new Set(["HOOK","WORKER","SDK","PARSER","DB","SYSTEM","HTTP","SESSION","CHROMA"]):new Set)},[]);if(!t)return null;const K=k=>{const M=de.find(F=>F.key===k);return(M==null?void 0:M.color)||"text-base-content"},J=k=>{const M=ue.find(F=>F.key===k);return(M==null?void 0:M.color)||"text-base-content"},ne=k=>k.level==="ERROR"?"bg-error/10":k.level==="WARN"?"bg-warning/5":"",U=(k,M)=>{var Z,ie;if(!k.timestamp)return e.jsx("div",{className:"whitespace-pre-wrap break-all text-base-content/60",children:k.raw},M);const F=de.find(ae=>ae.key===k.level),Q=ue.find(ae=>ae.key===k.component);return e.jsxs("div",{className:`whitespace-pre-wrap break-all py-0.5 px-1 rounded ${ne(k)}`,children:[e.jsxs("span",{className:"text-base-content/40",children:["[",k.timestamp,"]"]})," ",e.jsxs("span",{className:`font-medium ${K(k.level)}`,title:k.level,children:["[",(F==null?void 0:F.icon)||""," ",(Z=k.level)==null?void 0:Z.padEnd(5),"]"]})," ",e.jsxs("span",{className:`font-medium ${J(k.component)}`,title:k.component,children:["[",(Q==null?void 0:Q.icon)||""," ",(ie=k.component)==null?void 0:ie.padEnd(7),"]"]})," ",k.correlationId&&e.jsxs(e.Fragment,{children:[e.jsxs("span",{className:"text-base-content/50",children:["[",k.correlationId,"]"]})," "]}),e.jsx("span",{className:k.isSpecial==="success"?"text-success":k.isSpecial==="failure"?"text-error":"text-base-content",children:k.message})]},M)};return e.jsxs("div",{className:"fixed bottom-0 left-0 right-0 bg-base-100 border-t border-base-300 flex flex-col z-50 shadow-2xl",style:{height:`${l}px`},children:[e.jsx("div",{className:"h-1.5 cursor-ns-resize flex items-center justify-center bg-base-200 hover:bg-base-300 transition-colors",onMouseDown:D,children:e.jsx("div",{className:"w-12 h-1 bg-base-300 rounded-full"})}),e.jsxs("div",{className:"flex justify-between items-center px-3 h-9 bg-base-200 border-b border-base-300",children:[e.jsx("div",{className:"flex gap-1",children:e.jsx("div",{className:"px-3 py-1 text-xs font-medium bg-base-100 text-base-content rounded",children:"Console"})}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsxs("label",{className:"flex items-center gap-1.5 text-xs text-base-content/60 cursor-pointer",children:[e.jsx("input",{type:"checkbox",className:"checkbox checkbox-xs",checked:u,onChange:k=>h(k.target.checked)}),"Auto-refresh"]}),e.jsx("button",{className:"btn btn-ghost btn-xs btn-square",onClick:A,disabled:a,title:"Refresh logs",children:e.jsx(S,{icon:"lucide:refresh-cw",size:14,className:a?"animate-spin":""})}),e.jsx("button",{className:"btn btn-ghost btn-xs btn-square",onClick:()=>{v.current=!0,y()},title:"Scroll to bottom",children:e.jsx(S,{icon:"lucide:arrow-down",size:14})}),e.jsx("button",{className:"btn btn-ghost btn-xs btn-square hover:text-error",onClick:$,disabled:a,title:"Clear logs",children:e.jsx(S,{icon:"lucide:trash-2",size:14})}),e.jsx("button",{className:"btn btn-ghost btn-xs btn-square",onClick:s,title:"Close console",children:e.jsx(S,{icon:"lucide:x",size:14})})]})]}),e.jsxs("div",{className:"flex flex-wrap gap-3 px-3 py-2 bg-base-200/50 border-b border-base-300 text-xs",children:[e.jsxs("div",{className:"flex items-center gap-1.5",children:[e.jsx("span",{className:"font-medium text-base-content/50 uppercase text-[10px]",children:"Quick:"}),e.jsx("button",{className:`badge badge-sm cursor-pointer ${N?"badge-warning":"badge-ghost opacity-50"}`,onClick:()=>_(!N),title:"Show only session alignment logs",children:"🔗 Alignment"})]}),e.jsxs("div",{className:"flex items-center gap-1.5",children:[e.jsx("span",{className:"font-medium text-base-content/50 uppercase text-[10px]",children:"Levels:"}),e.jsxs("div",{className:"flex flex-wrap gap-1",children:[de.map(k=>e.jsxs("button",{className:`badge badge-sm cursor-pointer ${p.has(k.key)?"badge-primary":"badge-ghost opacity-40"}`,onClick:()=>P(k.key),title:k.label,children:[k.icon," ",k.label]},k.key)),e.jsx("button",{className:"badge badge-sm badge-ghost cursor-pointer",onClick:()=>O(p.size===0),title:p.size===de.length?"Select none":"Select all",children:p.size===de.length?"○":"●"})]})]}),e.jsxs("div",{className:"flex items-center gap-1.5",children:[e.jsx("span",{className:"font-medium text-base-content/50 uppercase text-[10px]",children:"Components:"}),e.jsxs("div",{className:"flex flex-wrap gap-1",children:[ue.map(k=>e.jsxs("button",{className:`badge badge-sm cursor-pointer ${C.has(k.key)?"badge-secondary":"badge-ghost opacity-40"}`,onClick:()=>T(k.key),title:k.label,children:[k.icon," ",k.label]},k.key)),e.jsx("button",{className:"badge badge-sm badge-ghost cursor-pointer",onClick:()=>z(C.size===0),title:C.size===ue.length?"Select none":"Select all",children:C.size===ue.length?"○":"●"})]})]})]}),c&&e.jsxs("div",{className:"px-3 py-2 bg-error/10 text-error text-xs",children:["⚠ ",c]}),e.jsx("div",{className:"flex-1 overflow-y-auto px-3 py-2",ref:g,children:e.jsx("div",{className:"font-mono text-xs leading-relaxed",children:R.length===0?e.jsx("div",{className:"text-base-content/40 italic",children:"No logs available"}):R.map((k,M)=>U(k,M))})})]})}const Oe={COMMAND_PALETTE:{key:"k",modifiers:["ctrl","meta"],description:"Open command palette",action:"openCommandPalette"},SEARCH:{key:"/",modifiers:["ctrl","meta"],description:"Focus search",action:"focusSearch"},ESCAPE:{key:"Escape",description:"Close modal/palette",action:"escape"},TOGGLE_THEME:{key:"t",modifiers:["ctrl","meta"],description:"Toggle theme",action:"toggleTheme"},TOGGLE_SIDEBAR:{key:"b",modifiers:["ctrl","meta"],description:"Toggle sidebar",action:"toggleSidebar"}},nr=[{sequence:["g","d"],description:"Go to Dashboard",action:"navigate:/"},{sequence:["g","c"],description:"Go to Changes",action:"navigate:/changes"},{sequence:["g","m"],description:"Go to Memories",action:"navigate:/memories"},{sequence:["g","v"],description:"Go to Extensions",action:"navigate:/extensions"},{sequence:["g","h"],description:"Go to Help",action:"navigate:/help"}];function yt(t){var r,a,i,c;const s=typeof navigator<"u"&&navigator.platform.includes("Mac"),n=[];return((r=t.modifiers)!=null&&r.includes("ctrl")||(a=t.modifiers)!=null&&a.includes("meta"))&&n.push(s?"⌘":"Ctrl"),(i=t.modifiers)!=null&&i.includes("shift")&&n.push(s?"⇧":"Shift"),(c=t.modifiers)!=null&&c.includes("alt")&&n.push(s?"⌥":"Alt"),n.push(t.key.toUpperCase()),n.join(s?"":"+")}function ar({open:t,onClose:s,onNavigate:n,onToggleTheme:r,onToggleSidebar:a}){const[i,c]=o.useState(""),[d,u]=o.useState(0),h=o.useRef(null),l=o.useRef(null),m=o.useMemo(()=>[{id:"nav-dashboard",label:"Go to Dashboard",shortcut:"G D",category:"navigation",icon:"lucide:layout-dashboard",action:()=>n("/")},{id:"nav-changes",label:"Go to Changes",shortcut:"G C",category:"navigation",icon:"lucide:git-compare",action:()=>n("/changes")},{id:"nav-memories",label:"Go to Memories",shortcut:"G M",category:"navigation",icon:"lucide:brain",action:()=>n("/memories")},{id:"nav-usage",label:"Go to Usage",shortcut:"G U",category:"navigation",icon:"lucide:bar-chart-3",action:()=>n("/usage")},{id:"nav-extensions",label:"Go to Extensions",shortcut:"G V",category:"navigation",icon:"lucide:puzzle",action:()=>n("/extensions")},{id:"nav-help",label:"Go to Help",shortcut:"G H",category:"navigation",icon:"lucide:book-open",action:()=>n("/help")},{id:"action-theme",label:"Toggle Theme",shortcut:yt(Oe.TOGGLE_THEME),category:"action",icon:"lucide:sun-moon",action:r},{id:"action-sidebar",label:"Toggle Sidebar",shortcut:yt(Oe.TOGGLE_SIDEBAR),category:"action",icon:"lucide:panel-left",action:a}],[n,r,a]),x=o.useMemo(()=>{if(!i)return m;const p=i.toLowerCase();return m.filter(w=>w.label.toLowerCase().includes(p)||w.category.toLowerCase().includes(p))},[m,i]);o.useEffect(()=>{u(0)},[i]),o.useEffect(()=>{t&&(c(""),u(0),setTimeout(()=>{var p;return(p=h.current)==null?void 0:p.focus()},50))},[t]),o.useEffect(()=>{if(!l.current)return;const p=l.current.querySelector('[data-selected="true"]');p==null||p.scrollIntoView({block:"nearest"})},[d]);const b=p=>{p.action(),s()},j=p=>{switch(p.key){case"ArrowDown":p.preventDefault(),u(w=>(w+1)%x.length);break;case"ArrowUp":p.preventDefault(),u(w=>(w-1+x.length)%x.length);break;case"Enter":p.preventDefault(),x[d]&&b(x[d]);break;case"Escape":p.preventDefault(),s();break}};if(!t)return null;const f=x.reduce((p,w)=>(p[w.category]||(p[w.category]=[]),p[w.category].push(w),p),{}),g={navigation:"Navigation",action:"Actions",theme:"Theme"};let v=0;return e.jsxs("dialog",{className:"modal modal-open",children:[e.jsxs("div",{className:"modal-box max-w-xl p-0 overflow-hidden",children:[e.jsxs("div",{className:"flex items-center gap-2 p-3 border-b border-base-300",children:[e.jsx(S,{icon:"lucide:search",size:18,className:"text-base-content/50"}),e.jsx("input",{ref:h,type:"text",placeholder:"Type a command or search...",value:i,onChange:p=>c(p.target.value),onKeyDown:j,className:"flex-1 bg-transparent outline-none text-base"}),e.jsx("kbd",{className:"kbd kbd-sm",children:"ESC"})]}),e.jsx("div",{ref:l,className:"max-h-80 overflow-y-auto p-2",children:x.length===0?e.jsx("div",{className:"text-center py-8 text-base-content/50",children:"No commands found"}):Object.entries(f).map(([p,w])=>e.jsxs("div",{children:[e.jsx("div",{className:"text-xs font-medium text-base-content/50 px-2 py-1 mt-2 first:mt-0",children:g[p]||p}),w.map(C=>{const I=v===d,N=v;return v++,e.jsxs("button",{"data-selected":I,className:`w-full flex items-center gap-3 px-3 py-2 rounded-lg text-left transition-colors ${I?"bg-primary text-primary-content":"hover:bg-base-200"}`,onClick:()=>b(C),onMouseEnter:()=>u(N),children:[e.jsx(S,{icon:C.icon,size:16,className:I?"text-primary-content":"text-base-content/60"}),e.jsx("span",{className:"flex-1",children:C.label}),C.shortcut&&e.jsx("kbd",{className:`kbd kbd-sm ${I?"bg-primary-content/20 text-primary-content":""}`,children:C.shortcut})]},C.id)})]},p))}),e.jsxs("div",{className:"border-t border-base-300 px-3 py-2 text-xs text-base-content/50 flex gap-4",children:[e.jsxs("span",{children:[e.jsx("kbd",{className:"kbd kbd-xs",children:"↑↓"})," Navigate"]}),e.jsxs("span",{children:[e.jsx("kbd",{className:"kbd kbd-xs",children:"↵"})," Select"]}),e.jsxs("span",{children:[e.jsx("kbd",{className:"kbd kbd-xs",children:"ESC"})," Close"]})]})]}),e.jsx("form",{method:"dialog",className:"modal-backdrop bg-black/50",children:e.jsx("button",{onClick:s,children:"close"})})]})}function rr({license:t,onActivated:s}){const[n,r]=o.useState(""),[a,i]=o.useState(null),[c,d]=o.useState(!1),u=o.useCallback(async()=>{const b=n.trim();if(b){i(null),d(!0);try{const f=await(await fetch("/api/license/activate",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({key:b})})).json();f.success?(r(""),i(null),s()):i(f.error??"Activation failed")}catch{i("Connection failed. Is the Pilot worker running?")}finally{d(!1)}}},[n,s]),h=o.useCallback(b=>{b.key==="Enter"&&!c&&u()},[u,c]),l=(t==null?void 0:t.isExpired)===!0,m=l?"License Expired":"License Required",x=l?"Your Pilot Shell license has expired. Please activate a new license to continue using the Console.":"Pilot Shell Console requires an active license or trial. Activate your license key below to get started.";return e.jsx("div",{className:"min-h-screen flex items-center justify-center bg-base-200 p-4",children:e.jsx("div",{className:"card bg-base-100 shadow-xl w-full max-w-md",children:e.jsxs("div",{className:"card-body items-center text-center gap-4",children:[e.jsx("div",{className:"text-5xl mb-2",children:l?"🚫":"🔒"}),e.jsx("h1",{className:"card-title text-2xl",children:m}),e.jsx("p",{className:"text-base-content/60 text-sm",children:x}),e.jsxs("div",{className:"w-full space-y-3 mt-2",children:[e.jsx("input",{type:"text",className:"input input-bordered w-full",placeholder:"Enter your license key",value:n,onChange:b=>{r(b.target.value),i(null)},onKeyDown:h,disabled:c,autoFocus:!0}),a&&e.jsx("p",{className:"text-error text-sm text-left",children:a}),e.jsx("button",{className:"btn btn-primary w-full",onClick:u,disabled:c||!n.trim(),children:c?"Activating...":"Activate License"})]}),e.jsx("div",{className:"divider text-base-content/40 text-xs my-1",children:"or"}),e.jsx("a",{href:"https://pilot-shell.com/#pricing",target:"_blank",rel:"noopener noreferrer",className:"btn btn-outline btn-sm w-full",children:"Get a License"}),e.jsxs("p",{className:"text-base-content/40 text-xs mt-2",children:["Visit"," ",e.jsx("a",{href:"https://pilot-shell.com",target:"_blank",rel:"noopener noreferrer",className:"text-primary hover:underline",children:"pilot-shell.com"})," ","to learn more about Pilot Shell."]})]})})})}const ir={totalGlobal:0,totalProject:0,totalPlugin:0,totalRemote:0};function or(){try{const t=localStorage.getItem("pilot-extensions-status");if(t)return JSON.parse(t)}catch{}return ir}function cr(){const{selectedProject:t,setProjects:s}=X(),[n,r]=o.useState({observations:0,summaries:0,sessions:0,lastObservationAt:null,projects:0}),[a,i]=o.useState({status:"offline"}),[c,d]=o.useState([]),[u,h]=o.useState({active:!1,plans:[]}),[l,m]=o.useState({branch:null,staged:0,unstaged:0,untracked:0,totalFiles:0}),[x,b]=o.useState({totalSpecs:0,verified:0,inProgress:0,pending:0,avgIterations:0,totalTasksCompleted:0,totalTasks:0,completionTimeline:[],recentlyVerified:[]}),[j,f]=o.useState(0),[g,v]=o.useState(0),[p,w]=o.useState(0),[C,I]=o.useState([]),[N,_]=o.useState(or),[L,R]=o.useState(!0),E=o.useCallback(async()=>{var $;try{const D=await fetch("/api/extensions?all=true").catch(()=>null);if(!(D!=null&&D.ok))return;const T=(await D.json()).extensions??[],O=T.filter(U=>U.scope==="global"&&!U.pluginName),z=T.filter(U=>U.scope==="project"),K=T.filter(U=>U.pluginName!=null);let J=0;try{const U=await fetch("/api/team-remote/extensions").catch(()=>null);U!=null&&U.ok&&(J=(($=(await U.json()).extensions)==null?void 0:$.length)??0)}catch{}const ne={totalGlobal:O.length,totalProject:z.length,totalPlugin:K.length,totalRemote:J};_(ne);try{localStorage.setItem("pilot-extensions-status",JSON.stringify(ne))}catch{}}catch{}},[]),y=o.useCallback(async()=>{const $=t?`?project=${encodeURIComponent(t)}`:"";Promise.all([fetch(`/api/stats${$}`),fetch("/health"),fetch(`/api/observations?limit=6${t?`&project=${encodeURIComponent(t)}`:""}`),fetch("/api/projects")]).then(async([D,P,T,O])=>{var Q,Z,ie,ae,He,Ve,Ke;const z=await D.json(),K=await P.json(),J=await T.json(),ne=await O.json(),U=J.items||J.observations||J||[],k=Array.isArray(U)?U:[],M=k.length>0&&((Q=k[0])==null?void 0:Q.created_at)||null,F=ne.projects||[];s(F),r({observations:((Z=z.database)==null?void 0:Z.observations)||0,summaries:((ie=z.database)==null?void 0:ie.summaries)||0,sessions:((ae=z.database)==null?void 0:ae.sessions)||0,lastObservationAt:M?wt(M):null,projects:F.length}),i({status:K.status==="ok"?K.isProcessing?"processing":"online":"offline",version:(He=z.worker)==null?void 0:He.version,uptime:(Ve=z.worker)!=null&&Ve.uptime?lr(z.worker.uptime):void 0,queueDepth:K.queueDepth||0,workspaceProject:(Ke=z.worker)==null?void 0:Ke.workspaceProject}),d(k.slice(0,2).map(ee=>{var We;return{id:ee.id,type:ee.obs_type||ee.type||"observation",title:ee.title||((We=ee.content)==null?void 0:We.slice(0,100))||"Untitled",project:ee.project||"unknown",timestamp:wt(ee.created_at)}})),R(!1)}).catch(D=>{console.error("Failed to load core stats:",D),i({status:"offline"}),R(!1)}),fetch(`/api/plan${$}`).then(async D=>{const P=await D.json(),T=P.plans||(P.plan?[P.plan]:[]);h({active:T.length>0,plans:T})}).catch(()=>{}),fetch(`/api/git${$}`).then(async D=>{const P=await D.json();m({branch:P.branch||null,staged:P.staged||0,unstaged:P.unstaged||0,untracked:P.untracked||0,totalFiles:P.totalFiles||0})}).catch(()=>{}),fetch("/api/plans/active/all").then(async D=>{if(!D.ok)return;const T=(await D.json()).specs||[];b({totalSpecs:T.length,verified:T.filter(O=>O.status==="VERIFIED").length,inProgress:T.filter(O=>O.status==="COMPLETE"||O.status==="PENDING").length,pending:T.filter(O=>O.status==="PENDING").length,avgIterations:0,totalTasksCompleted:0,totalTasks:0,completionTimeline:[],recentlyVerified:[]})}).catch(()=>{}),fetch("/api/prd/all").then(async D=>{if(!D.ok)return;const P=await D.json();f((P.prds||[]).length)}).catch(()=>{}),fetch("/api/usage/daily").then(async D=>{if(!D.ok)return;const T=(await D.json()).daily||[],O=new Date().toISOString().slice(0,10),z=T.find(K=>K.date===O);v((z==null?void 0:z.totalCost)??0)}).catch(()=>{}),fetch("/api/sessions?limit=50").then(async D=>{if(!D.ok)return;const T=(await D.json()).items||[];w(T.filter(O=>O.status==="active").length)}).catch(()=>{}),fetch(`/api/analytics/timeline?range=30d${t?`&project=${encodeURIComponent(t)}`:""}`).then(async D=>{if(!D.ok)return;const P=await D.json();I(P.data||[])}).catch(()=>{})},[t,s]),A=o.useRef(y);return o.useEffect(()=>{A.current=y},[y]),o.useEffect(()=>{y()},[y]),o.useEffect(()=>{E();const $=new EventSource("/stream");return $.onmessage=D=>{try{const P=JSON.parse(D.data);P.type==="processing_status"&&i(T=>({...T,status:P.isProcessing?"processing":"online",queueDepth:P.queueDepth??T.queueDepth})),(P.type==="new_observation"||P.type==="new_summary"||P.type==="plan_association_changed")&&A.current()}catch{}},()=>{$.close()}},[E]),{stats:n,workerStatus:a,extensionsStatus:N,recentActivity:c,planStatus:u,gitInfo:l,specStats:x,prdCount:j,todayCost:g,activeSessions:p,observationTimeline:C,isLoading:L,refreshStats:y}}function wt(t){if(!t)return"";const s=new Date(t),r=new Date().getTime()-s.getTime();return r<6e4?"just now":r<36e5?`${Math.floor(r/6e4)}m ago`:r<864e5?`${Math.floor(r/36e5)}h ago`:s.toLocaleDateString()}function lr(t){return t<60?`${t}s`:t<3600?`${Math.floor(t/60)}m`:t<86400?`${Math.floor(t/3600)}h`:`${Math.floor(t/86400)}d`}function dr(t,s={}){const{enabled:n=!0}=s,r=o.useRef([]),a=o.useRef(null),i=o.useCallback(()=>{r.current=[],a.current&&(clearTimeout(a.current),a.current=null)},[]);o.useEffect(()=>{if(!n)return;const c=d=>{const u=d.target;if(u.tagName==="INPUT"||u.tagName==="TEXTAREA"||u.isContentEditable){d.key==="Escape"&&t("escape");return}navigator.platform.includes("Mac");const h=d.ctrlKey||d.metaKey;for(const l of Object.values(Oe)){const m=!l.modifiers||l.modifiers.some(j=>j==="ctrl"?d.ctrlKey:j==="meta"?d.metaKey:j==="shift"?d.shiftKey:j==="alt"?d.altKey:!1),x=d.key.toLowerCase()===l.key.toLowerCase(),b=l.modifiers&&l.modifiers.length>0;if(x&&m&&(b?h:!h)){d.preventDefault(),t(l.action),i();return}}if(!h&&!d.shiftKey&&!d.altKey){a.current&&clearTimeout(a.current),r.current.push(d.key.toLowerCase()),a.current=setTimeout(i,1e3);for(const l of nr){const m=r.current,x=l.sequence;if(x.slice(0,m.length).every((j,f)=>j===m[f])){if(m.length===x.length){d.preventDefault(),t(l.action),i();return}return}}i()}};return document.addEventListener("keydown",c),()=>{document.removeEventListener("keydown",c),i()}},[n,t,i])}const ur=o.lazy(()=>V(()=>import("./index.js"),__vite__mapDeps([4,1,2,3]),import.meta.url).then(t=>({default:t.DashboardView}))),mr=o.lazy(()=>V(()=>import("./index2.js"),__vite__mapDeps([5,1,2,3,6,7]),import.meta.url).then(t=>({default:t.ChangesView}))),hr=o.lazy(()=>V(()=>import("./index3.js"),__vite__mapDeps([8,1,2,3,6]),import.meta.url).then(t=>({default:t.SpecView}))),fr=o.lazy(()=>V(()=>import("./index4.js"),__vite__mapDeps([9,1,2,3]),import.meta.url).then(t=>({default:t.UsageView}))),xr=o.lazy(()=>V(()=>import("./ExtensionsView.js"),__vite__mapDeps([10,1,2,3]),import.meta.url).then(t=>({default:t.ExtensionsView}))),pr=o.lazy(()=>V(()=>import("./index5.js"),__vite__mapDeps([11,1,2,3,0]),import.meta.url).then(t=>({default:t.SharedSpecView}))),br=o.lazy(()=>V(()=>import("./index5.js"),__vite__mapDeps([11,1,2,3,0]),import.meta.url).then(t=>({default:t.FeedbackImportView}))),gr=[{path:"/",component:ur},{path:"/requirements",component:er},{path:"/spec",component:hr},{path:"/changes",component:mr},{path:"/memories",component:ft},{path:"/memories/:type",component:ft},{path:"/sessions",component:Ca},{path:"/usage",component:fr},{path:"/extensions",component:xr},{path:"/settings",component:La},{path:"/help",component:ta},{path:"/shared/:data",component:pr},{path:"/feedback/:data",component:br}],Nt="pilot-memory-sidebar-collapsed";function jr(){const{path:t,navigate:s}=se(),{resolvedTheme:n,setThemePreference:r}=Ft(),{workerStatus:a}=cr(),i=a.version,{license:c,isLoading:d,refetch:u}=Mt(),[h,l]=o.useState(()=>{if(typeof window<"u"&&window.innerWidth<1024)return!0;try{return localStorage.getItem(Nt)==="true"}catch{return!1}}),[m,x]=o.useState(!1),[b,j]=o.useState(!1),f=o.useCallback(()=>{r(n==="light"?"dark":"light")},[n,r]),g=o.useCallback(()=>{l(I=>{const N=!I;try{localStorage.setItem(Nt,String(N))}catch{}return N})},[]),v=o.useCallback(()=>{x(I=>!I)},[]),p=o.useCallback(I=>{if(I==="openCommandPalette")j(!0);else if(I==="escape")j(!1),x(!1);else if(I==="toggleTheme")r(n==="light"?"dark":"light");else if(I==="toggleSidebar")g();else if(I==="focusSearch"){const N=document.querySelector('input[type="search"]');N==null||N.focus()}else I.startsWith("navigate:")&&s(I.replace("navigate:",""))},[n,r,s,g]);dr(p);const w=!d&&(c==null?void 0:c.valid)===!0&&!c.isExpired,C=n==="dark"?"pilot-shell":"pilot-shell-light";return d?e.jsx("div",{className:"min-h-screen flex items-center justify-center bg-base-200","data-theme":C,children:e.jsxs("div",{className:"animate-pulse space-y-3 w-64",children:[e.jsx("div",{className:"h-8 bg-base-300/50 rounded w-3/4 mx-auto"}),e.jsx("div",{className:"h-4 bg-base-300/50 rounded w-1/2 mx-auto"})]})}):w?e.jsx("div",{"data-theme":C,children:e.jsx(us,{children:e.jsx(Un,{children:e.jsxs(zn,{children:[e.jsx(Xn,{currentPath:`#${t}`,version:i,workerStatus:a.status,queueDepth:a.queueDepth??0,onToggleTheme:f,onToggleLogs:v,sidebarCollapsed:h,onToggleSidebar:g,children:e.jsx(o.Suspense,{fallback:e.jsx(te,{}),children:e.jsx(Zn,{routes:gr})})}),e.jsx(sr,{isOpen:m,onClose:()=>x(!1)}),e.jsx(ar,{open:b,onClose:()=>j(!1),onNavigate:s,onToggleTheme:f,onToggleSidebar:g})]})})})}):e.jsx("div",{"data-theme":C,children:e.jsx(rr,{license:c,onActivated:u})})}class vr extends o.Component{constructor(s){super(s),this.state={hasError:!1,error:null,errorInfo:null}}static getDerivedStateFromError(s){return{hasError:!0,error:s}}componentDidCatch(s,n){console.error("[ErrorBoundary] Caught error:",s,n),this.setState({error:s,errorInfo:n})}render(){return this.state.hasError?e.jsxs("div",{className:"p-5 min-h-screen bg-base-200 text-error",children:[e.jsx("h1",{className:"text-2xl font-bold mb-2.5",children:"Something went wrong"}),e.jsx("p",{className:"mb-2.5 text-base-content/60",children:"The application encountered an error. Please refresh the page to try again."}),this.state.error&&e.jsxs("details",{className:"mt-5 text-base-content/60",children:[e.jsx("summary",{className:"cursor-pointer mb-2.5",children:"Error details"}),e.jsxs("pre",{className:"bg-base-300 p-2.5 rounded-lg overflow-auto text-sm",children:[this.state.error.toString(),this.state.errorInfo&&`
-`+this.state.errorInfo.componentStack]})]})]}):this.props.children}}const Qt=document.getElementById("root");if(!Qt)throw new Error("Root element not found");const yr=ss.createRoot(Qt);yr.render(e.jsx(vr,{children:e.jsx(jr,{})}));export{q as B,H as C,G as D,$e as E,S as I,Ht as M,we as P,Ha as S,Wa as T,te as V,B as _,V as a,X as b,se as c,kr as d,cr as e,Ft as f,W as g,Y as h,Ka as i,Va as j,Ma as k,Ra as l,Mt as m,qt as n,Jt as o,Aa as p,Wt as q,He as r,Er as s,Cr as u};
+`+this.state.errorInfo.componentStack]})]})]}):this.props.children}}const Qt=document.getElementById("root");if(!Qt)throw new Error("Root element not found");const yr=ss.createRoot(Qt);yr.render(e.jsx(vr,{children:e.jsx(jr,{})}));export{q as B,B as C,G as D,$e as E,S as I,Bt as M,we as P,Ba as S,Wa as T,te as V,V as _,H as a,X as b,se as c,kr as d,cr as e,Ft as f,W as g,Y as h,Ka as i,Ha as j,Ma as k,Ra as l,Mt as m,qt as n,Jt as o,Aa as p,Wt as q,Be as r,Er as s,Cr as u};