From 5147307eb4b829b70c7aba9729d06049d5c2648d Mon Sep 17 00:00:00 2001 From: Max Ritter Date: Wed, 29 Apr 2026 10:06:52 +0200 Subject: [PATCH 1/2] feat: bugfix workflow redesign with new /fix command MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds /fix as the standard bugfix command — investigate, RED test, fix, audit, done — with mandatory end-to-end verification. Slims the existing /spec bugfix lane substantially. The workflow change addresses the issue where two simple bugs took 21+ minutes and 400k tokens halfway through. ## /fix — new user-invocable command - New skill at pilot/skills/fix/ with six steps (investigate → RED → fix → audit → quality → finalise). Always quick: stops cleanly and tells the user to re-invoke with /spec when complexity exceeds the quick lane. - Iron Law #4: never claim done from unit tests alone. Step 4.3 is mandatory end-to-end verification — UI bugs must run browser automation via Claude Code Chrome / Chrome DevTools MCP / playwright-cli / agent-browser; CLI/API/library bugs must be exercised with real invocations and concrete evidence captured in the completion report. - Step 1.4 adds explicit Instrument-when-needed guidance with SPEC-DEBUG markers (cleanup grep enforced at audit). - Registered as user-invocable, model: opus. ## Slimmed full bugfix lane (/spec) - Dropped Codex from spec-bugfix-plan entirely (was step 7) — adversarial review on a plan with no code yet was overhead. Codex still runs at spec-verify time. - Codex-once rule across spec-plan + spec-verify: a session-scoped sentinel file prevents re-runs across plan iterations within one /spec invocation (was re-running on every annotate/verify cycle). - spec-bugfix-verify: 11 steps → 8. Dropped redundant plan-verify (no-op), runtime-verification (foldable into quality), post-merge-verify (squash merges with no conflicts are safe). - spec-bugfix-verify Step 2 (Behavior Contract audit): tightened from ~6.4KB to ~3.8KB. Sub-steps 2.5/2.6 merged into 2.4. Step 2.6 now enforces mandatory E2E verification with concrete evidence — no claim-VERIFIED-on-tests-alone. - spec-bugfix-plan: tightened red-flags step with Common Rationalizations and User Signals tables (inspired by superpowers/systematic-debugging). Step 3.3 adds a concrete multi-layer instrumentation example. Step 4 fix-approach-selection defaults to picking the obvious fix rather than manufacturing fake alternatives. - spec-implement Task 2 (bugfix lane): drops the per-task full-suite run. For bundled bugfix plans this was the single biggest token sink — full suite now runs once at the Quality Gate, targeted module test runs between fix iterations. ## Iteration cap - spec-bugfix-verify Step 8 caps fix iterations at 3. After three failed verify cycles, AskUserQuestion presents Continue/Pivot/Abandon — stops the fix-on-fix-on-fix death spiral that previously had no bound. ## Dispatcher / model defaults / Console - /spec dispatcher restored to clean split: /spec routes bugs to spec-bugfix-plan (full lane), /fix is a separate user-facing command for the quick lane. No --full flag, no auto-routing between commands. - launcher/model_config.py: /fix and /benchmark added to default skill models (opus). Console useSettings.ts mirrors. - Console Settings page: General Rows now lists /fix and /benchmark with descriptive labels + sub-text. SPEC_PHASE_ROWS rendered with sub-text. - launcher/banner.py + installer/steps/finalize.py: /fix and /benchmark added to quick-start tips and post-install workflow list. Spec-Driven feature description updated to mention both /spec and /fix. - pilot/settings.json: companyAnnouncements line now lists /fix; spinner tip updated. ## Docs - New Docusaurus page docs/workflows/fix.md with workflow diagram, Common Issues table, mandatory E2E section, /spec vs /fix decision table. Sidebars updated. - /spec page trimmed of bugfix-only content (now points at /fix). - README: new /fix section with How /fix works + How /spec handles bugs details blocks. - Marketing site WhatsInside.tsx updated to mention /fix. ## Other-session changes incorporated - Console: parsePlanContent.ts + tests for spec section rendering and plan annotator persistence (Bug A + Bug B fixes). - pilot/hooks/tool_redirect.py + tests: extended. - pilot/.mcp.json + hooks/hooks.json + scripts/*.cjs: minor updates. - pilot/rules/development-practices.md + mcp-servers.md: updates. - installer/downloads.py: minor. - pilot/ui/* compiled bundles: rebuilt. - .devcontainer/*: minor adjustments. --- .devcontainer/Dockerfile | 3 + .devcontainer/devcontainer.json | 3 + README.md | 55 ++- console/package.json | 4 + console/src/ui/viewer/hooks/useSettings.ts | Bin 6125 -> 6165 bytes .../src/ui/viewer/views/Settings/index.tsx | Bin 19617 -> 20827 bytes .../views/Spec/annotation/PlanAnnotator.tsx | Bin 6891 -> 13465 bytes .../views/Spec/annotation/useAnnotation.ts | Bin 9274 -> 11617 bytes console/src/ui/viewer/views/Spec/index.tsx | Bin 19158 -> 17007 bytes .../ui/viewer/views/Spec/parsePlanContent.ts | Bin 0 -> 3426 bytes .../plan-annotator-persistence.test.tsx | Bin 0 -> 17555 bytes .../tests/ui/spec-section-rendering.test.ts | Bin 0 -> 4952 bytes console/tsconfig.json | 3 +- .../docs/getting-started/installation.md | 7 + docs/docusaurus/docs/workflows/fix.md | 119 +++++++ docs/docusaurus/docs/workflows/spec.md | 24 +- docs/docusaurus/sidebars.ts | 1 + docs/site/src/components/WhatsInside.tsx | 2 +- installer/downloads.py | 22 +- installer/steps/finalize.py | 4 +- installer/tests/unit/steps/test_finalize.py | 7 +- launcher/banner.py | Bin 16947 -> 17144 bytes launcher/model_config.py | Bin 11608 -> 11660 bytes launcher/tests/unit/test_model_config.py | Bin 21785 -> 21804 bytes pilot/.mcp.json | 6 + pilot/hooks/hooks.json | 2 +- pilot/hooks/tests/test_spec_stop_guard.py | 1 - pilot/hooks/tests/test_tool_redirect.py | 334 +++++++++++++++++- pilot/hooks/tool_redirect.py | 244 +++++++++++-- pilot/rules/development-practices.md | 37 +- pilot/rules/mcp-servers.md | 37 +- pilot/rules/task-and-workflow.md | 18 +- pilot/scripts/mcp-server.cjs | 2 +- pilot/scripts/worker-service.cjs | 4 +- pilot/settings.json | 4 +- pilot/skills/fix/manifest.json | 30 ++ pilot/skills/fix/orchestrator.md | 66 ++++ pilot/skills/fix/steps/01-investigate.md | 57 +++ pilot/skills/fix/steps/02-red.md | 31 ++ pilot/skills/fix/steps/03-fix.md | 46 +++ pilot/skills/fix/steps/04-audit.md | 60 ++++ pilot/skills/fix/steps/05-quality.md | 34 ++ pilot/skills/fix/steps/06-finalise.md | 60 ++++ pilot/skills/spec-bugfix-plan/manifest.json | 12 +- pilot/skills/spec-bugfix-plan/orchestrator.md | 2 + .../spec-bugfix-plan/steps/00-toggles.md | 4 +- .../spec-bugfix-plan/steps/01-red-flags.md | 33 +- .../steps/03-investigation.md | 82 +++-- .../spec-bugfix-plan/steps/04-plan-fix.md | 79 ++--- .../steps/06-annotation-check.md | 6 +- .../steps/{08-approval.md => 07-approval.md} | 2 +- .../spec-bugfix-plan/steps/07-codex-review.md | 23 -- .../{09-continuing.md => 08-continuing.md} | 4 +- pilot/skills/spec-bugfix-verify/manifest.json | 32 +- .../skills/spec-bugfix-verify/orchestrator.md | 7 +- .../spec-bugfix-verify/steps/02-verify-fix.md | 86 ++--- .../steps/03-quality-checks.md | 6 +- .../steps/04-plan-verify.md | 16 - ...cenario.md => 04-verification-scenario.md} | 6 +- ...tree-sync.md => 05-final-worktree-sync.md} | 4 +- .../steps/05-runtime-verification.md | 5 - ...check-feedback.md => 06-check-feedback.md} | 6 +- ...-review-gate.md => 07-code-review-gate.md} | 12 +- .../steps/08-post-merge-verify.md | 3 - .../steps/08-update-status.md | 35 ++ .../steps/11-update-status.md | 15 - .../spec-implement/steps/04-tdd-loop.md | 10 +- .../spec-plan/steps/11-plan-verification.md | 26 +- .../spec-verify/steps/04-launch-review.md | 11 + .../spec-verify/steps/07-collect-results.md | 7 + pilot/skills/spec/orchestrator.md | 5 +- pilot/skills/spec/steps/01-parse-route.md | 2 + pilot/ui/PlanAnnotator.js | 8 +- pilot/ui/index3.js | 4 +- pilot/ui/index5.js | 2 +- pilot/ui/viewer-bundle.js | 8 +- 76 files changed, 1490 insertions(+), 400 deletions(-) create mode 100644 console/src/ui/viewer/views/Spec/parsePlanContent.ts create mode 100644 console/tests/annotation/plan-annotator-persistence.test.tsx create mode 100644 console/tests/ui/spec-section-rendering.test.ts create mode 100644 docs/docusaurus/docs/workflows/fix.md create mode 100644 pilot/skills/fix/manifest.json create mode 100644 pilot/skills/fix/orchestrator.md create mode 100644 pilot/skills/fix/steps/01-investigate.md create mode 100644 pilot/skills/fix/steps/02-red.md create mode 100644 pilot/skills/fix/steps/03-fix.md create mode 100644 pilot/skills/fix/steps/04-audit.md create mode 100644 pilot/skills/fix/steps/05-quality.md create mode 100644 pilot/skills/fix/steps/06-finalise.md rename pilot/skills/spec-bugfix-plan/steps/{08-approval.md => 07-approval.md} (97%) delete mode 100644 pilot/skills/spec-bugfix-plan/steps/07-codex-review.md rename pilot/skills/spec-bugfix-plan/steps/{09-continuing.md => 08-continuing.md} (76%) delete mode 100644 pilot/skills/spec-bugfix-verify/steps/04-plan-verify.md rename pilot/skills/spec-bugfix-verify/steps/{06-verification-scenario.md => 04-verification-scenario.md} (93%) rename pilot/skills/spec-bugfix-verify/steps/{07-final-worktree-sync.md => 05-final-worktree-sync.md} (91%) delete mode 100644 pilot/skills/spec-bugfix-verify/steps/05-runtime-verification.md rename pilot/skills/spec-bugfix-verify/steps/{09-check-feedback.md => 06-check-feedback.md} (87%) rename pilot/skills/spec-bugfix-verify/steps/{10-code-review-gate.md => 07-code-review-gate.md} (87%) delete mode 100644 pilot/skills/spec-bugfix-verify/steps/08-post-merge-verify.md create mode 100644 pilot/skills/spec-bugfix-verify/steps/08-update-status.md delete mode 100644 pilot/skills/spec-bugfix-verify/steps/11-update-status.md diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 9973c599f..ec22b0732 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 61edaa296..166f25c0b 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 d81db38a9..68ded98e3 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 RED-before-GREEN discipline; 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,16 @@ 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 — Spec-Driven Development (features) -**[`/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`](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. -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. +For bugs, use [`/fix`](https://pilot-shell.com/docs/workflows/fix) (see below). Specs are saved to `docs/plans/` and visible in the Console's **Specification** tab. ```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 +166,46 @@ 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" +``` + +``` +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. +
-Bugfix Mode +How /fix works -Investigation-first workflow for targeted fixes. Finds the root cause before touching any code. +For local bugs. Single file, obvious-once-traced root cause. No plan file, no approval mid-flow, no separate verify phase. RED-before-GREEN discipline still enforced — bugfixes without a failing test don't ship. -**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. +- **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 that don't surface from a static read, 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 (`try/except` hiding the bug, swallowed returns) are forbidden. Targeted test module re-runs between fix iterations — full suite runs once at the Quality Gate, not per-fix-task. +- **Audit:** Single-pass scope sanity + symptom-patching grep + **mandatory end-to-end verification** — re-runs the user's actual repro against the running program (Claude Code Chrome → Chrome DevTools MCP → playwright-cli → agent-browser for UI; CLI/API/REPL for non-UI). A passing unit test alone is never accepted as proof; concrete evidence (command + observation) is required in the completion report. +- **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. -**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. +
-**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. +
+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. -**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. +- **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
@@ -719,6 +750,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 54e54bc96..d3f78dbf7 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 d8889ef0788554a071232a33301c6a422eff3928..536bed4cc5f7541631ac4ea4f86448598cc308b0 100644 GIT binary patch literal 6165 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 literal 6125 zcmVRu_ z(h%g(ULv&N1l`okr|E$pW<$*ZO6wT*sT#PiTFU6wpu=`^rQ>1GJjnJ;^9wo3$=RDJ zaMok@bcE9-btz%#&UT?EM^^`oTT<24HIUJv3+V9IqgcrKkk_)!=^IBh?Hl2M3{i*DJylW)=NACoaZ zD$e{q!hnOL9FDiu_4C^f4@UtZlYH-aQ2zlKdw-XQ4vq+kuc*0Oyto~NmP!FZ@3lo|I{(+iQ|shf6?bl*gNwTu0L*)O?i(4dQ1J|wzRip&N{#n1R3B|?VKhO{+N2ev&?GfPi^th9ld zuWQ(MOM`)F@_4O!*KQ@>`(C`WEJw=l zg=@9PjH#qaS%g<0Lv8(VY-AtgyeDjmpzh;;|#@ z#$UkR!2?)9&dDxPep^(3>H0HLmVr{fEWR zxA~$1#}?$N&;p9rl{n+U;L_UT1lD5k{T)#2?>(Q4MZx2EZ1_f8!f=m<3E&^O9@Uy* z0VYIpB2nuUnUT#&dSTWv|D_xx`j1bABS40!>7ey)cZGM%G>O303Fgv?YXyU>5ki%> zI|_BGu6I%^t7gU5E`a_E!Uf%eqH}!s^*Z7MumPW26m;mpE0y=$A@~K59o@9Y%$`mX zW;vvJqzej93~Nx36&MYe)xuvt*bWhFJ}cTU5y+uwVNeePMx8M=CIrt?wYP^nsN<|0 z+#0r3gfihpcaf<+HK+{_CtB(VxvJ2+j;7qE*<4z>seDOSDq_LQez0^JNBwXhCROGc z`TX26FrGbsUUvkY(S*sLS?G#o<`MFW&u3n|PeQdOHtC#mfx?e5keHC77!kb$+rBoE zkYTfM+7S)$qQD9@{4ku{it=IBs5IJG2pKRtdo_}x8nrO}1$=)8n`buC*mU(K-1VI` zfAf^d)pSPYZhBq(4GY_gd?8d)Nenk&lrczOF-!F59+3R{cn~&wd#*wpt1RC61*4?^ z#~l;%l#Os|8p;X87DsdAZlBXn4fJVi02{22zwwx@KURYRckJ{8SPXwIo>4pAJMyq= zXXL($(Ncp{OViw#$tdp!d2Z>LfU@#_Vn4PXzTSxYNuPGcNtJR?VxwOaw9mBOXh;W* z$nGShP@X_(H!|M~6hCN&8(aDbo-F4L=V0fTzHVq-9`}n*$QEAFZ%;Zq9K7Jszubln zueKHo_@=t{(OkK+j(cTZoh}AwR5nT#yR%;6%W?}Gx)-|b0ArAdHMESV2|o+CPntXz zO`|>>}&=x_EmJQYs^MtC`P*L z;lTjB6L|6xuoQ7#Lg?Zx&sFAEsZ;H(X0m&y+2Mu4q^gP{&3}O>kO4l@97A&L(U!-g zGng405ftAscoc+mDW&9@`wrBmbnH(}B+NK^_ST^SWg(JP=-gI12bU>R|oP^Dm`+$xO<1REe*&iQh>IrxVs7% zL_yf5K(g0j-P{^~Mh>6(D|bwDv(F*$fFDu<-$h8Z%zDH2t6?|yia)(`yDDyhJM>uYV8;@!DCX{fyul>^DlgB@`dJiuik4(l|mU*Vk z)Q97wF?zPW5Z3^X?oEFyXTshgudJ+l0<=0J*7g7e(7~QKp#{2umD>nt)TskkZRgp+ z0rp$Va|=ouys48#u+o|Xlb)5!*pD`Im#&SNh(#o5rjiInt)=)srgmN z=YYDUe68<}Y`ksm(l;y&q1ndkM1&Yp%P(Y25Tq{frc1))EfRco_YlehDbvpe0$J;t zs}XBoUF&zn@`PPhmEa2UxN+$|3m?p}u_7nM^L7m8=Mc<-nZ19)40dzzJessHY%z?R zrM}k=c1dwQ38Vicr1@pJqo45Y+ha1cndeM1P*g~I^|16hHtTf8(n5S^JgtHbzPFKQ zq?|(HKuCO{RVgHZGjpQ0U$GHtHNZNLrJ9V;;iu%oZXWDnTRmpTOM&Uf-b;}46!fz& zZIt*9ZIE*ad_+)0#Y>85FCUxa5LlwKD2gt0eMPEh0xG2Y-8lwA*W8RL*&}w@JDU5( zt@_=*yysJWcU>1uy}!0R4(T)QcN$NV5MWr?@dVR*NzGM5Db4J&42eT#5*(%XW~kdC zS@4fp;4iiCG_{-Qk^_I44>P>1z$JA<77USj%sgjYJ5v+6oO7LU_F!ZMl-3?q!W;L# zYh~On*Qx~skrL1ewY_HN$lwG}OVh?&J5Q^u8sP?h^vVt`(jvSBzdp z?JwW=JHQ!xk(J7>grT4|8lt*QDM(6>x?aKR^r~6V%Ajh!rKSZav3W_(npLQ}oXM9p z@-SVzokR-Iixe;q>;0;tc@ke-lssl0G+jblgFf+$20-sOBXp6%)|)ss729b+pxnK2 zbtOECRq_{XSXVNoLNh>DMQk4B4U6L`IvDFXVF7}=4)J>if|9Gx>~M1 z(*qhSvWrJ(Rr{>g-}8)`HdpZAYZc{4^7{^K58F1BA#>4Gx6Ww(mZ`hOk!x~Pw6)cG zB%afJV1p!u7|gNM4OGLp==0*QAGnRO50pB9Kmqf*XU@OfN7bR07yjXY13XJZS zF>NuIbejjSHGH(#3-;o)nGAyEYt6)PdzVA&gPDxM@}vw0h}c`7nruig-dl%I1NMtk zFtvRYAXT28e4}Oebu1WNTA1qSfko0obivbP=OPe?3bNSsnyy|;{6NV|C^?%|pbna% zcV$Fxpi->#^m5Y#E<$x{;2;=IOh0Z|f@53nOeuNXkfeWPtC+;p9sTC57#j!m103QE(nwa?rx-z-=BDmJsH;jl@iy~} z?GjzDLoGh5og%EPWuNVrv~ARn zfsN0$0!-~{b=c-CgGR6gF@rb!2B3LXmkG*vQDqhyZvVj>A~9f?G>vSBx~!#hPd>G_ z*-ytC^yS~B_-x!1OBGazCm{nw8eU$!5gI&2(MFO)2EAr-@8gqKcUMijOjaOGsBBXg zQvhUDoDdtxm$PJ`jrmH{LO$EbSN>li?uS`B2F#GfKVONrocNIJ&XUbt|&_%ZILqia@PD?(RTiUN}Vd9pA?>+bF9S+2=x zbG#uwf!ZWMSVfcRbS;U17{Tb`GS%=~FTL5nl#ZoUHF}FEof!r9devPqfd0IYKPeLS z*H1h+s1U$8vWXeF#G~7e(O#T9D+y3eT{PPVVq~sYKw^%Sx@~*E%6oS)28O2j@#!!z z)~r!;Ro$i3dk4wvl_*fbwR~ecOWx7LF$=+^KCsq@M&T)TY;4KpM~H0yD>Zxe;Hgzk zKLeRzvw~89=~A(R|m@q_a*|tER1<$Rhf|i zcauMhv5_fx+Cvp#_j=iV8Cv0kR#4`J`mop@@)DoQBS%C&_(2Z++|#&Lz8w0#O!pRd z@;5^|9fi=SGE^@std=%nX-GCx76XM+a#x*C+U%v@lzy`%MuhuEXK#WeNfuCoK``lH zWgR5*mL=a*o1ue6v|VISb4bw|dfv@`-jt5*9%DqU7XrQFRl<|D23!$T$=!@=^n(YT zjLHKtXqSDlCd9}ZPKh3TR#xp#_F-$$oKh~=p2m?F`g`deV|sItyNNIkJa-Ze z|+3$!2V90e|A1+`773r=e(1I*OEx?OA6n1(ypVb=P!M1eRPfm__ zUYWSU0C7vLkbJ9Rv`oNCeVu|aEB#vH9(`16Yt)F!{%O`p1%Kva)%2^LXX;eIb*Y`e zf_ekAL0cfcADl+t%uK_o9>5%{PX}bbE{d~KlP5CwMGZva5iO%k8I|uZl9`98Nx?Y+ zh2)zGc$mSTg2%xNe^0a7DFQMHyS>$o_JzNW!345`?noAey0LzT`okL|hvPq6c_qDb zX}FzbzYA45X(y>k$bR1@LU!;$vjL2M&PR<6%`h~g74kh^HbnTUlYxVyhfL5AN{Zme zzEZ=Keo`uTs%ZFu2cJFz1zIz1@y_dP-$B}x2I1u3+7}dB4Esm3WMdpz9&GwtL2kq8 z)D=T~w?xnU$;2#`zmG~_ zZ{L1o|Ij~TK4o#1pP~1`#B35ukl|RB0OF_x#p{WnSupnm7iaEwb;UwuAcM9EDn)Gt zYkdhMhHy^w*dUb;bTbMn&NU27Fr!i>f*8gPx=mcv$Gm(5-ZeqngTd0Wri{`e`g+!6 zdMzmhHSMB19o}SAW7{s?{4rQpM-X#g zczT_%-9P-ebliTvQ7xl&_`O0X0`k9_Q*We$A&Wdd1@G9B=Y3#2ch*x^@~RLY%=+6h zA;1EHgV}Dg&oE>mnHfHm-ja+*Q5SWg;~&+I{Uyb|($;c)3-y_mj=H@Q;pUYci|IOgFf^q> zq8mp$)sp(3CjS#AF{1Q{LZ5h-5a0~M;Il7$<7w+pcTj*fsZ1>uo0Ixc>;HcqdQBwl zaO(Xo&BOUTNlbv2)8>bL*#G-`nxqlnwVSI)0=$oTwBsdEE-lfz(()7ZrwaINI>d=GKJd(P-M#e z$*bG2v`}ShpH4(qaf1jn!%7HB+$eyXj8*8KS@qe&Pf}(h+$q#&L{A1X6y|}^!O;za zPl1t@An-K%lHa_Sz5&G>;T6N*a|d%w_6#*6IUp-px3@fN(t~i;FCYQCsap=PfwhU6 z)D+yAi1ncK%AfBe@|bdcUT&8XI2#{Bo8sYkODsQ{x~Yb+h};m}5O)_t*kGn`lG3eDa>LbsR5LyIQ)IEl5bgo`t$5F|G{MI zyam7ec)RAcxSTEM?8w8{P{0_TL>1v2iA1~(D$-Np#^$7k93?qW0R7_!KrzesM6bzq z*Z0N@@(ptp)186mvJWa=7~A+s)3X%HqXk_Vp$F}Emdw5Tt(R=5g$=7>sUQdJf5kn| z<94lhQ$W~01r8~hAc6CPbvlBG_O(`W3^_Uvqye3GO3?=BUeAepK(c8)rRcr0JP&ai zPWhvWgSoz4d!-ez-c6wj9kt?FYV)QJc(6W>KGjPg0VOkAwDBHsMmf?Yx=r$LT~0gM z_NFFxmH?PmXNoMZWLU#2)8tFvLd8#U`CiQIlA&I=&0ib_nvrh~O@wY|^nmT+oLwU2 zB~gVRvuoVCVSKh^%qB8o~iD6cK{@? zdUO|1{6tTt>V)zq#v|LZ^P8%D*haeG!w#0OJ-W2Q9RbQTY4uFe$=cpp7{ou<$n8mt z5l5ZNd*GzM#R@q(0(8+xU64c0Zw@#~c{KgvZ5#2AdOP)pue zuCnA=5{n&>1JFc64y-2QatbL*4P*M|DP@x9#ni|G*4FC!V z>aa3j<~_TbyU(@=uZoaj*hJdg2F%utwaxIk!omJIC0ZkoJEJ`M@dveQdv+`0FD;G&pU>vC7IB^gD-YnTD@HQiBi0V`VXE3nOTQS0xQ5J zN~J9UeKKJ1oC{u?sg_$CQ>-qvL#lCk$Uf>|0M|v9y12TePh!Zx1D+<>n7{6KC|$Iw zz1{DzfPLc}>=JB>6!%iJ-%SkVd8X(QLi}Z?e7%q7GRBCHzU6f15wmeBVm^-R)yBuq z{|5>JnBI!(F`9H9nZ^;pkp1B%0)203I7cMjQLD*_w&x0`Seusw8gGf19&D0fo%&!o z7QcCp{S}JfOOzR$?+$l_5M~aAb;IAUW9q%w=)vLNRN~Hbx~3SlG&m zJ5%6eFOwnvU5qPQ&*jo(h?C-Wv6rvd~+2o@Wj-@$Eez{!ZYXzbz^WQoYW+ykJ71_AA_KO%p8 z9Dx!SWguN@MmI;PjMX%gmWI{_Enajj?-vH;=?~o}+E9M~a z7}tF=T61ZUX|9m(zKD0^ClQug3x9t)bbW2uo9<{|OJKghh=IPhte@n%u+w!8a=o2f zCVOH@&cq3o{q}&6+j={_G>3#>9Ir`heezoOoN@dAw^~iz z>mb)0f}Ie*B$0Y>o_3f1X9dCj(x@>&Q9Kc)ne&5C^)&<9;MF@q!A#<1;suoV7>!>+ zbjxqEAwK9k_40>Vof)VF9SWO0WC^(sMya0hCc)uFC;JSx$8j(LN>c?!uetuD$oO!Q z7f>lJrZB2P-l}ig^TFL&n`6Yxl76^9s5I$_`#e?pC_*`N`=B`1jn&hSE@hqIu!rOy zxYYtZQbuL{lE}v6WQK%ukji~@oDAALzm1({_M|^~;$A|V@>f*lfyLs!NCMw6^nOdo zyDJ7Dw-o9buYah$YJUQqr4+ewL(Kv$cH~wMe^JD>;g@+}msgXB?Ai#A?vZ(OZ z1;R$|tii#IVEDR^F+y32OK*Z*=?m$l0RJR?GmgQMg(5k;Wag#V-*|51T~~sp%u_n8 ztPEN`NG9byqX9+li%=GTDLtsClf)bdIjnsA%q~P<4o>qml%Y6A!TgTY2+Lny2DK3e z_FTZ@zJsK=Q1#n+bedi3DA;wdw|4F13HwM8^d1vqqzQ>T{triQyf&R~t5V(brIbcSJG$WuUW}Gp^;@b#O7l88O zbX=;!LW_*dQeT>w>b%XqUrxLi>v94Wrw|U z!tixsh(g*i%2boB)r_Tu!)ukBhUfmkqi0vjx;Xwpd|QGoTIS*O>g{&uwqTapCD%Jf zz5<`rT^|G2&XFcSC>Q-_#VSv}aI(H@Cz`YG_@pd1OIiQ$DxID*fdMvYZe;{zTQ=+m>7>lG$?$ z8rRIT%aGWR2AdY&R-nzMcebHvRx`Y$I%5ypvM^(`r&quV>y;qOQ|LD|Trl%^XZ@6! z-?n&bqrpL1RYXXg>{2X4b5(y#)_Ay6Bd(~MM_g6lPNM^SJt zb(Uk)3EUXi=iSoqkmca^BZi)n93a2=t*BPxaMFu^1>%hmAPuUjyUc%6T-uBiyC%5{ z4##8|e^sUt$`BI_J((o=Vn+O?f|F0_^A|Ruz`1r${%I;2j@=YPd|o9!!~Za7c%G{= z9OmLP^ulC|r#}0KcMfPfQ1E$!4Pane{Aqk=L@bWal?zN~Nk?bDGlt`cx{_j0t)~OdFo9&YQ1ML< z7}&)>Gh){tecar_8-LT=o2z`{!8O$9kEm)X~T|D0RdU=R}fN+V1*d+K~5wDJGl zh&)-__kH9kIz+FVR-_qg18fT2G4bt-&m$C+cR@ZNZ|m>NxY6sx}D80g~;*AJK=vP)-%f1&U8 z*zH*8VE7HE4mdoY_KTyESVBeJHfix-b9|FU@VI)a`&=Z-?p13pLUz9C9UV z#K*PBZtRo)bOo(&m=HS|T-`%ka$B36h~)M&389UZhrsxo9n z@&2oOOkFuch3ic7`*~lSoiiT^Z!O}dT?(hNw!GF+e7C-g5s{zksFu?P7hwwO#A;}m z{QhZaWey{?(PLDi4*IxZ6u2vn@VJg6;t(G4Yg6>ylFV?J>Cme(a98G4>UY^ueo+V% z4&D)IPd4m9OAbrX#eD&i5g`y9H?L294?poEK7?=AF5NcuDWjJQJ*@7tI0F?4!?fq8 zr1McI8a%(tBG_Dct~9J6%>;3aEn5X|-Qr^(ymOlOox1^reRWGbi zYUNmZF#U##w62ZxnD`#$|5T*lh4VP@TeRElXB+7G=e#`bAs-@Y_#%0Ix-l+}i-g$v zoELrL5ZaIND!pI~%r6v#j~Wz>P3|<-QSe{tFhi+S*NkP=ZL+!vnRfDPnxb`B!{0dJ zgy0?p_xolZi1;P>M98_FTLpA-SmzrJ)8;(knSK+f*j|W`+Q@U(Dx;K*|m2U8N6#y3@g8Zouk*lx;7Hg}64Lr7vv8Oj>lNN@;4m}+~ z!1E@idtj8Ui943(PdDvTGsadfL`rW(7B5KRyIJ3?P-baPxGRThy<5VAMX)nu9V{G< z#^waVkk;bQ-T;IW`GV<^uFB!F{V_-wO2wpN4yK$S|4ncOl_3Iq+WE8|lPC}j{lU(* z`X^4e#o=y7EFTv=^jQeXGu?@?(1}ny)K@9MXp!}}sb^FqqF7`xoy8+Qm=o?Ydk|k5 z!k68lZ= zhI&w5azDfs{v#myb4%wJol`_??YfeQ7y)o=%?cH3Ta2n4NCU2q}S!W zjjEO4)mcwx>j7--#J_{|A<{AKjUrfHm4C9x7wZx56D8f2-A=?%PA7t;K_s&KMeL-J z^OUjnsvxGSU)Ra!m%7Gt1I|rgPA|3Uxh}rqAN<`ai*8@gQ`j+=*tJ7QU0c%)l3Laz5@LOCN3#t=`Rldr%^GKmQ%DPup+-^*m;)=S& zGJR^nM3+H_lbX7G@;m~1m<6jDy6`QRM#~Qqyn5T40}`0^2HQ~amDfolQdJ3)Zl_Yk z{VnADgA6I-Ul9#VjK-Oi>ZH5%YgS}-@ws@pPw?+#^;tZJ88+r#GTt2kxu@u_UB5i$ z@yy(VI35Zr<=lyyrNCvVE(*cSmYW}2L)5+7e?{hd;mI6@i132qhT^&ez>0Ux#l(Ry zV)%tUNkMHo*`52uF%+2fbM^&?YndiJ!KhSdJJr_v&(R#@_pxniC!%-rEsVK@xmQy| zWU#L<>E~SQ(hxV|@@YeL3MyA7HdITMi{;256-uXZc8fv@eqc^w9qE{z7i~=B{a_#L zL95ZNz1p2lB1Mw0Da1Y>Qja~5hvm`x+q z{6c+z9${x&FH%~p)Mnc~GqmyDfhlrSMwFz+7U(4mG9inMPNchyoox9Qivy1A**kKD zTgvjN8c!f;A;S+aa^N5=roPk+u$^dq?V)5T_XvN)a{iW(&^US^C`_X!bz17$~36 z>|&>v7br2nC5`xYwfjGYb>Py4ecdNzpF*CGhOwsw1B16vzhwHrc-#4Gow7rG@nsb~ z04-$*{mcsxZ0rOko%M@ph^y=0`X-8A2Pu3vVAmz&B31wuN;A0VFgF(Wyh22i1wcMW z7)k7e`Fppl%1mOHc(q;(cI21J_th}VL$n`#Hk?O_u;ayo+G&HxS>DvmoQW1xcr?wC zC#+lRFEg2(g#oAIs%|`ZF(uAR-RiNTOxexl9!|GQ9zEjc)OjXG9L|F{{X2h-kbMgB z%c;RW{)jBj+&W!0CK$G@p|#@=FRuyCY5o+iGzx7;S=vEv9|)X@>}o4+770$$K-^DL zc?N`hN^uYLm(P&+?jya)3um0U#~Sne4{93|tJwr+bKKbBxGtF=uK{u-yDr{T0~+#$ z8yARAau?|FuA4M@udhQ4CsSj$LoR&4;7V@l0ZMa;QQ9Fh2uw@D6z78~1@7Tqn|Ec? zIk1uVbB*NF3+Qf+wU3j-OkvovRFo-3dS$+G+t8T>{QP8PU(E^T0?&h_#}-wCh5DHG zKhDGK0ZG4H7;AdG4)ku8Os*PNStT7`5Haa^uF%NTh2n&Ti*lkjAi2lWw^?L@A=`yC z07zq+=h7SH{p!mRfQwun1-o#mCh7%Ben^%v%z(kwe<2F}newp18|#*jN6!&}Q{x)u z1wlLxsSem*G1R0M&#baxo>%fkO&k{M<~z$oKECF?h7pRzkI7_Wj;XE;)+qFp57nQB zJd0?zIjgMR3^}uPVd-q&5G#Y(t0}FFFp)Pc5ZRuLc&y)ebT7;;cK+tCxPojN`fhr@ zB4ca>9Qi-0jZNxT!&)3lsFjySBOAygVz8$&34N(-h<)nNvXDL6j)&7KFm7R?%C@d- z9l+dARH$1*0J3mn%c2Th$Y;EXc~+XQ{lD3sa)G#w&_jcyIE~g%2YMXy!jONSGfx2v zWTmku>41*0VEf!~Ee1S^Lgt44JCk)-JOrHSV%^>6A$%R^xx@zYEy}0KE9umgU?q?f z6oNva>s!!sWznzDA!q*2Xq8WxT`Y_cON?Hxw|$Use*3s94sNV=fdD$SVc+?B7*KAW z0v5@<1Ud`UW|(D-=ku!k#;r$AdeQNd_fa6d7hU^!jL8Rzj=TJL+A9c1;-o;ft`$>m zgj3^zDX7q6s^HJp;U2nEQoRgMj}$$RTmdW^0##XMbo7fiq{J9DimLjf!#lo1dZGXS z*-29+VAOfGW-+JKvQytMLKU!dC|4<7{cL1@n%0`8-Ipb?Andep0XzBTzyerxGEdZge7cx#bb(1=e zK8UyJHl9q482#!xT7#{km)*FN8w5sZqYgq_^0y4qKq0>%=`Yw!i4~NLgd))lqJCH& z1WTN=#-Pm%B2iW6oAOa`X%dq@@IE31JkblMcBVhVIddhW>*y$kTAa)jev#D#D2my2 z739U2Zx$t&Qx?XFG!Y5qXJklJ?bPExFW$mgB1lN2A*Tu_o7O_>_&zmo#fTr)w%DVx zFZm3CO-n~^km2uu{)}yk|768uf0+%)GqgQl%e>Ycb9#>ggB;gw-zy-$JXi0I+2<@5 zV#+N-bglVpA$^$6DFMh0h>*{r)vo-}hF@f*zi`QU1n4K2p4hUNU-rbc zs#w8GIam~Wg=F(Okqt5v2uAu!Nvw3sEnb4~Jv1N^nBp;(ik`~CQn&8gqY-WAvr}Cb1 zM4Ou~(6*F6h^&DZ+u0~hpcKq|p9Us{E9VK$I=7J- zEjloB3qKq<cRKwaI6Hr%dksqio;{v;_3 z8d!C|>JTeANzAnDJnj2JJg6B?TS-9$T|&<5<$wa;-I|&BSK!ajfj=Q}MdadYMj_g7 zen;U{k@gXUKgR{pP0Wr)S~$_pWwE|G%eAa3dbDq)_9&?b7Yvu6P^QMiAmLqnvBP0H zaGNbA5!5Ay+=Fnb5qnyv4Io&&5*?-mA-r&?dc+np8nt2JCtO72sN>MW-McC zT=v{3YTz`xz!jJ=own}CbZ!bQ{=>BCifdJ*HCJo4*ip6lEXgs;b8v+eduLBlXZpIf zO{T`Md%JuN8;-Of ztuEm8Ra}DV<)&_e$sRD1ONgYGSctj{{J_PBWd%^(OgIdX`DB*3-~86dtIX;rb{JQq zzJm>62Zmi_tnHfK9?^YFz@eDr0hni{y-x2imwoutVb$$mCd1JJ@RK*Eb3VYUCzEju zD3nW;*GBUU9}17JLiM00nP97pO)q9{-|bfIJiji7dvCfIpL6QDmq7NfnCC`gAJX=- zLAwMpj!niZOgViFJ+e8gL-O`2iT=rNz$Q;21g|k&zEBxI6VEDv+qJ+#z*iVX~+6xz&n6969ux!y26i`~03jU+zyz{OLp zIddyANogpy=I`_Do{6dJ;t5HWSEM+9CR88dMDjLge}bwB+802Op=ekh0<%3$k}ld9 z5O|xwkfmWMC$Ck4f>&31;do{4Zz<^dw`YKzJ*(acXd3^vSOlZLMD*}_6fkFD$G;)I zETipIt!33xj@$sDS4W9fP>bH-Uxnn3dYIF;Dw;Hz#8B3S zL3l>8l%Vylh}0O-L{UHMA^OOjp6Wp6$Yz=2#$EPxB~xc=F|T^St$oq2ldyrXJqje^ z+}3Em)g-rCqe@yZ70ikdsP70kZJY9Uq19&&Rj9NCJ!D4If+Ts0-NIn9%BCF}7LT07 z4hT`I+pX?tBx=yRv7PJACa&WAq?X7QEz_1m#aBg-t%=uS%NW1KLlfxBaUu+i{Jc3J z3Rz=B{xI%YrYBJOp%@Pag|9Ek6WtbJzZu4M=$?l&)grog&jA^9xFvwlz$>N7 z&nC*Lc1aMJyE9G^b%FF>mh<<+S%BsZS1Nq&{ey5yn$T?^T|~0$b%zUj+>nDeS`X69mFXrvR;`r%Ct@qzzxw?n>bcjG5WJy9Fab= zlv?*YYbEopVJh7gMCG2rJ9pyc_#V<|h2$M^-^KDX-@fxoJJ4&Yc@PEn}z!3)Pl)mC#CJ+580Zia9rBpH)FD#g^ zruDgRpem#n!`><-mBtWA>VAdc0Q*1wK9%LHnZiL!Jg5k&&HbMbp%#KGal7y+9=~ z8#%HG6XtLDx&&R$q5^c{Y>5Rc$SRzbE}w?!VBr_vr<9J#`H1hPs2io#{86=w@JxA) zY1N#9h$pVbBT9N+#Vrdu&!J<;r+sOy~D$#Bn?w-({Yz3 zg&-Nhi$gd+ojXc;V;!XE5xI2e0LS4g%f-5ap5!IYS=tw`pUqS56Al+8AOYV*Rc*lb*jw=ia-yc|iGs1cd7HWFN9ph6bCKmv3nNZ| zk*s98&E(nk`$|rQ!bkJ*-+0^cCVY6E8vpr|v41^!IcW|ua^d-i7e18oUFvKvZS5vV z;mZNqC4)CFV=quue&K>ni$vW0^hTuxUkmBe8n~o~91Dv^1vr%#RoU`3%wZnDJx)Mp zH0#Zt(Aqd|IZ88VF3a;fpkgk5M_&ctoY#hj>h3s?5oblDO@Fr~#I=X~ZAE*XJ9H91 zM_ra^_UaIt{Qig-B!P`-kMKoAA(2NZgPMxP&IIB3KtHR&=E-552y72q4u*2%37st; zv)ciN=n!6OGvr3wjV5>3@z){2IB^alp93^NV{9Z;`pox!)C&A1oeZPIf-7zKNi@As z!^Xk4XI%6zYdQ4Pf@`@>-j@btTLGO1QC8z~doV-?mef+R=Ot`UjJKSRI6>M9#(T*_ z^ovI125C!q6?}|iLU(Q`^Lpb;TuSo2icEY{PpD0^0uO5mL4OxqR#bOA4{{-Bsu`63)S#>41ig;gjj#ml) z3*y_%9}Cb5F6M(lv-!*5gxci-w_b9248sytreGtK*YH018)DX4@(eg&Uh!u(Ve|!v zcRNg9s#p;go(swUP*8Y>O?&deFbWJz{g3z(p7h&w()wRovl~c*5=O1X?=sn+VT^mjd&2uF z15Hu*8^~2olP2~re@f$;zU_`HzX(Xs5O4k<#m0Ks@#^l;3&WZ}DV0>zD*s5jevO46 zZU1V{U^XeCYsnKUxHRw3qbdb08^75cR)1FT?w$v>l4+Q~bg0x~YEDjGh`d(`WU1&2 z+4JAhdxVq%1Hp3IM@+vk&Q@eA|HEYb$pvwU_IY_PVyG3#LV|n*E4vxE7?P6oQ%>3I z%uIUrWaKDU#Ywo2Ul4O`pO7A;oz;DpgqW6SpW(rhG48ckW9i->_6k$JI;q>DQf&O4 z^E0X>OWFBU!jK?vn?VwLt7Z*)$wD9tU_cK)2}27 z+L@VmHm@O~3_UNRpAX5_!hMTV5gZXQQWCyb)NlX9eN<=BBRJ}=ByY*~N7wFxOVhN4 z49Vx>t`<^4O#!q^lo-pk)l9kP^EP6WwU0@SHbRvXRdDFOYlk20fRf)QLof28bW-0#dNBCy+r~;Ou9p0(Sc$lJlBxTJbn|T`2^BlQgB~7*?Z|k= z9(@xXpR@JT?KT$S{h$}!LW=pPR!JlpqTBzlfq$Dy#GEP{5a%HgP%zQe7Lb^QIGSWR z6yK+*dzL;(=@T{iZSrSrcAX?GXRKvaXjuT!;I~EXXbK#VFXcWaE`gdpUAI--djV2e zO_Nss(3$`1U>5S^Q;+TfzX}!Ny)Lu2rAHZWIU*9h#988ZBuKmD>@wYCKogR*QFV4uIDw1e3-P53)4Ybg z0Vq-G5OBIP_T_^9IMVDjg|0mI@v0WA7IXHj}^=Q;eoDs_&z2};OHEGHnl^N@amy_H^{kt z;mYHk1-=}1X+nY`G1)X@Z3^2!=R3vXUdysftFl(p>~zb4dcqPTU*tMND*jJVDgSsa z`p>5G6kJg(DL?bj4bROk*PQ}k7#}Bo@`_QR@8hOX#u{NevQx$$E}IV3YJDPGT5v}g zx|FyO%T)T-s$hqcgwvn8TS)Cx9&31q10FSJbwAU?L=PqR@R(ET*UIe7>-=!zoo6_W zE3+rkK@oYy@D(?)`)a&owKm{pb%HfBNbVlBu3~-z#o)oslzVx7#ll^g5lgl0e#!pf zAV5Qlu5^6aomOK3E1Ji>^>Js7s;qo;dqaRln{lIRJVBv;R<)2woAGXzNdLXuxp=I) zR*>$yf&^)5>p`X19>Nm|?m+_Lc$)?47>_o^XKpYHfi~ryWGS(!nRDJh{GO=dp~9Pe zsEiL(vUJZa27%8I;2}kgA^6X5kR2N97}|#`ynDmQ6K(^g?#awgSu5&juFF7M|FfPb z$W|a5BSOb)V-8GEQwWZrNI72J490NUgMlSvC@X79^uX4S2xkA+3sFHX!ram(#d)F5 zKWsEf7*V9DP?+s(x&k~ek}eh<2OOcU3;1(THpIfq6($ zlt{|P6FTx_l4|^G9$#~!TU9#)DT@9H^4|T=3mrKDM@=+zv|I}9$%*UT(ic*ZM zN??BnjY+F!7A@?wtp`Y#9s1(oagTSk{FP~a2CMs3lCm$x)649M0;#-gKF+Sma2J!h z8k5eLu}{iM>Y#G;5vrY<%8U*7Lm2sJh!*@4Li9VOXgx^H^KYjGU)gMu4Kfg`o2^fz)d`Hqb*Rc3?p-7dWbFHZddzsn8~ ztSQPHs$6p7G7gNb$_vg$8kj>;(HVy9l&~nfnX0Gb1&&kx@?jcJF@p??iOO0KOU&Zu z8vQe)Hcf(ou}&yrot14f4gn(qLsvs=u;;K*sP}8?#+RE20sE;&IMmip1`1&=H(qHl zFwS!EffUfx(}}~sszy=wR(efLno*5cg^<)MfA|PSid=2+*n{%hapNM&a95@haDiso zX$MRZ*ND8W%g28;%<3@?1&V@=SR>^F%`3WsU2V^{G`x_BoY3IlQ=O+x$-l-e(oUeeWtWZTf1nSE}pAg<5<2L&WsaR6>?fuYIFC}j8KS(YWiZ^$ z7osy+=pybDO-*;1-d1Gv~-*y9nMd>k~3-Z(>+VM++)xeO<)rf4py_+EvV}^h-F>VKRNk`76)nAiSp4X z4!^8)JyvM1hD7^wv6KSE+eFQY#vxW1^~h&aG)G-QZnHomJ*i=GibFN9ZJV}(vKxb_ zRi35qrxzxle`C)R{tw}URLaC@;VS#IeW3;W_mbNbclnwyCK%(iLOX zEU~HGraKnsJ+pLXF^;Ud%p04rN3jz-3^g6by9kq ztc@$@In-L5M4;e+yq3${bt@Y+D+%WUpp?ao8|pPX)Uez%C!rDeP_zT&Hwj$?TlVHR zC$c__Yb1wKJP$&!pzv{1W{>9edaNvmZq0jWS5nu{^JVzyAXuMl%Ny4ZCG~f291rDe zr%Su4IEoOGw&UvArwJxwJuSo%5zn6PKO7WFod@XI_>(HaryOMua)(-@T4yGvs@p&x z)6xibQvpG2`|WYyECAC*2ZBx(faU-%D#ooLMps&x57o*&(A(b<(Pw6obg!*J%1lb* zgvNb;LEkyiNsTh1w-m7xYQQB{jYLZ7B~di;FSo~C}2&w z;6;>u!-r<19(l*?hb@unK6BneraQ**k6!7``T`^L16Art!93>*L?^5L7N!H!omc%| z!G&kP?*B4)5qR@q_GYBk@?jtGA+8eI=!g8DCuxLig2D4iyug}_Ab|(sS=a(O;S5z0 z8>tQfR%#dLcR(wBu?qf>)4gQRf24PEOfckgo8u`%<6~k|PDU)`1QYELsWTL;>b9KV zg?geN$H8BlfK96eFn)vnW^%y%ikbk%M}(I zBSO`$#OdoYX&hsgiPyl9iB^y+RGYWRo8}dDPCU#vxG}0Cy}UpFw?yludusc9(PMw4 zkT|ZXp@H%>!2CRYzJQ$0^*qvvMF;z_cNorJ6B*V<Nw!w=0(7>v(5<1%-G@h zDtJ<$-XM7^do+}tE)p;JLq3G8n65zzKq3c1lu@`^p@q}Sr2{;(DtZtJ6m z;jzqVJ`I{B<=zu&oh@uoS~TH$MqU|^yGkhlcLPmeK zl^`a7hgNYS7;c!ARd3s_TX{!xS#s+QK@Y_^~W5kZcT2#gCgYWgL{_V~gz@{V_9^7RR z7A)L;a4~XIj}URKTH@Z%(Tp-eTeX+Hy?+(~dy>rR@(jo=AX&?kP|nRSP^BMik%=(q zCVX_r_SCiv{z-Y98Ktb~UxGQ@L?T*3%Z)7muFd9+g9mhOAiB33fY&U|ed}<=oRFb; ztHV3YLZKz-HEDZQW7wlwy1Av;pQ=2}37s2p1S`*-L=7RNr+CkXG1!mc#G_>7Hxf=SPpGzKq?p|oSNjn zvdp>TA$UP$4{mB&$##}V(NmWPi&BQ=%ij7`^c*1}e5`l!NLGj1QHb@IdsG%Nv5?E#Z4?owyTk}m-|E+EFj7oCB^USHD zHB!2?d|8ZwA3XS*-~!m)LSLL`O{&?ncPazD4PJ>St=6$n?CT)-b3&y1f}}Fdxbn=+ znrRRz%m}hd1&fUZqSe~u#@DmKRF8=NfXIW>WN&s21{>Jcu^#s*fGC%%QmPgvb;mP~ z=pVu*L(Lso0u%8nJZ$Mt`*~A++QjqD&4Ip3r257>#;ju(bjr8^P`XCrz#`0_=4e_x zGi=xpLdEQ|_1cvtQ_3P$2XTecOx3dLG8qqSV#U0z@>8=*-cl#vQ%w1a;gpM9aaasY zy1z}6oWV>f)y5|~c})<0`obKNNL=Z#cO**l>>_+0j!tYmVSyx=Zd+MhjPI2ouJ#%; zr{vq1nc-kPLDUm=dxGf;vc>!}e%E#cksLEtt6S(_P0WW`Qfe^hlEhxeom*HafrTp(l^}DC-RPRg6?<2f~24k%J}ZR;X@O`scbbnaOo%@;cj2 zm`Tz(7JJq`$0%1M^HS8iPY`vsY4{M2si;9NMX6acZg;4q4P^LBL!18NMn-%zfl~$l zO?egnwg#OI*67MsNN*Q&+9si->lTTUv)sp^_p-dKqh#```bKk>E~r&S`OnryM#=WL zBQz*roseNkJfrhZC#kQ(_5ZB?jT}D7Vk*9M4=E!f@#dqGBHUtAr)qC1UR{w+ChmyG z9dg0g+__5^LVo|2v+2bi2i3E7|yDd~!Z!g-wT{m-# z&(8s~!u{m9ozlAqC;ZF`x!C&VZPHt}G^OJP!3+kRS^2(ZJ`;(~our0)4i`8?2_ z4L*I@Bj9ShFWf)0KP~%X?;$p`cRcMeOfk?b#hva$W61*r4p`%JGC1-s!yOK-Y=0t4#jcMuG&M3pE4;%>F0Uv+it zaYBVIvnT5;Rj<> zX`FP*Ob68d=ldZ#oYHk>yAIb!dN(M@*6q=En_U#m8Pl4$GV*;3`Tb5dASBa$wEoM# z3uyBZ%@&FaW8e=3MPre{IA_GFVkCbhz#nzF^Rn979mfP{Mjg-RQ&NI&M`@ z*J2noB`)Elz9h{{?@XW&oB!h^na`1gv1Ej*_yooy?5drt$3lWuX_?NI#gcp}eZnX9 z`9!U_5M*TTOofJm(I72ilUxJrg3#jW1IkG-^mTBLu&siB?p)yOc(-ugN%##sR8Oqf1oXS zmhqaryOI$bF=ICmcb4n?o5x9^X8Me~%A1#x54$YX$&QI5Dd>u= z(J^EUk7H|Z&Y^_OytFdSi`F0H>3$-{tmB^KtR@{k^oQ!1tCXSV)NW`?etjHO>+4T= zweg4>>Y5Ta4$!KI48%3XjLTJ|f|}D1&DbEJdOKbs@=ZKT>yc}JB4sTJ1r%Od@kDM$ z$PUVsj#Z48;%`}BV6tOFF^%c2{3?FrB@vnV&xL?UW(~2_=l!Ty{{B_#2Ul9$wrCte zcaLN4FIA}~v@^ks|GD1$rIg2fEbVwxI_-LpOlx@TvVnUNe8ERWAq~*3H+!o7*HB=` zWf^#2Qhl3=9l-a#^4D(U4Fj1Z+VZKs-~0iF8-cMN37IVG;OtLwL%V0JWpI?!(`%0;`R4V z_=c#loSflhE1LJ(Yh)VgTXJk20IdN1AL%79pA}=&D$lKUyMW2jagbIdn4fIN{m|ar z=A{nd#wi!lH{!Rj$-GqlIiXEV7$KcPQ z&3($|h)QmRe70EU$E-s~+*qAZFMr^|^FGo*DRlKyuKe$c()7B-Cy43>Fmy~AXAYVP z!(_92Y+>u7n@wxdq&J0x@@iXffqm`O%FtKf`b0jzsB4AWeh88I?}d=26huGuD%>QCYZxE*>|A5OONRvf&ECn+3D8W za;;>N0r*EQ!V2@QJq*?AW));gTGEo>H)cDqrgpB4?3~mhS{FxPuaLBv8BsL4aPlHA z2fvH1>)}`mXM5$mfJ7eccru)ZWlz9fK|(ZsYWNi2v)+Tj)5`JD6npxa9hBMEg8a?l zi70nQ1w%k;_23Pq@sOyZ_EMh|9hg$2H9}3HK{)*V-k-<~&ZN96e zl*qh*Iiq0pr%WD;vuhdb?lTOq4APt&3K&L5OPQAe&q(&ecBQKkI;}zLthmhk zul%UW!r{Rm@PYKg-4d|k(R6KaJ80N|MQMXitgsmfZ@0~MgHkCw9ujzK=-sb+=q+2OW2WXKhPbD zapekt&Y>lxd4VPi;!SAVdd*!<#B~kuIt_4LcXr1A;Qg)@=I3PVTdXHPrIfLh5zJ($ zfF;3_YD=>moG)dK#JCkW0ag*I?ycX~ikH;Ws`uxc`-QyZ^x%FAAFZEn)2DeK+Hi9w zh#5e`e=_pY&WK0X>$MW9{z9gvEz?y3D68mnOIUbmWq;pnyu^K|Z7GlD#xc_7D9X(Q zlIR^D#lq=M{uC;z4zRJ*pqGjbwt@x3I1{DLHXFfQ8N7+Ln(-@^&(s7I=dbDL;+3KL z_Li@_0u8AM^hu{#yO^CM+A*yB0Zv#^+8Qs|#mdmJ)B*f8AJb)@ANJvZ&kI9t2m$oI zUM&5m2*girR#6l%`x$*)s|>H9KbAy8!E+fD)=Ky{RGo4qQ6UYF%@s<9fdMAppm@f) zC!*9icEezRRKBZ_%`-dgp~`z6mZw3%F^+Kxdh9m^Icw%!IzfS_Yv=i`JAv-8OXBa8 z;6Dg^X1!Q3M92S-KK}aD(R#{}5m-QlV|z;%zrl#!lP#nu2WwFPWP%8w4_@ z_6X>#)4eAf@`e~e3`Q*598%uyn_0c-*@RaehpM0$j->rNvpIjV5(JR2!}B8^sYb@c z%-$6dRz#kX6fo;pP}fG4GXZNi`IT`&1C%#`vs9gFp4nucNXpT16u0PQk|%^Sx1%-5 ziFwAF=x=$W8euN)m-(_{U?16~@7t$lKZZ*i|YC`p=EY18vj`j9u&D zG$oKS$(GW?Pho>9dXRR0lrKqVT%d`Bh!!nN>QmS+ZL7w$Xo|zZ>w^bz> zZr#hL%!O3%p~FB8^#K3vTh?lO1M>aMXp2 z(D+7=@&>e{6Il69yQ(E|SGLzKbnxjt=6H{KPZYc}PC74rh@IPaLyB=R72q6=Yh$~u z{a$(b8q#40@DNy4|JI)S1~G4BGB){7up9DIVhZv(ZuOxdOQ6GXA#+U8M$OU-bIZ>v z=|~wTfZ)#nK^{gDR~jFH!9+(VIcm^ynoyS5Y@Q|~EM&ALo)#u}pT>Ab2ZX^e1lqYK ztan3Uy?iZvc?;QjD)OX?4BBx=FGxC^5nJOAEFgqAc<_k14J7C&OHhotl&k zrT0M_s zCyF-U@`NM8prq{g%s)a;r`DXu^kXP=z(jN@&r~JkJUH(;^<%ztE)BjGMYv~^7`^Oxny{OaTCRHx{dI&A?7L;)y}v@3DMGa$m`$?j(JJ@u$9Sj})V z$YKl{+Xf=I-DNh+j~*DR3PD72Gn<;?lEO-xi=zsYreGF&GjsQu~;Vu8u!`4_-D z%Y;GpB-2O{qjy6DQjFrvC?u)DU; zEXIYYmd;Zm>a|O{#D9dby>Z#--YyG%8Vg5~5H>-HIfwF~j%kJTe^(!~{LnXuZ-e_a z@3OyS8IMC-pan!!uHR5xvs&WTVD9d2qa5hRn_kYi8IIntYKXn_6{s_)%^C@2^>jJH z3x2aX!hqNqrsa;!7#wFtRXZ}O?5VL3;mck7HEN5I-tBnhVfQfxjhxSXp*l)Gl#O3> z_fbL<3wjZR)ts#O%nbdPq!oQLn!IeY9}EvFT{ZXfZ{z!K$cZ7zn5o&swdedXF(yKk zM=aYxKBA_l&BL})=xl$n!p19J+|7AnGMqBzFidbu+85LN(mxeS$S;)7t>J!aJX|o! z?#kW8U`MVA3iq6g$Mh05{C2#WdcH|IyrsHeH>p;;q6f%CQ!?B!tnz7M7EA*uBTK2{ zT2eX$_$FR!U(r+9;{T@ltR{Ai4F#hbxx%+!FHP<{p7ir8W{us1*F*my?N)@_jPE&c z>9)=lUyj(#i7d(O;7HdeDXz}TUcIOXRO)d~b)=$Ti{|h@nk>PGLuU3U@C;-iJc)W=u&?u z%|6^ErKax?Vf=W}p7?+&h@=7u3a-JDXNk`*0&&_IYqNc3UDM~!kM%`}hUO?;?&awX z!P-sel>n%5e7$9hzHKn&pv4TPmx%20n+C{l&D3ks{{MG889(;i&o~J^R?Ptf4IcKU8-Y ztV`l`55)JiO+n%-#Z2R@pt?N z%7ri0tYlOS%v(Df4@%okX|S%9v#0b|YO&{Fqtl)TaeKgz=;5p@I>5}}RJu;bPpB2G zEk&fQN|N9kZ+%P&A#&M6Yfw&Y7bUQrRWO0>9vB$wA06|n>Y&Z<>+-;8BI zWSllu$~SLPjYs77QUe6$#M5Azw-60~HklYyd`O%%yi)HEuZ5-}BOWJc*>AdOGZe_c za@gH?(P;N(xMJP14mC-Yk2xpvb>0VIOBW`=c7pjbW9us&B7EmroSBIL)gcL;qth_$ z!dN!Xj&hBa*KCU4JDzu+!V7hOvnU95*K_oxTKLV6<==`p@LitPj|Sxj?2g+cFbT~= z3!jE0p%ncWN>I;F<^59_nZd8`RpA%ct&@uroY04kC;iX&awDM_QNf-3G4M*T3YdC2 z*8>1BM4N1Zd8-$fI`|ND4O4cLVFh7SFk}>I)UQUCcn?QyhfMU6k@Prn}(U;`lgy+3XhSwUrczsIQ zz$mg%5j{k({dt&9t)cna_&E7*FCdabFjivQi)uZBO#>?+#3aN-iE2T^ADRx61Zhk|fpx@%s@u%}x}5a&;e zC30a=1^^XO7)+)qz^QBo>Y4!4^byBmH#@lp#-ELkxw%8^VRBeTK*=niF7K*1*G(y{ph)!R?#r$>9*uG4V*UK2y zgdUHYmxlnA)VInjN~f(EvXXH{+OM9);9dlB^$dHt`>uf25IsZWr9y!*BXKBK~Nc%}$wtn`q`q*IlNPl$9Awji%Yo*ObC5!ntVQCY);JHNx zNf~XLX8{6K$2R=(1)K#PM2yBR=_<}*{+M;{Cs8#yA4T2`y$*>{66l z_*dm62MZ^1u?RT=M4~8njnuN8IXQyK_(t+i$){{qS+rADIViF~b5@ef;Ccx**xTac z;7^;Fa#Zfd2j__~29%e3@>mq}rJeN859rKoaMnO73P>&GVVJ3Uw=1{PW5ayrg3pd^ zN1uJ`Fjc*0g;?^dTw39hW+2gEZ)CXoAe&!wx2f>=>2Yw&(?ANH$jm zlY)K9`q2jt>G)Rhq9mfw+>QsIb|{M4veXkTFE_3ATr9`97zuLV7XOjo29dbU{B0`Jk? z2#Phkek?lM^a;$gK-&t@X&P7B4=%1MMoz{;7h=)4yPe>cuB8X}p!8@EYa|3+(Z|53 zn!@Unv=Wo;Tp0@Eudd9Qz~+caAOgIZ>u<+S?&XOx1QKjB-$$N?Z|AkU6b;87z z$-bT70BG*AOV)Eo7-%}BfB5n9HX}Sgy}ek#mrFw$>j`+N_eJkFMgsCy7G>Ln7L;a~ zTwZ{&bmNCJkaOm&^^P=)E811T+hCl~zB(bD!7bIldJoP#G3VY8OAD z^-tE95$Es2(Dn_JmPn+ywm1+CMa1gSn14<1={M+9go}oQrFFOr$ zkh56mW+_`@G~GE6e)}*R&2bsWe?;XR;2J_e;i({(HN1R(>3aJB% q#expvu9II1=X{Yw;C}1<6~wr@69-LTt;1pCYmykI$y(eK6=)NNbL$RT1^c$a2-IRH%VLbIB?N5X#WwHv-HjtTupR z^{Aj?OwNBp-v#alpK__SGIA2fU2w}?yJ+rozZ{LSY>s7v-1b@ZfVx5!Pd%`LSq^ZI zrny40g;t#btzaeob2LmI#*2`^m>Wb@v4uY`LO{1`8M3k9Lc|(yJvI}G)obGa{7>?l zURVLNVC`S7;o75O1=P;seS@V&B}3rt+NXkbIajc0^(L|Of? zq0v-rkeT@}nm{sVCQVFhN{(23ZV`xugy*-i5N_W&G?4=%&WbS47cQ-sZ=8{ie69lC zVLSh17PIixvoi}Ae!};3cI}uQl$QH7mDT_8+ZP^*`d9S|tZIo)Nv(zjaRJ_Q1=8EN zgC1OGmagJ~Qld%wOJLCzBqxT=Np{X=qBo?o<|h!?^~FHYZkrb2l3%KCTmJP|FTi|+tfk~ z0%wc#_~RqT(Fncg|GGE==|p1#qx(%l<(5KG@bf6wPwfTQ{;sN|AgEdH&%QbpJY-C| zrdlg%rSD2Fm&hTqh4ywve9f?8va}SsETe+!VQc;ym22giLzTx#< z0<)=s)zV{#M3tI>1&+x&l@YhKo9OEJlKJ7#s8B&-+$ah(P}*q~$XLd(z{O>JH+(#g zD_g(GaO!EZPT&(%K&6YvO=lwyo&N$J%9I55?$-rU`XxY}Q4YJ}Dwzj?oZsNgC^vXY z(A65iQ8PvrBy}0bGDoX^dX|qtX6!V+oV;G2t$ax6d7PdxO#1424Via-C}h=+-0tf6k!r|umBTuQ6DuZzwY;&S*#|9p^6YuFMvL_2@r}BZ|tTP72DVpN!itHR1 zS=3z%D9Ql_am>4#%1*6qX3Eo+Udj{%1KGzS&?kPhr%xh^0cwj3pk?Uvyq+`R@?hmo zT)DS4^tfv*;LnUcr^%o9H9f9U+)&^@Jk+b|^lA)FVp~3X7*#AUGHLQg2TI*D1&Ddt zODht;VbU0E0rE3IJ>-%|1t24RbDKjqNoR#<_a57mJbN_eXbx+}u4D4C4z&O4f}L!M z&WJIZJ}P0E{sOD2NPnYs*`)GZZ{#J`QQ>yB1#i$pTm#UyQjvcVjHPEYs+Xkbl~Tw} zQiPp1%t;z)tX`VNH<@4Qz=5zF89+iBFTdNnE` zR{yNm_y%J$!nqSO7RC^LJz&hlb?6%xGG@zcM;pzp*w3Y+((bcH?{4p$+6P6&pJnQJ z6#qpZtLRRY>DhGGO#h)vwvyj*;olz50W@9zDgl7>ef!C&SZBDlu~R`? zHP;y_j#9MB*H3Bu_jW9&1Wv?CZG$zqabk;A$gjOdb6_E40z~h6erWgIw=+_|cFKT# znGif-U===?rsb@I;1kx*PqSZk##!XBUQ)vcw3+}UfKAM*5}Y?Pi3{Jyb=4{{p0}>n z)#1vGblSw9z#|gCmTNO0vuEg8APf$=R>6BqvV(05g$7=*iu@C*9ka9-AHf8Y<5(dc zZa-QbF;A8MqxCrY;(+%-6G<596+B4kFt5w=)lY;$$D{|qcG+nQ9lWr#wo*s|d2SjLUbCI6=rk5AIQJMyO zQ>dlA!Q>S}QU=pSPly&%1F*%NPbO>$V}mY@hmTZZwaV45m{h#;NuE|m8Y?b z`kPS8i(#@@InuFoB5lKe7MmduF@5?a_@`{7rn^~9G~PLi$P~~LgysbfjLjbiG2F`6 zfOQX3l3X26Enn8QMP_R930?)he3qpeOYdss8m6+aWY;WUfUfigiZ^#Tbw&&V5SvXL zpf`Rxp85HS+h-?r3JGRJV-U>dE&e1X|EzfyRq?n*Ed`XKKlV^Y_A$FSHbpsj>ML=6 zRFv@n4e!clm!7T&m*uD;(jdrk(8{$Ipe?4Fd9JN>(1NDTG#&C@eMmYxRRc`mZpIjh z&mDG4SK%t;@8*J}^Gi=1j1oWpU!RR`#sZbSV4_LAT>;OvqPosei1a<-4F*qV_O!Ee z#Xxat5G=)VQW)D@O%Z9%ZMmcp20*P%ts%ehec5`b1@nNy0|%NaF_;BVKs{>vG;ZmP zB5056#1XNW@bJQ0h82Hl-gKSkqku+M(1bb#U4X^tS++1F_R*U?NP7=o0g5CO>;<53 z(%R-JTn&DRKH{Zh8;vv1Qztomnjjszx`U^~=s5q-s5#&=L4dT0nc*L4QOpX01fEM6 z{at=jc6V;iW3XyP3HV-px|=F@+r==`ut)&};}YVP#%t=Sc2pFo^dAJ0Q2C^KI*zKb zH>?Bq1>84`QXnt1tdj6>eEr_2ByE7(Zf6`6r7-EeT(dwVEsGIC<&@U>o4Vj9l^?rS z02S|F@FTmn^)~N{u9dDI@OF8XDc8<3^fvYZ5$^~(h65D<{an9!H8N3((f{e({tC2k z6%vv<6nJJzoKR(QO`gjp>9B?ci&%6Zqj7U9bOpLiAg(~Z5bR1~3`Y(xZil7a(_&Z4 zNOP^47$P=j()n`wUvHwFdx}r9Sq?ZCfOm-Lpp$ni(o4`;Bvl;P28LtMq(b!7;;wBR zZFCrv?X-)ipnkLNQ|`ml(Gz5%5amW@8VhZe z7QCFl2YBfDdvdT(hR+E$n~kxbQ%tJ@Pmn0*w4GlvZCkk^HkW)5cpGM<7gPNHeD7lZ zX{)QW(@Lbk#U*T_qO!QQiBSM_nFyY)7eI0&NpBvqyL-wMXg8_r_?15Fc#t`}z0uS9 z9nOPY6jUMyt;|%D1k)gUHJ;!@GCz8X*mYWEMVS_=UU#3XCv!0{CfjkGXy)A}`(rdUI-8_8f~DaF z`pFh2YpM94}>`cG+E=z=9G z6J=0~)LH@Zvyy~HuoRw#TkltA@TH{lV=PQGq>0S+6`xQbH?PAQ-m1&xuY>N&q2Q^Jsjo(QNXu*+JOxX5W)?zUl8fPiY!5~3 za+a!Tszt-u7YmlT%GMkCX2fZr1Qym|f1;birD8T%Dl7q;4 z;3FIHM#>GtXr!;zn9@^@nHahEYo=DoaHr39d5{?4^}(Px6D-%T$Z!7ynZr#=WX`uv zkyQ4V&N;xFF7lj>G0`a$=mx?QZYTQ}W(*q5@4F%<%$~4Z-|Z3|9B@05of}A7I0HZA zQh3EKW3W~U)3aaHJ-J7ZVP^@D zi!z59Bl1rNlW|*ir>b4eP!Rp>E%`7J7|1$z{0HQ?q`_ z4EI?Vwr8z?G-j*YB34Cv{yj(uLODH?bcjlwBYPX)Rm?E;^sxsdAVcSbQUXxIk*3ru z0?_}_2T^WcyTYsiuPJ>Uj~O0YisdNe%+cmS%lp%PfCW{q&E4|_WQ0*ku^fuNinS$! z(iz?sUHB;YvLf1R{tME@EF+y76&q>ow{c5wuve9Q1K`d@On>uTD- zr!hv%ijq(b^49V}(XN6R@~_vHwynKm)PJY*P11BqamM3KJhZ3c=@?RSQc7Rr4Xq3z z2Ab<*CpJQBcq4Nsi;Kw%Ue`%v803<^z4$pEq&tcWU^wPZa|&k~H!RVOeXKuPlx^+k zOs04W0pJMVSd_c(6@xt0E%>3ZC973gMtYLb?Z&hQjDb?`?NrjluMhDYd)N-B!)sG> zyt5CkD~|ea_8>mcV5&w76~h|Q7Ws?P@)$u{c|fS_tnqJKY8Ze)Q4$~%J?dv4LdYl? z$I6_-=)gqr|5ddHRwPYwY)59@3=nEu)M1&cQ9-2}G#9=QQJn_Aq`KXC-$TTAm6y`K zZHF>+txDju57fAiTM1rj|NWn{oTx-v8g4mh9p=zPo2LrQcw0CM=OA@+{<3nYUPvE3 z-nqt=&zK83USp%Xe>qomEdT=%x2Mj}MLHpX2Le~UzQIQKXx(Bq+*++1YrU|iow@1J zIG<>B$_|H^i6>n^aNU{CtZrH4E+3DQ`^OeDDeFghFrXoZ_~&-dD}1lzVvE09=ac&2e}^Y;iSYH6I5bQaNHpKRXJZ;lkf^FxVZd>O62VYO|AZrMV zb<(J$csW`%OV)V0t0fEUp9ORu4ZnTrGO&)%sIa#fJOlxLNh8`q;T{GMbwoDkdhx2I z-=MC>)i-4dB5_#ATi{WYQqnbwl6>D#-F+L;@XS98tv7v6X&&Le!Zc^|DD0ikq}1A8 z8j0F>_YPThaM3;>Q4{sPIC;9L7`?82H!U?g!Pbn77Z%hy`LW6kv>P%mFJfd`H^xAc zL&)pVI3K;AV2G>-D~ZXPjkr=GR$X6ZP@#VO!Gwh4K69C=zW`{eM%pb2`?pGX0Wz_W z_e6|H7)^3Qoe?3S;a=SnYpBc)G1{*{^<80|Rz&Cjce)+T^mDWi%UGsiT4i!`_ zAYhEkom7*N*EvO6o1o~f>jhTS8o$6|;X}13gKhZHkQJR^Lg}9fL*~QFU!b)@PwOeO zvx-1IWJcpe>pK`VK^s+x+67eHVInjz@)pP+i2No-Ry%O4h{b5E@{CevbRKPK;Xs&Nv zfREuy8pc}H7CeouDUajO%dwr>r2N3QCU1U62G7^`xa*Jx<-{ksShGJVI-w`xnaPrq zGR)eGI@@w7+@TboDN?iFwrJ9K9`)Oq6CdTU&4?)SroARF{bITjmD# zlUa-n9o;b6lvnM1&XeEkZMZ#sYrkp^6Q5eWBON)7(f<;uV_bQdKMP*@h7Ox)*FPyV zDcVVH%veBg86=5g>!~EzA|1h&GXqlV&qd^i4Q5a zg$KBstP2bPI!Ye3gquU81S)?!hknBut4J+$VM#eU|h8Bssqjjrb{5=0p{FHv#=w> z2iE#0?n8xOqmj|@#(A5++N*d~ajhUqn?@*;lPaC?H@FOXv_sPB+zsI{L45~1IHo00pBCT|PZ4p$NANR<{}ooFV0enpuG?giv zr2uD>iGFraUUxqNjs<^Fz!^7K+?|^FG9MS&s<(Y)(wP0jf9VoEC-t_q&4V*B6N%YU z8&|xyP>e9Y5ai8i@Fih4O_sS#p(SRhutM``r)${pK5Pamcg8^hqf za9DE|$bLV!XHPHQ;z*P*13D-RAZrjSz!ymf)CnqkoT}1i;NhPW1|d`QM-vS`d^}Qj zOZL(dTmYZn`R&QL%gg-Em%z1(2cA+(`=Cv}(Rcc9sIdyao31))#Hn zTOtooyUtC?3b4+lCz6SF3ev`?HCeh-$l z(%rnloV=2ZKgQ>amgv;A*LsLY9Nl6_{v!T3eD~WBJTt4=Dvi02)p3tu zZ}Gxm(4{_z8YKnuo}{EDxlbGw6U^x`m0A>9pmaA4>Wp`JgUeA7eRLuHNpV1vfQzw( zLqbHLrbe)9THE0pY%`>A7|#^KZTanz`OA8mxQA|xI%JH^hC6}tGnum$0r<&ZN@@Y} z8P2p#iWq>g5^EIFAsH(b{-z`6vNiW$Z^+EwT0?PcH;zMpEWUZDINA@%c^18MHtw}0lif#c&+ z&(q!-K&0{$rt=m5=f?@uNg9U%OF13OsnFU(WNv2=+>bMNh1AkDDu8N@WgYLhtv^(B z;V(&GC)0YvfRQJw!B_d4fvs`H@A>cwK*enJ>gHY`l$Avy^LfNjW)1KB)+H-S4ayG*9YA|Vlsz=p5MEh zo_M6CA$>`KT1wmmH$iZ|nou(GUSYxp)qq34P+V;QdDq>)!bqdxxfo2k-b>uYZT^At z+a)ebG2&vj?fpe7z&~|iL2~H=%8={8^XV)(CIC5!c%YcTc?fkv2YiO zIrOd+V>DA%d(hOO2akY;Nfs|vg>K#v_y(%=n7)=I45!EUS&lrrpH{(93v!(Okn9+k zT#NNK`7R-+1)MXP%6!boJku)}6=^sX&+@uFNdnDM%J!z@X%G)kIQ~0^8>`6#AfVR8 zyVh@VyCzHe8$(mK-zpD|?23M7`b(CVw)HFmuJI?)jjpgYM-*t8WhTY|Dg&<*B-+B7AWRJ9VO+QQ1jE{XXw%F$ z3{!z4&H}eTo7hvo){f-*eSj@@J%iyH`%i6z9i?{(yC*i-kPl~xzHkESM-HF(88$em z$S~bcHpZjwK>)n-rZ*@5e{7NPaFXgpuV}1J(?wj*wmf9!o#vUg+L#UShhyv z(SUV*Qk!X^qsLqC2KTA---$0p zl~^9`hoASOS6fur*;e2I$G4J|;briKp-BAxoe5T3h}d)ZI+g_hz@dB6V{~lWs;-gV z%*2j0YIvwB+mrbmj<^Wf_STwNT;qS$cs*MqT#14q6ghWN`v7m(ATzj;_ zEU_8rS*DP83Xng@piyk7VIezuyp#n`s8oO+<7vNrvDU?62;O%Qu`V-Sryq|LHGEzVF78fY$7B-Jl9xYb5#C>jHzFEO!C@$L;JuzCCY;9(a{2;O@PEUoNjA zG+;WNK&PG<1|VM%lWC8#&xDQF$T%nh;`C&-mR-j}2&LPDgz%7T0oq&~Hmd3F_>9h^ z+i+X1s!ty!P<5C4>g7{%Mi=y~d%3e-H-pd{2gm38x`F5fngnpC)b}l?pd?|bM3S3@ z1E>cw4aCN}5fY1$gLq1Z0#N;;K@Z*-b-0b4AU63j4r#&13F8Tolc8>AwVQyemzP<{ zbLAm5jt=Vt9Zzow*QH-^XZF2f?mhk+eZC0}`ZPUq$~fV3$vXd8oCXFJ6|#VEcnJKu zpH#K&rMEJoo7GPdBzZ&eZf;!hjkfLKe(TFMHqRudeysz{w6qylnGpn&&JKP~L=u>J zoH(%*P(c?X5_h5ib)lgNtEsvq4ZN;+4Lht=0x?k+Su0MbbuZ-+D^+- zM2<`||76nmv5!>s zlTiFWA2ip1agE2!@#BG21)s#a?8RmawB#RKE!SE{jbXGcl$q7ec0JVIf5QcIKjbpY z!$+A9Y2a^>-LNeZx0eS z3;Lf7`4()M|F2#ybhoZe)7NM!PQeGRrX{iZ?1Lusoq313j}m@dU0Jn-nX{%tjP;!n zI`;9Jk7+kb?jV55FteU0?{R6+evK$jdSsQSITtV*ij?`FU#zKC*9UVPXL($>rzRSMbDR9Y-Ufo+t#i;tI8e_yce zN-xwdbARM*;};3wjdWHCT*P}PAqnb%$2icXr6JIB*WafG9kh-!TtI_Nej#wqisye_ zjcEx>Or1dhts=qza0h|H;aJ%|0){wXqOGOb5!-(}X29xxBDH{*MBvwrYk1Dek?cy_ zQ~eP2HTesi$BJ^SE`?vY>!aE$(=vX->y+;LRL0s0m)d-Z-D$ZVI+mzv9hH4EB3J*+waKT2ddMe!?=5r$ybi$zS$2v+?PGuS+a>la)T&X=*YGIx@2EA5C^xJV znLNtBC{3RrSLW~x*P|!FKgpP?hP=Drl7qM!o^};QU5kyUR5ZMdlUAGS9aZ~CTC^#x zKvvF8L)FgjMRfA_@lidm*HqTbi`jYdr1jaWi|r{a3%t+Nk$X~MzKH^mc4^3g0}Z|= ziByDEOajgLcrWk@2>F8 zF1(QRB1_$^aDaHtHpab=@6$VF+eNyK7J{T)o6LoKrJ#GDGmnfc;jgqUh2C{j-9}4C z7U7UHz`1AU`g!Y!7N_zN9H5HE1l?|$gI z0a1ZyoQmI)wfNso;U?v}tQ_+?J4$=ZQb*s4An36>kmPJdUvazLqFp1s&0*P2Hen9n z$G)!6b86uslpbasp|$7Y%_EhQFbt(06{k#Rf!L9r?X;_f`t!#BgX5wC)RYc|>+}&6UF6!; z*aln&<>HJhI-J{H7X0JG&LCWF&T#7Nbx2Eh^f6_kTGwb;U46$>Oh)KDZf7;M>(!fS z&5$)u2IJT8v@xI9PcDVOc(Jc}VwkT7~oQ$I`AAeM@OTg9qTJ_*Xmwt#x(xMjP1r zl@Uw7`~Z|N4jJ8Ux;AtuN=;QE4(jl)w`K2wA#dG>c17uKHGqg#ffJlm)^7V-QR*fG znx38s8z3cu<05;RWz5O;&+y6^(T*zQv~M+CHMiWc2p)IcS zoMpu^2U>nBL#TqhzhSs`;`FI`9{Wy2yKk#tyY51Zw6yVIqtB^(GyHRZ#c)3?zgcVP zo!3zBTxwajABTyJ39U8-;^x^pe{~u2L0w0k>a$as@WR+{5IiMpq6o`g%(AKq8M=2o zTyLNO$>{dmQ7fA#-KdBx^O&P&rNHVA*Ivn-?9Q1P);Y%a1ZQD3yV;!cJs7#+LQUmT zD=)?gE=TqiS*=%F4oo3No2UV?@>8IJjoM^(d7rFYyGp+TXQvjBgWg%R8U%nY(&dVL7cPJyGyYe36cza@L^zm=HIpPGKK5h>pFP z1xvC~NblRXravP1qw%(H=7p2%?%y!-y6JU(Iq*4-2B}u zZAU#+c$TnDH~Z5Icylv4R{ely**=4&1iVmC1Gi;N>y870F+chiaxK(-N(g#4OZc162Do!xN;G)FCOzD7~t=_yMz+_C5zv`c4?3Oxr zRIeWoA?OZ8zx-17GR_scm#ix5-*rF>&XpV;LW6L&jQj_PnkjLfP#>kIIB!a8Ndhu> zHb*k#yi41rx%lEJT)g#^;x#DB`MzyT8~GnU$8s&A(r;iMDP7TVjgAp{S)TlPp8Ndy z+=n?;ihpBwWTh_~$|z5u!L==R^d;|u5ISBvA0D-FPy*X_`MTe{8lyn|%U^yE$kb06 zb5%I%Wzd`@^~-zr<)^qJWbAML25n$NeT|>VQ}P-YQ>0}eZHRx1z1Ro~xoQY3>u6A{ zf9X{@Vol-?rmT>$E%PSU-j>^7I4om)mAs4T>7VWyr0IXAUvxz%QV$xR=77wnYLJqomcKd+PPlD-*t+bbRbC#hZt7;}&* zEWo9e>bdGVVBEZ~&MYD1m8R_Pl_2$yW2i++F6O=p$vdjFF35_PHz?%K+cS9yj92A_ z`8xWo-7O@=H*WlJz++xf9>^YCnm!|(WwiYS-1FJx=99ka23g^wVl&-#JA>j~mB#P< z1;|?G3DVS36yJxtzB`gXx5~I4XajYx^Q6reMBBztbVMJ|fzEJbqBm3=LYFA(BS0Hi z8waRyxPD76e{01dl^vu}8PtW~p^p;gU)?AIGum5nWw9TfX6*st-O#o38~dLXQapz8 z=JmrW7XiV`Bd_ciN?jdGAPDo64u#UX^RP;A@}8*1&?|5@<-ODh38@x2dif84J9p-Z z$XTCy*I?0b*|gQh-L#Tm*5nVg@RBJaP49DK%z}i*#@ZfC*5hB#G>y|Jq(8aD@G`n3 zY_@;mYtWmXOY#@0wuPMd2+z-A+;J~a$w|a3;MlPiozl?)nwRM(5A@ur)= zRO(Ww5DljI0idD$K0!cppu~8KUT{95hIPK5{Q;TRU@n)1h;Ej|k0x1AbW^o%7T%_Q z?D^n(0*#Th#3Ldk zW8};l2Y4vip@g7$5%*K@cMlVJEHKy9hXeYsAlrTWiA*-1Mm9+^W>%{Fk3*-PrHCqh zDyMu=0)88?w}*^* zPuNfqb2Q;;o=Zbh3t`uDD^TggBIa)NxJ6~bCn!I#+wh0!+Qi^Zu9}s#tEFrgEY^6Q$cUh=dB@&IRP@KHZ@YrPX9fwS-~4)nH9*ppb1hxmt55LdnmZKC zHSDrG{#z`~YG2;D3Xm20o-G2$L^f~qBBK*FJi_j@tE|QiiP0zhv;8OxwI=!%NCGW& zs0ra_J|OIp3%JFOKi!0;#M%1{w|~B_kTSYUikB@f88zB0`4a-3J|I~(3uV9N9+~V1 z?iONn|4=Dg6bjGDCFH{wjdH!>B}wGrD;wO68FnpPpT2#uD$|g-5!W(PVJ?uK5tlK} zRA@87@shD`$;#}sT~PRl#wWLSr%}OCFGpGDtd-Pj0u>vJ5tzjADMqQBS7G1=m20&P zMQXQYNdj~s4`&YVZC3j_UQHiGd9?ojmkYnLSpvbb9&IRF-W`8D(xGd>5>!H9Yr(gBc;KNXfWT>OK7P`0I{z>bo3)|sgrAU)? z4+LqAIb~mp^K9k*COS4CTInp9<_c0{p!wb8DIW8{HbvMDPK861w|npYfX&pwK7Bl* zN|^s#)3RX``v`%U+Rq;luZi9=2L)&s4%DteE0vHw*ICdv zg3kP1Meo;*R|Soxw5Z9J+t^Pm!d^#4)8dLTX24sUh8@0jR?ck0e!;Msdv4h%Vdm9{ zT3>rZ4wyHK2sOmNwPGBsTSareK)#>JIq+IEF^#2sLc*)^t|~&P_-LL*<}%1`(=}PF z+N_P<$^^_>`cxh-UGArW(}=n_;Z+DYseDn!gZpb^|7?fCG|Fs3$dt}T6cCmu?8&4n z9|{o5#u0u|r!Hp;lUY)?1zw1I04cl z4^S^|ns|%xUE4cz5^T^@k_Jz)%FqJBH(g=$najv7%tSk2Fe@arASpITp#l|iQbhNy z*RiMN;KWB+oycB>x*L<^v0NT;K^eNfCs3DXRV1f)dfA)r7^%coYn$;!fvDh?CV#=l zvh9v*DO!wTOo%Kh)x&^l#K5mxN+W#r#??OB{N=|B3*Gs}W)D4>vJJ(6`-5CxlE*T4 zg;9z^M&U|jc#BEbp<&q`tSq{jR`?i=RHjII=9!Detx-Gk%^}$<+MS6{GXI+94IY+V zlQ=XzEY9V@m+*L?WN#`YP+hjflL)a0-Pdr}H>^acIB{M@kEM;z^yf*H@?|UcVA1_E zGG`l#eiUEz7d7<5e47Xnpi-9BNpLH=;s-U`*be!+tCRTihl6?u`0_15OKq0?JvF}p zrwkiR18ch4#0FSdaK6{h@UZ~lt|P=r4m9+fUMj!rQyWof%o>KlEm+^|QRz#ezoKxF zmC>}bMR>uHH<`#SE4D6)q4|#-9Q9CX|jkx zRJD#p>26C}tqfEZkN0X@rB6uB4^fMb1LvRy=;H9+`~0JN?A#&^YH;AC4C0j#7$VI~ zg;2iI=CEyf{o0l|4d}zE79M70A)4Dp;|83c`4FTp>K*gm<9A%3K%3apXf&OfiVj|yAJ=Em2Dal<|gcgNDqBk#V!_{neW(8=m1UsNjE=RK}q+r zYE_F#(_9R_(DzE@#5UY>9x#h_ww7pA&aOS$z`W5GW$M^i_2eaHpjt{lZ-9prkB0ms zIwIR5qNXDPe&jw@uw>%UBfE~OCU}y$A0~Gj@BTzTA(8=aho*4QWBKx;r;so)@i%81 z?jOlC+40IMQ^YdLN&-H|HWCxZ1`QV?uZlq4Qu;=8NjCnVEi~Cnrma^UiNKvL-zj!- zdQl>*bK*x-nmL7$h26x{+}zyIXhGcjA7zSXr&7?0rl#`^kNVB3keYKc$yjaygP+u^ zH*h!p!o?HTW?n`akFmRJ|6^HE);`4DBLDn7v_aG4}JIaglNosW1R5%bP_!@ zjSiP)bCVi+E(VQ+?g03jqw`K^I`29vDy9{;De){6G0Hv=QM7He>niwFGY(tup(z4% zLXQ7$*`a9`j}|ov_?2NE%eKzGSFg+5-lc)>1@Mo2u?#G0;l3t!y{60Xp6z1Ma$@pbZm*q&Tdp%=3t0@gLy;|3~! z$1E9_B&lD*oTAIS?*HhQyN)COk#$Dwarg{s$=q69Y-4*N`Oe6$& z(cqLjt{c>_f*5P@@Q6SyWSLIIgRm+<2io!&5VM6nViV zeN}f?81}gC`S-evnYtwO(Ougmau=}#HnSE~C*ti_HJmS8-VdMftiK=KhfANbE+Z$- z1^|b+@+ezH>AaPuy>ZwUyQlcSR~>9x5I;?95=@dyY#*lNpGxI;7XP&_;>~o>f!!QO z+I@0}pO)sJZ;lVk=f>sAjY84TY|e#u>GAgt87~ui@*cf}u$qPQ8oh$pZ9yFz7dAMZ z(*jsO?LIO#7!Iz85n?1U1P8^z1p(!v4_wKD+?)@~=`%NuWGk=?>mREI99T4j_%fW^ zuHhekP6=nLkE!klrK_`qe!xx0P990IsIM~lJ5YYbN*ZHcvhQV@2OA6e&}Oo#xtuvI zlq0km<}60ufLh^#0sd3r)nkkmnZQ&CP4aIT91P z2gtCT5H_-+MYaunqMg;4w2N44gh7Vk^no^_2j-(PHiPP(8&>o)`U#iSFgNs;DNpb= zQ9p!vBdy(Bn=oEvJF&~m(a`3_@6dGnw`6g4l`LDhaD49dZdl!89V1z_cy83U;UbRW{qHFHW8A4+fVM#7xZ+DUy`cru{YUcaOCDVu1XL2_5059t@ zlu8u>n3LfvtZ}!BiEK3gP7}2&X}Fmu_!;F&QLrMta2~=d%=$fmn~zZQZx95l)|Zb` z-M@9|R?EORRj`()qKe1PFHG}A*<3ntP_@`dT#RT$8io(weID8sPQ@e(;cDdkS(Y!rfw!!y0di@@dB-7X8Kq%X;Bj97^Fd)dCawghp_OSng8{qy7Pgz#3c)l9|px4xWSIuv((E z5|BH_J!RRz`y92D@yzY>JF3f(te)>BORmR(ym>1i0fOI=spWG{n~(a1vKn-(d3;pD z)ziGkBoRq?D!?}j)@Ga_Rgzvutt>rJ>KgiWn4ea2sWTM)kE_M-OrNr<&~b5#}IH06mw@m9x2$`XC@ z(Xjge^UhQ}Q2{MZNr40*?_$R_4g&L;v(v&X6%L}@Oy*<9aB@H3qK;MCe|Fl3Wil*| z8s#g@!C>4b*x8NpEXB_yjAh%p&}ZUoGUDciUlNj7_CNSN(o$m)P_kgPeICCdmxZSH zNnV+E=D{{ed3B{zYRxGnPvrJJ`h6fe{oMf<3*y30A1~);uLR^6Uvdunj+3H=s6zgd zF7|1-jMk4Jabgj5Xi}S8nFw6$+HzD0E)pRvEoe!7pw>`i18Q%agV^TVila5}Sd2uN~ zkN%EurKispj51Sq?v3^8?eakgs#)8-qkpy#KVi=g2Bkx_LP6C^=ceNcZ*GX!FmExd zepRW`#QmNLjSa~>c68QJkm=b^)HnxgR{Q0N93q&W?Jv`(q@`F4F=-+d^-U)x`SvW} zFW6o^4IGt(-a_W{rfdSP0oo13jB{y}m*89@nq2Aq!Gk4WZNrRpI3I`y*J#tpe;^Sx z8G4UGEe!p=$X-+XhzVY7yhPAmU5nC^Bd{UhI~}2T!X$_XUrYc`C+4Z_MsX^FAIQGq z=RCXO{!%U3%ukGYnrW@AIH!-X8+CYs7{ zOY;oH1vL`DE`A-oQ2xAjwEL}CKBt7+zyVh&vs9fI8gl}Na2;r7H z;G*WK6(%k2F$Tpg0$RxrBi*uLmuiLddoE3jS~yg`}4I^@V z&ps5%XYsA9G%H@+08-fpKSCGWKQH=Jr&qKD$xmx(T5vD26<~29B4vAwe?0Cfx6WrW zcK~TGEcK5q+i1s>g`>aud449C13R0Rh%ufGV)rk|{k1<4ena(~X*3HX+5iedpX8l)=DjgMFcB+E&m&{Ur`b<-? zI@O;bpw(!7ifei4{z##|QiQx+6(@>D7q=PQ-pEDsZOp~^7~mH2uLG zX>awLco~n($l$_->%SJs*J$b)-fk=Th`;X>jZwf9hxHU!tvNPnpfQF?Rb0vJBwD85 zN37li)=7=sQi|fzr7^wqL2gPUjCl};=&9EtsGqMCBtjA3g?_+$n2;DCm?Y8Us4A>6 zpjzosaYTTx1&J`($Go}j1;$1^kDYl&{mlRo<P}dWQ=^?=BUxjr zWCfaJK?#1fo6L(6Ut00sVWGPepA_}zu;2BM7EPjx_KQpQmNz6dLPO2j_S4YF`Zb`t zK+(P=lgqk(7^1)> zaD*ak)W8YAk82Y~TIokoCP2vSMZnzh=~B~Lu5NV-p?cw2+Gp?@R}jHGq7X~;(3_%E zojXduyZ84cZfQol-lN_LgG5lR(cpOQZS)6KxFwduu3v-RRh_RrwON@?9t!h1;vZxk zQnKp*APmM>itrU3hemk182pzYson(S+OH>oGYA9!SCvxW$Bj_!0O_+K{4;M85Qy$mw5Y*aZ;_7K3{K`U`9- zgKz~6{HI&n!GN)uh@4Y*mEn9edxN>pI_h$fa^dKH#1xJjuHq5!bq%rg_ceZH^t@U~ z-T-2k28EsETD*8uCR5hBi~AOufTl}0;X*OLcdXVwJ=AK+QhBY9@0Muu({`;JgjjJq zq@p&OJ~ObxAmFdNBfKXCqgCe8oDJhtLqkEK2r{t}bl8_2SSEs)rw|LlL2VlH>!r*> zKhy(kC6GsgZxHws4d@Pad@@i ziJsc;c3mgd>&wW6DHcu|GW46D05vo8pnwsR|HtWlPzo*mGD$3npRaD;P0OWg1KNax zz?YalKq;FQSeADg!v;?;S-I6Mm0+JRk;PcSKk{9#V_ousw>)WG{#4Bv3meH}7lUk# zmG#xin@z&Chf-Txv-m<$(ZTN$zEMc|n_fCIPNj!)7#qM|7UX?$4TY|+6AXTjT%#KK z0m@y}wP4>+@oUy~yhrwe-Oz-+H=`rG6S|_(4%8af11MHOc>L4|sSr&X@aC=JQ|kEJ z3^X&L-VrO3MwQZ0a^OHaDwUB!s&{+VpHug+mbenn^2ij2lV}w=3osM|X5yWqtJQnc zXQxq^YAucc=`is3LLuZsZ&%NaM|)>FeKV|P76%>yp6pEj zg;|xmj1rvS19w=_D#1{;)>tjXQYE z2gWOms$mC4T^I7!)6BaOF7}q5b=3&2D)|j8Y-3{>&TgMcOD$LCAuET&+5>byX3A}6 zJr3Iu7|{}pGaX`ngGl^7OQB*|i~ zK%j}=I27(Lst{D<`NjYtDfkT+E`qy`@J$v>+0GC*X_OVC+VrWVHQo8OM;88QGnQja zG|vz%%Uw9#05JDCy)}b#)X~G*Rz>IPgGI`8jV=mlV`^q83H zoOmHFGY)WU@5BQi)<<rQZb1uDI}&ny;T#W+J`VPA?AORh2=w?X>q%jmvEy5s7l-X$l{#>Npe#=)RqM)!cg zpIG6;EEhTK*M~ff66w^cIm3v`&>#|q4Vk1kZrn0x>4k>4mT|U!z1*mKA!&EPI;|^B zLVl`X_L%2U-)}p^eb&P5CwF5ajz1)Cj~|cEqkjtt>!|6_vOSY9U5xxw66ZgKcxB(m zujQ*``JPUA7VfvJid7Dlev~gRahzEBM>7wU$K@&6-@Rjx;meg#g=(F~IyT~1<1)xD z&;Vc}5nWqi{K@!J45O2;OuGrzzT^E1@B@APrhm`*EgLSUDTyHOU9k!0-`wd3%v6S^ z^wiYsd9R^3`~JcM*h-bq$*t}}S@M_qQteMZzAkbix`}Z`g9e2FVh=Ux5=5NH32aHD zKl>%Lgdb^ATX_z4%iyS|IY?y0lx1i%gs! zydcUxRL67YA7jeY_1a@K55w?3h8NZAwRy^N&$sLwlNHOUXkgF+tMX%S%7De)oVjG`g>^8(ux%B6G9tUAW@cOe}c5WNUQ1gw!MUG3Mn zKx$!QGR5bDZ(4W9tLSC{n^YqIpHbaVAQUv)TAC)0KFp{+nP)INf`%|VWydK+oz~+(nfQBZpsR)I|P}Q z(skJvSi0RQA7<9U^u}`G!33`6Cxo)UM0W3F4?@8Q=u+{k5!rG@#I);@%RxDd$@%Ul zACU$r7_O;M2pHA8=V3vGtW#Da_8Ss%zm-@_?LueqQ7EKOUDscRGeUZ&FK4>Rd1QDi z01%)D*?w9yX8qS1EdD0;EThl4_b*=?3G}QOGo_ksL9i)9?orU@Z-O}NK%XhVL!OPW zXI1n_VbNs_GB7s7$I*uIDP5s%Ei!iwJZ&|4We~v#_z+FYVA5kfVRN%Lhur*dO7A$e zbB5-4$>h!L<$9z96}({~gml)1JmX;OUo*a(b5_f&rYER;>P%xpY0J|SwUJ?Y)xB$^ zluHskS&Y-njF1X-z`)hoWYrq2M(y_p@G?q0q5!#uA#Y@pmnNlm{b$2YQg)ixm;Bd+ zo7v!VBg!OOPSKQnX$vp(!lS%^cO>+yVu34(d45gx8xI?q$Zr37xzXCDaky|;ENQy` z&H7&=%rRE4J*Gb7?-N3zM^5Q7AQw@0xgLTS{o-?=>N2)A;j|o8v2Fh;q0twQh=Vfk zbaGlHn4T+W>F3=h0`I#~dSRGrH82~bAB^ndTtL%L+#9JJjgFRkrKsb9{q zoD{!D&2Sewj_o@P91=>aZn?TP;5)Z!YOSH}S$K@Z+v|J2Nz1N zJevrC$ljLIc8B_{KO0es$MzkrL9%Je2Ab%UTH_kFJ8x zt;KQ$@?fnf>e<5MuOv1G+5*^P?-V((N9RKN zC&?yc>!zu=P)-vvL8n(Js!3vUK|EX}n%p&nKCd`LR|CMDxE~WojI=*VF>W~}-3&lw zRS9dga%U$NSo+Ki>0u6r^CJ?30f&XcPA;n%Uq4#(l`^v#}X~eA<>LWP%tKeZP5&()G$&5?hAKd5^uL>{wVf%0TeMGsr)zXH~@*;1?@p zWSwa==?dyjqQKj+4nx7)_c~hhF^FRxuK#zt_Z)iK30VP=7oSWe%nw0873LmCP6LA3 z#8@BePEU4nRSBI@p)4&BNT%8(4*?3}8o$9E4gELkBT*{+(yDwuqdK`Zr+e^ z*{{ZJ{`O;SY%j1g=AHn!kUATGyi+^aw!`zGELX~lkxMJ5&rB%j-DF^7T!L}DodVKa z-F~V(#a}9t;=#Z9aU~{)*(9e1m|nQ8xKqFgt|3)1aE6n@+6Ji-DQmYLFrVEE9#vA? zj0HQC|1v^0)(XcalMajPXFB}TjowhGO4AS0<@Lbw1<+JgV6F%phVJ!HRKj4eH1s+j zY_F45>x8OuSz(AGNuGd;CY)ja(D@eHLFuMgw9e|wq7y}brAU4G@L#OVbXTn~oV_Aw zyMq;8J;6Tv1eICREfiZ}^<1t$T7@#wPf%W;BB73SH(LHP`nGpB<_ za1LWgW;eZjSpE+6k^YJa|3L8O#YI~Ob5~s+g!kZJD~RkoAOHOn)kWy=P}zPQ#5#&k z#$kxj*&^4Nwy1!;Vm~MqB2zCSX|XJatPgl8Gu_wN?~VXP`|o?JyyD(|6pEU|fypT` z<2~bah;fc)n_5p@%ZUY6@ud3q9e>yj9~~;wSB%wBDi~c-1%Av+{gOfgV2xJ#GgQh& zWb>#WfpZk(vkM)%LF0tpM+MGZWiKruoO{pjv|{Hh7NUenbrq2USRebDJz9o+H0UTg zpRBC(EVI-sMLe~E_kcYQgj#A8E=c3?c=?>zSy7TIL&lmfZDE1UvX)`hd(ffZz_HWV zBn_FWwz+NBgn0mgMG4;Uc`HLJ$O(Dg6RTg^H~Wvu=hq5rz8Upi@T#y#3sqeoz(zAK~(mWK~5u+y1tHOF+V@etPVuE8C z##NpXC&~smG*7VGN;x5#jr{C6mv?z(uljxE%?q!S>f*f&Qpy{!@96i}{$wBe5Oq$M z2I;XLYhvmMypjsHHiw`nisRxDg4qOWX5!~(=9Jhmo)L(DEu)D8{KLS=rysll=eZ!` z-M}X8NnG3T0agJGgu?$iqM6}@SemnuXG)R1hm3xPXQMWWXz{Tz_^1da$?Wb!L3+0V zmUFl0MU$0QV(%{OHAl|CHRg~sqo)1F#Bq|u$OO;>Gi%yW1vg5wJr8lppBS6Vx_@Ns zy?ZP|#(}+U+$m#+p)%ll}gOnDN}$1m1h*2bNoH zhb?<0bT?t2ndfc5`_4QFJ)YoD-lw zBn^1DQ11~ih0~OO8iigZwl`2U*mZ$Dk(}QR$p}ET4qvS2F*A=JBMkCyq_s<7*FRBu z)JEiRVxA)2i2W;oyGsMfX5Ptx63RN$4VPvLN+He@%Kkqg6D=k7eVRlP|2z?(;DD^?(3|`GLZbHP2Az0f5-M27|oXl+K ze~p5)|G?mub?cghbzOv!cj{T>*2{dky6AeAG4R^ihB`#i^Ss}?^&0eCHPcMxXJ*dTS9u;xkk z-=dbHEl|A#ys->?wRiouX?aOsX3P;=I)f2&yP%xV{rqs_Zdvh^Gy-;k%`ljyQ;%hN zrcmrP0b)L>qgFz({MQ{Y0Ik>B>tY{;$f+=80yhU7We(X+^M})xMM7y9!q^D?&TkOy`0creQm7O=0C4QdW<9Q-PQ$!m8L&hPb8j6I&5T2%eUVrRMKZC$o79dWJflAiU_M|g!G5XYnbO@O7;3TLs;AF#{`IPOMRhgtPDvx<> zz}||Pc3-{bG>5x>k1vCaNih&cYCW+C#&v+`d#FZ?;%pufEnLxOZKyOAAs+8t0B2sG zK(y|)i8dm5@61u-*Ug5d;eb87wFcORalixo6AW0(1R~Edurkqn_K==#7RpR9NjW7+ zbj1Lsu+1x3;iC#Bm~?v5G)7)|v#lkdn~}Dk z*qvld47jDHUizoh0E5l>n*|2B1=)W4>Fj_f`xVPJj0n6B9-ORm2C(pYxPhMHz*`I1 z0OY}vWzU5MeWRa&|27qBx`t4KoIH5(V{xl*M4%D&^k*4h)sPgKTb9uY%P@yt*{UR6 zw)+T?^_3&gv1t!lZHlsuOF}Q1YtNh-qgycF(0N1y&JpvYE20;C_!;V?&qL#5b{D!I zK=>25J$ZYlV7r$;)E5oAQ8I4P+pr4uK~X}O6P~SbF(t4KZG7#!BVHT$`IfJ;x1K!A zvT;#Bse!)*k8KRy!>gARAV`$wit*fvR%?-_GZ|c)k|bax11yk)ViRc1^eIO~_h6Fd z`nj*J{7aK<9Hw`8$o*hcv$!_^1B?iMr+}ua{i$etx`$3?K}RTdQT5tR&ZO1SDuO9; zY}YbJoSDn}pryVjwpzt*>tv746^6fNs7r;3Dz9FQFa8+Q#!9z!#s1QHiJq|o?)faIGsPf6)uu{;cu9)O+Cr2CH)75|Z=8E}mU$SEqaL!`ZR zXywHXU`W*&4;E}{q3Tx;Mc5z+nvS++mN%5itv{y|!{EU2>+@O7;Qm3>b5}oC3-&oL zBo%X!c`G5r-S?b=n|F*{v{W6y_=o^7b%t_m|y`lMqrtm*W#5Y`+kzupsNQZI%4=XzaeO?_M<919;Moip}IUhm=<(n<^Jq>jeR z+vh{%`&`SidV)z-E}PUxW0lqA zezsH?}PLu zKGvd7jSz^hU1VtS_SLD>Uxvj24GDo6h#*8pc4~g>EoJnQ|Jv>tv8Bv%-C;2MWyM`X zBbEdOMzxsh(8+$pD}Z8F7r5%(ncab%%!8nDGlbeXw~#7DCFH-aM;ROYH9(@yxPyv) z`X76WIzcLwcvw`8oVUe>*C<^1d?ce_czsVxy_Z$}D*th0+nHMDhb}(IxNn40V{Ca% z@dHuBThh+;j`V2I8CI9=PQG7y zEW%dlt$kG=Otzb0VIS4&91HopLAv=)W-5#keuvh#ql@+J-FLF<)a@B!a1~;LtKfyQ z&kQ1wf8fLCp-vEg%mu1&lU@4b*<~6PittU)lvrMaV-D+V_n+IEf?|zTAh%ayO3S?~ zZMFzJzdf_Mw0>4G(*!rBouA`!-4QCFA|L?Y%3v z{FHMhnu%!hgF3Kf&NHVCz@23bVU*yrrDl-eaRqLtG1X8Wy@Hw$9I54}JhrHAit!tU zaVou1=EEmgmH8ahEYv)cbIH9z*LC=EYCnnT_854_LeocN)6k*hD_nsXIwhFf{Y$f+ zgL$&=+>1uRr`(nudOgy|5?Q?)0j!y%0Uh}0%e>*@FHX7LUEfG>B@0_{HxX*KkQB{w zV^l%cSbwKPBcCrZi{XtPJ9*UiW+n(|_ukDaBoifAX?CWmLZSu)QYrlVB8MI}rb+Rf zW^9|83GMc^Uq0F3>-JjQuMngB#?((*nJz~AQ!6D9ys4$Q92 z)H$7YNJbc5N<^p+`#7t)r3^3{CuXSn=@9utRwP4YUlodimg9wo(oI8lHmbSLCV((< zPw+;^{kT&Ql&7g?NjMZ4)erHl2g+SMSQw#QL$cic~nG9D& zvGdZ>R!!bZ+%03c;k7F{HQ5VG!J+?_N{M^>NHT4kj!NN}1Z*ZU1VRPUHd+*|IB?xm z4q44k;e;)8K9}2xxBOa>62hgmowncGJFKX;aM>?|;-TcyOQamknx;WJZLTJ&uN8lq z=7PW`sWP#dlJ6_`)A5j|u*$LVfLj9ZYlV^5VYpBI&{pQ~ck=AQsa3%UC>K8Ljp321 z7%IJG<>$iwMT9_C*U$M>;J%z7F}cMmBRROx=!(ncb?R|k8i^qRM1!d zb%Sp6wVrUZso~#2tVNS4BD>?v@P_mohgMZDc>NOqy+g*bB0M>a>+My{*bRr6qf`N1 zBx@8()xiNPJ81!uzmwy;I6h6w${}&G!HNvDqvUZ9MB&L@@5+O2=VR!|ocXnsWdUm2 zqwv`65Whb(dVLrqqgx^AU#E#_Nt2>w_fhmwT-4ZoBeK3v%1t`>m?YzpUi)Z&>rAuu z1UFtDA`@eJf?3s9wGTW!dEHyyy_*dMtc!>E(M3{{bmH&QUU4{UmmxQ*I4;$C;wAYO zl<6^CoHvd6A|D9fQUj0hm+%M?UpUcRvX=W7;ut#Y90LW&IB|HCXYt8=fU|c~_Hv>i zS!M*DC2a!PFss{v&JT^a25TI#?qh$xEM28Jr;{sRFauX+aO)WL6k5C(|7x7ZO@pRf zUE#_*V||uoWqFLAAxgIDPv>u@ONm*_D_YGKyng_&702+O&_bPKuhvx%$qJ0r!|1%XOoJyqHrCI=wCuAN9mE9FrVCME5N||3gW1J8c3n z|CCJwWl!b7Pi#m&e?BQeTIGWZql4`I28Y==4s)n@a}Gdf(w4CQ=!u+7sLe(m#5^<{wCFI3cX!o?DNdSQ1zPv z6mljBeItO-N3L8%UxcKLgX`(VU;Zz(lG*w#4QhHL5wY@NPe|Uk^%D=_@qk{V=qu*L z6OSw-=j`EI4V7&Z_M67zv`m>mEm}HrYfrxgk@zBMTk6Ltok-?A>E< zFn6=Cn!;US0s`2061Z^owf0I6sSs84gCuqCHPI}J>U)p9+b7CZ&~UM@o!K8R&2gIB zfWRZf`gUc<4{BonSRw6?eL=!dW$~#l(coIE&n~p7;DqML4u6ySh9vkJhcQHX6=(&e7MVscnBTW#EYiBp$Dk z3>vKs3(=*SL-Fk~vghOQV}1W^x?p=eTnSM7Yy zLeXJEcxlbkUtieb$e_>fq}+~VDsu=VgVG=Wg78WK=0h$+`kV0G7}=Kab>Km=Ra0nw zTe{42<54$9MiT0ST6C+=1yWJLchQk)HC-2MMZS}rwIdr%MlgA0J2}IDL5@uAAwRnt zGgX#5@STj4tIS-l!co}E@W(*G21>A-bZBJHo*2FPCjQ_#*xoXTNtBsXKgMF=Cj_q7 zslwE`^5%sCJaV#QACDbD+`aMCG3-k9#LFn&Cz)5p1jPMHIbv~|^u+E*9D|It zM$M2z;A~55E)*_6il>KR$9Qz@<~0BQWK|&fLmEZ$dsO{o0Z(3h#w**@+h58R2bNO3 z4f!*`2zf};#MM7x2=bR@YPc@HoERR(e$$bn6w00vrD*rQkY_DU^;!?AYf#m?lzFCC zHQU})QA1)NYF1cM2Z)>YZ-#3*`)ZY8C|nuC zv6r`T<8O;^CNkq};$chX>Y%zh**(MK{r^aNM4*;Bc9NG6o7jofW5|eb*^_r??B3kL zFDjjY2Pla#s2&CX_N`T}JwRIBu-D7J;PA|P!`(q!t?NPa=5o#k-;R$%^p`HBHCHAwDiwrE$6GdvP3?!JDYy3R z^^STjO|<`bkd~;8|5%6AfQ{2<|By>9TUPeTcG!);6<>E=2+a>m<0S9#T}2y~+{Uo6 ziFs61Hp6QB6TIRD+-HmeKB|e&LWkVAE8zubg{A2cfb@FNy~LodDOe`+aQc2 zuQhNr*|Z1*gsIMKTrB~U9(kq~;2gH8fKdKj3>=NS1bS4A$COYj z#z07ZUaeONh3BTwU%PX0=`+hQ)T)*_MP#WGnzOsP~pGm`cp3@mP`J-*%9Oj$}u-<9t;A zwFVf?I8NocKelEx34!?!%5cfNuNi-DX+)haAdTMVgZ{wVn9Fr-;qD{BXp+O2sD4A$3^8aOH?tvcrbF$V?d=J ze;pbIyWC87%z!k==JUd^_*s`thXnAAgH5jwsGkLefqlFY+^eZa2*?DnOIXnDP}LYx@W zR!3rN!KWHmj~2rSDf~fO(g^*mK1*SKyT%3gBE@4>?aC`EP~RWdXZs((i`2vN19>pE zLA#$Xa9kQ|QAGm_9RdxyJ*w^Wnm#LLzbCP;`UeUs(L2zsZVcI@vv8j~>|=6f0) zi9ytkv#z|qpZ=AiirVjl)j>s5KepPrWG*Bi?@+NEr5O(U_z0{Ls%W~+JHt>B9h%^^ zn`Mw`(Y=KUbd3;vF>D#7`HjqDN*VyzYhZWc)%v)q08-K++CKE7aj&p6A&c_9D|`@F zXKjPhO+X$J?j2*hx*AvU9!Z}G&;K)hr_k!FG4A>n!1!DrVFKRAl3vFDY4nEjtOAnAH{f`X1I}ke z8b!|}5Z0KEEJDgV^P*yNk8p`*Ub`;%>?ih9K>7*mE||K*W3;mSYA!qGEWeI+_sTb- zq6|FRlX50es|jF_QIfN4PAPe*|B)9)nJzJR3g5yB*xD#@W@W`Uk`RXMOALvd^jqe5 z9QZt&14^V~@1NM_mSoJUVp?FLn($e$C=vMj`Ut>+%x;|JX(PawWoPoT)8#?gxOlHu z1IyXY3e5ZD1*z^5x8{&aZ%t6DxxZ7Z^&QuLejuVv{#B19hriC*ahP)I9G4_n-l*%v zfN;`tw_&za{@vO)v7c^*57R5L)(_j7A@pH^=|rWBPs%dy&y%A&lk8RL^reSyFQg-l z%5+xb&WyGNO-^IXAS99pNDd)7%E~Tb*^-@BU&<-Rlv`d9pW=i(gfPJMmxUFSjjQC7 zXMYzyxh0}SMtB43wSb2_R6n}wtjtS5Jl_sMzoq2Z?88CtL`ZJb?6InKO`)Ic*KHEd zF$TOWAuQYwI6@RTt9Wg}H{Ri<8%CaQJkYEcR&%>UjBzB!UQLEx`n^dU2|y;MOD4gS@*sQwMs=Xwoyc+^sN9!#@F= zCOX5qYXE04E1xxFD4(ylEj^c+nIt+)2)WY~VzDUZ!Vo6-Oa5@IGNKm5f7#0RdAJeb z>3x4)FLx=0q0cOhZwn>m`0cXSr6x_ncN>HN|3(c%;v4Vh$5m2vR{Fh?+KAeK21A~tl3#)QJjVj;k zaU*Hs%+TC`WH-i0cWY%CpwaWlJ*^?hYVFUY6m@VRHH`JlNG1PcKjvn6i$qx}tzW0; zZnc=corPFYLlk6_-lMD<;|xK^X^pmsVp zb!LrnPc}N9KPXOHla`^QG=*|1&(q#AD`+ofGGtGj2=U|0i94`r@EEQs8#TOIY@?mM z0J;5xU5d&89n*%lv>}+zX;c1AS9RxMh-&jdL}E(V#0$zDdud18)-E)wYK8s#n(ZE1 zJu*_t5dBHl^QHwhpG=)W27_5gq*V=nf*>gwr)@|WL(^U2S)zF9mwv{~t*H!1o_^Gh z8V>qPGmO@En5;$7EJIx2QCk4?vvAu&3R|8@Rca_?xnLex-xqaabmcNeAbI}>fy=)Z z#svtIaLhaup{!SQ5caU|o?=V@PzPayK;04fORW;|;ZTo?!sxvl3xL9aUG`E#2t?@5l3al4PHU^XHhYM~$L5S3ZBdpyaM zYX}7R-n2~CeW|C+5Dz4T;TGUL`d`b%imKe*JTRcSBtCSEQxlp%WpeP)gP}m&vgw(p zev+yup`h{0$$?IS&lR#bA=J{>iCM+p*;JHD^}f%Ixv{a!a~WYhKEz(`kW&lws|#h`qw1zZ6l0x9@4ZVF4eU4OLg9?d_;*RIMPWA`=Ti8r8z2 z&$$(VCo%vYypaqg8dtraDOBF~C%{XoMfr&%Ago|B^yFo6%x(9!9oNU(09dmj3_;J& z_zsHRv8NTLY2NcdMeZqs&E@^EMu&$*rZcPdHP1NLOAuIh02En<{;L534_I?jh4r1| zt48`nx6$;IDvcFX`fBwVcpQpCrlIQ$H!rfl>n{llbP2ew^Yx5Z#|LX6 zd+elzs+%tf%Tk!+;qQYCPL(sgE>}1oAT(G0e@!B!4E#!2k2-=eF!Y_P!0hF_{6`rv zpVCCYlT*eS^U=i6qAU=F+TF&`Ors}A75&;G7xx^L6l2dig(kNDarXt1CK_O3Etl{? zDA0-?Mp>wE+wu0OB~p)#3gaTR0hyUi_;vPNtwI?@cuKHQoXR?&0BvpLy%dKKz=dFl zJc}A2FUW9@K$u|2VD=AfHjrQcDA_*&O^NMgx24y^|4#-mo7K$;>l^HcyuR~Br;%k; zAn|&yZ6dpcQHFkU@;0K%H$m&&bhT$*zgzP*>KA%jgc#x^XVoY%BMKA$dLcP4L zEfwZu+4U_l2S-}^;mfo}sU4pE4yM?g7@oYvD??j)X!__pfn6BY6$)GAcVxD|M2&s$`jLu)%GxX~Kj5OjLFxW+&<1<0uE z{5wS5@Xo4+H(IV4+XA4yG`TL62vUc8t37)YRI5DRuATm1iO@N|d2up=FcaP;Ot*u! z(FYkelWu8VoRf2?hoC=gZ;q59G+{8E2Byf6B?&PoHKd|#JNB>+e{A5vHiyJ4ngv-Z zZVOw4NIAz0stL`!TT!|*8V4xz^-!Rqe`4l?KrQt)Z>?cDqC==-KGZxwaXM;lFlLjw z;nV^1DdD(_5y!!=T4*W4NiSm3<7NBJSj&JyZN_-2i4FN$N%tE>(bCl}{DP=e0p#%* z0Kq0p$Yc5>uT~iaIDfObU+~ro)&|x;@x2tkQLi>TD_xc5hRAIL2HUWEDV@Ne9%e%aI1ikz z)PbGhW&j9O?r>I(*amNvN`qvzAMQlgP+D%Tu26UTTo$CMfp_`KZjN6pVwpWbGMC*= zXC*bFP$D&^u#0VHec((q<_j=h&*VM4mr+#p_2kggUqfI zv-{z_CY##crf#Wlr`bs>+~Tuntxs52H(eU-W1K}k&?*XN2A`-1ni)F_x_!CD0XARx zBMiz`QD7`ZgLa`{LqB$0Uvy^8=jEtg;apN=EIC@%T;=pqBvZY=TPl}N0x_HHOOe<1 z_Flc56t_Ql!kxx>#aa!)xOvsH5|QnvSg(i-o%eVN8Z+Ocqms(sG;5P^i7T1SQKbh0 zDR9)WhO?`9o^1K%EIo2hTAPY&wNDCEp4as5wZWPSF&%X!_l0->x7|8mgnA;sb;4Xs zQx-?L%2$2h-Prv5_1DMuHtlUmoE~HcH~8B}3gM}gxgUFIY{{M#SbGY;a#KJD>3toc zQLQ(BWoL!L+||0P#z0KTXtaptOGm=#klS;-Bua0Vx4n-H=ZKy00)uEHH;N}P!DvL> zddV8eo1lu2mw{E=J}T*8Id~dCEy1#w{Ky#F( z^!Z<6c;QdPbEU6OmdO{kuln>^UT6trn#|3sy!mUsZ=u&|kBN)aThp{k->4&icY}7m zNteXfc=k~>7Yu!$fMqe)5~}<;#XGi%yvWYB8K%GMtHMN>p=gwX4J z?=Bb#d|D4pDUc~!pu!K@0BfS_q(^a$3q*D(Z=-VQXkh&)(I)jN(j6ZjM}%W&e)+=U zD8(;@?*h)r`Q%9Hp6Fx?E{ zQhCfegXqi9tJqolBSBWdHdg3;6a^Yl#0j-QDxnk6PG6Ln=%S@`WYkI^5pSqAo`iei zFv;i8Wa<^Tn#3G`xOe;whVGUnb%ROd`6&sVkMwMqwc6Ix0YelGj&mkQzd#wpsCWUt zLFi6icRKMYtCB+uM^QDuqc*aD$tSRxjM!+EnXLV#(k2wSvmnNR;UO`@xwGyS zj}MYvjEQz3IgLM#j_^1Q!&S+}yr8?;)6><9iRaco9)6KkU>l0}ryIi^bdY%ojMT9P{fo_81g^^eT05|;@*})I+Fe1DUfHko|UBAMe8+wkNf(?HtyfYcwto8 z788@n0Hp-s3?!;2;Ze=5U!2PIWJl1b?fbka{bP`V!}DM<0}j9l!{!|lUS&0fhF-~` zlc97$$h3{C9K#&3vt$`M8r_#56evKnmJy8QqlYLW8cSg@{zOGk_;y}T)}sU&nt-mJ zqqR~@x7vwcwBk<9=`P21=T}AT5j34!oMJx0QA8hr|IA@XZo)DpWEnbKp(rwvcHg%n z+nPz8tVqvsiQD9QdJ`JpM|vytp{RjMC~ z&d&BI)$MarlD0cgj!A4944q^K1bcEk`-Bo(QG_gmJmi9CR@J2?)AP2XX`xuVaCu2d zdb6`;Wa=F-Aqv^VXk;hDv6GOwBGpJ=sd3Fo1S5n66qrG8ec?Y`VA?KrPwEkNU0kf| zng`X?PEjOk@V*`Hv_feE(@Hcu?pO?ta`5+nZb~Eei2N8Q;19<=e39}rdfXQla8$6c zY)NBWd|(LF_Zje6o)-43FTvg3(ts6HeAs^dG>sO0-$3R?mNAt`vO5VDcL*#u*laVq zKTr@FJe8_Kj4hQi&5tp{ewQiur(Qq`i3J!1hpYP3 zFQMq$-0t4gsQ*nmNa5~SP;x5Hrq1YU=anHtTkc}COq#%Dsv|xn`~_nHa{a{7Go8vJ zu3E8kmdmJHe+)sSfK$w$=c( z2%a1`%S#0hs>R6m`U#o$Ag$b=V8SGDi#04W@>bbGR?j>MBLQL1^|CfdMM1Y%zetj9gJq zbtdKaX^$o0pYf%*24IH^QmNUaM_-9ip9n3rvX_@2^iQ@Y>tbxmg=-EHRZ%8los9|` z%Tq^}P+LWRoMuk|$2-psJ**dmY$m1&v61DEq*Vl4Mo&(-h-ujI7)36 zxqy|H2IsQoKoBS@PNoRFDKkZuD)EGs#6C_sr6L}zzHbydbhaQHkT*Ouxoy$-1V@5PWT`k53>!EmS^k z!=zc(yeV@*KWf;fdx-?7LSYNk7uIj&4*V0*3$PNaz2}3YOG3AQQQ*PT&9fN*&c!{; zj$jp%h5(dyZX>mP|8xb&hp(@iN*^3a&G6+v(?~&q_EGU4V7h&2A!FC-D*ojHHux$0 HB|g1V7bh#1 literal 6891 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
  • Ef?w4BPm!aHCpr((wSrD@=Ait<1?DE8`Ns7c=;4^4MnRj=J7ISnhB< z95%vV;kUHq)UF)>IsGZtFS2{Bz#hsa2vJU#|h>;3seUnu~M2rJuBXa4EJRxE` z7yqSJp(i#7g3lD;PXZ|HEqH^I2Lok}KYC#JJBC{B%<)_bH0sBWd#}7rb~N+Z0)!3x zL@xXH-=nO`OOe1I6DiagN80p2vUq}3!kO4G(p}`6RFT->@;*l|P*UlHFGUSx-ndVR zhw{LwEII?$4revjY5O;zd3&g^kgkH9b`si9GM;pGpS)mkH7|&~tnIsAVv}XOsJ~pH zpD3HX6dP8fhoI^C*GXj)0Mcw!09lK&+vbczYGnh}@6CRVzi>OD{++~h)}n2Pz8_Y*%B=e+F~I~^{{BnZIw>Lgm1mI2CHTk~B@s2QH1Ua}FTRYp zQiU%;-&(MbCj-tLa#DLbj#1$J8a?M8F=J;@XOE#qq3i-z2>OyA5WCEvc%OrO?syIH zath-MIiltr*%prl2Ext(u92MR!8p|ou;_B4o*`MqGzn3wp~T;sj|A_yu#s-u;w0_! zQg=pP)yrKeiAn&Jv<4P~1d0J<-V%@my$yF6-_^hsjus{kQ|0vE%lbI=wHe_sU}hZ< z`bAq=$-HRvno_wKJv9TwO&-`2$kkf}WCCcR^TJJjvwOBvyw*0zq&uC7E5h*T@+19v zV|$Sw1ki)EN^hVZJwbx4m;(}$@4KP#Qrmx`VMpgvlaV?le6eKQ^vYzv3VhlyKL@!` z>keOAz~Am(^>n}!cRRnxK%2NU4lWvQ;=@;^^t8v7dO18G*bo>W|yr zKnUSNJfSE4sB&MXOx}0D9QYf&AP1owD}2tl*`02jGV?}q=4Zb4i_!4@Pu5?ll#nJ& zVkoTZ-Y$D*roJ+;RCu$~>-X7sSI<%vL{k8Fkiz0kLl z{}4F#VxZtxqYtg`2WW#2`Z6jp`(&#OoA5-m+S4{gq4f`!(I{d1!z9GX&n&Oc&v+=t zE%SnJ=cAY;up1jDR}AY4ExlBrt3n_8_X!79#wI6*>0CY)H)KKWJ38)2s0)MC*O1p3 zG4cOdPjB+3&=y}LrC-o)AnM}rYAFZB=PK$@P5L%AunGzhO!!>W<$N>}aqLp-Z>976 zf)0~G6v@@;xDKsnmKlw%Bl@P-A;mDQAqhV^n1EB@XVU6Q-rj8dsl$B?JAi=6Gdo*v zt}$jIzBXxIt@)^~R-=9&RDi+??%-gL_J=6(yyT+x=yr`b6C9gY)RJ4{*4a$A%PM$>q#_p5PYviH>2y zAmzfu;I(Hj4tjpdu_~vz>~7h0h#CS~P1dQhXdo)~{-c3zN833W?dLy3v^H!xAFM}N zZq!4{U@J1C4Ha#nhAJ_*|0)7(q*plH$BJ5u?I!F69U}EK2cjQhO6rO%9RB=WVNN#K4~u3{S>M)qGN~XX^52GK zNNA`^u^lp@rulctsi?l~V^`sbBk$Orkph=Qd8K9Njyr0F@QY0P3Z5W9svyvgmZY%Q z%d)}|-}LPto1p7CEdx9}608O2Wjp9bNiq3D_Nfi52SQFSsIgfd6V#=vo$0_gxczS- lcxw+i^ICt4;1B1xt9cD2BayIgjT%RnrKo9P{#dQYfSCOtXN~{> diff --git a/console/src/ui/viewer/views/Spec/annotation/useAnnotation.ts b/console/src/ui/viewer/views/Spec/annotation/useAnnotation.ts index d2c4d872485854bd965b819f0d0d0b906c69036d..3a929d6abbcb8118e0417ee3c4dccf3f5d5d5d71 100644 GIT binary patch literal 11617 zcmV-nEuPW;M7hsrH#*(8_A+WCT5Mh6SC)y6Xhx1H| zC(na@`&~vE1#9)CUpa??i<_tTDMSL@eBPLQP)`3U;q()6b{O`BKAd26g=AJ$ktOrf zg<{W2F;s3ZhW_P)Oq{CApJTTk<3{Ln`>Ah$l&ErV^QcUQcEcY7s5{_07)cg>LKPcb zf=<{S>e$GqWHQZOEw70NTqifpya@@u%F$+b!3vR{D0zNR_~42(F2_eG4nR^;G(b>MP-v;1j z5LKi`JG_L%Kw0z(Gmx)fN|DV8Lf8+~Y!I{=aeAv$E(+wpSR3pGPqCf`=J(+1nCxVK z|AAVnmP!K)f&p5gaIV!o_bI^r>Wo#H3o0(@+c4?9OQq8qY>y^0_a+4Rg|@Vv2c9q` zA#qe^G#(@23q*-rqype|81@n2Xv1y-#~+bkJG;>`7-v~yfx*y4#ps7sra%?Q-MVxJIjPp zH6aeG*t`tCubY=wNwA#-V~nV#CL(1O?kk?#mH%lM zL$ala&Ez$j1=Q&I0WV2t4Cw2%8WV#o9K)VQA9B-ghxMsEK*bS9U^)5P>n1r$jNBPm zR6n@Ma=}I{1Bnyx3b-GxD+->`wG+$MdNcXl%RSryy*pOwM@QXW7I&`ckF8B_n(HG- z)))Eyb~ayxCx}n7{Z1KqYLuJEky)EhzH*fW^&*GBaAXz(e*mz+$9=lujVgC>z5?>X zS}-*gV??!@A^5|!IbW|~!A(0OweE%j$|=U`R#KAwy0779|y zyfHaTkptWeGCGer&_IFv)ns#Yo|UTUkW8h`2u|RFh}ai9@JF48)<^H=3hl5g*i_EE zYIg+*Or4BgpIFSWfgOG*&C_P_%VYv=w>FG!)gXSnCM;qM9@pR6ack{3x-k2JD^oBx9+KX=pnxEQ{-$~Fcop7#a*mtv0N zPlw>VVGT=E+;JRzup|2P*N}?^GeLHRIDw1^T2^@wu#%x3WYB50f&Gh4Uq!yO3v6!5 z6uJQjPK{qyKqqS=gtE+h$|=8b>RjBA>FQGsF|U6OT1p(#Yf{YAm4_3|%PrVld>#A= z!W0uIK8V%^{Bpx!G}Iz)dGIgf%tz0RJGT}W3IOGU_pps4N!N<(eGL1X9x8zjIHlF&+urKl?KmGpwH zB`(@0Mp8H86t}@z-leR%oD#PoWA80~f0T-GSLHM$ez4k~qFI(Iz8!8K3qonVxVVAc zwIinU3ec7yOaR~2#X#A;^I&-qewCNrnQ<+v49zq5S&tyW4yK+czM4V&nIr<{a$Jv~#Qwvljtx+O;t3mA(RfuruZS ztEwZPj+3D%uMK2jJ>;w8S))9NfA%5rpW!NlG?Pm0PL$f49yW`Y#Y4+YJ0Wu;^RqQJ zG!}NYnhv)GQ^X705tWPx?)6%?8|Vv@#@+E!nuVR!M($bNa!>2_qGhY4waJ{NvN<2r zR*D^6V>TYe3XxBLRxntlfs0#NUjZM*i~Xi8w+^EczDC#X@#{^bze68nEd#N&WLdp) zrmnaeLOwJGMaYcsPzl+^4Sza35kHG-H>^VlIMQtdb0S^+AQA*B;n0cDz4wQNHlFGCyw@x{)8yS1|C`j z&jnc%)W7jD7ys5WHDZR{{ERw^9pEylqbT5!WPbuScP?U#_I(`Cmyvy2MDo=FGp&Xi~q1{rRmh;e)9LwE$R! z{Nd2(RC>wd6YBBc!?yb_jaR2$JhEmASC|Lahyy{D>x2^~%f|j2^Tb*KeI;@0Ij|Dm zax-V?0mYiqXt6smbzh25168MI+!fiD^#G;ReAIBSW0XM|rQ+B0dMdYAC&d`jJK^-}6>*_LB+9rS_7X z;1@GE%_UNwPEeX-sffh)m*H-QN@)19IOgV|2GE^4G1%o`BL>MAZpf0-ONZt|a621E zpV~-A_Ep0vAMke9L0wT6A`5xY+hhBQ%QThq4(8@rr}j;(0;KbZx^gLOHCf zyfg6#P_dkM3lH8zybp5F6Eyo=(`NqL#Kw)UylWL_hrttndpuK@b8DQogQ`-FWa>|XCBxWS z%Xr>)%T=G$Lx)6wa@*x^3p)+$x0@UgeorHFe3*vV=MD~7i7a$GQO@Qj;4xOiha4lk?`0bDij!*6r(i+F`xg2)sv zB#v)34SEUI55ieEFmgfn@|`*F{yFvEC}hTRHza242V4a(!BI`6x*P0NQj)xOfh?tB z#kv{$nOb+aj^$|yL&V4f;nerWUYiCw(A05v4)%L*i_Awq>=V!7>0@46tpm7KE z^0}$(|LO0mF=Ub3jcUm@!jueg$EIf>$~jAMW<1m3fGMG~RT1yP@zJ$VJf`WD6(xBC z8nK7O(065hc|d9IHbKDWT0~4!Srpyjiy`PA0W_Itl9q3UdbD)Z)A8V^`6zEK(Q2c> zfgoct&kv#-SxH#|>eY5jx@Z?-zVM?ql3bhqop;}0H~vPl7++yQZxfr;+bW>I(pS?r zuA0oqmM^&LwsIg>Nw46z-08(;WPM3fN*`pZNCAPCjZ?wnI=LiS5V&Kr|1~%&orzl! zV7Zlg{j`QC*cyhY=XM}WnS`z$SKN)`>au*bvwnlUkZShhwwXKxhjqb)EXXb7)2RfP z1;V#>xs4yUn)k()y<8aVRQ`|yz{KXCZl^_mT>YceJspREhIBB+T@G<@^ByDrGFOvhT9{QC@sM}l9anUO?Y>J!!eHIrK zy@Xf91lZ-I2U(B@x;lC%uZjm}EEOm>Yrje1te^GvUoX?vFp*oreZ6h31DO8P!Hu)( zM^9`@Xj%~sU1k7fjbS9;GQ>xU)8ifGOg3%S$8S9q5QI{Td}EyG&iyd(0;mVZ5WulD zWET>XpiakEV4`Jai};Lyp=|ZET!tw_45x8MYR!9*CVVkd3vcVH39yCO3&_1_LP}2i zPk6+Wi@q^@r)EI{9U-VSxZBFoX+Jk<=t9f&t-A|Z!mGJB{j5-XJWA)kCp+A-1VNT+ zlu4VV_*#`wHX+qLVl7R(V1dG;IASb+NfUB_ICsLRqBFN%EdSzg0-#@>d-|h5Og^IV z8v#0*?4(FLs|2};Q$=z5899r_3*qtL&Dqy}>a62zwh3$eW*>62bCy$VvcbShmpAa- zW*RHnf!f|q^BDLUDWKi6+`ZvMP>9jvKL^!^|IG zdEo?(R1KI_H=H8->Ng}S_6UnjZdKfnPZ|}n^C^Y;wo(qiu;%rn((LMGw-P-p&Kj>Y z8L5~sXNe8(fgy;mniDRBoCG=#IYXf7K(tAKnHb_6EA6Rok-G?_ZUTtYHcd4iVrW$K?0KDYLI1J5_!=01m?w3Qg#pBh!mda#IXTWo=UE(dhvWyo58^F@Z|gHvkRqj@IGuvA}o^)x1=r zN;A;DthrteXjM+rqVyClBdeu!KSdMNaVSf#SA?ucI?0` zK;i{xoPwg9(iD&|4o+-Lz%uS+I@NeMtWse9g ztx3^G5&o+uko>&ThCfLy9gf@8;3BBh8%yg;7l4v*KBZBngIIyC=H+5jji#m{2O@o{ z^N#u)LULm2{r)lgxAyEd&IDB81#I!U5ndPv_ciuWE(K^Xb4yI}c>DsJUjb}C+6Eb5 zWY=2`BZ$r%m+)Rx%_g+B3LOhTZVCFS()KpAV`XrnLDz|(%)w!ARrrGr=iX?ZwSav} z+8zGY!=s;XPf?9$-S|0m0Wv+ri9JWKC%7*5{lDyrz^jfp+AH`WpwArXjQi>7Dt{7=UBzz=$38f+zt>0)H2Y5USeao5l5a$_W- zZyg=n5*8~d0ZB(VDZ8Vx?h}Qla9v$#mE#ZsbDG^0A+&m0$Q9Fh`S^`1Y~RSqz;Yn5 z>VhHh9|<`_RCjb(@jGnNNE{rV4sPSKc}qYj{kS2N=lyq%|Kt~P(E0B8Wndw-kKSsL zi=Z+@hqWV*orC(&rmsm$fOXUy(h3eQ#rw&=ha(PzL84~C5CEPRa(flgF!YVtleybo?v~xk1DF8Tk z*j51*!zXzYg&aL-*QF4e6zg+DpB15D#-(7zb=GdzoA0&Lf)kRVHudj!WcNyZ43wx; z8w$pE7&9i_o=!~~ovT(NJPvc+!)8Wyy&*-6$0OBOh#n!l>>L*;_u;|e5m0<9Z8_pm5)=8z zPD?fKLV9U8wUnaDe6`F|bsV*+Xw{eW)iNj`ft>zCub zoiRoF0qVe$e`7G|TYd;hIu)67JET|Uz6RWtG6|=vBhT@7s2req3nZot+h}38vN&6+f%KEK@gd!{jGaf1E%53o; zFqms2jp&Vb9##%m`zgGIj@D3>o<%J&PKtne$N$+mfp}F{P$|^};?VEbK*|E53JeRw zt2FG#h1(e8_nia`P2M>4D2dj@!8e%ItwnE1mCaPo636kmZmNYqG<|}Vs!OAVso1QF zN%@sYawg(X^>YkJxlD!z^G_$rIcnEADpY814pCQ+F|}c_=MWn;O@$-Qt9b-0JFL9} zjKBL8tb1imO4@Ks*2O zt&A(@=MV%Qz*M%Rz1~1a?&kGrG$Q2m;SV*(m*xjw@-M)S>GcF|hpfq{!48)~@}R&i zeLEHQ!O~!9(?F1(g%J~Lcb`X$t)wmLW-mj#+qWMC4(kv8T%K#lDPTI4 z*sIxPhTc_jX>)l=(4lJdofOQbG7K(1=&8(T6x&ad=SHy~B0^YkgJyQb?Ys$clQfdE z7DCMeWTp+a{?r*JFL&4ZH6z9=A}P#gGc^9I$jz=IaMzf2}br^P-hqPJ=D|L^njC=JpU2^)c|kawvOyl z91yV7-Btr|kYYk$2qNmyzIS)$etVz3lno9k0tovt6`H*Q5kiTvI)>N6`e>&;1*NH*LpV8D8F&K8-Dx_ z3q#vwF`_gT7c^V^cUA)A1;DKErwHH5bs4*~1=4?eq{2T2xJ(|!;+`z85TBAhQ9>Nz zFx1iC$s4D?xZksrpuBCd4IL(ffsU#K0B*tE*ALNq5ZKs*YDxo@{3)vv4!B#|6aFnx zM8O<&$z4iwet{obI8-3G#5q&`DJ7a7&^hOuOv@yc9ULk+nFOciiWD(O{ZXtrlL>+d z(i;NR6Tr%3AbLIKpU!<>`J51kN*p>O*&APZR-JV_yI17a7HT?ttHuJ`bkIcs$1ht?tHu-0uo*&6W{OeJ{rGEDo;C0$s;e*| zxE5QBi_KRYquWLce+foS$T36BLI5WQuO@rGf@f-*BA{ZLE7Y72WCzXs(jwtPRGR!E zc9xN672CnQ^tXi?_lp?UL|v8XWsfi?CX&Ym#HL69e+ma{M4tduQYX@?HW9z2YM}=zH9CD*z9-EP zrG3sC$;t5+TxOiCT9fompWbf{MwP6(D592%UXDOnyCQxoZ3I$4r}z(+x2XntMl+1* z8Tp)sifS%9y;i+92_#3l!AR`?Rc?$re4`>SlE7Wt+!SBE|DM4fO>@Rz6UDkwXV0iN zVJH(%!8en>4_VaP*o${RTR74su1#keGZ0H{cy4#+D@m_UJSzX1)vOOymTjJpQTC`S zvuy`7#oT$b+>^vOpwp9Jg{rqMq5kxJAA<2490i!=iZPYV+YPn~t+u^i;(`sGY|)4I zr+{|LoJ!CQsmn?u&2GLl`gZTN)C!&w$wlDYNSt=T)b+5R+cFc=Oqn_nb25ubE|d0@ zxDkh7VRG0d_(OY!T{^7QJPLjB8pKv-a(^A@CkK?5?F}y&gQ1yfhq1A88fGFgmnyiBBk+G zCZuYbDvC`P`eMO0K#l&!FCzA$5B_{OY%{0a6YML*TJ9h1bJ>`$D0#qL!l?M+{*(1v z#Udz3SYQ2)(io?nF#RQa-n5y~iER4Pds;%wDv{aU4EgowA%Kf5bN1=1_@|Fp8f3kQ zOA_lcrzO&xw$p+yQ1|K@-(xItfLs+c;mn0o&>wp_lWdcNMX?_GxR zSl*Go+z!^Al{1I1pndb3U;^o#V36MH^}o};sjbt7<|7)*YjkA6PgbvqB?l0wb%08j zE}aX-Q}-9Z1ZA(-L%wz_pAv~~)9#)Masl?4I93**g2=?Znvvdg{qLMP^Kc09i&75P zwhzzw)%IidzYbIgHnf54>(?t`H$Gj+@P^ad=Aj?I4-Qtn!S1M8fQ99yp$R4Z*Uj`A za&^JMu)-HDU`AQ(PbKrf;?&2vJ1F^0Iwo@hJQ77yJ0@xC2o}j=L^qs+Z}1wa8G0yT z&{ymTnz^$d&<7ou!xFfW@0+p?rCXtF4V5@ftw-l^jR4o3t}cS9ozNBL+vXOOkHw%c{t0L81Wvz(S1}R$6}Ec+mf3eOEz;#xI01rK*_*Q zYjOG0P8-al>};nQlS#^M3Q!IyE1O&my4h<2P+jDbC0%bh}+BX#@~n+Fo>R zOiTfjGX13(5c*i*DKGtIGEXk~yn^XDN&8jM7fAIJODwoTn`sQI<#<0Ven*#?6&F^a zb?YBlb6dPYdxD(y8<#qOabAd zitywfzlncBkK~p>B?FUqnftUZHNV2S(&QVV^&9_O{%A?7@;v&EUy&DrQ+I>qP;X=UyHSl+wpw{JJJUK}M)tWfEhz@OQ)yB9P!ycnf)`xh;N) zkTVTZCc{olDlUA$WS2Xg+nsCU?dE{N*C%x$Lvcba%NIfRV_g1_CRwPIyi#uC%e+tF zHa*xB)Tf$%X9pC7vQKLYTjQZ$^)?>sIHSZt6B?o>oH@&8)8 zTt~-Ii-{-YpO1&~B0f5I-R5V$(Rwygu$A}8UrSr&p(sx`+;$xZeuly$>*9nctlU|t z`~m|qsy7l!c4zT#W;R?95vLkhG2!aRJx|N+{x`Fz8vN+&nZ{=szGjHUSKT&?c`7HoR$#tzi)htOTIk3)A&N?@mF^>qPR+|o#_wMiYD>v81(g=~pDV?_3WMG*ue9$Jc zCHyVq05Sb}KH6IE~exyf!8nbXVH4=2Be{MulR?ZGbx198V8oM|BBl3^_UsnU5 z59%dyECsZlyT6!DozOR775^6bqWiP&08s>h+z#htP(^O-Ezb{yK+Q_vNaC6y7pobL zuz)Us=^cvsYFM5Z$QSj39f?cbQY$A@>oAN%XM-r1V?%vNr7dvxK6jhd4G*llN^$V~ zT7*1yGMNxzE&^qokOxRi^^)90UeTRCaTS3@!&h9yBboq<;$vbog0;BVd`%@tbYD7WqE5JbY4Z}GpUa8UFy-wF@r!FZVqj6{Advd8$lAJ`_KYwJj zSoMmX;AYsBxRLMT@)vc*ShQGQZcg9mmE`YEKhp!?h;K?$QZE={kJJm}{T1VqKFtZ? z-QDy9lz~C|d=fal{rbouNKKJ$P1Zi;$L4zdt@7ue-q+ zAfwX-(%l1pg|6#3Qv_%k-n;S2(upZzh=vbXUagQ$V`yJc!b z674We;w{mS<+t<=b4DAe()A~mZ(`RnA(hy$%|$@s@@Vz- z>%K10OGPeAChDjT(y4ae?p=rwo`&BgsINq_Q4|#MAvnZy5v;bixmH>lwVPf_XB7%yv8IOe=i1&W{ zO5u|E)RNc3yOci^rCDRA&b;Qwj$EW+;5k3cQs>A`rpjD$ce+}NIN3nnHJ|kV`++^m z{ldKJRObq2LKv$>%K5d9$e2~onQ#8U2&5dm=Jv-;QX6&3ZKlF|^;|lHeH`WE#utRY z)x#Ijw^G23?bFy?oFbGv6}){Vdx?xT_T`iujzosyRAx>M#`!P$| zYCxq=FMKDtW+eVd?K*gWW<2(Hn}nc2B=WwQH_F}j5iRzZ>gr9C4(1itKy53}v!E~h zqxz#?EYae%2aqSdVfG+ko*RrGVr>{>tU?(LV{xz88tFBW)yP7SzN9(MJ;6PEzNh5t zSTJrmw+zWHMdLFkpyNk^@^BfMWsYWMY<=wys%mN~N~x#hZ~|L4(c{nZA`KtX>BQ*2 zx>E-20DqGcw8&TyASVT=c=Bp2gNZr3@1+SZo|T=k3bQilp;hPA$qpLv>O{uS9o*Qa z`SeeM3(?nHos_X|xfH#J8)CKy)Lm|SdXuR#&RwQN1b~CS>s+PUF3wwpOTpZPfAMdt zv}-PCd9lotwAH~@X%-P~-@eLd7GC_R(-NWH))@aT{C>;5C5CfhL>jMrAy>zE@bnDF}f-!L}1y7&%0}Y=}FX f?{n=|IM3=|a>+ZTr_}fPTAjd7EHaF^X8z|9%!z?y literal 9274 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 diff --git a/console/src/ui/viewer/views/Spec/index.tsx b/console/src/ui/viewer/views/Spec/index.tsx index 6a8c60713ae509ef2c26fac6c4b55845cac92173..3bfdf91abfd3a8d654b92ad88ff42818b765a8cb 100644 GIT binary patch literal 17007 zcmV(lK=i)=M@dveQdv+`02j;u002YG{+QHmW_P(Z+~!cC<}qfUkbF=!)9LSXwQjEv zu49NbiKJy`WTeH*a&Rk#^N(uk8bVP=rukrbWpCa!ReM2-tpN5k&#&dWy+KYWm7oLj z8~=?l|DWEI5#Sk*Imp z*HyuwuSCeePCCFTdS@j7-etP#JsYfX8Z{i;5;{LEKT8QZ3B?7;n@1bss*IflB{!JB%0!m*8DM$6{&#~OWUpFm zm+E2mNoa8K(It=t5+v%&oM5#&8|&9KljFBFC96!V;>l6Dpzussy_|nQ(ChD=*&Q1S z`4u?+ptL1nX@tEbMnq|ln+aOTsLcjXkWGGMz9t#Z>lP@6T;WSJSlWoOiJy9(k05FiMDR~Mh~N^lX6U2+ zxXkZ&ye7$Ov?xapv5*CbJ7YElI4$X+7&Ik5C36)_$f91i2eBSjL}4Wu@NL)Q^#N6)I$%Qdr7;&zA)ijX@l-c8@vt%ld{a*Z@Xom#&(z|Wp=`;Q()_3HE-l! zKJsgsqPBtq+Rq{V8Px;m3P=_F-Qhx24Hye`H5-x-KgBvCt-I?{kI{Yq`vI*a^H9s~doFVi)R} zz3w^d)WvT=LQmCv`gfhnqH2&_pDnJ z#2dC$JL4cg9VKtSvaK%?UD^67^8m5L+g3bQHro6`lANA#+f_M!M|b3ytBv+v3vgpx zHOqGMGh;%myOsfds5yW$q}7AIk(<@KvQ6pcL`@dr&M(jZFbU|+|51p1cb!WIx%>7~ zCjU8K?m-bkCz*W7o;gSGuQsC2ZPBolhPQ923>-XD^PErw6Lc_}off9v?o5p$_7NS9 zF&GOvBT`Mkd{;DA*q-P*$BiA8=y-9cIL7|OSU%u`*2%8_Ja2y0?Z+m{e@bX?FHZhn zKn|#1+zz5bS;7fT7m`5kcKb|FD?1E=@o65kS;#LViUp1YP)=L8i)B*B=#8v7ylWsq ze})Q{fIyi=Y8C!99g2DetZe0J-54<2I9!aDT5%C)Z3THo6A`}x&N2h;7;n)`Zo1Jd zv}rs+b&Gy^(j?a?+1pZNjr7a}HJBIrErPnS_JR+=H;NYAqr}m?1flta3{u(`derl~ zjZe0E;9+1@?%VU3pI{PX0DWRX33&vgB3jk*Gh&f!M-j<= zn(l~@B-eiapx2d5!GptM5B*ed(FI2W?uvh@wd?|Ah0N=CTmC<0dy8Hdo34$fGf3%d zWd%Vj1+P1JeagZrBn7A)|DJ8ZcBmS9TBPC-E>rphq-<@~2{kRzI{}Y1yS>2mtzryW z3|#`t&E|q=5eM$P4fCC55&aVbeVD;>j>RSlEr=v02csNpVR)Tz=aGi&BUu<$`jUXe zW({OHa$%I0`V96S3%o)MXE!}pa)7j@=1tMaD+Qn=exorrr=G+5xvI@jk z;ZVdq7>&+24Y!~JPS|lrpDQi!_x1cmsj5r?M>nXx<702KW&qMo}8pCk@O>$=kkrHFhpN6 z1~n4*w@A*|Vj%zQq=}fXIW9K0!sk}7T%qjY%eO~8NdZ817TIJ9F3*8`A=eX$xvA~t zaTdjF>^$f&hzG}H<;v4#VXow4F~bu`6&leoL|;Om9L-hhk)r$0jg8{vj@^yIh8^6h z4*hR|C}o?k40X()`7V0K`f)L?q{I+Q0u5yixKU=G<5h3wl_ier7I`A}fjV-t+p40B zrPPL2HLoPz@w*`k&fUj7S@iozz{famVyGQi{ha1{WVk$+`S zV`$64AxtH4kI8bXqWf3jsT@J%R_;L1Qr!f5)x@^Bb#$i>c^$&2=ehk|T}J zD=si(6V&V2O9|$I75RIa2CPLQlRGYK&TYpF!&(tm7)XgOM41`Xy5}GQXbmopttVm_ zmPZP{u64}4Y@n^33kH$p8F}xo(+D=i7Au~vP9k}mgwf)zkp#0+Qf+HAqyyd@pUvy( z-W~NEGqFJ+2!KQZ`|2_;Ylw%e38-+ssWIN&3<~N^>iCCEvqru(D-p6UoMK`}>ajb_ z-lV*Lp0+If18cob2}X?iMu2BkUZTZTAM8$2i#)z1(c059^~J3j?0KbO_h;@y5J#ym z9g7S3gnRsm3kBV`)5<+!8#JV~>rAG#y&M7Bxaq0nQ8#j8f5I=V05Xb+>a|spD9yH&5oipLVwG=P32( zxe6ka=P%|t$k3U`m!~~e>n4t#Wg!jFCj{WDmhp5Pctx`fv0fe8a7VOZ;7TI_t=q<+ zANu22)9C7oTrFri7Yf}w4p5cDteJkh@^b75Z=YDdXMt`5;WelL-bLTp5cy5}fU!+a zKX4jTMKUNH;pK3vb)RFFRfDN+D#NG;V$Eqt1mpN&kz0wqn^T_{#0ahegf5wb26sy> zrJtPO(B<c7OI6Z)oR;OOr9R5*FQJAT0?!0^ z$I>fu3YuNN@@y{v8+IzD(c{Q6!MPEiT-TCNO71O5trUn|5t+d7&zq#ac8BM>Rq|LF z?{s~5l!xhzOd!nA{Ri=?qHgTKCd>IwA$4z=Y*4xkN~WMgM`>cJ3VhcO5QNje&>hjM zk1!d2SwDZ{p?R^Sse+kkO`oOk>&BaVJsp$Z@}rp=?vPSF#uAp{#W>*;o{}*y{PcmS zCQFI2*n_}Ox*LZd39}Gwf?+-w_7`$8)96yU>VkU<ek+8j70aE=!N3Ml z#>nrH__Rj|`)Npi`9mdjsS1R0Uz`tuautSTcFm62q>I%5Redp_AskowaIYLtcnchMk`N>`U0bz~J)i zM=59JX-jXC15RJDDJEsZ-}ST7`=(Rngp1^y{Cpg|@^*oqCT)zircjDeLw#eQq|K?o z4a(G1{mpgiG3Dr#X-Z@5t7a7Wg4BX81tZdilw2Ar=q^y~M2Pl*S5v;0lDk}YGuY=4 zxv}tz&Z~>vQ*Ow$wDLAg3j$E`iHOv5gP+$v;W`F97o-MqtWFLrMK=Thg#_+BELY|L z{WMIsoE`Nj6apdFxgc3_gI_Tk*6-+AY-o9 z0QoP{Wlt5fIX&o4#SE$Cqc9{7dMT1VUzdmhKvg4m+i2$D`n#z`Zn`aCyt043Yfig9 zC8P?jC{m&`ni!juf=AC>lLjucBn%zDO$)YH47pEI{xTh~(6iKqhE0gp_)(+}Sm`(v zAupc^DD;f?n!mClBnHA+-jNg?!SP@aM_^#N&iQDQ@NlvjkMgJ3DRTF6;|sEF9Nzz( zk$m62Gjp_fG=3t*}?!dq?`P$4AgBjGUjF;Q!av(Liu1F5PuVq4TZ z|04h5ou{Ooz^4&WDwwk+%))XE#T(tb62)mSxg1D+&|pXx3tE{XTSh$n*c&(m*K6{8 z`jOOOxWo_NP*+P`I3CmX6F&|NA{X_PvYv`T-S@*{SF~{#D`hwW?Ln9_EhC~cCw>WZ z#O$9V|2(KjRF%6Kv|j4X<&R1f9gNL~!+LHf=$N(~TnR`2&Hck6?-N+)J{m$kV7;JN zBwDxekjDQ#efQH5#6^4efamqq^}h$@Wz~a+odq{UfyZA=J^(e9Po-<<)-eRRX_%|1 zyOg?0IA`FQC01agYHi6i2g(#ZtZYhf9&8eSnzF#U?J_r^X|AML)d#GtLYhRa*21Qf zJT*G(*$M&~iy)bkjD-dq>Yv7WtcZ$gPKuT(A@ z2C)%VZfsnvohuATbW+EHHiirJ_eJD~q>yM$&la1l32b?XlM`Y%C~V193g>8|22Iigu)%cZ8@t`a=l&MR?rpZlp2^%?>*Zh%V}5}_$SO&^sw zEMmA(K}clrqIqfkC<4fF==ry^gUm=qpAVXa%xMKzIQ_1{*uQZsO zel#;OYT*cpyyC8bK1rCNV6TrTkmI3zh zXrZUY_4MR4Q^Fv8YMH8gD1SfV)&OooZHbrFIvpvf?q;_gSn)mSeFqv+!kIg3QX5Z< z)v*^#5Tg~Z^e;^1B%1u5n}3J#CB~-18^j9mu<;;xDVsb5+)4u!+k*x$1X7*6#lmSg zE1;fBLf%Hb$*7-~t?DN~7V`HO=}r7CJbND~nKSFBVm-Zl+3?!BlIBKxcWM0V{Zpg% zBtsti28I<#2c9gjB?>3!s!5J7u6q|i8p#QZyR@E$572JDy&)xQ?g?~V3#px6JFA| zEI%!q4#F{dXVC$y=z2-va~25`B#5I3WYf4X?ikXZX(TqJA;KH?U^Nb1O{N~$F`A6d z_m-15-$@%a5qIvQDt#;HYx(1ff8+gznd?i;^1LJ>U4inx#ujI5GKZ@Xs{*6 z?d`$aK}iKrQa{UKO2dY56*zj*cmMdz30k@NLD8&N0cU1BI{vWH-{%vj=^D>>8t#@& z_@dS!y!d)IA z7uEyrY0#EOYpmq242v#k>YD*VvRrZvmR@FaNUU9REVjNoKAoioVzQI2Y1;Woa3!c! zE~Sf;bXg==A@DY38FCXnwGFDuS+eSX2+5u$-E>^+Yy=(GNoDq;QH)(u$XE+#{Ca3p zjmQ>|%pVN~57M^nOSREK97T{VxY?1`LO3TP0W09L1cr&by++#oh*(!ijBp{$OFT+N zF*372=bI!6<_RfB+#D_N2Lm=faG?@LJ7uc;^3+|mBkp}dR;-^(+6gG1eW;m%Ui582 z@L1Itoiw_lg2xfldeo0v`3cA=WWQYf8`pw5|HkfS2}v@T_nYJC?;`JaVtFdKH6pJ6ZQkbt*GKkJ&`Ym~m-`gg7$T%myO#+Vr=k{tUn1#|w2^{?ao(t<9O)~Y8d6^X9s zcKfhyW;;CPX17JfnT2Yx1Gu-9*jeAed9{yV%_etf0puF*gO;@*nlOK>PucJtRRR59 zu9SHn1g-i+q4GmdniDC%rkn|#TO|gMvKIm-5gCnNJ`#sZUJA5HJ$iRi9Z``t{XS8y zsGQ5|Fp*LCj|g9l%;w+>BG{*1(!BUbQ7M@f3po04Mc`>uNAIe^6+B|LdgT+?X?SD_ zInRk=GVl2XbYt4-$1f7b8JNne&PDas{hrpm=YnaHCd2@vbj=$s9$dE!Ns|?bAr4jf zYK;yPU*V8UfJw_r#Ng%ap9g4BzT$jLqtazrZDB9Vokh#Gg^;G@rM$c)1`tGQGgERE zYzy$)E6%xLc0F@3y>!)_wTW4XNatQ?QJ3g9X+d1Fll?_9=lcG!Tnw>w^6v zjId`lQ*H@1w41rIDjM(k8OaTM>zOi<{%p&a8RJqi5?y3fuQ_d>E>kY1=d#=X8{0@%zsEwL4K zOPBqL1;vu&u(vztwd?G{GFC0oW#h8?MIbC}c`23lu^OjNTfL85D*gg%0)V_tFKclP zLD4P|2gkNc3Hp2bFT&FKVmf0>3-5F}W;_5|rT4k!b#HiqI4ns{I_<}pzj zSLyQndtdU@^i%Y8s4e88lNWBoM*x^DgE3XfpZqEWn<-N1%I}leM*H&Bmpa9`n)c2M zRRm5&7y*Bfj|au|Iw3c#wFsOHPZ&nQVr(_I&HzY|fJS;-VEe2#*q52w5C9CEz}}mYZu2d8*hbq?rAnrbQWbrpLHGTT~GFl zHUrbDw?W2n8B4>I*Mp}-Y+5ZtJb2JvWAG<^%4`lKH*?$!x5BY)oVcAC7rpbEWpQA$t(#;O#c%#h<9iqH;LIx`TNlF1NSYjFJfw{Fq8GIlrskmw-lV`pI(?5b< zT*F7jf(3<@cWnV^nONRv4J>Yj6UM8=g2R#?LQ9!eDQ?}9y{MOXcczt^w2DSOM_(=u z4fpBpM}rv0>wPiY{A{oV%`C{ldV>ot;{CJckgCpdrQW7P)c^MZJoo!ON(zl+`jB?geQG#BjuO{6OX11U2v#QC8$0iNXyI36eUpDICk;K z50*JTL=|4K{mXRnyu%TGW)?aZgAstF`pR^KOKt!MrB)T&PBx!Lq}jJwP-u}98OI9h z^Ey8X;Vmp2XvzX|W#IznZx!7-s79(leYghGx`Gmi5_m7YfM}E^4qdH*4jCnfgl#|o zP{VZ_e|4|8KfTHdPGwkQ+b8rbJ$_~5;aaQ|=sNPt!^eDGc$ASgiQV)E`hltdL%GA= z(ZOYkF70NJcUywjt#Ol6rE>HVUlEF9_^-#Xca2idAPXKY=S=cBj*E+8Vc&fXfR10= z0**dDqf9<-BaNEXWa^g~atjWqL);%lpiThC+7omtY&Tin6TvYnJTk^e0275ZRO&J;1(k z_0N?Q$QpVTzd#K5^|3`nk)y#7F@gTdTvywtd(W|7EcUf+p;Gq<2x}W7RUF+W>kB@p zp`Hdn-{J?!m0$D$r^*shy7RNsJ0U<&AG>fFYC%E;0t4TJNQ1YMC=(C5HFszL}PG$!Y*`!{q6N9asZ&y?4WSNGHg=3r6<0D z@|CaZ<9r$DE)@3-nbz;+xU+bG#r#`ajjXjF+~o-cu0V@xr!_&SC=kWXZK0}OIwa+$ z@Dlt}pSK7GO)ONBQ>?rb;O5s8-%>+?#A)@$JYmE=cH~N;$QvX-to~XbN9}?LRRg!N z-jjc!hyL|nA%-{+dk}8$_-hK9-FVpcA2}bWvdk$@f=A zL0C|#*JTFMGJ{$mu)3z4C}%zV0-FAUqgh%$h)5rPpihLkRL0!!NT{#0!=bPH&UYDr z(INz*n$gB#Q)RQA_+30P5Ca3$SBSpx$EiqkI@cM7Gse-CWxz^k(`NC{ zlm~rgfi~M}{lO@W6U&MlI^S6w&IP}S2dK_-QIx3 zFEr#P{UCO_V@X>cHPnS8KctXo_5fc1K;!qs8keHleRcgPPmOrveNRKj-a0j`EF3PP zoBwvFi+$@=yg+9(GCh9@Kdzi;CoVTh-U8<{?ax?SA5?q4p5`QVnw+yFGL{b}m%r4P zOeH_l2YIhwvx43+0iWw)YDD=Libm~Y%M!FbNSaDmgAe_&%E26CUVKjRUn?RF*@w0S zt1e*1IZU2qHIbVjcTDR&!$C=wezzEEX`rNK9#oaC#j|aU#%8fsZ8453RyEQ2MKX|~ ztuHkjWW^bttKM8evKzG1xOqRmMsTRoT1=nI(PED=L?C%FxuCvQzFLXQAk`1fE#PGQ{Uj+4_(D>!QC1r( zUJI<%Bo}g*tm!*ZzRpLlkNJzU0kwU~(D|O3rlQZG)?D(SXLdkPcF%`Z5p#@Q-*20N zX}N_l8w}D(CZi$zC4IxHGxMi8G=%gULsXus*RFkay!AB?SlF_Gl!X0`fIgiSOBDxM zW(D@7*RDA|9ihX!2NYwvwbv5V3-Rrk83@esBd4NQ8 z^Oog{o#m+}0tq}SQ=WGZg04UIMyK7R>Fyh9?b}sE)#pt`MIN-zd^?w|M#bT8sj^Q? zMt$_DZJ8|%f#6B~ew#^&-vXN&b3}<{_*1A=A+~yXj%?b53qWJf0mpC;072mQ>SjNk zF9oi;#E#9-_IO3WN;q`rND7VinC~Bu*j}E9aR2NPyjwX~@k(G4vcs!Q9aDW>*vxOB z+~>%7kCMu2XA2-N$0}okNjbCbC&;-~c~SN}^=#HKt6zokgjmVI#fRLgZ?jnq_7!bi zwi1&|@HwLsdv;Q#>aAT2Y?Y=7z^Z#eE(KFP+NXIZuV1Yf2cJ;fb2X=I z`@I>Q=Ctgqbf3a&|IyJNfWi$7{Ce5*^MvXmel86OI1iQI*&<@x|7i(ZR#`-(B88lC z0)09bcd$z*@z>kE6`cgxm7*v=y|@$Vy}B27qI`p_KXXnJiKeC(eV}RKXAAJ(ql{R! zTaG^W8lEUiQ2i$w*owd}LB#XSjGqHPa-F0Me4C=zIwh94T7ziZMSP#rw<>ShRCcax_qjHwah{QwOFL&N12(*Xq{itq# z??W>7RoSXyJiLFw<+%t|h6fnWC%4bqRZG?Hk-T90QNJ%ox=a0Avf|w`N$%T{Pn^~? z;BxNyGKzxHrv_Lwq-AB)ZxFVL+&Xf0<}L+P$aKF(sYX}iA$XNedOLU>Ma``XG*A~i zg5Gti&hD+@V>LUKiR0+cytk}cJEdUfw4(SP6)ksiItct(S6UX9+$z6=A$+CX7>u6Rzav`7nWwn(&y$=@oAHeZfL6EhK2_In?FDU9g%R5l z13(mfCmf=k)sgNn5&=TK0-dt+nNUr5XGW{uCP%~BV5ACXf9f7ezG(lH^1D?uXkh(= zJjtg?5?QB+?B@cqy~OX!Q@gPUe*pDo8xvj2dN>eS^@-}9jVj9)CPaS<|;TdX}t4dZ|dJW|yD)@@R3(%@$9vqNhavX}1l6RP{ z;xzPD?4h88fMiDVi#SGy3%C-5o$w8z$$gLU)Yb{O7~ZdZxedj?pZ1MCnPkSQj$o6~ z^@8G6BSP!#dz7*G)nAEPsjA3FA6x3l8)_=-Wb~BkgLuXJB7R!3`si4dte2fT(?AT> zIq?V-YN*F~!Np>dc2_O=HZbVKu+$F7bOUG75X6n38X@F}ayfD@RF1cPJ=73WIjF! z468s(3Eyq5B&s2=r0Y8@Undr>r|EIevc_jH(O3R-XB7JjS=PP%%d5Wh#qI#+^o2!x z){5>B70sp=TT-Y{@{WyJ0M~QckK;8`P-(GhC8701X+oVyNsD+tz4&rum}zG2!vJa& zHLnxcwC7An3m(H!1z#Xux!Vmlk-3!Kwu@7l`aA^~xT6*K0P%p*{8$CuJS#e&&Z+S_ zGQAvT8rGV%ffjhd9d78MF#T8xQ%in>yWXr?7O~0EfYi`cmXzg|J6`>f-wYWM?cJ?J zCO8s8uWT}M4j5=hpZ&t2&2+{oYZ(ShW3`ol5g3=4Y}EZyh+nwHC|Xjei5-tn2#J-z zkyFbqH{;kuY1y4#Sh%+hl9JP+_4A87Y7jF7az*hVvIbY@OXu?1&m_?@vLPb@=Y0@S z+-l|?Kj3r$>aa5i2y3Jl6)^t7Iv zu2|)3);$HDIIOZJME_d|!0@*07-&{=x6<>2D!kfO52!p-@g;5R zPaoz>Ki9=}IVO#zuxHh$<7e`BDmO>XM{N&-cRdz7Y(5b**dEol2E57jL$V}h{rac1 zCZ>^J%Qk^)sqNmP>+!tkc@szf@H#l;Mikn%Oy*U?bj(wKMwOMg@c*~X4FYwKBz~q6 z_>Z%_bfW5HgUP>Op_(%)R$jw`c~v|}jm4x+U3s;7L;_>n)j$jZz}|=3c8}oEAEKYj ztE`i9Z9Y&)pxynrfq0ixl9r9;=QTQ}-Im=OhPC`2AkP3m*T@6G`lxOU!Cw)}gE9uQ zD_bKJZ2ctiC(Na4P@Fnl%v1*rpM;}K2o1^AmH*K#nao4SYAc~66dT?(fj-Rp0`$X+ zLb0B7O(-4MmjCp2>0vx%H#CiCz>^omb4V_m2Y`|QY(JvKq!>9 zD2jcB$Q(x+H`?m+r8|&0D#GZ~!^~;9g_Gj)zl0t|$3g%$-nQf)bmRuLEDgt2!3dr< z8ZG|wQ@)w6)i5NU*mL&k73HfI;!^x0no#m1Sl3i75l8Lfg>U_v__{nUu%8LMOfOP) z-KN~ki_9i$tdot0p zMIbAB%-?0>5*&ffbYz1thN$fgM;b@=ngRq#XnOL+H6lfz0TnSqC-ds#Sk{ke!-Xpu z3h&k4@u2;UM5ZFSA?%LAfVPi=%lYQWfh_#{xBXi2z<|S>uzVqgIoVej1S1`OZZ&>< z9WgvYKsy@8YXh?lI#YF-Y^7cKc_(c7v_5n-cGU{r&jh&M79{1E3!WPw2r8j7-9Ku> z{7S6arfp4l;n34Sxq0e1)hl?e!ewkCuN;@>>s9eEOpwTWV{G2KM#{#tXCjdeM)o;G zRGeHvgl?|>CD%g1Q)GUnfQrKar5Pxu>_u0Jfaxy+N2@8aV0}Z|>OK7bT0jaDhJM*6 zNQjT>rhm~0#=@|PY-0x*I%a>y4aFa>= z)?Zp0loRx0I9+UaTcMM{1>#mYVPp7h+)}_kyV~qr8LzKW8`bwZ8%(DE{4GZI9Z6G1 zg}nfjJ;}!~YqHDK@CDPNV`q{O$7Yq)kxtI3vp6UajQ{G#>Y;oSZQcHOQ}FUEjfSs4 zN^z-oR9&`my+(N>;^@k>>yPn_s{41cbbj9wvba15Z;#<&W@`YxuB}Ndo72HT@uHmy z?4GKeIDdhQNlzdpsG#BNo}Im^JL7(Ty}Cr9J|`@3S5`DWL}n1-Z-w0Iw8r3zmJrUQIa971b7hpTUX zy7-i7P11j0EQ$Ht+Li#^4_W|AF7M4$6;jJDDRzQ^b@EBD;uyci?%C&LrRI=fc2;+X z+vC9KAzgKmAA;DNVv=N5sp9AZ%}&+b28r04&c4Y;uuak|J(?{;HzBjSQr5crStcx@ zq}<0I1geLx?Tl~gUWLgur#ZXauN_du@8!k=ND5RZ>gK|D)rhu9=ttI4<3~wni~TG# z)z*S!yBhi7d@UCwXVapeN2wP>hZ9qHu9qs~3T>l&Lw2dk&dC;lyW9&C3+&G;B-wOZ z9$qEnb&Xwl_&(a~u;C85!0SOJ+al^ML++NB=ML;|iyZUhE^t4hB>1q2XbU-O03hN4 zEBXa!msKK|#PFKaO<93nZwmzy-UKE9up)S+CGO(rviWwC%^n>HGa;LJ7tC{HbX;PG zP*mKBzE`lL=ebSa)^-O5(wnK6UKaZ;I`>qwLgw_LX|mx18_U?J(XJfSP(jB8f6;j| zw=Uy)`=wzyOGjVe)8o|j)=nI$+ zLl@BWO>^|_N6K@(>d>dy1*;Wz7Arz=8w6Ui;b!{*8usqK8(jCT=44mt8Da#UiJCge zS2Cp4_u2ySV=J1m&+fh06nxr`Rt`JP?Fc*q_mp>>z4|KqK?m2Dok5VaZgqj;5dFd1 zs!~>%QIz%)u+N4dvrN{{GS*rq>c?L3?gp&K=>@gA2rULBU^mDs+hTUV^OHU1lpo8gEX z`2aT{0_~|nR^Tg$@I6~PNDLbnCo)at{6K_8;?kDgUHF(#Tao7(Gp!X+={(C(t>+9W zWR0hS^6a(H=01xRa2ALyKzlrvvgrCV8z6ymyxDjhIhGWk?$$koMP4c7%k0(U-G~h` zp>85*?y+a1Pi5XT&iL%8LogCu29>T_gV#-nikB#{P$fN@`XKO+W1YA~G+BU=}9L`z2N{i8b(J|b+R6%sP?k;NL zk#(hl;B_9wtI%${4y~giO7C9JESZD{&l_!ix@!rE06IT}-WJk#Z;yFPCtzXcbj3jGS()-Y)NCN=42Z!1$K9}TIkI)Gr#=_T%dVQf3nCj1dP?;SHY4$m-P$RPu3(Svqs|Jf% z@Fc_>99a{5Ue|N^5Z^6Qo477rKk(knT3$tB!bXVMJ_-J!KJH&nkiX@u73|Zb9|=@& zn!HyZ)=+0yjN6qBTsZ6W zIYqqSg~n&UuU`g%k=_7uc83=#*14Krwb!IKtY|<06<#Qb~X`m z1P+NiZVe7StL14x?|)INTatMK%c>$*BxQiX@B~B)_pLV}hzCw+`>c%M^OYU<@tGs2 zLv#4vbr{;l8AOgYob)frCa^>Bn6+;`dp=%H!wTt<6fg2n>ut=n?G&wYD#cu0sGA0v z)+6cOP~frdrQh+s7@qn@PsSsy?arH_v~z4nMRBOr^w&sq(g{$wvP;A zmHog>%Xzio+fM#en-^6KxsERvWCeJnRT`Wbed?KI`)IZd^DK?ON08j!Ib*RugCVK=P+VH)OSBpf+21od@z8lVvbEMBFHM zWgXyOpQ8eLrLe@T`JULCmv!7eIeTd&1v4Pu2+tn+O~-ge2af<`z9a6qD7P$^Gx!c2 z&?m@+nMx)ip$@(T7Yz)AkJg#=C`CI~v;4I2bYtKq0_|&Q(8lFn7cY81TITQ-oP~rX z;l5fif90XCy#g)(%q>qW@A1|S529RFo5Xj;ebo!&o494jqqZG}K4u;=aLPO|Me{U( zSMnYT&3|#eoZ@NjtB@SVTpApU4utEeR=^x`XxwQpLt6xk1SOxsqyh1iarXgDDk=E3 zO~k5@!&B$hy6E34r)teNhYh1BqITl$6|y{+&LMS|mM^)K`RX2-_CGp7C2A!KF-&JM zj5#O?lYd!((k0)C?*sIYp^Yk%=owMA)NK7L6&G@ihgIaHW~C!QFG7HrN&@A%Zl5QS zHFGKLCfc&#{!Ro^3Px|PRP{B~HdZ$$9(r|`hadQDx2p$&%MOIc+f*(cwbo#5-RE6{q5{lb2#@UoCA}~x=-4?qq1A>{N;+k7Sb|V-&$1D>D@&s zGA~Lo^W=}KX<*3Oe*&%aCxkmbq858o_<|=dp8hbz6;J<@BTzIgL71j->P7!8YGqlF zcw338a{t%(EFLV|;#noBXYtm(w*21Csl;~53xtDygFyd-9h5>Q9w&{lOq16&p2-So zpK`S@%ggFnC92(H`rVg(-B{>I@fl?%?G8LOhmh~3zS|WFLlPK2%e15Vu(y?QjQp0+ zPK0C))~Z%J?})P;lXEfxWyNDp*^T0m{P74D=g zqQv~y21>xLg*GqK6WcwLZNMiY7M;L5J06Pj5IHeh@b&7$!)J+u05_P_>RIALt&M z^E0gmUdA(uI>}@b7hMvEe~IDCnj&Hw;PMG>FMTU_w^Sl2lnc?bfwpoidl7J19Wf(p6lV4PBtR|Ho5 zV{locDA)Aw zoJa~#r8A6R+7Wd4%=E1<|t>!REsng;Bbpr}o4a7e` z8>ZNL1iz6?DYDc%fhh->r^%7khBh{8+9?yjTW#7hS7 z4i}4+B#fLQd;)I_s`z)0tVs>Lk^3QpRKZE5hgsg+Q|5{=Rvl~@Q!cS7kYOGDac z729r6yrip#uDNbJWoUknT%}b-uA<akGt%E5JU3@cOgSOvrNXkKa z-ycCe)5OxC`QgZ)G{u|fu2z%0l4tc29jWaLz`JT{@P2eS2$P)p_pZC&DQ@iziB5$fe z`O7dgE04+}Q9``y(0>TXQ&^D4SE0y}05?yS?+VmmXm~H}{6N^&12EE}QNC;$Ydt zvk82c-QRHIIe%6klcXT+Z?e(6@M)Qf2gK>%_xI}KM~y4R$@z;Dp&ryzKxOUxajuL4 zHbdI8u0%pvFf4Qk-q^3JS&@#a&1wweF`R#T^!|z#;U>Sid)T1tyseJU;bItHZ4sM| zD=1kKwC5P#%K@?;_zjhsZIRFAFG{T@_2<=~Tiv;h)|-p-dLF*iST^C-q|UU=hPo;D zsQ7qq|HR4I-sq;wtPsnsxLfcN1x&W>RQ8aqhqb0Cz7KKXj;Q4h3t+I-)hM$}Le z^NP?!{{W4cWtqV&R@Iz-Wu$qlFn3;6bM4$ zqpR77;E0v&L>M?k{-jjtVSu4YzLpD%1dWcC#FYj@aSQ^vbVbzV4S$=}UhxOg`e^6I z6X&Puzj-&b4uDwyS%P;R3?)@09FRTD2{AQT1jSyp+^ODW9)+{i)3kmh7}kN}Xi|D|Uj2w5>_^x$t0T^8M+j8%N{G?HpAUm76A@FueE3nZCLP~t%aW#dy z!q5D*uj>Rkys7BhY^vY43Cs^T&d4PI8Q}O-85p&VpyH?K$D(=@?$T)xoNqd6FApH> zF^xzaSv}vptHo*hgG(~oTRFRgc(1sEiz#NxuIrxFxluFM97H*aDY?vKxu$`HWnVc(E|Y>q(UFEVG1hW=uCx{tZ~PO#cMJ=Z5$%M(i)VlXdT%k|4xo{KiNzbfN`> zf%7i4NvgO~?ay8H?E{%X;N%pgb0PA*as*Ty-#cbN@Iqw8E4&+}*Gcu&rocki6$%iH zYms`PQo%}Nfg27%WjE8vsXZMbsynaG8dse`TxQ8+r&kcJtecPvZG~8XuHAts7zVNF z))!BnS~~CrnvKrxmZ#+E0XK&FndstX`(c)1@ew#19)HL2quRM2pRv#Ebz435YrM(D1izJZl0d zMWGm9B1>eEJXHO^9YfGAbHA;>i}03#5GS}BeY3wV@3vWdNpj#wX^*bEhh2am>@aCk zLcWUFBL!y50LI)hVRSoqbp9=kN|W1oCz-}wg^9U%6Kn^_V-xw*EPZJG=x+9&~2v=~1^T@GV5 zUhf}Fy_b*R?EcCY^UEraMm)cHT>e}j!y3BPNUz>alF%yzCR%{JxY*t+~ zGQ@De6RDK>wg_N+Uj97Zgn3FubYnF-(qAm z&LHwx4$r*&znNi~2|rF|Icnt)6JM`BRt=;kvmQc~nH>x01`N_T)f~$PA>P#B)n;hg86!xz zx*LL(=dck#-z@*1p#CYBNj>ohC_6Js{L;;*e~t-Xx74vJxDC@#sOSPbyTH4|Tn@1x zO(H`$th?6*_KB+SH;0)_7poqt2*?lkKu$}Rpe9Lp2Q@LWy#+)dg0VOlxr%Jt1RD3=?4e&yxo9iv|sMQmeT# zDPwZ1Aa9A0Xy0TRW+uAH;_!Cncw(fX=dRD}9R+ zjVmO&KY_PDdmKXq%`!fRTx=pA?XQUJO&*iKm=^_qKqD?b*<}?UCe)lM@8~=>3diDM zzHrO=h!z~M6=73g{F@KrX-#mtStg)ppfKd{IIS|CQC}B@Tlus>f^}3Y*){{W3E5aj zps>Qt^iQf*dw>#YUCo=~U^I6dX@X4O0?QXq7)j-fj#UBWcKh07>fVTwgn&B%9m2VR zU(YK+1@v2eON|L70`G&19(kFb*1apIqV6WDOLpZU+QW9{Vr)xrXYCyQyb5wC2cv9} zq)o~|C$~-bYsIlC@Gmp|QT#s-E-B@t$@#b=tgO{wL0|n;VTd|zuDD?eHNMqliPd8? zl^K}^8nT?^O+|>LBxb?3RBn3?%d7&0zk{|dC7%2dRl$VR9% zMd}d0Hj7X33LnFl8wD)(Tg#W72K7@Y`7DyGlP*ToDMCNH@pgXFt-trY~SvZ4P1I9!`hFvj3e5ICsZ1WgCoy>=L0nGIRVUiF)dH&B= zF*CMBLrkz%=^`hTw}QfaqFm35u@2<6ZWX_S5KA*bE2w3H)yHyN6yii0IaurBL{D7$ z+09T>4t=#pfy8m_p`Q3sY5;4LucavzjVx7^4L7a8f$>UUC)W;!z~f>Y)=^Gx1&j)_ ztvMtT<4L24-0Q6Btj>n2VO{r9NUSFJGTA#^W}&Y8ZN^niv*pAVt8T|Wwjkiez(q9*6RaJZqcL#(L5 z7m97AH({0_ALj>Zs}z453V|aO64(T(_*zDMvIFa`C-?a4U*sj*=5kytVIgS?=Xu2> zJMyU(4!3r)#lk^}^XCNTMe#$a)nXZsQXz9c2l{cV78%g5imq)Aw?cKaYb#_%Db=E3 z6~)mj9!Ls5%c?I_&MNyBFNlF@sd!-daaPq+Kvf~3j6%1g_7b)!$B)cV;@|SV9zI$p zRh?GIEL#4k3itd8-H(3lsc23lNqz}L`Y<@T8!)=k7QsQ{Cv_ee+Ig$wX{>kTOw$EH znXo5A@CSvNWop1J%CMJ1CK?vmM9=j_aHtN@8eE}(x{q@uaD(n`nXK5cpZx?kU75;g zax*a93xaGZ%g5yx&djac%CzZ0>(@B836K}9E7I(zz2a)-N z%rul^Z8_By7pA$%h4W(&5{^wb){NVT!%FT0@OkI-p)WFm5j3B`Ku>L>zFwN8<|dk( zSR+W}W`pAw3M3l|%R+fO@l48AsM>G~4uQX*>_ZCJLDrJ${0yUN&!3`xY*kb#!dg~q z;iENKbhK6oGZ)+y6KdgKv$uSUC!f?bC8dF2ph76HyLY{_}c)R$!l z_V_vfxq4{B7B(*<2L6C+`A3~_+?FtiW5%G=fHmRaJI!=-h*C;9ag`GDL4qSPf7@&^ z<3TorvxBPo1;*khY0kOYhfK@JCD_lnViva@2@D<(pjRqQ?k}QbIu$5aC^?)-34Qof z1L)XV2+yd9FdBgO@H^A;ly9#xSU6ctn1lxVMHI_Z=;Fyn#uV=)6H_sceO@4J7;g`K z;qpM;P#aM?fZnMclECUu>6OCK{Z4W08Y!veo*529B!IP~4$P7%7+tNyr(u-fELB7L z3TD~VCdsEv-pM!hW6Wwy=$c_GtfGu`9~h<$9`mP}ZwA%6mxby5y%CE=5|072A+wgG z?j<_jFUehQJCy@zFmD2U31wx>*iy(jc|sy=QX^=VAD={msPeD_%jpmtvA9y5Q9u;U&%SS1kC|a9qYtsl_c|em@WNt`-O1vdV1mmkS0>18q|V;$_l=eftWV;#HR-#O)bFZh27w+iBN%(C6AH-gL(pn`(YG(UBk}H5c3zs>KBZK+})89V1 zRRL*V5vA(^c2$4D5mEFAk-MIv^;wkNtmI3sagONE9RV^gHYNn<>)|#GnTK+A+fLCplAWUg+uM;#V1K3_-7q{FISwq3=<0PaHdBBuw!5eYVsYxi-jz zN8-!M`#?7X>WkD-i$k)Z9mBcMO>tNm3x&r!uj1LcBchHz*j?H(d#THwfS_j`>oP~C zT!3gH6K=Z52>OUE?vetxI11be-9wq~fCfhei0w!QaN#j)Fw)qA$@>JGH?fDk(X~@R zNq>gs2fjhT@f=+rXq-_!lbzPSSFMEgd!yFwhb$>=)2Wy!r*bI7k}GgH8Jl1cYA1;m zN=;0!O;AfjL$>O7Jaw@)Q=Zjo++F~OYSOwID5DOb<`)nCU z?q0^Tvun*j;|y#1j4bjnZQ8)FLB3Cp-5y3stIbPoJR~ya>d{wiMA$btP+ z9(Q+k#|@Y&*tj~o>lg;|1muIWrWY}dXLx5sXt?O&pJAQJN73nWIPse zeY8vDZ4#nC^Qi2whL_r?1CId2BG%lA>T)D5Cu*atUG(_kf-ex=~ow@4z4U@Ga4fBl6pxQ0OF7uB=Dc%??1ziRhq% z`BKVyxA|nZRn&slq<|c2klk)6Ulaq2LY3Q9evyZ*!JomFQg>wsNn&@ZJCP$UU2TEGtDY zo?ZvJaVgGrgC=JE2I?J|1R6o@e%hExN_v>C;(Qv^c?{`os*D2OKz|L`EVK;pWi!J6 z_Tidt=Q8r~GfkW?u`uV@3lCtb_w24cg%kih<75T+5fu?uPJIm0UJO zJcw@tso`joe%#QCKvAjYzJ{AL=pn;-R6#qTu59_IqSrI&8;r1RJpK!$mm!ev23r`o zi)%}qdQQPLg9;O-!AONgoGi=Tu($KC9H>5kfzjFTM8TIlW=Wb!(VMKDK=OoL;%8eK zcITySr~{uFt=c6l*Lc%=9sYCtL1x<&^jPVr)_RkT60zr z#gpFLr#z`-icf2v6AT&@mVlap3rlpr8Hx17#TpiyIyTABL-$OlkeA;!?<>E@johY= z{Ew5D7;==j)U+_Oq1(CHq4Nn)L#S9!wv#$S7fS-4{+^d^Cw{bzv*dT;gn5%}DqwKN zJhMjNmJrW>5BU^i&q(jTl5`=6oF7tB{2s?IHN6quK3WO6ouL2sd~X9j9{jx8*V&bJ zjz`-Z3hVF|t4O62GGTBhFiXvAY;5Ij&f&3hMMx;?lCebIz8m#C6=H1!LCCRdO(9Lz z0{o2Dz|*<#(aA?{@k4{NsEwfh;PD?$YmqIsX;Og9Qk!NntkyFLtESCujKyibsUe6t z#6W;eLXkkffHT1!I(C+hAa{k@rRkfSro>%t*vJYbjQE8M8 zN6f9-r;9uFn7_rl(sBOgx+<>iR}J-RlvPatX$V=d}QdO+s#rtVa= zX$^qhLiHHyA(C;o{CrFcLFIuX^C>uvQP(Y(qYWp%W`1SAfi;*8@;b5^U{Z#= zBuXX}M<5IKcC<~XqaDZc1Jm-t%n|X8HKMgFdrb&I@Ly}KamZuid*b_u;NxhFbf(Jo z{^A%EKvmOm>!+k z0ti*FP-_Il|Lyt-Ce~%>a3T7c)iZ~KmN2b)BZK~oBwH&G{{Ja5a z+15|1NbJ#9pmf`Er-70}ys^~Di2&jdbtr^B*}dmU4uvj~N~pir+)#f)I8V=_ zOd+-YImxlyMeOZz3o03JdsLzHUnLfjz-n=f3syX>B22Cn=Pr(r<-wqEU#hZBTkirf^&HyEw z6h0%b0@`g zHJX|z7o_p3hk^3AZ0KQ~4U;Psm3|60SMlIs4O=$-fI`+I@D}6TbSpkT=my&wp*1Bg z8}}q^S_vE{c22f99%Urc0(Dd_xcLOh%OBtIM&=g8bok6H?|7I2EQvya#s`{AxP@S| z#!xl@(&;Gl(#%{fm8k{1ws&Je>OJ)2=q=25eGlQf|-~OH|Q$hV<%eWE9q_&?V2GRmY6{w@B>%R&+Z zy9hG1@@PtgmG~&&1_GD%2>{HinJ&W)`6m$Tk-80NHtXG6i;MVVPTOK}v~o_!su$U{ zsDt~`BCCr|nYUXku_6@M%#NMl|=$|=SFN$6$7J;<2bX_=|piuj@+?R79*drZO zfbu?We$@-A?s3P*jtJKbGVLjFG_4cbPUc!)M5B;jmq^Qa$n^oGq50oMC%!8&ewAx- zMHUPhLAwCe=f$c-fU+&m2$LaY2w%ugX{#ZdaorN8rs9!#^W@}39jwuE{AQ^8V@wa= z6{O0e7RHkmb;A5432v+@jsm2b4RD>t!vGr(-BnGmOJ~n4^9QqPDqC|NSWO z^1AKJDp0~0-Ua>(I*>pd#c;LRFt<+w;$95cU}YW5I*9gzddY{Ap>3JpbQ;Flb{03m zMgLO*txt{VYg;w)To#0;>~}@B5`}>EGyR#>Il>7>|C>;D}Rr&V>yr9*XTSsLA7;0G^(y+UtKyU0SUzZ#I|kS_V62e?WCz-_ydOk&0mv zmnLRXpTKeoKA^Y{M!)?ti8#?!*AsqydcKF*BUqc*>pIV5n9|PISp?B;P9uRpFBdJK zfwyM33UUC%5p=yL7#YH|0TxSJD zLEbn;wwKyedZ=0K>$)XM7|S@ydwxPni)>)pw43wR5D#|v`dH$SPIl#1Od8kejvWQb zloykf)7KT^`L~s7zWf(vg}u7t>Vq?MxzRT-lQyH|&+umHh@~&b>s7l@%>fLx)gJXL zY+D_pXXB+vVn!-8Gya*<>$@yJA?w8v$Zuf?9ifynmex`wCh2)>lM@cIb_ zp>NiD*j-f{m()^BYfqu;Si_QG zWVBOzNVA?QvM9q)0Qfu_AFtn=u^Rs>)&_A&a(<|u1q#|^&-wQ+t9-d`dX@p|I5KYS zm{tepHOF|0qMQ1})%hzWz@?j}bz0t&BRlD+eqUz8V>L<<|HKWN7436CntxjP*w~`H zL0`~709oSvV8J8Sk5&^G3ISQ^^uc!y`iaKcDQc`ygcH_#9CN=eZBH#MXu5OG#wCJp zJ>m{k4;7V~rmiMp)AeRbSB#7D@}#XVT|jaP&A+?*bCpRQ!mbp=!pl7?fykq8fz>3s zshm&rFSw=oM8e`|KNCAX9(7NcGfTMh-K;awRtzPpNBKZRb8!~LrH*x~q&~EjUgapQ zGZ!+!Uslwbgk{@)SU@0|cO^TSRY{oUUCW5r1fRgxk1_%L;;B@c? z9!yHiAEnz0ZEkB&HhwxrmlDHXFqLsg>z?LF<^QQSS=#J4HROOVacinEEZR)r5}ADq zr89f=FMP~JRM?p(S6!0$6@hsKnA8Vvid=XMcxjsqixA2lc~YXO%u2l-^-G$h##7$r`4IbC}o$@Z3L zmHx9=t)z^oo-TtB?)pYRFL6|tb=1^nuJk9IqSdZW39aoH2TnZCLU(!ryrfZoc&DMi z$g6xNh2yiQ7T_O5KW?HvG(|yPg%RlsqHeUKC%KzdFS)klV?K-kGfVA2VZzyX{TMc$ z48-W|i?$CY3AP<5@+QRz!8_|o5eHvxPmuGB18xL+mWOU_Z^>ALUP8hH>dftXSuTI_ zESF%ZuxA0XEe6fl z%e*apup7u7mmMC7H61ei6KeYn^(vQ~#p`OoK~T4&AUwT_SUe+T*mSdjP(kL(z)r4` zXmox_Dx5D!lf$g|A#cgr!g@S^4niZ&IQC}kV&W8iVOn(NT_=m|sjUM&3^)%M|0juF z;#r_39$Ok|Or(7a>R8;%zng4IJrOFl(SjB|FcVyNjoGJ^&1l!@K|$;F(pwh7gFN|k zn%%{(<)B^|OqVmMdTfZQUGUr&_GkEgR%hjhQ?K^K#PYiO2sCVRVYiH=l&b&dwyPlU zymc|Aa(bho1Sf2wT4*-XShMgo6$&viqU|UyKGrYBHl^jr8`7DC?y1ku12i*#rLJeR zoxf=LniTPF&Y`}mhl5KG=d3Syko23kwrru!I5V5@R8T;TJb7i*m~j!z5922 z`hJzftQF{oV`BQOg(n6avLXO^$1EjcX`B|j@Ct@IOGX?+q#-}R1~-)e-fB!_$`pO4CiPm#x}_a2m>W-cp6aS08YM;PTe@ttrc#A%!3_+SbH$2 z0qCHCV~!pEgG_3XvOB3F)v>%9YzASUZ_TC(&`L_;tifQ@q2;tnCcl;xJ*^%y2UTi0 zWXdZG7}nwAxp_7$=ng?Q#fHefrzT0m)tD1?!wmva=(O1$D^e{qeJ$fO*L0Fc;6~B< z41amev;q+_+!!e`z*!bv)NB2t?u+x;C1BO3!NSq)UT!u5<;iND{tA$cw6&87x*$nUn$BTUn5~{>L9$*Q$Z=o4?9)HqxRsIPFVEd-ljd4+I8aNZ{tZ zI_jlIud1~wZjxHDO6rvB9~ zM$ijcm>E2mq{^%?=!X>b`Qex24NDrH=OnA>epYtB_pQMr-_F~a<5X@GhPTWvGqb18 zFojs;hE#Nis!@Tr@tqkMb78gJdGLkL3h=DiMe5!YF^tUZeN@n_s#8bikqb5iFJ^r{ z`%BSGE{ zLJRR*rpklv`%oq*on%_|>-&wAs;)&C^?eycY%%FcSx5D(QmjC<0vABsTagyZ9p&dz zFL0m>tU3&%)@rQ~f}jV_`%1a3yy+W;jv>7J=ADA_91p$_=;4X(s@D^asDsuR&`kUc%v*-%Y@;4s z2i(cHVi8HyDksq zn$ z>^x`^dfhJC(akvlzdVBH@@(%r3ckG~n(EGWC`AOok-Zs0m|O&i>7HvDg1XmdSfb_R zu61xfas%oH`G$_2N)I1jZQSmOC2s%LFK0#N%jhdie>xfIT45Y8;4uI>6P<`aM{4gJ zK(}l`eFo9~i7U_^gOKbsxw4}geNlx_#Dlph)a*NVLU~Pj!Ie6OS@9sRV(Z@8rMfV% zgUkvv7=1uo;_(CiImbjD?#jf=T8f^RrRkND-~pGX?-5NhnohWDH8_O=Ii04BDB$ni zt;QF*!m#MT0$;U*FKU=oQhzS;^c4F$O0tcP0KnGz91Em;+6#rj@@}N!%R(q7e^W}P zYkO=Nv^3nnTVV>9T_*5^S&`}|)k}K0cGou>VCHqazr6`gGi>ov)x1WN28{t?uPeXq zV+*>DzZOWyEr$aM!q1<_zb zO2|iODCX|8*OeaVVKL}&LkEz2_5}E3Yg~K|*H78~Ry&mcAK&D}{xe*W8m!T4l5uw= zUeZ9TLvyo|dbg)TuR@5K9(V98w@G{32OmIvmw?Z(M&2hYzut}~NF4fDz2v4N{o&ML z5nrMpLz7ls%gy>cKrKH*Jg@rA;XTh+xg+>Ix?aL^b(esLA}Fl}RFdZ;QPI&FqGn!= z!1I+6{$679x59aiH}Ptg`t6h>u16x{bEXf>L#h1aCq9{Z|v9JCL+c;Vac;d8Yns4kz`>(Z z_`-#ed%twf_R!M5+s%<=T|HvG*^L-U7&J7&Of@;2W~vwb5h+&BFOnqqll0`i}w zb5N1IVl9iabcq{zCCB$xz&LGUTLRwI!__k!d8TaKjt*PO+TD3PC=nN>LeqKvrm=$X z#q641Tb>~S{Z^8ebX|C$>vHWAvhm{`^t0c?Hc zOe+ObWn?{-7Y2sAWW3thw2fyHBZ46XYz&wn2dj+KW!d1-htlPP4dvzELC4gNsp2)v zDW8$goE-p@R>QlDTrR0!-CPz?>&-7*n;A>|sO;VrjYo0=<8;;p<>zFufjtemqgbwx{L~?!Jh3F?iF;dAlb@ z$_AXw{a&In1^;4-4c9Ol9r z-dBt{WDtg0hM$(<#s6#jO1RHqHUlwc2jUj#ipnIzXYFV_aB{8pS&7>cvBT=ag?`3Z zspbihJxurc)O6v<*43rzyf7EOqjro08d$2Hs2jLtpuh!}*AepACdXT}9+Ix3P}?-1B&8B4L9Pe(z_t!X1vS-Ku;`Dxri!e@4VU~#&! z7=KRen7(JM$m)E(kNghPMKNU8;c64;y-R8v52JG~(fzmxO*3#E_&%`qSXRUFy#51b zYp|4ERT9CiyDcyZhR3%#DDQZ})4t7_e5s}<`KJrP@vQs)jXurG{RZ9!dXo^DGcu)4 z?_kZDEl0cU;;BY2rFC})COo$1Bz0&}{Fam8*R(f@}9hbfG)4U(?9?;OKh|KcM?ab5h0Ee zJI(Ta_a!j_LI2>Ys+y>Tolm$_RSzmYoI$&R-0-!}v@m`&a^4wnkHp^u37)Y$LX4J> z5<1hd%#a0gnd}4EeaQKdXH@?Y)|ta5|D)Su509<5Lb{0b9Gb|wpsj_MB^X_3Lr5Xu zoKZ$3!qNr`qORlOVtKF&zcd&C(R;dm#tLWjN3oPf!WJWBupjLPV$%~87R&9B4qNRm zxi@V);DVFU>%}ryfYUb%A@D8D8-Dh&qH11{2~8NXdRRW(bnMETT@Da76d@VM?3=h= z16<%0Ee}ebd>)nBpNnEz%RM_8OvP`r=WaZW@;+BeGyT@Scn= zGchM&wq~$!w}2PQYbQ~QpaWl^obxA-d3UvIwnx13>*V)=4PH{w?+o2n*T5JZ@08Qq z&p+k+-r(pG5*Lf6ZP2H$zp-a$IWa3VikZ^k% z^6aag^|R{+XrS1(*0zj{p~orPSj4HEDUkf!U`u#Jg!ul>=o8-ol>)j_0XF)b zdpZ9clXMXm!aQ-ceI+=n4Y5I9P4K~W`I?2+LoR7PkXTnLGAY}IZ1S!YwGMA$JaD=N zU&{z_NjLMlbOI`q+MrXV(jZ;`ocp|cKOfcm7D?@ zAWcMj+rO;ej*%45`!ZD35tVh<%&Zpp2jCQOtLWFcBCa?I)e|S? z41Xv3?9Jz13b6Vfg&W%0a#q5{KPxIcL?5^<2L_o@W3;1VmG$rdiP&H?yx-0wbBqL% z{;ogfxherhS?3FNYmnIDJaPhm8?R5b&QY{!U3P0!{9O#tkq1ncF2@k5l6!R3ZLye{ z4yS4VD^u%P4mu$foo_xI1B`t&v7OJJGpz@r&(${w)5LNukri4G3?d4mWMKl?A|*lz z76n1H&Wu#X(@*_(KQOEq+Fsh%lZvS0h`h2754FSSG5)U$PR9b8(EI>5xecP>B|o2u zj31j7>T%(TGk+&Hs8iLixB_dIXSjI)x=G5LgFG{5W~>rK04P?grQVV+dcX*R_}tiE zc@jr@>A6w2qb{JP5A|552qPdmE@+SCJYop8s`+`mBh>W_k#Me+L_C;3=1h|Q+uzGr z-L!f`Gep;*dfyYftAdHVYQk2{PY*ZoNC5vtg&$nYqhf6j$BO!GJtplk;{FFH&`jKP zkYAwpO{lr!1SxiYjmv2;9Fv=dV*v(`&_VMi-K0UpBj>1K#%Cq=){}vm{Sdrf_`AcA zhm-wmCaDme6{@lmip(sXa6dT6`Znc)fxumziw(|~q8KWftB8LMvC{R2by3Yyoq<`- z+%(>S7n6+Y*y4)Fo@T&z`nq*rL<(gcNzm(WlU^~L$U{OA=z9&)xKmsMVb8B+vU1uY zAJHHfepz@Sig4g+&})?h*dH9pI=X-hqCYi6GqJhVgN=SCn1CRvV199hO%ftI=!4GA zbMc?RTQr)N67t*>ppvMi@zg<*B!DVg5~_b7IE)vXsvEf*;N5~ZiT9umfhx8S3%nA|09Y>|QzzP43kt0h|8sT1A zv}r>pQPe;dC#$@S+!0?9eC1?kXdNp}e24Vw;rr{wyBXbzpwlJo>stHe9qjm-R(WfX zx-#R-QIX>V!M|yfJjVP+cGJQAIz`5N2nUAAtb&}ynGm4&9IJZ=h5~Q*)eH93K*M%e z&F5HV&I2Ns+3w!iw(eobG+$hb^?Dxj$2YXa0BzT`7QJI}nEw)mS-H)<@mU_pj&*?= zUEFPI09~j6!)9XaKOi>WFYorG{Rshm(#+y-W>bpY^YFf&0K@6bBF#_g2N0*)SIL;b zBqY}bgzu&)gLRtYz@zpu1eH?M&PXpW?7VDf64gt^@F`wSP9tJkH?uW^gMofUKEm`` zG}^5W47w#r>K)U7PG}BuXPRdJ2l7`AluUrDc;ctYOt{z>`xQ7nYg!Kzg5onA_95O6 zW}gdRg0NERyXfXsR@!ITe&#V$=olQTW&`IRaM~xnPzIaMjM!{?U{wLP&_@y&{1PzV z1o2#Q$PasuA3ez#gSO1Wj85Vw!^>dctM*znk%jFfYjVI|e*T1gUiTJQ9guez;|X+4%=K+YFb6 zhz=!o#QF(UW+S4z^H>0Jgf%(b6_TEoHXg{-ooy(~QhOOy(*t7Lgpvuop6U|g?TkwaVcTYmRMri&OiIbV%>qJfZC*VdqbI;kmqAvBg zPYqtBT2!6VUyHpz5NuGBMx5NWzNCC}q{3UEW32#gf#Q3tq2|?h42O7rlAu8Uc7&aKsCn>#3^U}UgijvDyd`9dIu%&|q)$FU_6@*Y$h^N=Y z11~@Y-brz|Sn|*+Gz$W=qU%=PNYxOnDuRw4xw1Qey6aPune-x6@A1IkJ*-E`@O@|7nf zxCs4?QGR1*zC8Yk;b^L-tEV`e=8%9kDqdl*MFBe*3MGxjUG^!8*p9F zf_r1GskeJ)41anKxF4fQAX}HC`JXXIoaMwKgKmo^06SXd;LkP+@-TJjvO8o0m z`2i>+-+t#&!DmH@i7Z&Pc>6M2JsvM1&M)bv$L$d5Xxw2NRJ_H-JAG*CEE8?ozoiMf zBwlVh*^x^l79}aZ$yH-?_N}!Kp(eFFx{p03ZDZ&Y~dM1)+%O89;#MzUoeRRn-{Bw zwe>3H*<ORxX65N;AQ~v(#*E<)c33j#O10tA??!s%Z zgpMuO4MpMRsw*WL&~D;V`_c1D$cIFZGB+D$+^@Vu9GLmtv7iT0z;|awR={Y{y<`ae zC4$?0gB^j8g)a_F3d`e)baar!-qiFFIGp`}%1O}Os_q@*H6AFSOk_O5f^&vw}$N7xa#_Alc=zYU@ z4(mKq&C3p&AGdcZt?}5sbOZk23t*EhjkY`4XhCr(o>&OnBrNnVQ4CV48Iy zwsn1h-rD*y?#NPdJjzG#w^7ole+jm1>3V=$WQGp70Nzb$%`wXymL6BH8Qs>Aoln@{1Q)r_33-f^FF$gargN&?J@kRveY6*QBhQmH?E*Y4g#WC@~h|$0_M&Tvamyrfu9$5?l0%w72b8U(3_3)@Gv2FXtvId zHcAsF^8$j-c)|a72SAx%x>}YaA=5b`Jcp1 z-@ferDi~M|cCw`X%Q7!6y$Ui;Vpwjx7)rLG(D@RWE6PQ)nI%V6&@^s5>8nGnT^{hm z#L;=};U(Gek-fYGU$pRf;)I)p*>0~J%ntLjP0F9!!JZ4F>30$i=I?@9B)}!S&xtX7 z%C~N-DLqu*e@9z9_jqg$&-3@t?EnIeAl1bejGWKK;I#N%FuL4n7JYt4K3+xxwkKII zNpI0&9Nx-(Yz)2Yiht-RQchC31@d0XBT?!dVUTH&s2{c?tb}qQoW^of-Y^7-+qecm}mSkDy0B$Olc8OyTHkyt9!H%@VSO zBhgm%bZl*1fYnG|w@;+yzH4#!D=*(dEmM}jL2UHf zI*5B4e9fmuOdhU_wNd^Vv&t)aV}u^5_tcgIy?(#hK&7_!GGUqpU2+oBNj7A{u&L`& zQ!v6X0eyz8#;xF*RbsHgKMPY3N%D;oJ!A#n_aKO3Z>ZTfvbv8CjDS#LOo-@lLF(ai zk$|1}UJ1U-*Pb;^W-+D#puhP#_GPR`k=O5fno1T34h{UJ@%yqfB0K$9?`g8#JFPM)9TVIMwE%Kg+qOL=Wo_Q>YkHmxF}sMt8qAmUil8kU}k-hVi}+tt}63lmQk zf9K@xcI38Jze98(IXH_UfBXT@3NZEEORXGZ2BOy6>D{H3+7`qxemi;c}5-MiSPJ%tj87wyi?9+ zmVHT_zjqv~D6dfFCWW(0PemJavSWske|0m_y(d*Lh_{CKXZ`KPdZ2xLH}>2tZ-eM* ze;MrD+zQVF$aU4xDw=>jjp70`fC->i8O_d7x=vQoDNX_i0C{TPv)h5?u$iRCi{2KN zM+d>MpGICw2+fHu)t}c=EgOqYWxv52j9&SbbHIdv0)|mEuIfeVMjvi_YKU4d5lcX2 zhRUu#)%1RZ(#9R^ToUa$fhC4KxXNfLtD!YWoCu~Wt{Xg@Q&hIPpONUBoPj{=I72js zYA)69a{R^xJ7ISLlel`#`)x=c$D*bd}@m-SEiI_9xE3NkvIIi1>y!N*hE5dUGUI|@T0EM;- z%_LPNZh|-EG9j{Ijovy`&CdZzvSo?yCA^X=;g5pVDPlY`-AeDBkLqxeUrIu37vB+^ z!VMZIWpmZ{DEkTnrX$p}P-O|40D&@*Rb&U40xA@*Z&RrBNG|eH5ss{8npX{r;^VW9 z?EC@>yK0zFlo+sz(f5&HJ=wY#>yaF>$6wiGyEZ_h-OI8{Fs`H?&{vcZm+Cuujb_IK zX%T^K0L7eQfVLUcyD@_~t=JT5Ry^Q1A%aP3lSfh?_@PuG!V@9U{CW?`;!ncCul?{E z52sb}wz1dIdrUP6HVYG-1t&)w9APU4FekLI-xlL0sp6?1MC_jU=FCV}asyCORd%*J zd&Ojm9%s}x%(7V%2&=2gk=EgzeAnAS>ir2ChugmavZ2!%%|6^<8t?PNw3q7bV;6=5n6Gmj16$k4 z*|`sfBUGNav%DVn+s>F51aGyHj19uJ49}izekCe){utx0EHZzl*8TGW2i_q_<9*O2 zkuMqT9edn&^e86LS0=I;$peeCGW;UIhvH6mt$U-J1@v~zu?uO?09viI5}tCS0RDS` zu(_cAc+M6A<8hl!ozP*IUF8~OXV~zA@prQu6I;{_8reget zzp{y+BzR%DSEEWO*tMlL=vy-yfYBqJfy!J6-rUBvegJSjGb0W?s?Y93T{2(UysretsOQ&9etl+( zF7&i0_*_#Hk#a5stV1~kV!mTzXHFCWKT$q}rSM+nyC8A{NqEj~TKNTvTgUT9tiQ+5 z5ntt;BI$V-BwnA#O$NpL^PrcQ3kC8HjoYE@xUtWK8&15N3W2nhg+zC#Z=99%%P9>2Oq(D0*=4>7R zVjju_4drnHSS4q&gAOuOpD~*AvhLc!;Cq{Kie_~-Q@0C}_Rrmqb%Kj|G~>zWHd(nQ zYsrX`;C|s8FUA0NoCRC@{=Z56CjVdWO$ej%%oG!_(*~Y~Mux7Qi`bD8#n%YSs2t)T z-fKfdwxB~o==Shvxcb2|&HT+`^-A~*7 zpN^ZS1nANW<`if>Kl$009!A+qkmmwI4b)rcd*cc9xxFKV{egTFlC}S*4FXC8=5f-`dP+>V{mAj5-N0k%GuiH! zCHqkme=|5TKo$=B*j6`GNt4#wZ!G<1Ge^$I`yC>+avH6FdL+l%-M5#1P=sHXPLJS@RUHX>Jd- zl+9HeTIsma)geYS@}~xt5rccprv<*K4ksERzGi&4w3Eouu%|amL@wq5MeqD)SVV;7!XcJg~D?@ z*v~hKqxfnGXa43s_(ygj&0~X~$r~zb!0Nl07&Jl)C**qDd`@E6k zYV%}TIuj2H(lBTAVfbW`4{fhKwF%Q4VB4$6mfjtLnMHFL@;}XK%=pZf#ABY61zG8? zi2}n(v#!5H#9^2gQjgZs?N$^PUL*hxye)HRJ!}hz?5_VtVHn@byjln=caSf}s>JxK zZp_U2CcUfLG~8o;m^6l{0W4u>EG#=1 zw13TH%Xr2uR$nGw(*ZC>oKAP+H*-jjOHRg(_WZ}p^9;Drj%Lv6#k5~o5cI2`6AfJ_ zN#Lwf-%?(l5$z$parbgY9t@4blAg|0dV|93D#{vT68$C57d2FDvvG zjzg=v|2*l}wpoBYgc=e=S6j>u=n3;y5cCroqJv$+b8+cWy&}$JJa=@F-IhZ1r!`F& l#mS_vCdMUxHFN$|b(PE#yiDU!#3d!+6YAv>%A3t`8~ucP@Zmt8(_R;L?{Zq}?Tg5(*`J_Jcg+@> z&nC>tb*y4dT(JYC-+axvxVNs`kit=@I|8uZ#H7HX63E{2S2{2`)68+1xv6U9{HzJ*50(enh%gmg49>+k|9;v- z#KV%QTcEQzAr|F2lXHG^Yhq;l3F#}}^2+>VUo+xJNU!ZV8DES=F>XuhACmcLiAC1| z2@~4zq@It#-OEj9nvf_bLC#SK9zIxv>zM|54d8nBA)(V4rVdJ#Bhfxi7_{ZNdt6LL zA8J|6afwueG6&h;eCJEe?DUr9$fu~TW&KPhqYKi~A9%-Z*XsTRNXY6tMX#1ZpEMZl zoXLG`3^3I^nbgnfP2vpb0eIhm=M;XMPhntLHdye)mU!4#=Q~v@AS2_>5ay*6?QwpX@Pe%5qZtz^><~3GY$g$x?qZOGvbVJz%z`&5zk3i` zz$?S=F1T*vl|jc88<*up(+(4J-9iFB#V2Q;1L~)$*dCpgccJTPEKgDutG{+BtiAH0 z{CC6Ui)pnwg|F`dDqN-b28Iq_jeM(AaX(EMQ)`%e3$^QqZulX%GbsFPaN|MzhAxY8 z0%Q>iv{SMJ$o@jTiyB{s@!@@v*0}SdKR|z`nVH4l z;2(>qN!}Hi<87x%)43x9+curSz=u+hi9T>5vwu6Y-{?LZ<1lGfH2zfQENABW#_<&i z!9BB`%J6#>g#tN#FQKk#YGqmbT$aa&#j^#os_=PQ`q&+Mc0Y5OMLBFK4@P0u6lsAR z7TVNZOl=JpL08WFY&HDr+g2QFI6aU^!U{&itYCmDN{l&y8c0EbmxXtij59}FrThbF zc8%5h#3YMJD%J4!6IJr0Q-&LNruEN^}wZ7suALF@=*0Q#v8ZkOu?YoOnUi-}M|lEhH}O=N**$JqKs0w#cXNuQdFDGxW6cz|P7cw7tbaBD&9 zruKg@546sPbr3UF&_DZ2>;ccE@};KXKy-DI-@i3goZI0WNrWO##%VLCQ^j&4sGF}^yB>UN-jUm2wrB%HD^lQ6R3Dm_@Ne2Z%R#&__b4&sfk|$b&o9?4 z#M%IvofpX<1m$J)QE1$~PHyIex?+v@^H#}V0b&k;i`xc-TDT@+AhasC*-BIB+KmcD zu$;S_`gbOkcQWksV)|ujCG7L_8_SBKcAiYO$;I7FQ<85+1C#9F0pR4`xVGsqphfpg zQvtufdTkE=&*cOZZlK71##x>v{?UOYoM>(vjhkq<5fO@&L`_qwL|cA$--qW!l3Qb` zqk=t7+6oM5R`^%gq9@+;z^)_*Q)!y81?Zr@ic-X%5T-%Ho;1lvC>5oF+!X47Uewna zm(YlZ1NKj|M?r)&1iyTvjj*#CLs=Ev6F*=iThxs9QH12mEnDIJ=*RLlNFmJ(SG zW)^QYR%?d+(-6bIft_gbxm%~?6m2yj3EQ`txGQwHxiJpZ6i$JE(6i~^7n;~g1N}z} z087b$G_&K@uBh?5vFAb-`P09xkcuw>*B+zI91HU;g{vgsbrBZrij@M+O3SAGwQOSu zlVQW|Mvs<*7LDtk@~s&5Fz7g|X1s0!Xr7$KCtSp2Q1-fRB}_~?mXO<%ZB^cmST>n9 zl)G`1Q^v|hghjc!s+qBBX5)asBlf}fu;2=rIgcYVag6B~Uv>hU(3$>VcEC@Sora{- zivO0T^{P+ zbXZ5Udh~L!(oGoma%te$?>Ty5g_?#Bk0Vu7s$BglEC$eRwD39C8(_G1YM|nEt$qAo z2MH*zTGtxu9d!U{Ue*3Lj1a-)I0De`6pu;hwP~1MfJIlv8>m+Y@8@e%E-?(fxtfIQ zG*U{t?AXO*d>0xh^dqIABdehw|G5HX@h(kve>u5 zrDyAPtFekIk-ayqZf9S1pla5dd!d8uqVtxo;bA4REa$vU+l~H?bV$<(FN}o_NdAUn z1whH+#PA?@bpRlh{gkWbf1NmSN@&YDl;HfF|KkRJ7$-TnS5K=NX&g&;us*01!V>kD z5l8O2&|ia=Hfv=ZEz@eU9ALlKQ;!C$8%jKo4L4E~Zashgqs(DmuUyzcf; zePZfhx9Dxfklps@o9fR>-obo1=nkEl{uXQm8sN@R5|CY-Qyz(i6wL^k&kNkul z=r)P;(AH&|*eBgEIdiGy>k+SxifI^|vNJ{;)XpM!m`~Mv{1RlT&-<$_bbBaff$7e2 zWUhagkZSsVDs@?a^H+lxWOONM;kH6T11Zl$#)v&VU3Q7zMW4svhHhFevo!g}FO26J z$W)!_EJ5Js$yYOryVpkvA2Q``|2o(9xdXDoV@!XBoOZ=ks%@rF7ALcq-Cdgc3GNLq{a z87gPqbWqc&Fc?6yerg(d5S)P88GLRb61O#_*RuTvSrIdCcW6#luP41}@Fv7ijm7(} z=@G`0+2LYEls!%~hxyBDw7&iIUQLYPc{KsPTc&sh|5?a^1}+5s~HppmN(_8564Om@VuRlVE)edVJ50W!e)IyYR5P}qid7(yj- zinr$zgCxH+$2i1MEJJE?Rz$O z1EZt3oB;nz!32u!3v8z!#dqet0^zTanpJ6;eMgQY8G)*F+>P}l>i0ao-tGS0VYE-7XOk72r1xbwZ zii^gR)AFK}v1`qA;JFq{4iv@aT4{YRthfYs`mgVtQ_V7zm69U`GPys_Zl{h(MuI>F zGo)oYMzy!2thO+9(JI;;kFyiy6)^%2=tK9sNR(X*I_}_Ue=0boEldV3qWE1<{Wt?l zpuTyCz9QPpB1BUjY3^VjTZ8|p$BPbbae3d+lp>-ZfdTTo{jWtC4cuD=pkLB&H<&3_ zwiRNM^NBO?w}Jy{bm4AxJb2yl>r}z6kq}ocIwX?Wf=&1PSOj1ilqvk3)*7z{MJueY z%@MG=p6Og*;{UZ(C+c@=e^WnVt7ks>4vvq>dsC9W!Ei~6)G&nC4HrA%u=Ir(JC4Yh EEQsp02mk;8 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..f66f6cfcf5782e014f95adc830b82c035784bc12 GIT binary patch literal 17555 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 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..180c518f8686740f172aed2d1b60190b2ab47bf9 GIT binary patch literal 4952 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 /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 — `/fix` means quick, `/spec` means the full workflow. + +## Workflow + +``` +Investigate → RED → Fix → Audit → Quality Gate → Done +``` + +### Investigate + +Trace the bug to `file:lineN — function() does X but should do Y` with **High** or **Medium** confidence. + +- Reproduce the bug. Restate symptom, trigger, expected behaviour. +- Skim recent changes (`git log --oneline -10`). +- Start with `codegraph_context(task=…)` for orientation. For local bugs, one or two targeted reads is enough — no full call-graph traversal. +- For UI / async / race / timing bugs that don't surface from a static read: add temporary `SPEC-DEBUG:`-marked logs at component boundaries, trigger the bug, read the output, then proceed. Step 4 audit greps the marker — leftover diagnostics fail the audit. +- State the root cause out loud before writing any test. If confidence stays Low: bail 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 — re-investigate. A test that errors for unrelated reasons (import error, missing fixture) is not a valid signal. + +### Fix at the Root Cause + +Make the **minimal** change at the root cause. One change, one variable, one logical fix. No "while I'm here" cleanups. No bundled refactoring. + +Forbidden: broad new `try/except`, `if value is None: return default` at the caller when the bug is upstream, swallowed exceptions, silently normalised bad inputs. + +Re-run the reproducing test → must **pass**. Then run the test module(s) covering the fix file (fast, scoped). The full anti-regression suite runs once at the Quality Gate, not after every fix iteration. + +### Audit + +Single pass — replaces the eight-substep audit of the full lane: + +- **Scope sanity** — root-cause file IS in the diff, no unplanned files appear, diff is small. +- **Symptom-patching grep** — `git diff | grep` for new `try/except`, swallowed returns, leftover `print`/`console.log` and `SPEC-DEBUG:` markers. Justify each match or revert. +- **End-to-end verification — MANDATORY** — re-run the user's actual repro and capture concrete evidence. **A passing unit test does NOT prove the bug is fixed.** Skip is not an option, no exceptions. + - **UI bugs:** browser automation against the running app. 4-tier resolution: **Claude Code Chrome** → **Chrome DevTools MCP** → **playwright-cli** → **agent-browser**. Walk the user's repro steps, read the page, confirm correct behaviour. + - **CLI:** run the exact command the user ran, capture output + exit code. + - **API:** `curl` / HTTP client, capture status + the field that proves the fix. + - **Library / SDK:** `python -c '…'`, `node -e '…'`, or scratch script with the user's args, capture the returned value. + - **Background job:** trigger manually, read logs. + +Bare assertions ("looks fixed", "behaves correctly") are insufficient — the finalise step requires evidence in the report. 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 → audit. + +### Quality Gate + +Lint + types + build (when applicable), then the full test suite. If a far-from-the-fix test breaks, the bug has unintended cross-coupling — bail out. + +### Finalise + +- Worktree mode: bundle test + fix into one commit (`fix: `). +- Approval gate fires only if **Plan Approval** is enabled in Console Settings. +- The completion report includes a mandatory **E2E** line documenting what was actually run and observed — not just "tests pass". Without it, the workflow is incomplete. +- Console notification + report. + +## 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 quick-lane fix attempts have already failed. +- 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 is too vague or environment-dependent | Ask for exact steps, env, stack trace. Do not 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 to the user's actual entry point (API, browser, CLI). | +| Three 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 — fix is finalised immediately. | + +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 | +| Bug fits in 1–2 files | Architecture decisions matter | +| Root cause is locatable to a line/function | Multiple sub-systems involved | +| Fix is small and contained | Work warrants a written plan + approval | diff --git a/docs/docusaurus/docs/workflows/spec.md b/docs/docusaurus/docs/workflows/spec.md index 064785b84..3bf9b7db5 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 60467827c..5429aedf3 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/WhatsInside.tsx b/docs/site/src/components/WhatsInside.tsx index 78acc8a55..5bfb5919f 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. /fix is the bugfix command — investigate, RED test, fix at the root cause, audit. Both honour the same approval and review toggles.", href: "/docs/workflows/spec", }, { diff --git a/installer/downloads.py b/installer/downloads.py index 6d3115a71..4b44b4285 100644 --- a/installer/downloads.py +++ b/installer/downloads.py @@ -16,8 +16,8 @@ from pathlib import Path from typing import Callable -MAX_RETRIES = 3 -RETRY_BACKOFF = (1.0, 3.0) +MAX_RETRIES = 5 +RETRY_BACKOFF = (1.0, 2.0, 5.0, 10.0, 20.0) _ssl_context: ssl.SSLContext | None = None @@ -176,6 +176,12 @@ def download_file( progress_callback(downloaded, total) return True + except urllib.error.HTTPError as e: + # 4xx → file genuinely missing, fail fast. 5xx → CDN hiccup, retry. + if 500 <= e.code < 600 and attempt < MAX_RETRIES - 1: + time.sleep(RETRY_BACKOFF[min(attempt, len(RETRY_BACKOFF) - 1)]) + continue + return False except (urllib.error.URLError, OSError, TimeoutError): if attempt < MAX_RETRIES - 1: time.sleep(RETRY_BACKOFF[min(attempt, len(RETRY_BACKOFF) - 1)]) @@ -188,12 +194,16 @@ def download_files_parallel( file_infos: list[FileInfo], dest_paths: list[Path], config: DownloadConfig, - max_workers: int = 16, + max_workers: int = 8, ) -> 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 47f99fcd9..8f9d7a722 100644 --- a/installer/steps/finalize.py +++ b/installer/steps/finalize.py @@ -113,7 +113,9 @@ def _display_success(self, ctx: InstallContext) -> None: ("/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)"), + ("/spec", "Plan, implement & verify features end-to-end with TDD"), + ("/fix", "Investigate, RED test, fix, audit — bugfix workflow"), + ("/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 2f0e4fc41..844396b1e 100644 --- a/installer/tests/unit/steps/test_finalize.py +++ b/installer/tests/unit/steps/test_finalize.py @@ -234,6 +234,7 @@ 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] diff --git a/launcher/banner.py b/launcher/banner.py index e6f8d50696a3663a1451a7a88f280af3c2141d98..6e786a61e49556b2672565b1fbaa3be188453926 100644 GIT binary patch literal 17144 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

    ;>7sFPn)Z%1Ioq2-LU=r;@Kk*`8 z9i}BMp)k30zpM`p7#4PW48}x`gnK5zInB_N7o`sW5o}esz%dvc{TJc|v%gaWQss{J z+N(%2W=7#$Dci%I2UsNr9XwUTy+M5p)}_*`x*17Vq<(xOSs8DEuU~D*aOPzBG~3q1 zxB~nzQ_WLIdumW(1X9(|>CSfTATVQIQPo}o% zkU#HkLAwtdAws?!8!ZHv0@O%O6sE+gWQP!Lx#;5B-G839aqkRs$ z{mFJ~tW`+Z#SU-Ryy9F&MsLoqu0;}7>er+lHg_gu=yURrfMbnk_Txh*z?<-haKB9h z)M!r~5#l_p!p>h9KV|?!{TWNR6cUL>T%&7lz?Y{hWg0V4CvEyp{`Hf<%8~I5(!%f) z@`dt~6efbZ11O?R{kKOnRC$MxC8^!ZHAn1ZZznS^uwJITm2*J;MZ^8zAkK27oo;S$sv%VX1zsbW9&Q$!v<0J`$VAG;n`>XS?S4z~=?D?jJMh z5gr!%@t%Q&EA>~g@e>kw%~xl&|GQBnW7E!2mKs>;%Y}E8lmE+5^;N93C7aefE+lz3 zYiBnD#zL@!PbM~w%dz-|n?SzPaUc*2xY`lkcX6#5U4XZ$Ku$uc{!ra|39Um-U5yj> z)8cdnfmteYYNG~xOrB{P+BL{cb6llaau)AfOJ4-2|3Vpe}XO#6~8v1aXD^aw!;jivI z$K^Lmz|q|miq4L!eGWJIS~n^Dg}FOV)+!BM%ao>9e6GI$IB z0*Yty>`%=aboUid#u_AuGNd!XA+Vdc9yVb@UL?kc1f773_S#7vv#S8rpCoaaDHuW@ zavFSVLi#cxEZ(-+S7|!2D>M~E>J$ti#XPzK^ZD}lRAt=6GwjT2Rr11fuOY4`kgQcA zA=#Q$#B(rQ4)-jJeF}#jqFH-Q8**vk4`CQ0yn6Cn~xZoa+X9}u?_llDptWCmtpl~;_RsCPR#2Vh4wQXhfDBU3Tq{p#9x8<*Bm znIV6r=5X1=C9U-8La>E!^8ND z)^0{92EIr}O)jG7-aq5UXv%sO0_CdKMr`EOXulr_udIhiWuwQPxY4Ez6th% zt%OV*`e;X>+5CQLEWUKU_vJJBI|9x4C`3~(dX?X?FCFc9<=2J+)98L4S~o0Dz=E$I z)R*tKnzd;Zk-`dD?eZ#ByC&+2i$j@)$7s&ED4{X5CAE450h1_u3QE6AQG@pSI-SjE zni2~Fy1^a-r1Ydzb=I~eqa@0t)y1TCca*RnkuO@W#`SlRYD#^^>8WlhYYw4ZG39%c z8LbvlPv8_a8!wDk{fmTSyrc^+HQ|PS?RB%&4uv-ba$7Wwx3+Gz@}hVSp2FweVbV9S zNv!@pVg&xuh2(nJ(jh^>3YnS4Z;t+;e*Yl`jJa368HK>`FlKF#zQSe(72(8=aXRYk zC11DdC={0n)w0c0vi2A5TJba_3(-Qq96^&!*f)6 zi~C>%TrGK6d$5K{`hDmMrUOkZ*UU@1ECTPnxv#nrZEAz=7#m#P6%HA{j;lIU5o}6n zdS5S&fHODs`1{*Rg`;^fTPQq!)EEMDZy1tT>Wj$H5Xf#B)9myw88*nc`a50r)Dg5* zNF+V4- z$K+z zln(WBBb}KJq;TlQr|Z*DjwXk;*q|jzsp`(jg>3D=>z(0kmN5;Tlg&6iS98o2QNs&9+zxfzsVn789IJWa^ci1O}Mp$_R zSg@XVxIg0aW6X=c42AnIX9fXh~CJ$SZDKY8Ks7tDf8q|mGOiqN1+!B z^iYZ+FI@X6_%R&0oi4xjf{YwREWyWo@gnv^PJ-s80Z(~ZrAh5b=(g|*f5nSq)yq{& zT7mPiFqbS4t;(%DjEe9b&}zRO`vu~d^O~Dz^<#@8HnZ9s+5X+-#gNh6=z!&M&zE8$ literal 16947 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 K?)AS0Vi_DF<00+< diff --git a/launcher/model_config.py b/launcher/model_config.py index 81a6020ab8aaabb2b5cb9cca00f3df552da4cb50..dac369f58ac2b4583f5aff38d79745747f0b3d30 100644 GIT binary patch literal 11660 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

    FCe71O<=M7O^ako|2DVFb2Y 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 WCvRoUWH3fVA?VN&uM^c6Dl52hna6hk literal 11608 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 Wxcx91k1rEBJjc6Heno#~S@b9eotz>7 diff --git a/launcher/tests/unit/test_model_config.py b/launcher/tests/unit/test_model_config.py index acc4cd74b2a96c0a0387ee365bf4cb933eaf77bb..b3e898962e050c47da4c4a28fddf1102f843df87 100644 GIT binary patch literal 21804 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 literal 21785 zcmV(lK=i)=M@dveQdv+`066%pb)Y`sfk@_~Z|#~Sr4z%VM?Rj{u0V);~aOF?)bK)oS}pjy8R#&nZt z2!L&kyWMngu+na2AOv^^8#RN(?-Se*b(I;XeDW9Z5wApZojE?OtMNP8nYJnUh&dkl zIg@#dI)PvFTv(kM(^A+()@rl>3GHY~NDm?CLrNStc*RR`XnTo7*Va;8$FipkOGYl4 zPRBQ{xpBL&!^&bukn&vWBdLdw>_dLW250PTnJ|S%6vQr`G;$zJy#o`a$?DgN)!7r? zban<52ef=`hIf_HYrA&g`wOPB*H7@vUtzbS{dN@y!@wPek{{mxdPqAgvR;ms`Sn(6 z3a&l}povaERaWoRhlGGfIhzsjFdAo;yTI-e%HkcMfA)WC1^1=F>$2=Xw3IH0V5RvC3skkHPCky2PWe zQJq*4a+ocXp@;~C?4ju%?>qV$&gp&Bl6&CHNB)k@4#JiKgIpR=?De8IB)5)`fjcL18Q1{GBti2;-I$l zvg9#a%K`%0E9w5?2=?Ax+H<_rk9-Igp0T@Gx_o)zU%CRu~HOxaKe(A1^am|thJ?aU!1ZXwZ z>>DlsWh6XW4|(FQe?L82FP^=MN56u<&MYaD(zq(Wz)}7XpJ5RffaJipE*A8b+P21! zY5nbZIk>+tx*O?oVjPRQlV0&?N6Z*CRA1DwxF9_s!)uq(?h*)QQ)z73$!nwP6FA&$PG>y zbFTwvQIoh*5aXP6@Y z`HcrDv10f4NCqbteA6*2F^e|h8gqI_8rE$E27*P=VVnw){>0yTB@c!L-~(yrMmn~t z@_=t6ukSa`*C`NIfp`d;=M_G8h_F@+#f1hvmFUpI!0-D1h-4bj%kTXyztoVW8GOKZ z_&?wJ)*<4=SIt#48Mtjm2 z?YO9FN`Ss8-F&~4bjCusw z0KP-$5&Zs$g%5prsDoNucT45K!d;?|}84LaZl`Xvl@h^1w1 z=y=%j{1DG3AVtO|`BApMLe?PHwc3uSF7|5@Q|VA(^i}$zDpnFuh<&i!P$<58Geo6~ z^*T}qz0}ZSq$(~DTcKbHkwCToP^cRdO)WkDeAz(%b?Kc678|G1{YFqI0Z4yCv_A~Bpl%XX1+9C`r$g> zzYuAprjAOy_N`w7=op@vZRf^(wHhmQl9nGCF zf_iPC5n5JTr!{HX%sz8=7y-9}Ro3LLUIjQBgaKOW^qxRAJ80Gb3V~DPG)>*Hg`N@qsqELg_ES3mZ+CZrDM?mUzNs{|v|FXS3n&`9HFA)`RB zf|R;y2uiCW);xWJqz8{QSxf%8CmKZehGX9thVEklXGhEF)~Q3Cy`cX1X;~NWj6|(U z^zpl=9@Mz;Oh*e(s1rVF?sdyfB(v$+Xc{^Mz}+rT$kO^V;p9+2;!aM=aONAhzcKEe zOx9i_J>t&mCse#$^f)?cFWNcFm1T0cvbu|!5%@a-?Gc_qB+-UR!sRM1v;#YsCCGc_ zl5x3GO;;6kC53wLJh0Lxc70Sw7W;y2yHZgR3w<<@J70*ubPPUbpiai2O&JXknHr9~ z;oQxxR@ktB7EE4mF~lMU#LbCLeU?f|P4)qBM1gww?T_U4^F~!%9SNyQ0mUWSn%{ov z1*?REOM?KXPV5pKnV*@Cf0PBl2^2jC86yIh*b%>g*F66|YSX^n$AwU=38S1)xn6(h z{cB&|jzG92`ud|*fz~UV{lah#L#+>bBP*>P`k`_wp&C-*JF%0AScT_@S58*={jm$a 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 M3Za-Z&|zp`2`X_2U;qFB diff --git a/pilot/.mcp.json b/pilot/.mcp.json index c4423eaa2..82a2b5d95 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 22a433897..6aa5c159b 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 69a0e5ca4..13e4c41f0 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 822645219..315823a21 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 5a5fc6c09..cf802cf68 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 58e64200a..2b9ffe9c5 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 148d9e519..be750d333 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 896da8d8d..6574b552f 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 f64224f5a..129160ffd 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 58a1935dd..099972a7a 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 655f2b35b..38437f97c 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" + "/spec — features | /fix — bugfixes | /prd — requirements | /setup-rules | /create-skill | /benchmark" ] } diff --git a/pilot/skills/fix/manifest.json b/pilot/skills/fix/manifest.json new file mode 100644 index 000000000..bfb61ef30 --- /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-audit", + "file": "steps/04-audit.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 000000000..1ef0bed05 --- /dev/null +++ b/pilot/skills/fix/orchestrator.md @@ -0,0 +1,66 @@ +--- +name: fix +description: "Bugfix workflow — investigate, RED test, fix, audit, 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 RED-before-GREEN discipline. Investigate the bug, write the failing test, fix at the root cause, single-pass audit, 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 — RED before GREEN. +3. FIX AT THE SOURCE — not where the error appears. +4. NEVER CLAIM DONE FROM UNIT TESTS ALONE — Step 4.3 mandates running the actual program (UI: Claude Code Chrome / Chrome DevTools MCP / playwright-cli / agent-browser; CLI/API/library: real invocation) and capturing concrete evidence. +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 000000000..a4c8c77cb --- /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 4 audit greps for this marker — any unremoved match fails the audit. + +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 000000000..b376a412d --- /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 000000000..d893df045 --- /dev/null +++ b/pilot/skills/fix/steps/03-fix.md @@ -0,0 +1,46 @@ +## Step 3: Implement the 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 (symptom-patching) + +If the buggy data flows from upstream, fix upstream. The following are 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. + +If a defensive layer is genuinely needed (defense-in-depth, not symptom-patching): note it explicitly when you summarise the fix in Step 6. + +### 3.3 Run the reproducing test — it MUST pass now + +```bash + +``` + +If it doesn't pass: stop adding more code. Revert your edit. Return to Step 1.3 and re-trace — 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. If a nearby test in the same module breaks: the fix has a regression in the immediate neighbourhood, fix now. + +**The full anti-regression suite runs once at Step 5 (Quality Gate). Running it after every fix iteration is the quick-lane anti-pattern — don't.** + +### 3.5 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. Don't loop here. diff --git a/pilot/skills/fix/steps/04-audit.md b/pilot/skills/fix/steps/04-audit.md new file mode 100644 index 000000000..a7667fee5 --- /dev/null +++ b/pilot/skills/fix/steps/04-audit.md @@ -0,0 +1,60 @@ +## Step 4: Single-Pass Audit + +**One bash + one mental check.** Replaces the eight-substep audit in the full lane. + +### 4.1 Scope sanity + +```bash +git diff --name-only +``` + +Check: + +- Root-cause file IS in the diff. (If not, fix is at a symptom — return to Step 3.) +- No unplanned files appear. (If they do, revert them now.) +- Diff is small — usually < 20 lines. If it ballooned, you're not in a quick-lane bug — bail out (tell the user to re-invoke with `/spec`). + +### 4.2 Symptom-patching grep + +```bash +git diff | grep -E "^\+.*\b(try:|except|catch \(|return None|return \[\]|return \{\}|console\.log|print\()" +``` + +Inspect every match: + +- New `try/except`/`catch`: is it hiding the bug instead of fixing it? Revert if yes. +- `return None`/`return []`/`return {}`: is it swallowing the bad value? Revert if yes. +- `console.log` / `print` left over from debugging: remove unless intentionally added with a `SPEC-DEBUG:` marker. + +Zero matches = clean. Any match = justify or revert. + +### 4.3 End-to-end verification — MANDATORY + +⛔ **A passing unit test does not prove the bug is fixed.** Unit tests can sit below the layer the user interacts with. 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. + +**Skip is NOT an option.** No exceptions for "small fix", "obvious fix", "test covers it", "I'm confident". If the bug had a user-visible symptom, you re-execute the user-visible scenario. + +Pick the lane that matches the bug: + +| Bug surface | What to run | How | +|-------------|-------------|-----| +| **UI / web frontend** | Browser automation against the running app | 4-tier resolution from `browser-automation.md`: **Claude Code Chrome** (`mcp__claude-in-chrome__*` if available — load via ToolSearch) → **Chrome DevTools MCP** (`mcp__plugin_chrome-devtools-mcp_chrome-devtools__*` if available) → **playwright-cli** → **agent-browser**. Navigate to the affected page, walk the user's repro steps, read the page after each interaction, confirm the correct behaviour. | +| **CLI** | The exact command the user ran | `bash` with the original arguments and environment. Capture stdout/stderr and exit code. | +| **HTTP API** | A real request | `curl` or HTTP client with the user's body/headers. Capture status code and response body. | +| **Library / SDK / function-level** | A real invocation | `python -c '...'`, `node -e '...'`, or a temporary scratch script that calls the function with the user's args. | +| **Background job / cron / worker** | Trigger the job | Run the job manually with the failure-triggering input. Read logs. | + +**Proof requirement.** Capture concrete evidence of what you ran AND what you observed. Examples: + +- UI: read the page after the fix, confirm the rendered state matches expected. Cite the elements you checked. +- CLI: paste the command and the relevant lines from its output (or exit code). +- API: paste status code + the field/value that proves the fix. +- Library: paste the REPL/script invocation and the returned value. + +Bare assertions like "the bug is gone", "looks fixed", "behaves correctly" without evidence are insufficient — Step 6 will reject the report. + +**If the symptom persists:** the unit test is at the wrong layer. Move the assertion up to the user's actual entry point, re-run Step 2.3 (RED) → Step 3.3 (test passes) → Step 4.3 (E2E re-check). + +**If 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. + +If the symptom is gone with evidence captured: proceed to Step 5. diff --git a/pilot/skills/fix/steps/05-quality.md b/pilot/skills/fix/steps/05-quality.md new file mode 100644 index 000000000..f8f50c556 --- /dev/null +++ b/pilot/skills/fix/steps/05-quality.md @@ -0,0 +1,34 @@ +## Step 5: Quality Gate (Once, At The End) + +This is the only place the full anti-regression suite runs. Don't run it earlier — Step 3.4 already covered the immediate scope. + +### 5.1 Lint + types + build + +Run the project's standard checks. Fix any inline. + +```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 suite — once + +```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 → your 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 check + +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 000000000..e55773d33 --- /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.3 with evidence.** "Tests pass" is not enough — the approval summary must include what you actually ran end-to-end and what you observed. If you cannot fill in `**E2E:**` below with concrete evidence, you have not finished Step 4.3 — 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 038e1fe96..2bf615efc 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 b2b717647..67cb9247f 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 7debd8ff1..8ac88adc3 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 3b9484515..573aa685d 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 079370b82..53c172bbd 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 ac6bd3299..f319f695a 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 dd644f3cf..3320041c1 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 d6a98a639..f3f8242e0 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 7a3f7378c..000000000 --- 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 a6700e22d..b9ffd4360 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 c96051e07..3f9bc755c 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 4eb5401f2..9ac968e6e 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 58c2b129a..0ab8ea2a1 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 c611db5a7..be808a71f 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 c849d9e65..000000000 --- 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 844a0ed42..4afe3a549 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 3b91138e4..fd5fce61d 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 9cb28cb42..000000000 --- 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 7243e4efc..0ebb5f34c 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 07e9a01d2..62e56947e 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 76103a10b..000000000 --- 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 000000000..cf1f58f74 --- /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 15af3db7e..000000000 --- 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 ae3cffcd4..a4e75700a 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 afe7fd05e..ebbb5487b 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 5b33cf87f..7c7f407f5 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 91b445318..10ed2f1ad 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 8b6700030..336f84279 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 3214ceb3d..e0497ecb3 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 4aa00dee3..04d9a7d03 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 fb58491ed..3b1ac9b78 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 c41ff50e1..f872139ed 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 3137a57ea..28ab3ae3a 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("",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("",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}; From 9f222e0d89e1f4bd4f9982ad2913cbce9a54255a Mon Sep 17 00:00:00 2001 From: Max Ritter Date: Wed, 29 Apr 2026 11:30:48 +0200 Subject: [PATCH 2/2] fix: auto-recover from corrupt CodeGraph database --- README.md | 280 ++++++++++---------- docs/docusaurus/docs/workflows/fix.md | 79 +++--- docs/site/src/components/HeroSection.tsx | 68 ----- docs/site/src/components/InstallSection.tsx | 6 +- docs/site/src/components/WhatsInside.tsx | 16 +- docs/site/src/components/WorkflowSteps.tsx | 92 +++++-- docs/site/src/types/uint8array-base64.d.ts | 25 ++ installer/steps/finalize.py | 6 +- installer/tests/unit/steps/test_finalize.py | 32 +-- installer/tests/unit/test_downloads.py | 73 +++++ launcher/banner.py | Bin 17144 -> 17144 bytes launcher/codegraph.py | Bin 10212 -> 11730 bytes launcher/tests/unit/test_banner.py | Bin 5371 -> 4764 bytes launcher/tests/unit/test_codegraph.py | Bin 13224 -> 18977 bytes pilot/settings.json | 2 +- pilot/skills/fix/manifest.json | 4 +- pilot/skills/fix/orchestrator.md | 8 +- pilot/skills/fix/steps/01-investigate.md | 2 +- pilot/skills/fix/steps/03-fix.md | 32 ++- pilot/skills/fix/steps/04-audit.md | 60 ----- pilot/skills/fix/steps/04-verify-e2e.md | 31 +++ pilot/skills/fix/steps/05-quality.md | 14 +- pilot/skills/fix/steps/06-finalise.md | 2 +- 23 files changed, 420 insertions(+), 412 deletions(-) create mode 100644 docs/site/src/types/uint8array-base64.d.ts delete mode 100644 pilot/skills/fix/steps/04-audit.md create mode 100644 pilot/skills/fix/steps/04-verify-e2e.md diff --git a/README.md b/README.md index 68ded98e3..a991e7cd0 100644 --- a/README.md +++ b/README.md @@ -44,7 +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 RED-before-GREEN discipline; bails out when complexity exceeds the standard fix lane +- **`/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 @@ -137,8 +137,6 @@ Just chat — no plan, no approval gate. [Quick mode](https://pilot-shell.com/do **[`/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. -For bugs, use [`/fix`](https://pilot-shell.com/docs/workflows/fix) (see below). Specs are saved to `docs/plans/` and visible in the Console's **Specification** tab. - ```bash pilot > /spec "Add user authentication with OAuth and JWT tokens" @@ -177,7 +175,7 @@ pilot > /fix "wrong default for max_retries" ``` -``` +```text Investigate → RED → Fix → Audit → Quality Gate → Done ``` @@ -186,13 +184,13 @@ If investigation reveals the bug is multi-component or architectural, `/fix` sto

    How /fix works -For local bugs. Single file, obvious-once-traced root cause. No plan file, no approval mid-flow, no separate verify phase. RED-before-GREEN discipline still enforced — bugfixes without a failing test don't ship. +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 that don't surface from a static read, 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 (`try/except` hiding the bug, swallowed returns) are forbidden. Targeted test module re-runs between fix iterations — full suite runs once at the Quality Gate, not per-fix-task. -- **Audit:** Single-pass scope sanity + symptom-patching grep + **mandatory end-to-end verification** — re-runs the user's actual repro against the running program (Claude Code Chrome → Chrome DevTools MCP → playwright-cli → agent-browser for UI; CLI/API/REPL for non-UI). A passing unit test alone is never accepted as proof; concrete evidence (command + observation) is required in the completion report. -- **Quality Gate:** Lint + types + build + full anti-regression suite, once +- **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.
    @@ -209,6 +207,137 @@ When you type `/spec ""`, the full bugfix workflow runs — for
  • +### /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`. + +
    + ### Status Line Pilot shell ships with its own advanced status line with real-time session metrics and spec progress: @@ -443,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. diff --git a/docs/docusaurus/docs/workflows/fix.md b/docs/docusaurus/docs/workflows/fix.md index 43ff813e0..0f802d8c5 100644 --- a/docs/docusaurus/docs/workflows/fix.md +++ b/docs/docusaurus/docs/workflows/fix.md @@ -1,12 +1,12 @@ --- sidebar_position: 5 title: /fix -description: Bugfix workflow — investigate, RED test, fix, audit, done. +description: Bugfix workflow — investigate, RED test, fix, verify end-to-end, done. --- # /fix -Bugfix workflow with RED-before-GREEN discipline. Investigates the bug, writes a failing test, fixes at the root cause, audits, finishes. No plan file, no approval mid-flow, no separate verify phase. +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. @@ -17,63 +17,49 @@ $ pilot > /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 — `/fix` means quick, `/spec` means the full workflow. +`/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 -``` -Investigate → RED → Fix → Audit → Quality Gate → Done +```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. - -- Reproduce the bug. Restate symptom, trigger, expected behaviour. -- Skim recent changes (`git log --oneline -10`). -- Start with `codegraph_context(task=…)` for orientation. For local bugs, one or two targeted reads is enough — no full call-graph traversal. -- For UI / async / race / timing bugs that don't surface from a static read: add temporary `SPEC-DEBUG:`-marked logs at component boundaries, trigger the bug, read the output, then proceed. Step 4 audit greps the marker — leftover diagnostics fail the audit. -- State the root cause out loud before writing any test. If confidence stays Low: bail out. +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 — re-investigate. A test that errors for unrelated reasons (import error, missing fixture) is not a valid signal. +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 -Make the **minimal** change at the root cause. One change, one variable, one logical fix. No "while I'm here" cleanups. No bundled refactoring. +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). -Forbidden: broad new `try/except`, `if value is None: return default` at the caller when the bug is upstream, swallowed exceptions, silently normalised bad inputs. +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. -Re-run the reproducing test → must **pass**. Then run the test module(s) covering the fix file (fast, scoped). The full anti-regression suite runs once at the Quality Gate, not after every fix iteration. +### Verify End-to-End -### Audit +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. -Single pass — replaces the eight-substep audit of the full lane: +| 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 | -- **Scope sanity** — root-cause file IS in the diff, no unplanned files appear, diff is small. -- **Symptom-patching grep** — `git diff | grep` for new `try/except`, swallowed returns, leftover `print`/`console.log` and `SPEC-DEBUG:` markers. Justify each match or revert. -- **End-to-end verification — MANDATORY** — re-run the user's actual repro and capture concrete evidence. **A passing unit test does NOT prove the bug is fixed.** Skip is not an option, no exceptions. - - **UI bugs:** browser automation against the running app. 4-tier resolution: **Claude Code Chrome** → **Chrome DevTools MCP** → **playwright-cli** → **agent-browser**. Walk the user's repro steps, read the page, confirm correct behaviour. - - **CLI:** run the exact command the user ran, capture output + exit code. - - **API:** `curl` / HTTP client, capture status + the field that proves the fix. - - **Library / SDK:** `python -c '…'`, `node -e '…'`, or scratch script with the user's args, capture the returned value. - - **Background job:** trigger manually, read logs. - -Bare assertions ("looks fixed", "behaves correctly") are insufficient — the finalise step requires evidence in the report. 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 → audit. +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 test suite. If a far-from-the-fix test breaks, the bug has unintended cross-coupling — bail out. +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 commit (`fix: `). -- Approval gate fires only if **Plan Approval** is enabled in Console Settings. -- The completion report includes a mandatory **E2E** line documenting what was actually run and observed — not just "tests pass". Without it, the workflow is incomplete. -- Console notification + report. +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 @@ -83,7 +69,7 @@ Lint + types + build (when applicable), then the full test suite. If a far-from- - 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 quick-lane fix attempts have already failed. +- 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. @@ -91,29 +77,30 @@ The full lane (`/spec`) adds: Behavior Contract, three-task structure, plan file ## Common issues | Symptom | What it means | What to do | -| ------- | ------------- | ---------- | -| Can't reproduce | Description is too vague or environment-dependent | Ask for exact steps, env, stack trace. Do not write a speculative fix. | +| --- | --- | --- | +| 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 to the user's actual entry point (API, browser, CLI). | -| Three failed fix attempts | Architectural problem, not a fix problem | Bail out. The pattern needs reconsidering, not another patch. | +| 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 — fix is finalised immediately. | +| **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 | -| Bug fits in 1–2 files | Architecture decisions matter | -| Root cause is locatable to a line/function | Multiple sub-systems involved | -| Fix is small and contained | Work warrants a written plan + approval | +| 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/site/src/components/HeroSection.tsx b/docs/site/src/components/HeroSection.tsx index 77bd8e5e5..267e5d8a9 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 */}