diff --git a/.claude/commands/review-fix-converge.md b/.claude/commands/converge.md similarity index 96% rename from .claude/commands/review-fix-converge.md rename to .claude/commands/converge.md index bf5ff1e4..71a5753a 100644 --- a/.claude/commands/review-fix-converge.md +++ b/.claude/commands/converge.md @@ -1,4 +1,4 @@ -# Review Fix Converge +# Converge Orchestration loop that converges to PR-ready code. Runs gates, then impartial review, then fix, then repeat until clean. Tracks issue counts per cycle to prove convergence — if counts aren't decreasing, something is wrong. @@ -28,13 +28,13 @@ Cycle | Gate | Review Critical | Review Important | Regressions | Verdict ### Step 2: Run Cycle **A. Quality Gates** -Invoke `/automated-quality-gates` (use the skill). +Invoke `/gates` (use the skill). - If gates FAIL: fix the failures first (dispatch fix agent), re-run gates - Gates must PASS before proceeding to review - Record: did fixes introduce any new gate failures? (= regression) **B. Impartial Code Review** -Invoke `/impartial-code-review` (use the skill). +Invoke `/review` (use the skill). - Record: count of CRITICAL and IMPORTANT findings **C. Evaluate Convergence** diff --git a/.claude/commands/debug.md b/.claude/commands/debug.md index 97fb0626..ed4780b1 100644 --- a/.claude/commands/debug.md +++ b/.claude/commands/debug.md @@ -7,6 +7,7 @@ Give Claude an interactive feedback loop for CLI, TUI, Extension, and MCP develo `/debug` - Auto-detect component and run appropriate feedback loop `/debug cli` - Test CLI commands `/debug tui` - Run TUI and inspect state +`/debug extension` - Build, install, and test VS Code extension locally `/debug mcp` - Test MCP tools ## Process @@ -16,6 +17,7 @@ Give Claude an interactive feedback loop for CLI, TUI, Extension, and MCP develo Based on recent changes or explicit argument: - `src/PPDS.Cli/Commands/` → CLI mode - `src/PPDS.Cli/Tui/` → TUI mode +- `src/PPDS.Extension/` → Extension mode - `src/PPDS.Mcp/` → MCP mode - No clear match → Ask user @@ -45,25 +47,60 @@ Run TUI tests and optionally launch interactive: dotnet test tests/PPDS.Cli.Tests/PPDS.Cli.Tests.csproj --filter "Category=TuiUnit" --no-build # Run TUI visual snapshots (if Node.js available) -npm test --prefix tests/tui-e2e +npm test --prefix tests/PPDS.Tui.E2eTests ``` If visual issues, update snapshots: ```bash -npm test --prefix tests/tui-e2e -- --update-snapshots +npm test --prefix tests/PPDS.Tui.E2eTests -- --update-snapshots ``` -### 4. MCP Mode +### 4. Extension Mode -Test MCP tools via MCP client: +**Build & install for manual testing:** ```bash -# Build MCP server -dotnet build src/PPDS.Mcp/PPDS.Mcp.csproj +cd /src/PPDS.Extension && npm run lint && npm run compile && npm run test && npm run local +``` + +Then reload VS Code (Ctrl+Shift+P -> Reload Window) and test manually. + +**Useful npm scripts** (run from repo root with `ext:` prefix, or from src/PPDS.Extension/ directly): + +| Request | Command | +|---------|---------| +| Build + install | `npm run ext:local` | +| Just install existing build | `npm run ext:local:install` | +| Revert to marketplace version | `npm run ext:local:revert` | +| Uninstall local | `npm run ext:local:uninstall` | +| Run unit tests only | `npm run ext:test` | +| Run E2E tests | `npm run ext:test:e2e` | +| Watch mode (hot reload) | `npm run ext:watch` | +| Full release test | `npm run ext:release:test` | + +**F5 Launch Configurations** (from VS Code debug panel): + +| Configuration | When to use | +|---------------|-------------| +| Run Extension | Default — full build, then launch debug host | +| Run Extension (Watch Mode) | Iterating — hot reloads on file changes | +| Run Extension (No Build) | Quick — skip build, use existing compiled code | +| Run Extension (Open Folder) | Testing with a specific project folder | +| Run Extension Tests | Run VS Code extension integration tests | -# Test tools (use MCP client if available) +**For AI self-verification:** Use `/verify extension` to exercise commands, +inspect state, and verify webview rendering via MCP tools. + +### 5. MCP Mode + +Test MCP tools via MCP Inspector: + +```bash +npx @modelcontextprotocol/inspector --cli --server "ppds-mcp-server" ``` +Or use `/verify mcp` for structured verification. + ## Iterative Fix Loop When issues found: diff --git a/.claude/commands/automated-quality-gates.md b/.claude/commands/gates.md similarity index 53% rename from .claude/commands/automated-quality-gates.md rename to .claude/commands/gates.md index 98599b93..56ac104e 100644 --- a/.claude/commands/automated-quality-gates.md +++ b/.claude/commands/gates.md @@ -1,4 +1,4 @@ -# Automated Quality Gates +# Gates Mechanical pass/fail checks. No judgment, no opinions — compiler, linter, and tests either pass or they don't. Run this before code reviews, after fix batches, and before PRs. @@ -32,6 +32,14 @@ dotnet build PPDS.sln -v q Pass: 0 errors, 0 warnings treated as errors Fail: any error — report exact error messages with file:line +**File-locking recovery:** If `dotnet build PPDS.sln` fails with "used by another process" errors (common when the daemon is running from debug output), retry by building only the changed projects individually: +```bash +dotnet build src/PPDS.Cli/PPDS.Cli.csproj -v q +dotnet build src/PPDS.Query/PPDS.Query.csproj -v q +# etc. — only the projects with changed files +``` +This is expected when webview-cdp has VS Code open. The daemon runs from shadow-copied binaries but the solution build may still contend with other processes. + **Gate 2: .NET Tests** (if C# files changed) ```bash @@ -44,25 +52,54 @@ Fail: report failing test names and assertion messages **Gate 3: TypeScript Build** (if TS/JS files changed) ```bash -npm run compile --prefix extension +npm run compile --prefix src/PPDS.Extension ``` Pass: 0 errors Fail: report exact error messages with file:line +**Gate 3.5: TypeScript Type Check** (if TS/JS files changed) + +```bash +npm run typecheck:all --prefix src/PPDS.Extension +``` + +Pass: 0 errors across both host and webview tsconfigs +Fail: report exact error messages with file:line + +Note: `compile` (Gate 3) only runs esbuild which does NOT type-check. This gate runs `tsc --noEmit` against both `tsconfig.json` (host) and `tsconfig.webview.json` (browser) to catch type errors. + **Gate 4: TypeScript Lint** (if TS/JS files changed) ```bash -npm run lint --prefix extension +npm run lint --prefix src/PPDS.Extension ``` Pass: 0 errors Fail: report lint violations +**Gate 4.5: CSS Lint** (if CSS files changed) + +```bash +npm run lint:css --prefix src/PPDS.Extension +``` + +Pass: 0 errors +Fail: report CSS lint violations with file:line + +**Gate 4.6: Dead Code Analysis** (if TS/JS files changed) + +```bash +npm run dead-code --prefix src/PPDS.Extension +``` + +Pass: 0 unused exports +Fail: report unused exports/files + **Gate 5: TypeScript Tests** (if TS/JS files changed) ```bash -npm test --prefix extension +npm test --prefix src/PPDS.Extension ``` Pass: 0 failures @@ -73,7 +110,7 @@ Fail: report failing test names and messages Read `specs/README.md` to map changed files to specs. For each relevant spec with ACs: - Extract test method names from the AC table - For .NET tests: `dotnet test --filter "FullyQualifiedName~{method}" -v q --no-build` -- For TypeScript tests: `npx vitest run -t "{method}" --prefix extension` +- For TypeScript tests: `npx vitest run -t "{method}" --prefix src/PPDS.Extension` - Report which ACs pass and which fail ### Step 3: Report @@ -97,6 +134,17 @@ Read `specs/README.md` to map changed files to specs. For each relevant spec wit ### Verdict: FAIL — 2 issues must be resolved before proceeding ``` +## Post-Gate Reminder + +Gates are necessary but NOT sufficient. After gates pass: + +- **If changed files include webview TS/CSS/HTML** (`src/PPDS.Extension/src/panels/`): You MUST also run `/verify extension` and/or `/qa extension` for visual verification. Gates prove code compiles and tests pass — they do NOT prove it renders correctly or works as the user would experience. +- **If changed files include CLI commands** (`src/PPDS.Cli/Commands/`, not `Serve/`): Run the command and verify the output. +- **If changed files include MCP tools** (`src/PPDS.Mcp/`): Call the tool and verify the response. +- **If changed files include TUI** (`src/PPDS.Cli/Tui/`): Run `npm run tui:test` for snapshot verification. + +**Do not commit UI/CLI/MCP changes with only gates passing.** That is how bugs ship undetected. + ## Rules 1. **Mechanical only** — no subjective judgments, no code review, no style opinions diff --git a/.claude/commands/implement.md b/.claude/commands/implement.md index 92ee99f1..deffac5a 100644 --- a/.claude/commands/implement.md +++ b/.claude/commands/implement.md @@ -39,6 +39,8 @@ Before dispatching any agents, load the specification context that will be injec - `src/PPDS.Mcp/` → `specs/mcp.md` - `src/PPDS.Migration/` → `specs/migration.md` - `src/PPDS.Auth/` → `specs/authentication.md` + - `src/PPDS.Extension/src/panels/` → `specs/per-panel-environment-scoping.md` (if panels) or relevant spec + - `src/PPDS.Extension/` → check `specs/README.md` for extension-related specs - Always include `specs/architecture.md` - Read each relevant spec and extract the `## Acceptance Criteria` section @@ -101,7 +103,17 @@ For EACH phase in the plan, repeat this cycle: - If specs with ACs are relevant to this phase, check: do the AC test methods pass? Run: `dotnet test --filter "FullyQualifiedName~{TestMethodFromAC}" -v q --no-build` for each AC referenced by this phase's tasks -- Re-run verification after fixes. Do NOT proceed until gate passes. +- If the phase touches extension code (`src/PPDS.Extension/` directory): + Invoke `/verify extension` to check daemon status, tree views, and panel state. + Then invoke `/qa extension` to dispatch a blind verifier agent that tests the UI without seeing source code. +- If the phase touches TUI code (`src/PPDS.Cli/Tui/`): + Invoke `/verify tui` to check TUI rendering. +- If the phase touches MCP code (`src/PPDS.Mcp/`): + Invoke `/verify mcp` to check tool responses. + Then invoke `/qa mcp` to dispatch a blind verifier for tool responses. +- If the phase touches CLI commands (`src/PPDS.Cli/Commands/`, not `Serve/`): + Invoke `/qa cli` to verify command output matches expectations. +- Re-run verification after fixes. Do NOT proceed until gate passes AND /qa passes. **D. Review** - Use `superpowers:requesting-code-review` agent to review the phase's work against the plan diff --git a/.claude/commands/install-cli.md b/.claude/commands/install-cli.md deleted file mode 100644 index 313b7bc3..00000000 --- a/.claude/commands/install-cli.md +++ /dev/null @@ -1,44 +0,0 @@ -# Install CLI - -Pack and install the latest local build of PPDS CLI as a global tool. - -## Usage - -`/install-cli` - -## What It Does - -Run the existing installation script: - -```powershell -.\scripts\Install-LocalCli.ps1 -``` - -This script: -1. Packs PPDS.Cli to `nupkgs/` -2. Finds the latest package by timestamp -3. Uninstalls any existing version -4. Installs the new version globally - -## If Installation Fails - -**Stop and prompt the user.** Installation failures often occur because: -- TUI is running in another terminal session (file lock) -- Another CLI process is active -- Antivirus is blocking the operation - -The user may not realize another process has the CLI locked. - -## After Installation - -Verify with: -```bash -ppds --version -``` - -## When to Use - -- After making changes to PPDS.Cli or its dependencies -- When testing CLI behavior locally - -**Alternative:** The terminal profile's `ppds` function runs CLI directly from the worktree without global installation. Run `/setup-terminal` to install the profile. diff --git a/.claude/commands/panel-design.md b/.claude/commands/panel-design.md new file mode 100644 index 00000000..4de72353 --- /dev/null +++ b/.claude/commands/panel-design.md @@ -0,0 +1,112 @@ +# Panel Design + +Design a new panel or feature across all four PPDS surfaces: Daemon RPC, VS Code extension, TUI, and MCP. + +## Input + +$ARGUMENTS = feature domain name (e.g., `import-jobs`, `plugin-traces`, `web-resources`) + +## Process + +### Step 1: Load Foundation + +Read before doing anything: +- `specs/CONSTITUTION.md` — A1, A2 govern multi-surface design (services are single code path, UI is thin wrapper) +- `specs/architecture.md` — cross-cutting patterns +- Domain-relevant specs via `specs/README.md` + +### Step 2: Inventory Existing Infrastructure + +For the target domain, check what exists at each layer: + +| Layer | Location | +|-------|----------| +| Domain services | `src/PPDS.Dataverse/Services/` (Dataverse data access) | +| Application services | `src/PPDS.Cli/Services/` (orchestration, cross-cutting) | +| Entity classes | `src/PPDS.Dataverse/Generated/Entities/` | +| CLI commands | `src/PPDS.Cli/Commands/{Domain}/` | +| Daemon RPC methods | `src/PPDS.Cli/Commands/Serve/Handlers/RpcMethodHandler.cs` | +| MCP tools | `src/PPDS.Mcp/Tools/` | +| TUI screens/dialogs | `src/PPDS.Cli/Tui/Screens/`, `src/PPDS.Cli/Tui/Dialogs/` | +| VS Code panels | Extension `src/panels/` | + +Classify each as: **Ready**, **Partial** (needs extension), or **Missing** (must create). + +**Prerequisites before UI design:** +- If the service is Missing, design it first — A1/A2 mandate services as the single code path. +- If required entity classes don't exist in `Generated/Entities/`, entity generation is a prerequisite (Constitution I2 — never hand-edit generated entities). +- If the domain requires Power Platform APIs outside the Dataverse SDK (e.g., Connections API via `service.powerapps.com`), identify those endpoints and any auth scope differences (`IPowerPlatformTokenProvider`). + +### Step 3: Design RPC Endpoints and Data Contract + +For each user-facing operation, define an RPC method: + +- Method name: `{domain}/{operation}` (e.g., `importJobs/list`, `importJobs/get`, `pluginTraces/timeline`) +- Request/Response DTOs with typed fields — these DTOs are the shared contract consumed by VS Code and MCP +- Error codes as domain-specific `PpdsException` ErrorCodes (D4) +- Thread `CancellationToken` through the entire async chain (R2) +- Accept `IProgressReporter` for operations expected to take >1 second (A3) + +**RPC handler pattern:** Methods are decorated with `[JsonRpcMethod("domain/operation")]` in `RpcMethodHandler.cs`. Handlers use `IDaemonConnectionPoolManager` for Dataverse access. Read existing methods for the pattern — no business logic in the handler, just parameter mapping → service call → DTO mapping. + +### Step 4: Design VS Code Panel + +Reference the `@webview-panels` skill (`.claude/skills/webview-panels/SKILL.md`) for implementation patterns (panel anatomy, message protocol, CSS patterns, environment theming). + +Define: +- Panel viewType and display name +- Message protocol (host ↔ webview discriminated union types) +- Data display format (table, tree, detail pane, split layout) +- User actions (toolbar buttons, context menus, keyboard shortcuts) +- Environment scoping behavior (per-panel environment selection) + +### Step 5: Design TUI Screen + +Reference existing screens in `src/PPDS.Cli/Tui/Screens/` for patterns. + +Define: +- Screen class name and menu/tab integration +- Layout (single table, split pane, tabbed) +- Hotkey bindings via `HotkeyRegistry` +- Dialog inventory (detail views, filters, confirmations) +- Streaming vs batch data loading strategy + +TUI screens call Application Services directly (no RPC indirection). + +### Step 6: Design MCP Tools + +Define tools for what AI agents need from this domain: + +- Tool name: `ppds_{domain}_{operation}` +- Input schema with parameter descriptions +- Output format structured for AI reasoning + +Not every panel action needs an MCP tool. Focus on read/query operations. Skip UI-only actions (open in browser, keyboard shortcuts, export to clipboard). + +### Step 7: Define Acceptance Criteria + +For each surface, define "complete." Use legacy panel behavior as the floor: + +- **Data parity:** Same fields/columns displayed as legacy +- **Action parity:** Same operations available (refresh, filter, export, open in Maker, etc.) +- **UX parity:** Same drill-down navigation, solution filtering, detail views +- **Enhancements:** Improvements enabled by new architecture (better data from existing services, environment theming, per-panel environment scoping) + +Number all criteria: AC-01, AC-02, etc. (Constitution I3). + +### Step 8: Map to Work Items + +- Map design to existing GitHub issues +- Flag stale issues that need updating +- Identify gaps requiring new issues +- Recommend worktree/branch strategy based on complexity and dependencies + +## Rules + +1. **Services first, UI second** — if the Application Service doesn't exist, design that before any UI surface. +2. **Reference existing panels** — the first panel designed establishes patterns. Subsequent panels follow them. +3. **Legacy as floor, not ceiling** — match what existed, improve where the new architecture enables it. +4. **Don't port code** — understand what the legacy did, then design the proper abstraction. No inheriting legacy patterns. +5. **One panel at a time** — complete design for one panel across all surfaces before starting the next. +6. **Cross-reference surface parity** — VS Code panel and TUI screen must expose equivalent functionality (same data, same filters, same actions). MCP tools must cover the same read/query operations for AI agent access. +7. **Update skills after pattern-setting work** — when the first panel in a batch establishes new patterns (e.g., virtual scrolling, complex state management), update referenced skills (`@webview-panels`, TUI equivalents) with the proven patterns before implementing subsequent panels. Include this as an explicit step in the implementation plan. diff --git a/.claude/commands/qa.md b/.claude/commands/qa.md new file mode 100644 index 00000000..084b5859 --- /dev/null +++ b/.claude/commands/qa.md @@ -0,0 +1,174 @@ +# QA — Blind Verification + +Dispatches a **fresh agent with no source code access** to verify that implemented features actually work. The verifier interacts with the running product exactly as a user would — CDP for extension, CLI for commands, MCP Inspector for tools. If it can't see the feature working, the feature isn't done. + +**Why this exists:** The builder has confirmation bias. It wrote the code, it "knows" it works. A blind verifier can't rationalize — it either sees the right thing on screen or it doesn't. + +## Usage + +`/qa` — auto-detect from recent commits +`/qa extension` — verify extension changes via CDP +`/qa cli` — verify CLI changes by running commands +`/qa mcp` — verify MCP changes via Inspector +`/qa "SELECT TOP 5 should return 5 rows"` — explicit behavior description + +## Process + +### Step 1: Build the Behavior Checklist + +**If $ARGUMENTS is a quoted description:** Use it directly as the behavior to verify. + +**If $ARGUMENTS is a mode (extension/cli/mcp) or empty:** Auto-generate from recent work: + +```bash +git log --since="4 hours ago" --format="%s%n%b" --no-merges +``` + +For each commit, extract observable behaviors: +- `feat(query): add X` → "X should be visible/functional in the UI" +- `fix(ext): guard against Y` → "Y scenario should not crash" +- `feat(extension): add Z to panel` → "Z should render in the panel" + +**Be specific.** Not "query works" — instead: "Execute `SELECT TOP 5 name FROM account`, verify exactly 5 rows in the results table." Not "env colors work" — instead: "Switch to a sandbox environment, verify a yellow-ish border appears on the toolbar." + +### Step 2: Detect Mode + +From $ARGUMENTS or changed files: +- `src/PPDS.Extension/` → extension mode (CDP) +- `src/PPDS.Cli/Commands/` (not Serve/) → CLI mode (run commands) +- `src/PPDS.Mcp/` → MCP mode (Inspector) +- `src/PPDS.Cli/Tui/` → TUI mode (snapshot tests — no blind verification yet) +- Mixed → run applicable modes sequentially + +### Step 3: Dispatch Blind Verifier + +Launch a subagent with these constraints. **This is the critical part — the verifier MUST NOT have implementation context.** + +#### Extension Mode — Verifier Prompt + +``` +You are a QA tester. You have NEVER seen the source code for this +extension. You don't know how anything is implemented. You only know +what the product SHOULD do. + +## Your Tools + +You may ONLY use these tools: +- Bash: ONLY for running `node src/PPDS.Extension/tools/webview-cdp.mjs` commands +- Read: ONLY for viewing screenshot image files (in $TEMP) + +You MUST NOT use Read/Grep/Glob on source code files. You cannot look +at .ts, .cs, .css, .json, or any file under src/. You are blind to +the implementation. If you feel the urge to "check the code" — that +means the feature isn't working and you should report FAIL. + +## Verification Protocol + +For EACH check below: +1. Perform the action using CDP commands +2. Take a screenshot as evidence: `node src/PPDS.Extension/tools/webview-cdp.mjs screenshot $TEMP/qa-{check-number}.png` +3. LOOK at the screenshot (use Read tool on the PNG) +4. Read relevant DOM text: `node src/PPDS.Extension/tools/webview-cdp.mjs text "" --ext "power-platform-developer-suite"` +5. Check logs for errors: `node src/PPDS.Extension/tools/webview-cdp.mjs logs` +6. Report PASS or FAIL with evidence + +If a check FAILS: +- Describe exactly what you SAW vs what was EXPECTED +- Include the screenshot path +- Include any error messages from logs +- Do NOT speculate about why it failed — you can't see the code + +## Setup + +First, launch VS Code with a fresh build: +```bash +node src/PPDS.Extension/tools/webview-cdp.mjs close # clean up any prior session +node src/PPDS.Extension/tools/webview-cdp.mjs launch --build +``` + +## Checks + +{paste generated checklist here} + +## Teardown + +After all checks: +```bash +node src/PPDS.Extension/tools/webview-cdp.mjs close +``` + +## Report Format + +Return a structured report: + +| # | Check | Status | Evidence | +|---|-------|--------|----------| +| 1 | description | PASS/FAIL | screenshot path + what you saw | +| 2 | ... | ... | ... | + +### Error Log +{any errors from `logs` commands} + +### Verdict: PASS (all green) / FAIL (N issues found) + +{for each FAIL: exact description of expected vs actual} +``` + +#### CLI Mode — Verifier Prompt + +Same structure but: +- Tool access: Bash (only for running `ppds` CLI commands or `dotnet run`) +- Build first: `dotnet build src/PPDS.Cli/PPDS.Cli.csproj -f net10.0 -v q` +- Each check: run the command, capture stdout/stderr, compare to expected +- Evidence: command output (not screenshots) + +#### MCP Mode — Verifier Prompt + +Same structure but: +- Tool access: Bash (only for `npx @modelcontextprotocol/inspector`) +- Each check: call the MCP tool, capture response JSON, compare to expected +- Evidence: response payloads + +### Step 4: Evaluate Results + +Read the verifier's report. + +**If ALL PASS:** QA complete. Proceed with commit/next phase. + +**If ANY FAIL:** + +1. Present the failure report to the builder (yourself or the orchestrator) +2. The failures include screenshots and exact descriptions — use these to fix +3. After fixing, **re-invoke `/qa`** with the same checklist +4. The re-invocation dispatches a **fresh verifier** (no memory of prior attempt) +5. Repeat until ALL PASS + +**There is no escape hatch.** You cannot skip a failing check. You cannot mark a FAIL as "known issue" and proceed. Either fix it or remove the check because the feature was descoped — in which case, explain why to the user. + +### Step 5: Report + +``` +## QA Results + +Mode: extension | Checks: 8 | Pass: 7 | Fail: 1 + +| # | Check | Status | Evidence | +|---|-------|--------|----------| +| 1 | Panel renders | PASS | $TEMP/qa-1.png | +| ... | ... | ... | ... | + +### Verdict: FAIL — 1 issue must be resolved + +**Check 4 FAILED:** Expected status bar to show "via Dataverse" but saw "via TDS". +Screenshot: $TEMP/qa-4.png +``` + +## Rules + +1. **Blind verifier** — the QA agent never sees source code. Period. +2. **Evidence required** — every PASS/FAIL must have a screenshot or output capture. +3. **Loop until clean** — failures trigger fix → re-verify. No exceptions. +4. **Fresh agent each run** — don't resume a prior verifier. Each run is independent. +5. **Specificity** — "query works" is not a check. "SELECT TOP 5 returns 5 rows" is. +6. **Don't fix during QA** — the verifier reports, the builder fixes. Separation of concerns. +7. **Checklist before dispatch** — always show the checklist to the user/orchestrator before dispatching the verifier. This catches bad checks early. diff --git a/.claude/commands/impartial-code-review.md b/.claude/commands/review.md similarity index 99% rename from .claude/commands/impartial-code-review.md rename to .claude/commands/review.md index 2f5e46ef..e6253248 100644 --- a/.claude/commands/impartial-code-review.md +++ b/.claude/commands/review.md @@ -1,4 +1,4 @@ -# Impartial Code Review +# Review Code review with structural bias prevention. The reviewer gets NO implementation context — no plan, no task descriptions, no "what we were trying to do." They get ONLY: the diff, the file contents, the constitution, and relevant spec ACs. They read code and find bugs. diff --git a/.claude/commands/setup.md b/.claude/commands/setup.md index c8e5d54d..7fd1c041 100644 --- a/.claude/commands/setup.md +++ b/.claude/commands/setup.md @@ -1,55 +1,82 @@ # Setup -Set up PPDS development environment on a new machine. +Set up a complete PPDS development environment on a new machine, or refresh an existing one after pulling new code. ## Usage -`/setup` - Interactive wizard -`/setup --update` - Update existing installation +`/setup` - Interactive wizard (fresh machine or new contributor) +`/setup --update` - Non-interactive refresh (restore working build after code changes) ## What It Does -Interactive wizard that: -1. Clones PPDS repositories -2. Creates VS Code workspace -3. Configures Claude notifications and status line +**Wizard mode (`/setup`):** Prerequisites check → clone repos → install dependencies → build → install tools → check AI tooling → configure DX options → verify → summary. + +**Update mode (`/setup --update`):** Prerequisites check → git pull → install dependencies → build → install tools → verify → summary. Zero questions asked. > **Note:** For terminal customization (Oh My Posh, eza, bat, etc.), see the separate [dotfiles repo](https://github.com/joshsmithxrm/dotfiles). ## Process -### Step 1: Choose Base Path +### Step 0: Platform Detection -Ask where to put repos (use AskUserQuestion): -- Suggest common paths: `C:\Dev`, `D:\Projects`, `~/dev`, etc. -- User can specify any path via "Other" option -- No hardcoded default - always ask +Detect the platform to gate Windows-only steps: -### Step 2: Select Repositories +```bash +uname -s +``` -Multi-select: +- Contains `MINGW` or `MSYS` → Windows (`IS_WINDOWS=true`) +- Otherwise → Linux (`IS_WINDOWS=false`) -| Option | Description | -|--------|-------------| -| `ppds` | SDK: NuGet packages & CLI (core) | -| `ppds-docs` | Documentation site | -| `ppds-alm` | CI/CD templates | -| `ppds-tools` | PowerShell module | -| `ppds-demo` | Reference implementation | +Windows-only steps: VS Code check, extension VSIX install, sound notification. + +### Step 1: Prerequisites Check + +Verify required tools are on PATH. If any are missing, print what's needed and **stop** — don't continue with a broken environment. + +| Tool | Check | Min Version | Error | +|------|-------|-------------|-------| +| git | `git --version` | Any | "git not found. Install from https://git-scm.com/" | +| node | `node --version` | ≥18 | "Node.js ≥18 required. Install from https://nodejs.org/" | +| dotnet | `dotnet --version` | ≥8.0 | ".NET SDK ≥8.0 required. Install from https://dot.net/" | +| pwsh | `pwsh --version` | ≥7.0 | "PowerShell 7+ required. Install from https://aka.ms/powershell" | +| code | `code --version` | Any | "VS Code not found. VSIX installation will be skipped." | + +**Platform rules:** +- `code` check: Windows only. Skip entirely on Linux (not expected in dev containers). +- `code` is a soft prerequisite: missing `code` prints a warning but does not stop setup. -### Step 3: Developer Experience Options +**Version parsing:** `node --version` returns `v18.19.0`, `dotnet --version` returns `8.0.404`. Parse the major version number for comparison. + +**Both modes** run this step. In `--update` mode, this catches scenarios where a tool was removed or downgraded between sessions. + +--- + +**The following steps differ by mode. See "Update Mode" section below for `--update` flow.** + +--- + +### Step 2: Choose Base Path (wizard only) + +Ask where to put repos (use AskUserQuestion): +- Suggest common paths: `C:\VS`, `C:\Dev`, `D:\Projects`, `~/dev`, etc. +- User can specify any path via "Other" option +- No hardcoded default — always ask + +### Step 3: Select Repositories (wizard only) Multi-select: | Option | Description | |--------|-------------| -| VS Code workspace | Create `ppds.code-workspace` file | -| Sound notification | Play Windows sound when Claude finishes | -| Status line | Show directory and git branch in Claude UI | +| `ppds` | SDK + CLI + TUI + VS Code Extension + MCP (core) | +| `ppds-docs` | Documentation site (Docusaurus) | +| `ppds-alm` | CI/CD templates (GitHub Actions) | +| `ppds-tools` | PowerShell module (CLI wrapper) | +| `ppds-demo` | Reference Dataverse implementation | +| `vault` | Personal knowledge base (Obsidian) — private, ask maintainer for access | -### Step 4: Execute Setup - -#### Clone/Update Repositories +### Step 4: Clone/Update Repositories (wizard only) For each selected repo: 1. Check if folder exists @@ -65,6 +92,74 @@ git clone https://github.com/joshsmithxrm/ppds-tools.git {base}/ppds-tools git clone https://github.com/joshsmithxrm/ppds-demo.git {base}/ppds-demo ``` +`vault` is private — if selected, ask the user for the clone URL. + +### Step 5: Install Dependencies (if ppds selected/present) + +```bash +dotnet restore PPDS.sln +npm install --prefix src/PPDS.Extension +npm install --prefix tests/PPDS.Tui.E2eTests +``` + +### Step 6: Build Verification (if ppds selected/present) + +```bash +dotnet build PPDS.sln -v q +npm run ext:compile +``` + +If either fails, **stop** and report the error. Dependencies are wrong or something is misconfigured — no point continuing. + +### Step 7: Install Tools (if ppds selected/present) + +**CLI global tool:** +```bash +pwsh scripts/Install-LocalCli.ps1 +``` + +If installation fails, report "TUI or CLI may be running in another terminal (file lock)" and continue. + +Verify: `ppds --version` + +**Extension VSIX (Windows only):** +```bash +npm run ext:local --prefix src/PPDS.Extension +``` + +Skip on Linux — not meaningful in dev containers. + +### Step 8: AI Tooling Check (wizard only) + +Check if superpowers plugin is installed: + +```bash +ls ~/.claude/plugins/cache/claude-plugins-official/superpowers/ +``` + +If the directory does not exist, print: + +``` +Superpowers plugin not installed. The PPDS workflow depends on it. +Install with: + /plugin marketplace add obra/superpowers-marketplace + /plugin install superpowers@superpowers-marketplace +``` + +Do NOT auto-install — the marketplace has known recognition issues. Let the user run the commands manually. + +If the directory exists, skip silently. + +### Step 9: Developer Experience Options (wizard only) + +Multi-select: + +| Option | Description | Platform | +|--------|-------------|----------| +| VS Code workspace | Create `ppds.code-workspace` file | Both | +| Sound notification | Play Windows sound when Claude finishes | Windows only | +| Status line | Show directory and git branch in Claude UI | Both | + #### Create VS Code Workspace (if selected) Generate `{base}/ppds.code-workspace`: @@ -82,7 +177,7 @@ Generate `{base}/ppds.code-workspace`: ``` Only include folders that were actually cloned. -#### Setup Sound Notification (if selected) +#### Setup Sound Notification (if selected, Windows only) Add Stop hook to `~/.claude/settings.json`: ```json @@ -93,7 +188,7 @@ Add Stop hook to `~/.claude/settings.json`: "hooks": [ { "type": "command", - "command": "powershell -NoProfile -Command \"[System.Media.SystemSounds]::Asterisk.Play()\"", + "command": "pwsh -NoProfile -Command \"[System.Media.SystemSounds]::Asterisk.Play()\"", "timeout": 3 } ] @@ -103,20 +198,11 @@ Add Stop hook to `~/.claude/settings.json`: } ``` -Read existing settings.json first, merge the hooks section, then write back. +Read existing settings.json first, merge the hooks section, then write back. Use `pwsh` not `powershell`. #### Setup Status Line (if selected) -**Important:** The statusLine command requires an absolute path. - -1. Detect user's home directory: -```powershell -$homePath = [Environment]::GetFolderPath('UserProfile') -``` - -2. Create status line script at `{homePath}/.claude/statusline.ps1`: - -**Windows version** (PowerShell): +**Windows version** — create `~/.claude/statusline.ps1`: ```powershell # PPDS Claude status line - shows directory and git branch with colors $json = [Console]::In.ReadToEnd() @@ -141,38 +227,98 @@ if ($branch) { } ``` -3. Add statusLine config to `~/.claude/settings.json` using the user's home directory: +**Linux version** — create `~/.claude/statusline.sh`: +```bash +#!/bin/bash +read -r json +cwd=$(echo "$json" | node -e "const d=JSON.parse(require('fs').readFileSync(0,'utf8')); console.log(d.workspace.current_dir)") +dir=$(basename "$cwd") +branch=$(cd "$cwd" && git branch --show-current 2>/dev/null || true) +if [ -n "$branch" ]; then + echo -e "\033[96m${dir}\033[0m \033[95m(${branch})\033[0m" +else + echo -e "\033[96m${dir}\033[0m" +fi +``` + +Add statusLine config to `~/.claude/settings.json`: + +Windows: ```json -{ - "statusLine": { - "type": "command", - "command": "pwsh -NoProfile -File ~/.claude/statusline.ps1" - } -} +{ "statusLine": { "type": "command", "command": "pwsh -NoProfile -File ~/.claude/statusline.ps1" } } ``` -> **Note:** Use `~` for cross-platform compatibility. On Windows, Claude Code expands `~` to `$env:USERPROFILE`. +Linux: +```json +{ "statusLine": { "type": "command", "command": "bash ~/.claude/statusline.sh" } } +``` + +### Step 10: Verification + +```bash +ppds --version +npm run ext:test +dotnet test PPDS.sln --filter "Category!=Integration" -v q +``` -### Step 5: Summary +### Step 11: Summary ``` Setup complete! +Platform: {Windows/Linux} +Prerequisites: git {ver}, node {ver}, dotnet {ver}, pwsh {ver} + Repositories cloned: - ppds - ppds-docs +Dependencies installed: + - .NET packages restored + - Extension npm packages installed + - TUI test packages installed + +Tools installed: + - CLI: ppds {version} + - Extension VSIX: installed (Windows) / skipped (Linux) + +AI Tooling: + - Superpowers: installed / NOT INSTALLED (see instructions above) + Developer tools configured: - VS Code workspace: {base}/ppds.code-workspace - Sound notification: Plays when Claude finishes - Status line: Shows directory and git branch +Dev container: config found at .devcontainer/ — use for isolated feature work + Next steps: - Open workspace: code "{base}/ppds.code-workspace" - Restart Claude Code for hooks/status line - For terminal customization: https://github.com/joshsmithxrm/dotfiles ``` +If `.devcontainer/` exists in the ppds repo, include the dev container note. Otherwise omit. + +--- + +## Update Mode (`/setup --update`) + +Non-interactive. Operates on the repo at the current working directory. No questions asked. + +1. **Platform detection** (Step 0) +2. **Prerequisites check** (Step 1) — same checks, same stop behavior +3. **git pull** the repo at the current working directory +4. **Install dependencies** (Step 5) +5. **Build** (Step 6) +6. **Install tools** (Step 7) +7. **Verification** (Step 10) +8. **Summary** — print versions, report any failures + +**Error handling:** If any step fails after prerequisites, log the failure and continue to the next step. Report all failures in the summary at the end. Prerequisites still stop early. + +--- + ## Idempotent Behavior | Scenario | Action | @@ -182,6 +328,11 @@ Next steps: | Folder exists, not git repo | Warn and skip | | Workspace file exists | Ask to overwrite or skip | | settings.json exists | Merge new config (don't overwrite) | +| npm node_modules exists | `npm install` updates if needed | +| .NET packages restored | `dotnet restore` is a no-op | +| CLI already installed | Script uninstalls and reinstalls | +| Superpowers installed | Skip check, no message | +| Dev container exists | Note in summary, don't modify | ## Repository URLs @@ -192,17 +343,11 @@ Next steps: | `ppds-alm` | `https://github.com/joshsmithxrm/ppds-alm.git` | | `ppds-tools` | `https://github.com/joshsmithxrm/ppds-tools.git` | | `ppds-demo` | `https://github.com/joshsmithxrm/ppds-demo.git` | +| `vault` | Private — ask maintainer for access | ## When to Use - Setting up a new development machine - Adding a new developer to the project -- Updating tools after changes (`--update`) - -## Verification - -After setup, test: -```powershell -cd {base}\ppds -dotnet run --project src/PPDS.Cli -- --version -``` +- Refreshing after pulling new code (`--update`) +- AI agent in a fresh Claude Code session diff --git a/.claude/commands/spec-audit.md b/.claude/commands/spec-audit.md index 4378d294..467bc702 100644 --- a/.claude/commands/spec-audit.md +++ b/.claude/commands/spec-audit.md @@ -32,7 +32,7 @@ For each spec, check these categories: **A. Acceptance Criteria Coverage** - Does the spec have an `## Acceptance Criteria` section with numbered IDs? - For each AC that references a test method: does that test file/method exist? (use Grep to search for the method name) -- For each AC with status marked passing: is the status accurate? (run the specific test if possible — .NET: `dotnet test --filter "FullyQualifiedName~{TestMethod}" -v q`, TypeScript: `npx vitest run -t "{TestMethod}" --prefix extension`) +- For each AC with status marked passing: is the status accurate? (run the specific test if possible — .NET: `dotnet test --filter "FullyQualifiedName~{TestMethod}" -v q`, TypeScript: `npx vitest run -t "{TestMethod}" --prefix src/PPDS.Extension`) - Report: verified, test exists but status wrong, test not found, or no AC section **B. Code-to-Spec Alignment** diff --git a/.claude/commands/verify.md b/.claude/commands/verify.md new file mode 100644 index 00000000..4d8abf76 --- /dev/null +++ b/.claude/commands/verify.md @@ -0,0 +1,155 @@ +# Verify + +AI self-verification of implemented work using MCP tools. Goes beyond unit tests to verify that code actually works in its runtime environment. + +## Usage + +`/verify` - Auto-detect component from recent changes +`/verify cli` - Verify CLI command behavior +`/verify tui` - Verify TUI rendering and interaction +`/verify extension` - Verify VS Code extension behavior +`/verify mcp` - Verify MCP server tools + +## Prerequisites + +Each mode requires specific MCP servers. If a prerequisite is missing, tell the user what to install and stop. + +| Mode | Required MCPs / Tools | +|------|----------------------| +| cli | None (uses Bash tool directly) | +| tui | Not yet available — TUI snapshot tests only (`npm run tui:test`) | +| extension | `src/PPDS.Extension/tools/webview-cdp.mjs` (uses @playwright/test + @vscode/test-electron, both dev deps) | +| mcp | MCP Inspector CLI (`npx @modelcontextprotocol/inspector`) | + +## Process + +### 1. Detect Component + +Based on $ARGUMENTS or recent changes: +- `src/PPDS.Cli/Commands/` → CLI mode +- `src/PPDS.Cli/Tui/` → TUI mode +- `src/PPDS.Extension/` → Extension mode +- `src/PPDS.Mcp/` → MCP mode +- No clear match → Ask user + +### 2. Run Unit Tests First + +Always run the relevant unit tests before interactive verification. If tests fail, fix them first — don't waste MCP verification cycles on broken code. + +- CLI/TUI: `dotnet test PPDS.sln --filter "Category!=Integration" -v q` +- Extension: `npm run test --prefix src/PPDS.Extension` +- MCP: `dotnet test --filter "FullyQualifiedName~Mcp" -v q` + +### 3. CLI Mode + +Run the CLI command and verify output: + +```bash +dotnet build src/PPDS.Cli/PPDS.Cli.csproj -f net10.0 +.\src\PPDS.Cli\bin\Debug\net10.0\ppds.exe +``` + +Verify: +- Command executes without error +- Output format is correct (JSON where expected, table where expected) +- Exit code is 0 +- Edge cases: empty input, invalid args, missing auth + +### 4. TUI Mode + +TUI interactive verification via MCP is not yet available. Use snapshot tests: + +```bash +npm run tui:test +``` + +Verify: +- All snapshot tests pass +- No visual regressions in terminal output + +### 5. Extension Mode + +**Phase A: Functional Verification (webview-cdp)** + +Launch VS Code with the extension and verify panels load: + +```bash +# Build and launch (compiles extension + daemon) +node src/PPDS.Extension/tools/webview-cdp.mjs launch --build + +# Open Data Explorer and wait for webview +node src/PPDS.Extension/tools/webview-cdp.mjs command "PPDS: Data Explorer" +node src/PPDS.Extension/tools/webview-cdp.mjs wait --ext "power-platform-developer-suite" + +# Screenshot to verify panel rendered correctly +node src/PPDS.Extension/tools/webview-cdp.mjs screenshot $TEMP/data-explorer.png +# LOOK at the screenshot — verify layout, no blank areas, controls visible + +# Check for runtime errors +node src/PPDS.Extension/tools/webview-cdp.mjs logs +node src/PPDS.Extension/tools/webview-cdp.mjs logs --channel "PPDS" +``` + +**Phase B: Interaction Verification (MANDATORY for query/data-display/panel-interaction changes)** + +If changed files touch query execution (`SqlQueryService`, `RpcMethodHandler`, `QueryPanel`, `query-panel.ts`), data rendering, or panel interactions, Phase B is NOT optional — you must execute at least one query and verify the results. + +```bash +# Test query execution +node src/PPDS.Extension/tools/webview-cdp.mjs eval 'monaco.editor.getEditors()[0].setValue("SELECT TOP 5 name FROM account")' +node src/PPDS.Extension/tools/webview-cdp.mjs click "#execute-btn" --ext "power-platform-developer-suite" +node src/PPDS.Extension/tools/webview-cdp.mjs screenshot $TEMP/after-query.png + +# Test Solutions Panel +node src/PPDS.Extension/tools/webview-cdp.mjs command "PPDS: Solutions" +node src/PPDS.Extension/tools/webview-cdp.mjs wait --ext "power-platform-developer-suite" +node src/PPDS.Extension/tools/webview-cdp.mjs screenshot $TEMP/solutions.png +``` + +**Phase C: Cleanup** + +```bash +node src/PPDS.Extension/tools/webview-cdp.mjs close +``` + +See @webview-cdp skill for full command reference and common patterns. + +### 6. MCP Mode + +Use MCP Inspector CLI to test tools: + +```bash +npx @modelcontextprotocol/inspector --cli --server "ppds-mcp-server" +``` + +For each tool: +1. Call with valid input -> verify success response shape +2. Call with edge case input -> verify error handling +3. Verify response matches expected schema + +### 7. Report + +Present structured results: + +``` +## Verification Results -- [component] + +| Check | Status | Details | +|-------|--------|---------| +| Unit tests | PASS | 12/12 passing | +| Daemon connection | PASS | PID 12345, uptime 30s | +| Tree view state | PASS | 2 profiles, 3 environments | +| Data Explorer open | PASS | Panel created | +| SQL query execution | PASS | 5 rows returned | +| Webview rendering | PASS | Query panel layout correct | + +### Verdict: PASS -- all checks green +``` + +## Rules + +1. **Unit tests first** -- always. Don't waste interactive cycles on broken code. +2. **Structured data over screenshots** -- when both are available, prefer ppds.debug.* JSON over visual inspection. For webview panels, use @webview-cdp screenshots (see Extension Mode above). +3. **Report exact state** -- include actual values, not just pass/fail. +4. **Prerequisites are hard gates** -- if MCP not configured, stop and say so. +5. **Don't fix during verify** -- report problems, don't fix them. That's for /debug or /converge. diff --git a/.claude/hooks/pre-commit-validate.py b/.claude/hooks/pre-commit-validate.py index 203f0339..12233280 100644 --- a/.claude/hooks/pre-commit-validate.py +++ b/.claude/hooks/pre-commit-validate.py @@ -60,8 +60,8 @@ def main(): print(test_result.stderr, file=sys.stderr) sys.exit(2) - # Run extension lint if extension/ has changes or exists - extension_dir = os.path.join(project_dir, "extension") + # Run extension lint if src/PPDS.Extension/ has changes or exists + extension_dir = os.path.join(project_dir, "src", "PPDS.Extension") if os.path.exists(extension_dir) and os.path.exists(os.path.join(extension_dir, "package.json")): lint_result = subprocess.run( ["npm", "run", "lint"], diff --git a/.claude/hooks/ralph-hook.py b/.claude/hooks/ralph-hook.py deleted file mode 100644 index e76f6e46..00000000 --- a/.claude/hooks/ralph-hook.py +++ /dev/null @@ -1,182 +0,0 @@ -#!/usr/bin/env python3 -""" -Ralph Wiggum Stop Hook - Windows-native autonomous iteration. - -This hook intercepts session exits and continues iteration loops -until completion or max iterations reached. - -Usage: - 1. Run /ralph-loop "your task" --max-iterations 20 - 2. Claude works on the task - 3. When Claude tries to exit, this hook checks: - - Is there an active ralph loop for this session? - - Has the completion promise been output? - - Have we hit max iterations? - 4. If not complete, blocks exit and feeds prompt back - 5. Repeat until done - -State is stored in ~/.ppds/ralph/{session_id}.json -""" -import json -import sys -import os -from pathlib import Path -from datetime import datetime -from typing import Optional - - -def get_state_dir() -> Path: - """Get the ralph state directory (~/.ppds/ralph/).""" - return Path.home() / ".ppds" / "ralph" - - -def get_state_file(session_id: str) -> Path: - """Get the state file for a specific session.""" - return get_state_dir() / f"{session_id}.json" - - -def load_state(session_id: str) -> Optional[dict]: - """Load ralph loop state for a session. Returns None if no active loop.""" - state_file = get_state_file(session_id) - if not state_file.exists(): - return None - try: - return json.loads(state_file.read_text(encoding="utf-8")) - except (json.JSONDecodeError, OSError): - return None - - -def save_state(session_id: str, state: dict) -> None: - """Save ralph loop state for a session.""" - state_dir = get_state_dir() - state_dir.mkdir(parents=True, exist_ok=True) - get_state_file(session_id).write_text( - json.dumps(state, indent=2), encoding="utf-8" - ) - - -def check_completion(transcript_path: Optional[str], promise: str) -> bool: - """ - Check if completion promise appears in recent transcript output. - - Args: - transcript_path: Path to the session transcript JSONL file - promise: The exact string to look for (e.g., "DONE") - - Returns: - True if promise found in recent assistant messages - """ - if not transcript_path or not promise: - return False - - try: - transcript_file = Path(transcript_path) - if not transcript_file.exists(): - return False - - # Transcript is JSONL format (one JSON object per line) - lines = transcript_file.read_text(encoding="utf-8").strip().split("\n") - - # Parse last 50 lines and look for assistant messages - recent_lines = lines[-50:] if len(lines) > 50 else lines - assistant_contents = [] - - for line in recent_lines: - if not line.strip(): - continue - try: - entry = json.loads(line) - # Check for assistant role in message - if entry.get("role") == "assistant": - content = entry.get("content", "") - if isinstance(content, list): - content = " ".join( - c.get("text", "") for c in content - if isinstance(c, dict) and c.get("type") == "text" - ) - assistant_contents.append(str(content)) - except json.JSONDecodeError: - continue - - # Check last 5 assistant messages for the promise - for content in assistant_contents[-5:]: - if promise in content: - return True - - return False - except OSError: - return False - - -def main(): - """Main hook entry point.""" - # Read hook input from stdin - try: - raw_input = sys.stdin.read() - hook_input = json.loads(raw_input) if raw_input.strip() else {} - except json.JSONDecodeError: - hook_input = {} - - # Note: stop_hook_active indicates Claude is continuing from a previous - # stop hook. This is expected in Ralph loops - we rely on max_iterations - # to prevent runaway loops, not this flag. - - # Get session ID - fall back to environment variable or "default" - session_id = hook_input.get("session_id") - if not session_id: - session_id = os.environ.get("CLAUDE_SESSION_ID", "default") - - # Load state for this session - state = load_state(session_id) - - # No active loop? Allow exit silently - if not state or not state.get("active"): - sys.exit(0) - - # Check max iterations - current = state.get("current_iteration", 0) - max_iter = state.get("max_iterations", 20) - - if current >= max_iter: - state["active"] = False - state["completed_at"] = datetime.now().isoformat() - state["exit_reason"] = "max_iterations_reached" - save_state(session_id, state) - # Output informational message but allow exit - print(json.dumps({ - "reason": f"Ralph loop complete: max iterations ({max_iter}) reached" - })) - sys.exit(0) - - # Check completion promise - transcript_path = hook_input.get("transcript_path") - promise = state.get("completion_promise", "") - - if promise and check_completion(transcript_path, promise): - state["active"] = False - state["completed_at"] = datetime.now().isoformat() - state["exit_reason"] = "completion_promise_found" - save_state(session_id, state) - print(json.dumps({ - "reason": f"Ralph loop complete: found '{promise}'" - })) - sys.exit(0) - - # Continue the loop - increment iteration and block exit - state["current_iteration"] = current + 1 - state["last_iteration_at"] = datetime.now().isoformat() - save_state(session_id, state) - - prompt = state.get("prompt", "Continue working on the task.") - - result = { - "decision": "block", - "reason": f"[Ralph {state['current_iteration']}/{max_iter}] {prompt}" - } - - print(json.dumps(result)) - sys.exit(0) - - -if __name__ == "__main__": - main() diff --git a/.claude/skills/retrospective/SKILL.md b/.claude/skills/retrospective/SKILL.md new file mode 100644 index 00000000..737214eb --- /dev/null +++ b/.claude/skills/retrospective/SKILL.md @@ -0,0 +1,173 @@ +--- +name: retrospective +description: Conduct a structured retrospective on recent work sessions. Use when the user asks to review what happened, analyze session quality, identify patterns, or do a post-mortem. Triggers include "retrospective", "retro", "what went well", "session review", "post-mortem". +--- + +# Retrospective + +Structured analysis of recent work sessions to identify patterns, assign blame candidly, and recommend improvements. + +## Quality Bar (READ BEFORE STARTING) + +A retrospective is NOT adequate if it only analyzes commit messages. Commit messages are the AI's self-reported summary — exactly the thing that needs verification. A proper retrospective reads diffs, reads transcripts, and quotes the user directly. + +If your subagents return analysis based only on commit subjects and bodies, **reject their output and re-dispatch with explicit diff-reading instructions.** + +## When to Use + +- End of a feature branch before PR +- After a multi-day sprint +- When the user asks to review recent work quality +- After a particularly rough session (thrashing, rework) + +## Process + +### 1. Gather Raw Data + +**Determine the scope** from $ARGUMENTS: + +- `/retro latest` or `/retro` (no args) → find the latest session (most recent 30+ minute gap) +- `/retro 6h` or `/retro 2d` → explicit time window (hours or days) +- `/retro abc123..def456` → explicit commit range +- `/retro "2 days"` → explicit since-style window + +**Default behavior (no args):** Find the latest session, NOT "2 days ago". This prevents accidentally pulling in multiple sessions when the user wants to review just the most recent one. + +```bash +# Step 1: Get recent commits to find session boundaries +git log --since="2 days ago" --format="%H %ai" --no-merges + +# Step 2: Identify the most recent 30+ minute gap +# Everything after that gap = the latest session + +# Step 3: Fetch full details for ONLY the scoped commits +git log {start}..{end} --format="COMMIT:%H%nDATE:%ai%nSUBJECT:%s%nBODY:%b%n---" --no-merges +``` + +**Commit count guard:** If the scope contains more than 25 commits, warn the user and suggest narrowing. High-volume retros produce shallow analysis. + +Identify session boundaries: gaps of 30+ minutes between commits = new session. + +### 2. Dispatch Agents + +Launch ALL of these simultaneously — do NOT proceed until all are dispatched: + +- [ ] **One agent per session** for deep dives (step 3). Do NOT batch multiple sessions into one agent — each session gets its own agent with a focused scope. +- [ ] **One agent for skills/tools audit** (step 4) +- [ ] **One agent for memory cross-reference** (step 5) + +### 3. Deep Dive Each Session (one agent per session) + +Use the prompt template below for EACH session. Do NOT batch sessions — each gets its own agent. + +#### Subagent Prompt Template + +> Analyze the work session from {start_hash} to {end_hash} ({date_range}, {N} commits). +> +> Commits in this session: +> {paste the commit subjects for this session} +> +> You MUST do all of the following: +> +> 1. **Read the full diff** for this session: +> ```bash +> git diff {start_hash}~1 {end_hash} --stat +> ``` +> Then read file-level diffs for the most-changed files. +> +> 2. **For any feat→fix chain** (a feat commit followed by fix commits +> for the same thing), run: +> ```bash +> git diff {feat_hash} {fix_hash} -- +> ``` +> Explain what was wrong in the original feat commit. +> +> 3. **For thrashing** (3+ commits attempting the same fix), read each +> successive diff and explain what changed between attempts and why +> the earlier attempts failed. +> +> 4. **Search conversation transcripts** for user corrections and +> repeated instructions. Transcripts are at: +> `~/.claude/projects//*.jsonl` +> +> Find the project path: +> ```bash +> ls ~/.claude/projects/ | grep {repo-name} +> ``` +> +> Find recent sessions matching this date range: +> ```bash +> find ~/.claude/projects/{project-path} -name "*.jsonl" -mtime -{days} -maxdepth 1 +> ``` +> +> Search for correction patterns (user frustration, redirections): +> ```bash +> grep -il '"role":"user"' ~/.claude/projects/{path}/*.jsonl +> ``` +> Then use Grep to search high-hit files for correction keywords: +> pattern: `"role":"user".*(no not|don't|wrong|instead|stop|shouldn't|you missed|why didn't)` +> +> Lines are long (one JSON record per line). Use the Read tool with +> offset/limit to read specific user messages. Extract direct quotes. +> +> 5. **Return structured output:** +> - Session summary (2-3 sentences) +> - Feat-then-fix chains with commit hashes and diff evidence +> - Thrashing incidents with diff evidence +> - Direct user quotes (if transcripts found) +> - Blame assignment per incident (AI / Process / Tooling / User) +> - What went well + +#### Blame Categories + +| Category | When to assign | +|----------|---------------| +| **AI** | Generated code that was broken on arrival, didn't read docs before implementing, shotgun debugging, shipped without testing | +| **Process** | No verification gate, no review before merge, working 14+ hours, premature documentation | +| **Tooling** | Platform behavior that is genuinely underdocumented or surprising | +| **User** | Flawed requirements, continuing to push during fatigue, not enforcing breaks | + +### 4. Audit Skills and Tools (parallel agent) + +Dispatch one agent with this scope: + +- Read all `.claude/skills/` and `.claude/commands/` files +- Check each for staleness (references to removed tools, wrong paths, outdated patterns) +- Verify descriptions trigger correctly (not too broad, not too narrow) +- Check for conflicts between skills +- Identify repeated manual behaviors that should be skills + +### 5. Cross-Reference Memory (parallel agent) + +Dispatch one agent with this scope: + +- Read all memory files +- Flag any memory entries that contradict the current codebase +- Flag architecture decisions that were reversed but not updated +- Flag ephemeral task tracking masquerading as memory + +### 6. Synthesize + +After ALL agents return, compile findings into: + +**Aggregate Stats:** +- Total commits, feat/fix ratio, thrashing incidents count +- Blame distribution (AI/Process/Tooling/User percentages) + +**Per-Session Analysis:** +- Time range, scope, what went well, what went wrong +- Direct user quotes where available +- Feat-then-fix chains with specific commit hashes and diff evidence + +**Skills/Tools Audit:** +- Stale/broken items (P0) +- Missing content (P1) +- Improvements (P2+) + +**Recommendations:** +- Specific, actionable items ranked by priority +- Distinguish between "superpowers already covers this" vs "needs a project-specific fix" + +## Output + +Present findings to the user for discussion — do NOT save to `docs/plans/` or create an action plan. Wait for the user's input before proposing changes. diff --git a/.claude/skills/webview-cdp/SKILL.md b/.claude/skills/webview-cdp/SKILL.md new file mode 100644 index 00000000..492a2d42 --- /dev/null +++ b/.claude/skills/webview-cdp/SKILL.md @@ -0,0 +1,314 @@ +--- +name: webview-cdp +description: Visual verification of VS Code extension webview panels via Playwright Electron — screenshots, clicks, typing, keyboard shortcuts, VS Code commands, console logs. Use after implementing or modifying any UI-affecting change (CSS, layout, HTML templates, message wiring). For non-visual changes (string constants, config, internal refactors), compile + test is sufficient. +allowed-tools: Bash(node *webview-cdp*), Bash(cd * && node *webview-cdp*), Bash(npm run * --prefix src/PPDS.Extension) +--- + +# VS Code Webview CDP Tool (v2 — Playwright Electron) + +Interact with extension webview panels running inside VS Code. Take screenshots to see what you've built, click buttons, type text, test keyboard shortcuts, execute VS Code commands, right-click context menus, read console logs, and inspect DOM state. + +## When to Use + +- After implementing or modifying any webview panel UI +- When debugging visual issues — screenshot to see the current state +- When testing interactions — clicks, keyboard shortcuts, context menus, dropdowns +- When checking for errors — read console logs and output channel content + +## Setup + +The tool is at `src/PPDS.Extension/tools/webview-cdp.mjs`. Uses `@playwright/test` and `@vscode/test-electron` (both already dev dependencies). First run downloads VS Code (~30-60 seconds, cached afterward). + +## Core Workflow + +```bash +# 1. Launch VS Code with the extension (--build compiles extension + daemon) +node src/PPDS.Extension/tools/webview-cdp.mjs launch --build + +# 2. Open a panel via command palette +node src/PPDS.Extension/tools/webview-cdp.mjs command "PPDS: Data Explorer" +node src/PPDS.Extension/tools/webview-cdp.mjs wait --ext "power-platform-developer-suite" + +# 3. Take a screenshot to see what you built +node src/PPDS.Extension/tools/webview-cdp.mjs screenshot $TEMP/current-state.png +# IMPORTANT: Actually look at the screenshot to verify the UI + +# 4. Interact with webview content (use --ext to target the PPDS webview) +node src/PPDS.Extension/tools/webview-cdp.mjs click "#execute-btn" --ext "power-platform-developer-suite" +node src/PPDS.Extension/tools/webview-cdp.mjs screenshot $TEMP/after-click.png + +# 5. Check for errors +node src/PPDS.Extension/tools/webview-cdp.mjs logs + +# 6. When done +node src/PPDS.Extension/tools/webview-cdp.mjs close +``` + +**Always use `--ext "power-platform-developer-suite"`** on `eval`, `click`, `type`, `select`, and `wait` commands. VS Code may have other webviews open (walkthrough, settings, etc.) — without `--ext`, you might interact with the wrong panel. + +## Commands + +| Command | Example | Purpose | +|---------|---------|---------| +| `launch [workspace] [--build]` | `launch` or `launch --build` | Start VS Code with extension (--build compiles extension + daemon first) | +| `close` | `close` | Shut down VS Code and daemon | +| `connect` | `connect` | List available webview frames | +| `command ""` | `command "PPDS: Data Explorer"` | Execute VS Code command via command palette | +| `wait [timeout] [--ext id]` | `wait 10000` | Wait until webview appears | +| `screenshot ` | `screenshot $TEMP/shot.png` | Capture full VS Code window (always full window; `--page` accepted but ignored) | +| `eval "" [--page]` | `eval "document.title"` | Run JS in webview or page context | +| `click "" [--right] [--page]` | `click "#btn"` | Click element | +| `type "" "" [--page]` | `type "#input" "hello"` | Type text into element | +| `select "" "" [--page]` | `select "#dropdown" "opt1"` | Select dropdown option | +| `key "" [--page]` | `key "ctrl+enter"` | Send keyboard shortcut (works everywhere!) | +| `mouse [--page]` | `mouse mousedown 150 200` | Raw mouse event at coordinates | +| `logs [--channel name]` | `logs --channel "PPDS"` | Read console logs or output channel | +| `text "" [--page]` | `text "#status"` | Read textContent of element | +| `notebook run` | `notebook run` | Execute focused cell (clicks run button) | +| `notebook run-all` | `notebook run-all` | Execute all cells | + +**Flags:** +- `--page` — target VS Code's native UI instead of webview content +- `--target N` — select specific webview by index +- `--ext ""` — select webview by extension ID (more stable than index) + +## Two Targets: `--page` vs default + +**Note:** For `screenshot`, both modes produce a full window capture — `--page` is accepted but ignored. The distinction below applies to `eval`, `click`, `type`, `select`, `key`, and `mouse`. + +| Flag | Target | Use for | +|------|--------|---------| +| *(none)* | Webview iframe content | Buttons, inputs, tables inside your extension's panels | +| `--page` | VS Code's main UI | Sidebar, tabs, menus, command palette, native UI elements | + +## Common Patterns + +### Open a panel and verify it loaded +```bash +node src/PPDS.Extension/tools/webview-cdp.mjs command "PPDS: Data Explorer" +node src/PPDS.Extension/tools/webview-cdp.mjs wait --ext "power-platform-developer-suite" +node src/PPDS.Extension/tools/webview-cdp.mjs screenshot $TEMP/panel.png +``` + +### Test a keyboard shortcut +```bash +node src/PPDS.Extension/tools/webview-cdp.mjs key "ctrl+enter" +node src/PPDS.Extension/tools/webview-cdp.mjs screenshot $TEMP/after-shortcut.png +``` + +### Open the command palette +```bash +node src/PPDS.Extension/tools/webview-cdp.mjs key "ctrl+shift+p" +node src/PPDS.Extension/tools/webview-cdp.mjs screenshot $TEMP/palette.png +node src/PPDS.Extension/tools/webview-cdp.mjs key "Escape" +``` + +### Test a context menu +```bash +node src/PPDS.Extension/tools/webview-cdp.mjs click "td[data-row='1']" --right +node src/PPDS.Extension/tools/webview-cdp.mjs screenshot $TEMP/context-menu.png +node src/PPDS.Extension/tools/webview-cdp.mjs click ".context-menu [data-action='copy']" +``` + +### Test drag selection +```bash +node src/PPDS.Extension/tools/webview-cdp.mjs eval "JSON.stringify(document.querySelector('td[data-row=\"2\"]').getBoundingClientRect())" +node src/PPDS.Extension/tools/webview-cdp.mjs mouse mousedown 150 200 +node src/PPDS.Extension/tools/webview-cdp.mjs mouse mousemove 300 250 +node src/PPDS.Extension/tools/webview-cdp.mjs mouse mouseup 300 250 +node src/PPDS.Extension/tools/webview-cdp.mjs screenshot $TEMP/after-drag.png +``` + +### Check for errors +```bash +# Console output (captured continuously by daemon) +node src/PPDS.Extension/tools/webview-cdp.mjs logs + +# Extension output channel logs +node src/PPDS.Extension/tools/webview-cdp.mjs logs --channel "PPDS" +``` + +### Execute notebook cells +```bash +# Run the focused cell — clicks the run button (reliable, focus-independent) +node src/PPDS.Extension/tools/webview-cdp.mjs notebook run +node src/PPDS.Extension/tools/webview-cdp.mjs screenshot $TEMP/after-run.png + +# Run all cells +node src/PPDS.Extension/tools/webview-cdp.mjs notebook run-all +node src/PPDS.Extension/tools/webview-cdp.mjs screenshot $TEMP/all-cells.png +``` + +**Avoid** using `command "Notebook: Execute Cell"` — opening the command palette steals focus from the cell, causing the command to silently fail. Similarly, `key "ctrl+enter"` may trigger `executeAndInsertBelow` (creates a duplicate cell) depending on VS Code's keybinding context. + +### Hide panel for notebook screenshots +```bash +# The output panel takes vertical space — hide it to see cell output clearly +node src/PPDS.Extension/tools/webview-cdp.mjs command "View: Toggle Panel Visibility" +node src/PPDS.Extension/tools/webview-cdp.mjs screenshot $TEMP/notebook-clean.png +``` + +### Check DOM state +```bash +node src/PPDS.Extension/tools/webview-cdp.mjs eval "document.querySelector('.cell-selected') !== null" +node src/PPDS.Extension/tools/webview-cdp.mjs eval "document.querySelector('#status-text').textContent" +``` + +### Read element text +```bash +# Quick read of an element's text content +node src/PPDS.Extension/tools/webview-cdp.mjs text "#execution-time" --ext "power-platform-developer-suite" +# Returns: "in 298ms via Dataverse" + +# Equivalent eval (more verbose, same result): +node src/PPDS.Extension/tools/webview-cdp.mjs eval 'document.querySelector("#execution-time")?.textContent' +``` + +## Monaco Editor + +**`type` does NOT work with Monaco Editor.** Monaco uses a hidden textarea that doesn't respond to Playwright's `fill()` or `keyboard.type()`. Use `eval` instead: + +```bash +# Set Monaco editor content +node src/PPDS.Extension/tools/webview-cdp.mjs eval 'monaco.editor.getEditors()[0].setValue("SELECT TOP 10 * FROM account")' + +# Read Monaco editor content +node src/PPDS.Extension/tools/webview-cdp.mjs eval 'monaco.editor.getEditors()[0].getValue()' +``` + +`type` works fine on regular ``, `