pan-wizard 2.9.0 → 3.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -8
- package/agents/pan-conductor.md +189 -0
- package/agents/pan-counterfactual.md +112 -0
- package/agents/pan-debugger.md +15 -1
- package/agents/pan-document_code.md +21 -0
- package/agents/pan-executor.md +16 -0
- package/agents/pan-hardener.md +113 -0
- package/agents/pan-integration-checker.md +2 -0
- package/agents/pan-knowledge.md +81 -0
- package/agents/pan-meta-reviewer.md +91 -0
- package/agents/pan-plan-checker.md +2 -0
- package/agents/pan-previewer.md +98 -0
- package/agents/pan-project-researcher.md +4 -4
- package/agents/pan-reviewer.md +2 -0
- package/agents/pan-verifier.md +2 -0
- package/bin/install-lib.cjs +197 -0
- package/bin/install.js +1999 -1959
- package/commands/pan/assumptions.md +38 -3
- package/commands/pan/audit-deployment.md +6 -0
- package/commands/pan/cost.md +132 -0
- package/commands/pan/debug.md +71 -2
- package/commands/pan/exec-phase.md +105 -0
- package/commands/pan/focus-auto.md +199 -18
- package/commands/pan/focus-design.md +67 -2
- package/commands/pan/focus-exec.md +178 -47
- package/commands/pan/focus-scan.md +17 -5
- package/commands/pan/knowledge.md +129 -0
- package/commands/pan/map-codebase.md +47 -6
- package/commands/pan/mcp-bridge.md +145 -0
- package/commands/pan/milestone-audit.md +23 -0
- package/commands/pan/new-project.md +64 -0
- package/commands/pan/pause.md +42 -1
- package/commands/pan/plan-phase.md +95 -0
- package/commands/pan/preview.md +114 -0
- package/commands/pan/profile.md +37 -0
- package/commands/pan/quick.md +15 -0
- package/commands/pan/resume.md +62 -2
- package/commands/pan/review-deep.md +128 -0
- package/commands/pan/verify-phase.md +53 -0
- package/commands/pan/what-if.md +146 -0
- package/hooks/dist/pan-cost-logger.js +102 -0
- package/hooks/dist/pan-statusline.js +154 -108
- package/package.json +1 -1
- package/pan-wizard-core/bin/lib/bridge.cjs +269 -0
- package/pan-wizard-core/bin/lib/bus.cjs +251 -0
- package/pan-wizard-core/bin/lib/codebase.cjs +118 -0
- package/pan-wizard-core/bin/lib/constants.cjs +42 -1
- package/pan-wizard-core/bin/lib/context-budget.cjs +27 -0
- package/pan-wizard-core/bin/lib/core.cjs +91 -6
- package/pan-wizard-core/bin/lib/cost.cjs +359 -0
- package/pan-wizard-core/bin/lib/focus.cjs +105 -2
- package/pan-wizard-core/bin/lib/init.cjs +5 -5
- package/pan-wizard-core/bin/lib/knowledge.cjs +331 -0
- package/pan-wizard-core/bin/lib/memory.cjs +252 -0
- package/pan-wizard-core/bin/lib/phase.cjs +40 -13
- package/pan-wizard-core/bin/lib/preview.cjs +480 -0
- package/pan-wizard-core/bin/lib/review-deep.cjs +280 -0
- package/pan-wizard-core/bin/lib/roadmap.cjs +4 -4
- package/pan-wizard-core/bin/lib/state.cjs +2 -2
- package/pan-wizard-core/bin/lib/verify.cjs +34 -1
- package/pan-wizard-core/bin/lib/whatif.cjs +289 -0
- package/pan-wizard-core/bin/pan-tools.cjs +239 -4
- package/pan-wizard-core/templates/playbook.md +53 -0
- package/pan-wizard-core/templates/preview-report.md +93 -0
- package/pan-wizard-core/templates/roadmap.md +24 -24
- package/pan-wizard-core/templates/state.md +12 -9
- package/pan-wizard-core/workflows/plan-phase.md +1 -1
- package/scripts/build-hooks.js +2 -1
- package/scripts/generate-skills-docs.py +560 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pan:review-deep
|
|
3
|
+
group: Review
|
|
4
|
+
description: Security audit + cross-reviewer check. OWASP/STRIDE pass by pan-hardener, then pan-meta-reviewer catches what the first pass missed. Writes consolidated deep-review.md.
|
|
5
|
+
argument-hint: "<phase-number>"
|
|
6
|
+
allowed-tools:
|
|
7
|
+
- Read
|
|
8
|
+
- Write
|
|
9
|
+
- Bash
|
|
10
|
+
- Glob
|
|
11
|
+
- Grep
|
|
12
|
+
- Task
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
<objective>
|
|
16
|
+
Run a deeper review pass on a phase than `pan-reviewer` alone provides. Two new agents:
|
|
17
|
+
|
|
18
|
+
1. **pan-hardener** — OWASP Top 10 (2025) + STRIDE threat model on files changed in the phase.
|
|
19
|
+
2. **pan-meta-reviewer** — reads both the reviewer's and hardener's output, flags things both missed, disputes overstated severities.
|
|
20
|
+
|
|
21
|
+
Outputs are merged by `review-deep.cjs` into a single `.planning/reviews/<phase>/deep-review.md` with verdict, coverage stats, and conflict table. An audit entry is published to the `review-handoff` bus channel for traceability.
|
|
22
|
+
|
|
23
|
+
Consolidates Spec B v1's X-4 (self-review) + X-12 (harden) into a single command.
|
|
24
|
+
</objective>
|
|
25
|
+
|
|
26
|
+
<execution_context>
|
|
27
|
+
@~/.claude/pan-wizard-core/bin/lib/review-deep.cjs
|
|
28
|
+
@~/.claude/pan-wizard-core/bin/lib/bus.cjs
|
|
29
|
+
@~/.claude/agents/pan-hardener.md
|
|
30
|
+
@~/.claude/agents/pan-meta-reviewer.md
|
|
31
|
+
</execution_context>
|
|
32
|
+
|
|
33
|
+
<invocation_modes>
|
|
34
|
+
|
|
35
|
+
### Standalone
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
/pan:review-deep 07
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Run after `/pan:exec-phase 07` completes. Requires `pan-reviewer` to have already written its review to `.planning/phases/07/review.md` (exec-phase does this automatically).
|
|
42
|
+
|
|
43
|
+
### Integrated with exec-phase
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
/pan:exec-phase 07 --deep-review
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Runs the normal exec → reviewer pipeline, then auto-invokes this command. Recommended for phases touching auth, payment, PII, migrations, or public APIs.
|
|
50
|
+
|
|
51
|
+
### Integrated with focus-exec
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
/pan:focus-exec --deep-review
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Per-item deep review during focus campaigns. Useful for high-stakes batches.
|
|
58
|
+
|
|
59
|
+
</invocation_modes>
|
|
60
|
+
|
|
61
|
+
<process>
|
|
62
|
+
|
|
63
|
+
1. **Load reviewer output** — read `.planning/phases/<N>/review.md` written by the earlier `pan-reviewer` step. If missing, warn and offer to run `pan-reviewer` first.
|
|
64
|
+
|
|
65
|
+
2. **Spawn pan-hardener** (parallel-safe with step 3 isolation below, but recommended sequential for audit clarity):
|
|
66
|
+
- Prompt includes: `<files_to_read>` with phase plan + diff + reviewer output; `<output_path>` = `.planning/reviews/<N>/hardener.md`; `<framework_scope>` block reminding of OWASP/STRIDE coverage.
|
|
67
|
+
- Agent writes its findings to the output path, returns confirmation.
|
|
68
|
+
|
|
69
|
+
3. **Spawn pan-meta-reviewer**:
|
|
70
|
+
- Prompt includes: `<files_to_read>` with both reviewer.md AND hardener.md (and representative diff snippets); `<output_path>` = `.planning/reviews/<N>/meta.md`.
|
|
71
|
+
- Agent reads both first-pass reports, identifies missed patterns, disputes overstated severities, writes to output path.
|
|
72
|
+
|
|
73
|
+
4. **Merge** — call:
|
|
74
|
+
```
|
|
75
|
+
pan-tools review-deep merge <N> \
|
|
76
|
+
--reviewer-file .planning/phases/<N>/review.md \
|
|
77
|
+
--hardener-file .planning/reviews/<N>/hardener.md \
|
|
78
|
+
--meta-file .planning/reviews/<N>/meta.md
|
|
79
|
+
```
|
|
80
|
+
The merger parses all three, sorts by severity, computes verdict (`ok` | `ok_with_minor` | `fix_before_merge` | `review_required` | `block`), writes `.planning/reviews/<N>/deep-review.md`, and publishes an audit record to the `review-handoff` bus channel.
|
|
81
|
+
|
|
82
|
+
5. **Report back** — echo verdict + finding count + conflict count. If verdict is `block` or `review_required`, recommend the user review `deep-review.md` before proceeding.
|
|
83
|
+
|
|
84
|
+
</process>
|
|
85
|
+
|
|
86
|
+
<verdict_semantics>
|
|
87
|
+
|
|
88
|
+
| Verdict | Meaning | Action |
|
|
89
|
+
|---------|---------|--------|
|
|
90
|
+
| `ok` | No findings at any severity | Merge freely |
|
|
91
|
+
| `ok_with_minor` | Only low/info findings | Merge with noted follow-ups |
|
|
92
|
+
| `fix_before_merge` | Medium findings present | Fix or document before merge |
|
|
93
|
+
| `review_required` | High findings present | Human sign-off required |
|
|
94
|
+
| `block` | At least one critical | Do not merge |
|
|
95
|
+
|
|
96
|
+
Verdict is driven by the highest-severity finding across all three sources. Meta-reviewer disputes can downgrade severity on specific findings but don't change the headline verdict — the merger trusts the consensus of the explicit severity labels.
|
|
97
|
+
|
|
98
|
+
</verdict_semantics>
|
|
99
|
+
|
|
100
|
+
<output_files>
|
|
101
|
+
|
|
102
|
+
- `.planning/phases/<N>/review.md` — pan-reviewer output (written earlier by exec-phase)
|
|
103
|
+
- `.planning/reviews/<N>/hardener.md` — pan-hardener output (new)
|
|
104
|
+
- `.planning/reviews/<N>/meta.md` — pan-meta-reviewer output (new)
|
|
105
|
+
- `.planning/reviews/<N>/deep-review.md` — merged consolidated report (final deliverable)
|
|
106
|
+
- `.planning/bus/review-handoff.jsonl` — audit trail entry (append-only)
|
|
107
|
+
|
|
108
|
+
</output_files>
|
|
109
|
+
|
|
110
|
+
<runtime_compatibility>
|
|
111
|
+
|
|
112
|
+
| Runtime | hardener | meta-reviewer | merge |
|
|
113
|
+
|---------|----------|---------------|-------|
|
|
114
|
+
| Claude Code | Full, thinking enabled (6000/4000 budget) | Full | Full |
|
|
115
|
+
| OpenCode | Prose "think step-by-step" preamble substitutes for thinking | Same | Full (runtime-agnostic CLI) |
|
|
116
|
+
| Gemini | Same | Same | Full |
|
|
117
|
+
| Codex | Same | Same | Full |
|
|
118
|
+
| Copilot | Same | Same | Full |
|
|
119
|
+
|
|
120
|
+
The merger CLI (`pan-tools review-deep merge`) is pure Node.js and works identically across runtimes. Only the *quality* of the hardener and meta-reviewer outputs varies with model capability — Opus 4.7 with extended thinking produces the richest findings.
|
|
121
|
+
|
|
122
|
+
</runtime_compatibility>
|
|
123
|
+
|
|
124
|
+
<calibration_note>
|
|
125
|
+
|
|
126
|
+
Deep review is opt-in for a reason: it costs roughly 3× a normal review (hardener + meta + merge adds two agent spawns per phase). Use it for high-stakes phases, not every phase. `--deep-review` gating by phase tags is a v3.4 candidate enhancement.
|
|
127
|
+
|
|
128
|
+
</calibration_note>
|
|
@@ -33,6 +33,59 @@ Phase: $ARGUMENTS (optional)
|
|
|
33
33
|
Context files are resolved inside the workflow (`init verify-work`) and delegated via `<files_to_read>` blocks.
|
|
34
34
|
</context>
|
|
35
35
|
|
|
36
|
+
<investigate_before_judging>
|
|
37
|
+
Never claim a feature works or doesn't work without reading the implementation first.
|
|
38
|
+
Before each verification judgment:
|
|
39
|
+
1. Read the source file(s) that implement the feature
|
|
40
|
+
2. Read the test file(s) that cover it
|
|
41
|
+
3. Run the tests
|
|
42
|
+
4. Only then state your assessment with file:line evidence
|
|
43
|
+
Do not speculate about code you have not opened.
|
|
44
|
+
</investigate_before_judging>
|
|
45
|
+
|
|
46
|
+
<citation_requirement>
|
|
47
|
+
Every verdict (PASS, PARTIAL, FAIL) MUST include at least one file:line citation as evidence.
|
|
48
|
+
|
|
49
|
+
**Before writing any judgment, scan your draft for unsourced claims.** If you find an assertion without evidence, stop and gather it before continuing.
|
|
50
|
+
|
|
51
|
+
Format: `verdict: PASS — feature works as specified (src/billing.ts:42, tests/billing.test.ts:18-35)`
|
|
52
|
+
|
|
53
|
+
**Grounding rules:**
|
|
54
|
+
- PASS requires: file:line where the feature is implemented + test file:line where it's verified
|
|
55
|
+
- PARTIAL requires: file:line showing what works + description of what's missing with expected location
|
|
56
|
+
- FAIL requires: file:line showing the defect OR absence (grep result showing the expected function/export doesn't exist)
|
|
57
|
+
- "I checked and it's not there" is NOT evidence — show the grep command and its empty result
|
|
58
|
+
|
|
59
|
+
**Anti-pattern:**
|
|
60
|
+
```
|
|
61
|
+
BAD: "FAIL — the retry logic doesn't handle timeouts"
|
|
62
|
+
→ No evidence. Maybe it does handle timeouts and you didn't read far enough.
|
|
63
|
+
GOOD: "FAIL — retry logic at api/client.ts:67-89 catches ConnectionError but not TimeoutError.
|
|
64
|
+
Grep for 'TimeoutError' in api/: 0 matches. tests/client.test.ts has no timeout test cases."
|
|
65
|
+
```
|
|
66
|
+
</citation_requirement>
|
|
67
|
+
|
|
68
|
+
<reflexion_loop>
|
|
69
|
+
After initial verification of each requirement:
|
|
70
|
+
1. Score each requirement: PASS / PARTIAL / FAIL
|
|
71
|
+
2. For PARTIAL or FAIL: state specifically what is missing or broken
|
|
72
|
+
3. Re-read the requirement text and the implementation — did you miss anything?
|
|
73
|
+
4. Revise the score if the re-read reveals evidence you overlooked
|
|
74
|
+
5. Report only final scores after this review cycle
|
|
75
|
+
This prevents premature FAIL verdicts from incomplete investigation.
|
|
76
|
+
</reflexion_loop>
|
|
77
|
+
|
|
78
|
+
<cache_priming>
|
|
79
|
+
**Before the verifier agent runs**, prime the prompt cache once. The verifier reads project.md / requirements.md / roadmap.md every run; caching avoids ~15-50K input tokens per invocation.
|
|
80
|
+
|
|
81
|
+
Run once:
|
|
82
|
+
```
|
|
83
|
+
pan-tools cache prime --summary
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
See [plan-phase.md](plan-phase.md) or [exec-phase.md](exec-phase.md) for the full explanation. No-op on non-Claude runtimes.
|
|
87
|
+
</cache_priming>
|
|
88
|
+
|
|
36
89
|
<process>
|
|
37
90
|
Execute the verify-work workflow from @~/.claude/pan-wizard-core/workflows/verify-phase.md end-to-end.
|
|
38
91
|
Preserve all workflow gates (session management, test presentation, diagnosis, fix planning, routing).
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pan:what-if
|
|
3
|
+
group: Foresight
|
|
4
|
+
description: Explore a phase's alternative approach in an isolated git worktree. Replays the scenario, compares to the original plan, writes a report.
|
|
5
|
+
argument-hint: "<phase-number> <scenario-text>"
|
|
6
|
+
allowed-tools:
|
|
7
|
+
- Read
|
|
8
|
+
- Write
|
|
9
|
+
- Edit
|
|
10
|
+
- Bash
|
|
11
|
+
- Grep
|
|
12
|
+
- Glob
|
|
13
|
+
- Task
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
<objective>
|
|
17
|
+
Safely explore "what if we had done X instead?" for a phase. Creates an isolated git worktree, spawns `pan-counterfactual` inside it, lets the agent experiment without touching the main tree, collects a structured comparison payload, writes `.planning/counterfactuals/<phase>-<slug>.md` in the main tree, and cleans up the worktree.
|
|
18
|
+
|
|
19
|
+
Unchanged from Spec B v1's X-9. Already narrow enough to stand alone.
|
|
20
|
+
</objective>
|
|
21
|
+
|
|
22
|
+
<execution_context>
|
|
23
|
+
@~/.claude/pan-wizard-core/bin/lib/whatif.cjs
|
|
24
|
+
@~/.claude/agents/pan-counterfactual.md
|
|
25
|
+
</execution_context>
|
|
26
|
+
|
|
27
|
+
<invocation>
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
/pan:what-if 7 "Use Redis instead of Memcached"
|
|
31
|
+
/pan:what-if 4 "Skip the migration step entirely"
|
|
32
|
+
/pan:what-if 12 "What if we'd picked NoSQL at the start?"
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
**Requirements:**
|
|
36
|
+
- Main project must be a git repository (worktrees require git).
|
|
37
|
+
- Working tree can be dirty — worktree is based on current HEAD, your uncommitted changes stay in main.
|
|
38
|
+
|
|
39
|
+
</invocation>
|
|
40
|
+
|
|
41
|
+
<process>
|
|
42
|
+
|
|
43
|
+
### Stage 1 — Prepare
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
pan-tools whatif prepare <phase> "<scenario text>"
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
The CLI:
|
|
50
|
+
1. Validates the phase exists.
|
|
51
|
+
2. Slugifies the scenario (lowercase, alphanumerics + hyphens, ≤50 chars).
|
|
52
|
+
3. Creates a git worktree at `<parent-of-cwd>/pan-whatif-<phase>-<slug>-<ts>` on a fresh branch `pan-whatif/<phase>-<slug>-<ts>`.
|
|
53
|
+
4. Returns `{phase, phase_name, scenario, slug, plans, summaries, has_executed, worktree: {worktree_path, branch, base}}`.
|
|
54
|
+
|
|
55
|
+
If worktree creation fails (not a git repo, dirty tree blocking, etc.), abort with a clear error.
|
|
56
|
+
|
|
57
|
+
### Stage 2 — Spawn pan-counterfactual
|
|
58
|
+
|
|
59
|
+
Spawn the agent with its working directory set to `worktree_path`. Prompt includes:
|
|
60
|
+
- `<files_to_read>` — the phase plan, any existing summary, the main project's `CLAUDE.md` so the agent understands conventions.
|
|
61
|
+
- `<scenario>` — the user's scenario text verbatim.
|
|
62
|
+
- `<worktree_path>` — so the agent knows the safe boundary.
|
|
63
|
+
- `<time_budget>` — advisory (10-20 min of reasoning/file-ops).
|
|
64
|
+
|
|
65
|
+
The agent explores, then returns a JSON payload with `{summary, differences, recommendations, risks, verdict}`.
|
|
66
|
+
|
|
67
|
+
### Stage 3 — Write report in MAIN tree
|
|
68
|
+
|
|
69
|
+
Run (from main tree, NOT worktree):
|
|
70
|
+
|
|
71
|
+
```
|
|
72
|
+
pan-tools whatif report <phase> "<scenario>" --comparison '<agent-json>'
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
This writes `.planning/counterfactuals/<phase>-<slug>.md`. The file belongs to the main tree and survives worktree cleanup.
|
|
76
|
+
|
|
77
|
+
### Stage 4 — Cleanup
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
pan-tools whatif cleanup --worktree <path> --branch <name> --force
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Removes the worktree directory and deletes the counterfactual branch. Best-effort: warnings are surfaced but don't block.
|
|
84
|
+
|
|
85
|
+
### Stage 5 — Confirm
|
|
86
|
+
|
|
87
|
+
Echo the report path and verdict to the user. Done.
|
|
88
|
+
|
|
89
|
+
</process>
|
|
90
|
+
|
|
91
|
+
<safety>
|
|
92
|
+
|
|
93
|
+
**Worktree isolation is the safety mechanism.** The agent can edit files freely inside the worktree without affecting the main tree. Git treats worktrees as independent checkouts sharing the same object store.
|
|
94
|
+
|
|
95
|
+
**The agent is instructed NOT to commit inside the worktree.** Commits would be wasted effort since the worktree is deleted after report generation. The agent contract calls this out explicitly.
|
|
96
|
+
|
|
97
|
+
**The agent is instructed NOT to push or merge.** No remote-affecting git operations.
|
|
98
|
+
|
|
99
|
+
**Cleanup is forced.** `--force` on worktree removal ensures even a worktree with uncommitted changes gets cleaned up. The report is the permanent artifact; the worktree is disposable.
|
|
100
|
+
|
|
101
|
+
**If cleanup fails**, the worktree and branch remain. Re-run `pan-tools whatif cleanup` with the same args, or clean up manually:
|
|
102
|
+
|
|
103
|
+
```
|
|
104
|
+
git worktree remove --force <worktree_path>
|
|
105
|
+
git branch -D <branch_name>
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
</safety>
|
|
109
|
+
|
|
110
|
+
<output_paths>
|
|
111
|
+
|
|
112
|
+
- `.planning/counterfactuals/<phase>-<slug>.md` — the comparison report (permanent)
|
|
113
|
+
- `<parent>/pan-whatif-<phase>-<slug>-<ts>/` — the worktree (temporary, deleted after report)
|
|
114
|
+
- branch `pan-whatif/<phase>-<slug>-<ts>` — the worktree's branch (deleted after report)
|
|
115
|
+
|
|
116
|
+
Filename + branch include a timestamp so running what-if multiple times on the same phase+scenario produces distinct reports without overwriting.
|
|
117
|
+
|
|
118
|
+
</output_paths>
|
|
119
|
+
|
|
120
|
+
<runtime_compatibility>
|
|
121
|
+
|
|
122
|
+
| Runtime | Support |
|
|
123
|
+
|---------|---------|
|
|
124
|
+
| Claude Code | Full — worktree + agent + report |
|
|
125
|
+
| OpenCode | Partial — worktree + report work; agent spawn depends on runtime's task support |
|
|
126
|
+
| Gemini CLI | Partial — same caveat |
|
|
127
|
+
| Codex CLI | Partial — same caveat |
|
|
128
|
+
| Copilot CLI | Partial — same caveat |
|
|
129
|
+
|
|
130
|
+
The worktree and report layers are pure Node.js + git and work everywhere git is available. The agent orchestration varies by runtime's task-spawning capabilities. On any runtime that can't spawn an agent, the user can manually explore in the worktree and run `pan-tools whatif report` with a handwritten comparison JSON.
|
|
131
|
+
|
|
132
|
+
</runtime_compatibility>
|
|
133
|
+
|
|
134
|
+
<when_to_use>
|
|
135
|
+
|
|
136
|
+
**Use `/pan:what-if` when:**
|
|
137
|
+
- You're debating a decision mid-milestone and want to sample the alternative without rebuilding
|
|
138
|
+
- A phase is complete and you want to retrospectively compare approaches
|
|
139
|
+
- A reviewer asks "why not X?" and you want a structured answer
|
|
140
|
+
|
|
141
|
+
**Skip `/pan:what-if` when:**
|
|
142
|
+
- The alternative is trivially decidable from reading the plan (don't spawn an agent)
|
|
143
|
+
- You're already committed and the exploration is sunk-cost sympathy
|
|
144
|
+
- The main tree has massive uncommitted changes you don't want reflected in the worktree's base
|
|
145
|
+
|
|
146
|
+
</when_to_use>
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// PAN cost logger — SubagentStop hook (v3.4+).
|
|
3
|
+
//
|
|
4
|
+
// Claude Code fires SubagentStop when a Task-spawned sub-agent finishes.
|
|
5
|
+
// The hook receives JSON on stdin describing the session, transcript path,
|
|
6
|
+
// and (when available) usage metadata.
|
|
7
|
+
//
|
|
8
|
+
// We append a minimal record to .planning/metrics/tokens.jsonl so
|
|
9
|
+
// `/pan:cost` reports reflect real agent spawns, not just manually-appended
|
|
10
|
+
// entries. Token counts are best-effort: if the hook input doesn't carry
|
|
11
|
+
// them, we log a record with zeros + a `source: "hook"` flag so the
|
|
12
|
+
// aggregator distinguishes these from fully-instrumented records.
|
|
13
|
+
//
|
|
14
|
+
// This hook NEVER blocks the main agent loop — all errors are swallowed.
|
|
15
|
+
|
|
16
|
+
const fs = require('fs');
|
|
17
|
+
const path = require('path');
|
|
18
|
+
|
|
19
|
+
const METRICS_DIR = 'metrics';
|
|
20
|
+
const TOKENS_FILE = 'tokens.jsonl';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Extract what we can from the SubagentStop event payload.
|
|
24
|
+
* Pure function — safe to test without stdin.
|
|
25
|
+
*
|
|
26
|
+
* @param {Object} data - Parsed SubagentStop event JSON
|
|
27
|
+
* @param {string} cwd - Project cwd (for path resolution)
|
|
28
|
+
* @returns {Object|null} Cost record, or null if the event should be ignored
|
|
29
|
+
*/
|
|
30
|
+
function buildCostRecord(data, cwd) {
|
|
31
|
+
if (!data || typeof data !== 'object') return null;
|
|
32
|
+
|
|
33
|
+
// Only log actual subagent stops; ignore other Stop variants.
|
|
34
|
+
if (data.hook_event_name && data.hook_event_name !== 'SubagentStop') return null;
|
|
35
|
+
|
|
36
|
+
const record = {
|
|
37
|
+
ts: new Date().toISOString(),
|
|
38
|
+
agent: data.agent_type || data.subagent_type || null,
|
|
39
|
+
command: null,
|
|
40
|
+
model: data.model || null,
|
|
41
|
+
tier: null,
|
|
42
|
+
input_tokens: extractNumber(data.usage, 'input_tokens') || 0,
|
|
43
|
+
output_tokens: extractNumber(data.usage, 'output_tokens') || 0,
|
|
44
|
+
cache_read_tokens: extractNumber(data.usage, 'cache_read_input_tokens') || 0,
|
|
45
|
+
cache_write_tokens: extractNumber(data.usage, 'cache_creation_input_tokens') || 0,
|
|
46
|
+
cost_usd: null,
|
|
47
|
+
phase: data.phase || null,
|
|
48
|
+
session: data.session_id || null,
|
|
49
|
+
source: 'hook',
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
return record;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function extractNumber(obj, key) {
|
|
56
|
+
if (!obj || typeof obj !== 'object') return 0;
|
|
57
|
+
const v = obj[key];
|
|
58
|
+
return typeof v === 'number' ? v : 0;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Append record to .planning/metrics/tokens.jsonl. Silently succeeds
|
|
63
|
+
* even if the file or directory can't be written — hook must not block.
|
|
64
|
+
*
|
|
65
|
+
* @param {string} cwd - Working directory (project root)
|
|
66
|
+
* @param {Object} record - Cost record from buildCostRecord
|
|
67
|
+
* @returns {boolean} true if written, false otherwise
|
|
68
|
+
*/
|
|
69
|
+
function appendRecord(cwd, record) {
|
|
70
|
+
if (!record) return false;
|
|
71
|
+
try {
|
|
72
|
+
const dir = path.join(cwd, '.planning', METRICS_DIR);
|
|
73
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
74
|
+
fs.appendFileSync(path.join(dir, TOKENS_FILE), JSON.stringify(record) + '\n', 'utf-8');
|
|
75
|
+
return true;
|
|
76
|
+
} catch {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// ─── Stdin driver ───────────────────────────────────────────────────────────
|
|
82
|
+
|
|
83
|
+
if (require.main === module) {
|
|
84
|
+
let input = '';
|
|
85
|
+
process.stdin.setEncoding('utf8');
|
|
86
|
+
process.stdin.on('data', chunk => input += chunk);
|
|
87
|
+
process.stdin.on('end', () => {
|
|
88
|
+
try {
|
|
89
|
+
const data = JSON.parse(input);
|
|
90
|
+
// Prefer cwd from the event (Claude Code sends it in most hook payloads);
|
|
91
|
+
// fall back to process.cwd() which is the project root when Claude Code
|
|
92
|
+
// invokes the hook.
|
|
93
|
+
const cwd = data.cwd || data.workspace?.current_dir || process.cwd();
|
|
94
|
+
const record = buildCostRecord(data, cwd);
|
|
95
|
+
appendRecord(cwd, record);
|
|
96
|
+
} catch {
|
|
97
|
+
// Silent fail — don't block agent loop on hook errors.
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
module.exports = { buildCostRecord, appendRecord, METRICS_DIR, TOKENS_FILE };
|