pan-wizard 3.5.2 → 3.8.0
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 +28 -9
- package/agents/pan-executor.md +18 -0
- package/agents/pan-experiment-runner.md +126 -0
- package/agents/pan-phase-researcher.md +16 -0
- package/agents/pan-plan-checker.md +80 -0
- package/agents/pan-planner.md +19 -0
- package/agents/pan-reviewer.md +2 -0
- package/agents/pan-verifier.md +41 -0
- package/bin/install-lib.cjs +55 -0
- package/bin/install.js +71 -22
- package/commands/pan/debug.md +1 -1
- package/commands/pan/experiment.md +219 -0
- package/commands/pan/health.md +1 -1
- package/commands/pan/learn.md +15 -1
- package/commands/pan/links.md +102 -0
- package/commands/pan/optimize.md +13 -0
- package/commands/pan/patches.md +10 -1
- package/commands/pan/phase-tests.md +1 -4
- package/commands/pan/todo-add.md +1 -1
- package/commands/pan/todo-check.md +1 -1
- package/hooks/dist/pan-cost-logger.js +54 -4
- package/hooks/dist/pan-trace-logger.js +72 -3
- package/package.json +67 -66
- package/pan-wizard-core/bin/lib/codebase.cjs +2 -0
- package/pan-wizard-core/bin/lib/commands.cjs +8 -0
- package/pan-wizard-core/bin/lib/config.cjs +13 -2
- package/pan-wizard-core/bin/lib/context-budget.cjs +73 -0
- package/pan-wizard-core/bin/lib/core.cjs +13 -0
- package/pan-wizard-core/bin/lib/doc-lint/frontmatter.js +270 -0
- package/pan-wizard-core/bin/lib/doc-lint/reporter.js +45 -0
- package/pan-wizard-core/bin/lib/doc-lint/schema.js +202 -0
- package/pan-wizard-core/bin/lib/doc-lint/validate.js +190 -0
- package/pan-wizard-core/bin/lib/doc-lint/walk.js +135 -0
- package/pan-wizard-core/bin/lib/doc-lint.cjs +287 -0
- package/pan-wizard-core/bin/lib/experiment.cjs +502 -0
- package/pan-wizard-core/bin/lib/learn-index.cjs +235 -0
- package/pan-wizard-core/bin/lib/learn-lint.cjs +292 -0
- package/pan-wizard-core/bin/lib/links.cjs +549 -0
- package/pan-wizard-core/bin/lib/optimize.cjs +474 -1
- package/pan-wizard-core/bin/lib/runner.cjs +473 -0
- package/pan-wizard-core/bin/lib/verify.cjs +23 -0
- package/pan-wizard-core/bin/pan-tools.cjs +247 -3
- package/pan-wizard-core/learnings/README.md +70 -0
- package/pan-wizard-core/learnings/index.json +540 -0
- package/pan-wizard-core/learnings/internal/.gitkeep +2 -0
- package/pan-wizard-core/learnings/internal/experiment-runner.md +81 -0
- package/pan-wizard-core/learnings/internal/external-research.md +93 -0
- package/pan-wizard-core/learnings/internal/loop-design.md +33 -0
- package/pan-wizard-core/learnings/internal/pan-dev-bugs.md +181 -0
- package/pan-wizard-core/learnings/universal/.gitkeep +2 -0
- package/pan-wizard-core/learnings/universal/atomic-state.md +21 -0
- package/pan-wizard-core/learnings/universal/binary-io.md +21 -0
- package/pan-wizard-core/learnings/universal/comment-syntax.md +21 -0
- package/pan-wizard-core/learnings/universal/composition.md +33 -0
- package/pan-wizard-core/learnings/universal/concurrency.md +33 -0
- package/pan-wizard-core/learnings/universal/dag-scheduler.md +33 -0
- package/pan-wizard-core/learnings/universal/data-driven-design.md +21 -0
- package/pan-wizard-core/learnings/universal/design-process.md +21 -0
- package/pan-wizard-core/learnings/universal/empirical-spike.md +21 -0
- package/pan-wizard-core/learnings/universal/error-handling.md +23 -0
- package/pan-wizard-core/learnings/universal/error-paths.md +21 -0
- package/pan-wizard-core/learnings/universal/glob-semantics.md +21 -0
- package/pan-wizard-core/learnings/universal/idempotency.md +21 -0
- package/pan-wizard-core/learnings/universal/invariants.md +21 -0
- package/pan-wizard-core/learnings/universal/io-patterns.md +21 -0
- package/pan-wizard-core/learnings/universal/numeric-edge-cases.md +21 -0
- package/pan-wizard-core/learnings/universal/output-conventions.md +21 -0
- package/pan-wizard-core/learnings/universal/parser-design.md +21 -0
- package/pan-wizard-core/learnings/universal/phase-locking.md +21 -0
- package/pan-wizard-core/learnings/universal/pipe-friendly-cli.md +21 -0
- package/pan-wizard-core/learnings/universal/schema-design.md +21 -0
- package/pan-wizard-core/learnings/universal/secret-handling.md +21 -0
- package/pan-wizard-core/learnings/universal/streaming-io.md +21 -0
- package/pan-wizard-core/learnings/universal/test-patterns.md +57 -0
- package/pan-wizard-core/learnings/universal/test-strategy.md +33 -0
- package/pan-wizard-core/learnings/universal/unicode.md +21 -0
- package/pan-wizard-core/learnings/universal/vendor-pattern.md +21 -0
- package/pan-wizard-core/references/guardrails.md +58 -0
- package/pan-wizard-core/references/handoff-decisions.md +156 -0
- package/pan-wizard-core/references/schemas/pan-command.schema.yml +39 -0
- package/pan-wizard-core/references/verification-patterns.md +31 -0
- package/pan-wizard-core/templates/config.json +2 -1
- package/pan-wizard-core/templates/idea.md +52 -0
- package/pan-wizard-core/templates/summary-complex.md +14 -5
- package/pan-wizard-core/templates/summary-minimal.md +6 -0
- package/pan-wizard-core/templates/summary-standard.md +14 -3
- package/pan-wizard-core/workflows/discuss-phase.md +108 -1
- package/pan-wizard-core/workflows/exec-phase.md +37 -1
- package/pan-wizard-core/workflows/execute-plan.md +14 -0
- package/pan-wizard-core/workflows/health.md +23 -0
- package/pan-wizard-core/workflows/new-project.md +65 -81
- package/pan-wizard-core/workflows/plan-phase.md +58 -0
- package/pan-wizard-core/workflows/transition.md +102 -7
- package/pan-wizard-core/workflows/verify-phase.md +14 -0
- package/scripts/build-hooks.js +7 -1
- package/scripts/generate-skills-docs.py +10 -8
- package/scripts/git-hooks/pre-commit +40 -0
- package/scripts/release-check.js +184 -0
package/bin/install.js
CHANGED
|
@@ -39,6 +39,14 @@ const PAN_SOURCE_ROOT = path.resolve(__dirname, '..');
|
|
|
39
39
|
// Windows paths are case-insensitive; normalize for comparison
|
|
40
40
|
const normPath = p => process.platform === 'win32' ? p.toLowerCase() : p;
|
|
41
41
|
|
|
42
|
+
// IMPROVEMENT-TODO P0 (v3.7.10): warning collector for non-fatal install
|
|
43
|
+
// failures. Replaces silent `catch {}` blocks in copy paths. Surfaced at end
|
|
44
|
+
// of install if non-empty. Required failures still throw / exit non-zero.
|
|
45
|
+
const INSTALL_WARNINGS = [];
|
|
46
|
+
function pushInstallWarning(stage, file, err) {
|
|
47
|
+
INSTALL_WARNINGS.push({ stage, file, error: err && (err.message || String(err)) });
|
|
48
|
+
}
|
|
49
|
+
|
|
42
50
|
// Parse args
|
|
43
51
|
const args = process.argv.slice(2);
|
|
44
52
|
const hasGlobal = args.includes('--global') || args.includes('-g');
|
|
@@ -472,13 +480,17 @@ function copyWithPathReplacement(srcDir, destDir, pathPrefix, runtime, isCommand
|
|
|
472
480
|
const isCodex = runtime === 'codex';
|
|
473
481
|
const dirName = getDirName(runtime);
|
|
474
482
|
|
|
475
|
-
// Clean install: remove existing destination to prevent orphaned files
|
|
483
|
+
// Clean install: remove existing destination to prevent orphaned files.
|
|
484
|
+
// mkdirSync failure is FATAL — without destDir, every subsequent file write
|
|
485
|
+
// would fail too. We throw instead of silent-swallowing.
|
|
476
486
|
try {
|
|
477
487
|
if (fs.existsSync(destDir)) {
|
|
478
488
|
fs.rmSync(destDir, { recursive: true });
|
|
479
489
|
}
|
|
480
490
|
fs.mkdirSync(destDir, { recursive: true });
|
|
481
|
-
} catch {
|
|
491
|
+
} catch (err) {
|
|
492
|
+
throw new Error(`copyWithPathReplacement: cannot prepare ${destDir}: ${err.message}`);
|
|
493
|
+
}
|
|
482
494
|
|
|
483
495
|
const entries = fs.readdirSync(srcDir, { withFileTypes: true });
|
|
484
496
|
|
|
@@ -522,9 +534,18 @@ function copyWithPathReplacement(srcDir, destDir, pathPrefix, runtime, isCommand
|
|
|
522
534
|
} else {
|
|
523
535
|
fs.writeFileSync(destPath, content);
|
|
524
536
|
}
|
|
525
|
-
} catch {
|
|
537
|
+
} catch (err) {
|
|
538
|
+
// Per-file write failure: collect warning. verifyInstall() at end of
|
|
539
|
+
// install will catch the missing file and fail the install if it was
|
|
540
|
+
// required. This stops the silent-failure surface that bit whoocache.
|
|
541
|
+
pushInstallWarning('copyWithPathReplacement(md)', destPath, err);
|
|
542
|
+
}
|
|
526
543
|
} else {
|
|
527
|
-
try {
|
|
544
|
+
try {
|
|
545
|
+
fs.copyFileSync(srcPath, destPath);
|
|
546
|
+
} catch (err) {
|
|
547
|
+
pushInstallWarning('copyWithPathReplacement(copy)', destPath, err);
|
|
548
|
+
}
|
|
528
549
|
}
|
|
529
550
|
}
|
|
530
551
|
}
|
|
@@ -1444,6 +1465,20 @@ function install(isGlobal, runtime = 'claude') {
|
|
|
1444
1465
|
const skillSrc = path.join(src, 'pan-wizard-core');
|
|
1445
1466
|
const skillDest = path.join(targetDir, 'pan-wizard-core');
|
|
1446
1467
|
copyWithPathReplacement(skillSrc, skillDest, pathPrefix, runtime);
|
|
1468
|
+
|
|
1469
|
+
// v3.7.0+ self-improvement loop two-tier delivery:
|
|
1470
|
+
// learnings/universal/ ships to all 5 runtimes (consumed by user-project workflows).
|
|
1471
|
+
// learnings/internal/ stays source-only — strip it from the installed copy.
|
|
1472
|
+
// Spec: docs/specs/self_improvement_loop_featureai.md §3.6
|
|
1473
|
+
const internalLearningsDir = path.join(skillDest, 'learnings', 'internal');
|
|
1474
|
+
if (fs.existsSync(internalLearningsDir)) {
|
|
1475
|
+
try {
|
|
1476
|
+
fs.rmSync(internalLearningsDir, { recursive: true, force: true });
|
|
1477
|
+
} catch {
|
|
1478
|
+
// Best-effort: install proceeds even if cleanup fails
|
|
1479
|
+
}
|
|
1480
|
+
}
|
|
1481
|
+
|
|
1447
1482
|
if (verifyInstalled(skillDest, 'pan-wizard-core')) {
|
|
1448
1483
|
console.log(` ${green}✓${reset} Installed pan-wizard-core`);
|
|
1449
1484
|
} else {
|
|
@@ -1607,30 +1642,44 @@ function install(isGlobal, runtime = 'claude') {
|
|
|
1607
1642
|
}
|
|
1608
1643
|
|
|
1609
1644
|
// Write file manifest for future modification detection
|
|
1610
|
-
writeManifest(targetDir, runtime);
|
|
1645
|
+
const manifest = writeManifest(targetDir, runtime);
|
|
1611
1646
|
console.log(` ${green}✓${reset} Wrote file manifest (${MANIFEST_NAME})`);
|
|
1612
1647
|
|
|
1613
1648
|
// Report any backed-up local patches
|
|
1614
1649
|
reportLocalPatches(targetDir, runtime);
|
|
1615
1650
|
|
|
1616
|
-
// Post-install
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1651
|
+
// Post-install verification: walk every manifest entry, assert file present.
|
|
1652
|
+
// Catches silent copy/write failures from earlier stages (IMPROVEMENT-TODO P0).
|
|
1653
|
+
// Missing files = exit 1; warnings = log but continue.
|
|
1654
|
+
const verifyResult = lib.verifyInstall(targetDir, manifest);
|
|
1655
|
+
if (verifyResult.warnings.length > 0) {
|
|
1656
|
+
console.error(`\n ${yellow}⚠ Install verification warnings:${reset}`);
|
|
1657
|
+
for (const w of verifyResult.warnings) console.error(` - ${w}`);
|
|
1658
|
+
}
|
|
1659
|
+
if (!verifyResult.ok) {
|
|
1660
|
+
console.error(`\n ${red}✖ Install verification FAILED — ${verifyResult.missing.length} file(s) missing:${reset}`);
|
|
1661
|
+
// Limit output to first 20 missing to avoid screen-flooding
|
|
1662
|
+
const sample = verifyResult.missing.slice(0, 20);
|
|
1663
|
+
for (const m of sample) console.error(` - ${m}`);
|
|
1664
|
+
if (verifyResult.missing.length > sample.length) {
|
|
1665
|
+
console.error(` ... and ${verifyResult.missing.length - sample.length} more`);
|
|
1666
|
+
}
|
|
1667
|
+
console.error(`\n Run ${cyan}pan-tools validate deployment${reset} for full diagnostics, then re-run the installer.\n`);
|
|
1668
|
+
process.exit(1);
|
|
1629
1669
|
}
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1670
|
+
console.log(` ${green}✓${reset} Verified ${Object.keys(manifest.files || {}).length} installed files`);
|
|
1671
|
+
|
|
1672
|
+
// Surface non-fatal install warnings collected during copy/write phases.
|
|
1673
|
+
// verifyInstall above already exited 1 on missing required files; warnings
|
|
1674
|
+
// here are for partial failures that didn't ultimately leave gaps.
|
|
1675
|
+
if (INSTALL_WARNINGS.length > 0) {
|
|
1676
|
+
console.error(`\n ${yellow}⚠ ${INSTALL_WARNINGS.length} non-fatal install warning(s):${reset}`);
|
|
1677
|
+
for (const w of INSTALL_WARNINGS.slice(0, 10)) {
|
|
1678
|
+
console.error(` [${w.stage}] ${w.file}: ${w.error}`);
|
|
1679
|
+
}
|
|
1680
|
+
if (INSTALL_WARNINGS.length > 10) {
|
|
1681
|
+
console.error(` ... and ${INSTALL_WARNINGS.length - 10} more`);
|
|
1682
|
+
}
|
|
1634
1683
|
}
|
|
1635
1684
|
|
|
1636
1685
|
if (isCodex) {
|
package/commands/pan/debug.md
CHANGED
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: experiment
|
|
3
|
+
group: Self-Improvement
|
|
4
|
+
description: Manage external experiments — scaffold, run, harvest, promote findings back to PAN
|
|
5
|
+
allowed-tools:
|
|
6
|
+
- Read
|
|
7
|
+
- Write
|
|
8
|
+
- Edit
|
|
9
|
+
- Bash
|
|
10
|
+
- Grep
|
|
11
|
+
- Glob
|
|
12
|
+
- Agent
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
# /pan:experiment — Cross-Project Self-Improvement Loop
|
|
16
|
+
|
|
17
|
+
> **Self-protection:** This command **scaffolds external project folders OUTSIDE the PAN source repo** to drive autonomous AI coding sessions against fresh ideas, then harvests the resulting telemetry back into `pan-wizard-core/learnings/`. It is a **PAN-development tool**, not a feature for end-users of PAN to invoke on their own projects.
|
|
18
|
+
|
|
19
|
+
**Spec:** `docs/specs/self_improvement_loop_featureai.md`
|
|
20
|
+
**ADR:** ADR-0026 (pending W4)
|
|
21
|
+
**Status:** v3.7.0 W1+W2+W3 — scaffolding (`new`/`list`/`manifest`) + external runner (`run`/`status`/`stop`) + harvest (`harvest`/`prune`); W4 adds promote integration with `/pan:learn`.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## When to use this
|
|
26
|
+
|
|
27
|
+
- You have an idea for a small project. You want to know **how PAN drives that build** — what shortcuts the AI takes, where verification fails, which guardrails fire.
|
|
28
|
+
- You want the resulting telemetry to **flow back into PAN's shipped artifacts** so the next release is smarter.
|
|
29
|
+
- You're testing a behavioral change (new `references/` doc, new workflow rule) by running it against a real, isolated build.
|
|
30
|
+
|
|
31
|
+
## When NOT to use this
|
|
32
|
+
|
|
33
|
+
- Building production user features. Use `/pan:new-project` and `/pan:exec-phase` directly.
|
|
34
|
+
- Validating a single-file change. The experiment loop is heavy — use `npm test` and `/pan:check`.
|
|
35
|
+
- Inside the PAN source repo. The command **refuses** to scaffold experiments inside `d:\PanWizard\` (or wherever the source is cloned). The experiment root defaults to `~/pan-experiments/`.
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Subcommands (W1 shipped)
|
|
40
|
+
|
|
41
|
+
### `/pan:experiment new <slug> --idea <path>`
|
|
42
|
+
|
|
43
|
+
Scaffold a new experiment folder. Creates:
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
<root>/<slug>/
|
|
47
|
+
├── .planning/
|
|
48
|
+
│ ├── idea.md ← copied from --idea path
|
|
49
|
+
│ └── experiment.json ← manifest (slug, runtime, created_at, etc.)
|
|
50
|
+
└── .claude/ (or .codex/, .gemini/, .opencode/, .github/) ← PAN install for chosen runtime
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
**Flags:**
|
|
54
|
+
|
|
55
|
+
| Flag | Default | Purpose |
|
|
56
|
+
|------|---------|---------|
|
|
57
|
+
| `--idea <path>` | required | Path to the idea.md doc; copied into the experiment |
|
|
58
|
+
| `--runtime <r>` | `claude` | Which AI coding runtime to install: claude / codex / gemini / opencode / copilot |
|
|
59
|
+
| `--root <path>` | `~/pan-experiments/` | Override the experiment root directory |
|
|
60
|
+
| `--budget <pts>` | `80` | Optional budget cap (saved to manifest, enforced by W2 runner) |
|
|
61
|
+
| `--skip-installer` | `false` | Don't run the PAN installer (dev-only) |
|
|
62
|
+
|
|
63
|
+
**Slug rules:** lowercase letters, digits, hyphens. Max 40 chars. No leading/trailing hyphen.
|
|
64
|
+
|
|
65
|
+
**Returns:** JSON with `experiment_id`, `path`, `runtime`, `idea_path`, `created_at`. On failure, returns `{ error: "..." }`.
|
|
66
|
+
|
|
67
|
+
### `/pan:experiment list`
|
|
68
|
+
|
|
69
|
+
Enumerate all experiments under the root. Returns `{ experiments: [...], count }` sorted newest-first.
|
|
70
|
+
|
|
71
|
+
**Flags:**
|
|
72
|
+
|
|
73
|
+
| Flag | Default | Purpose |
|
|
74
|
+
|------|---------|---------|
|
|
75
|
+
| `--root <path>` | `~/pan-experiments/` | Override the root |
|
|
76
|
+
| `--raw` | `false` | Human-readable output instead of JSON |
|
|
77
|
+
|
|
78
|
+
### `/pan:experiment manifest <slug>`
|
|
79
|
+
|
|
80
|
+
Read the manifest for a single experiment. Returns the JSON shape written by `new`.
|
|
81
|
+
|
|
82
|
+
**Flags:**
|
|
83
|
+
|
|
84
|
+
| Flag | Default | Purpose |
|
|
85
|
+
|------|---------|---------|
|
|
86
|
+
| `--root <path>` | `~/pan-experiments/` | Override the root |
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## Subcommands (W2 shipped)
|
|
91
|
+
|
|
92
|
+
### `/pan:experiment run <slug>`
|
|
93
|
+
|
|
94
|
+
Spawn the external AI runtime against the experiment folder. **Synchronous** — blocks until the external session exits, hits the timeout, or is stopped.
|
|
95
|
+
|
|
96
|
+
**Flags:**
|
|
97
|
+
|
|
98
|
+
| Flag | Default | Purpose |
|
|
99
|
+
|------|---------|---------|
|
|
100
|
+
| `--timeout <sec>` | `1800` (30 min) | Hard timeout in seconds; runner sends SIGTERM at deadline |
|
|
101
|
+
| `--prompt <text>` | `/pan:new-project --auto @.planning/idea.md` | Prompt passed to the external runtime |
|
|
102
|
+
| `--root <path>` | `~/pan-experiments/` | Override the experiment root |
|
|
103
|
+
|
|
104
|
+
**Returns:** `{ status: "done"\|"failed", stop_reason: "success"\|"error"\|"timeout"\|"manual", exit_code, elapsed_ms, started_at, ended_at }`. Run-state is also persisted to `<experiment>/.planning/run-state.json`.
|
|
105
|
+
|
|
106
|
+
**Runtime support:** claude / codex / gemini / opencode (via `RUNTIME_RUNNERS` adapter map in `runner.cjs`). GitHub Copilot CLI is **unsupported** for the `run` subcommand — no documented headless prompt mode. Copilot users can still scaffold and harvest manually.
|
|
107
|
+
|
|
108
|
+
### `/pan:experiment status <slug>`
|
|
109
|
+
|
|
110
|
+
Read the current `run-state.json` snapshot. Returns the full state object (`status`, `stop_reason`, `exit_code`, `elapsed_ms`, `events`).
|
|
111
|
+
|
|
112
|
+
### `/pan:experiment stop <slug>`
|
|
113
|
+
|
|
114
|
+
Gracefully halt a running experiment. Reads pid from `run-state.json`, sends SIGTERM, writes `status: failed, stop_reason: manual` to the run state. Returns the updated state.
|
|
115
|
+
|
|
116
|
+
If the experiment has already finished, returns the existing run state without error.
|
|
117
|
+
|
|
118
|
+
## Subcommands (W3 shipped)
|
|
119
|
+
|
|
120
|
+
### `/pan:experiment harvest <slug>`
|
|
121
|
+
|
|
122
|
+
Copy the experiment's telemetry into `<source-repo>/experiments/<slug>/` so it can be analyzed and promoted into shipped artifacts.
|
|
123
|
+
|
|
124
|
+
**What gets harvested** (skipped silently if absent):
|
|
125
|
+
|
|
126
|
+
- `.planning/idea.md` — the original idea doc
|
|
127
|
+
- `.planning/experiment.json` — scaffold manifest
|
|
128
|
+
- `.planning/state.md` — final project state
|
|
129
|
+
- `.planning/run-state.json` — runner result (status, exit_code, elapsed_ms)
|
|
130
|
+
- `.planning/agent-history.json` — every agent spawn during the build
|
|
131
|
+
- `.planning/optimization/` — full trace data (sessions, reports)
|
|
132
|
+
- `.planning/phases/` — phases the external session created
|
|
133
|
+
|
|
134
|
+
A `harvest.json` manifest is written at the destination capturing source path, timestamp, total bytes, and the list of harvested paths.
|
|
135
|
+
|
|
136
|
+
**Flags:**
|
|
137
|
+
|
|
138
|
+
| Flag | Default | Purpose |
|
|
139
|
+
|------|---------|---------|
|
|
140
|
+
| `--root <path>` | `~/pan-experiments/` | Override the experiment root |
|
|
141
|
+
| `--source-root <path>` | PAN source repo | Override harvest destination |
|
|
142
|
+
| `--force` | `false` | Overwrite an existing harvest at the destination |
|
|
143
|
+
|
|
144
|
+
**Returns:** `{ experiment_id, harvest_path, harvested_paths: [...], total_bytes, harvested_at, pan_version }`. On conflict without `--force`, returns `{ error }`.
|
|
145
|
+
|
|
146
|
+
### `/pan:experiment prune <slug>`
|
|
147
|
+
|
|
148
|
+
Remove the experiment folder after harvest.
|
|
149
|
+
|
|
150
|
+
**Modes:**
|
|
151
|
+
|
|
152
|
+
- **Soft** (default): rename to `<root>/<slug>-archived-<ISO-timestamp>` so the data is retained but the slug is freed for reuse
|
|
153
|
+
- **Hard** (`--hard` flag): permanently delete
|
|
154
|
+
|
|
155
|
+
**Flags:**
|
|
156
|
+
|
|
157
|
+
| Flag | Default | Purpose |
|
|
158
|
+
|------|---------|---------|
|
|
159
|
+
| `--root <path>` | `~/pan-experiments/` | Override the experiment root |
|
|
160
|
+
| `--hard` | `false` | Permanent deletion (irreversible) |
|
|
161
|
+
|
|
162
|
+
**Returns:** `{ pruned: <slug>, mode: "soft"|"hard", archive_path? }`.
|
|
163
|
+
|
|
164
|
+
## Subcommands (W4 — coming soon)
|
|
165
|
+
|
|
166
|
+
| Subcommand | Wave | Purpose |
|
|
167
|
+
|------------|------|---------|
|
|
168
|
+
| `archive <slug>` | W4 | Alias for `prune` (kept for clarity in scripts) |
|
|
169
|
+
| `delete <slug> --confirm` | W4 | Alias for `prune --hard` with confirmation prompt |
|
|
170
|
+
|
|
171
|
+
W4 also adds:
|
|
172
|
+
- `/pan:learn --experiment <slug>` — runs pan-optimizer over harvested data
|
|
173
|
+
- `pan-tools learn promote --pattern <id> --scope universal --topic <name>` — extracts a finding into `pan-wizard-core/learnings/{universal,internal}/<topic>.md`
|
|
174
|
+
- `pan-tools learn unpromote/list-promoted` — rollback and inventory
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
## CLI mapping (`pan-tools experiment <sub>`)
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
pan-tools experiment new <slug> --idea <path> [--runtime r] [--root path] [--budget n]
|
|
182
|
+
pan-tools experiment list [--root path] [--raw]
|
|
183
|
+
pan-tools experiment manifest <slug> [--root path]
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Examples:
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
# Scaffold a new experiment
|
|
190
|
+
echo "# Idea: Build a markdown linter CLI" > my-idea.md
|
|
191
|
+
# (fill in problem, success, scope, constraints — see template at pan-wizard-core/templates/idea.md)
|
|
192
|
+
pan-tools experiment new md-lint --idea my-idea.md --runtime claude --budget 60
|
|
193
|
+
|
|
194
|
+
# List all experiments
|
|
195
|
+
pan-tools experiment list
|
|
196
|
+
|
|
197
|
+
# Inspect one
|
|
198
|
+
pan-tools experiment manifest md-lint
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
## Safety guards
|
|
204
|
+
|
|
205
|
+
- **Never inside source repo.** `newExperiment` refuses to write to `d:\PanWizard\` (or wherever the PAN source is). Mirrors `bin/install.js` `PAN_SOURCE_ROOT` guard.
|
|
206
|
+
- **No clobber.** Refuses to scaffold over an existing experiment folder of the same slug.
|
|
207
|
+
- **Slug validation.** Lowercase + digits + hyphens, max 40 chars. Rejects uppercase, spaces, special characters.
|
|
208
|
+
- **Idea path validation.** Errors if the `--idea` file doesn't exist.
|
|
209
|
+
|
|
210
|
+
## Related
|
|
211
|
+
|
|
212
|
+
- `pan-wizard-core/templates/idea.md` — idea doc template
|
|
213
|
+
- `pan-wizard-core/bin/lib/experiment.cjs` — implementation
|
|
214
|
+
- `pan-wizard-core/learnings/README.md` — where harvested findings go
|
|
215
|
+
- `docs/specs/self_improvement_loop_featureai.md` — full design
|
|
216
|
+
|
|
217
|
+
## Runtime support
|
|
218
|
+
|
|
219
|
+
Works in all 5 runtimes (Claude / Codex / Gemini / OpenCode / Copilot). The W2 external runner (subprocess invocation of the external session) supports Claude / Codex / Gemini / OpenCode; GitHub Copilot CLI lacks a headless prompt mode and is opt-out for the `run` subcommand.
|
package/commands/pan/health.md
CHANGED
package/commands/pan/learn.md
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pan:learn
|
|
3
|
+
group: Self-Improvement
|
|
4
|
+
description: Analyze trace sessions or harvested experiments via pan-optimizer; generate ranked optimization reports
|
|
5
|
+
allowed-tools:
|
|
6
|
+
- Read
|
|
7
|
+
- Bash
|
|
8
|
+
- Glob
|
|
9
|
+
- Grep
|
|
10
|
+
- Task
|
|
11
|
+
---
|
|
12
|
+
|
|
1
13
|
# /pan:learn
|
|
2
14
|
|
|
3
15
|
Analyze the most recent trace session and generate an optimization report.
|
|
@@ -6,11 +18,13 @@ Analyze the most recent trace session and generate an optimization report.
|
|
|
6
18
|
```
|
|
7
19
|
/pan:learn
|
|
8
20
|
/pan:learn --session <session-id>
|
|
21
|
+
/pan:learn --experiment <slug>
|
|
9
22
|
/pan:learn --apply
|
|
10
23
|
```
|
|
11
24
|
|
|
12
25
|
**Flags:**
|
|
13
26
|
- `--session <id>` — analyze a specific session instead of the most recent
|
|
27
|
+
- `--experiment <slug>` *(v3.7.0+, W3)* — analyze a harvested experiment instead of the current project's traces. Reads from `<source-repo>/experiments/<slug>/.planning/optimization/` and writes the report to `<source-repo>/experiments/<slug>/learnings/report-<timestamp>.md`. Used by the self-improvement loop. Run `/pan:experiment harvest <slug>` first.
|
|
14
28
|
- `--apply` — automatically apply safe optimizations after generating the report (equivalent to running `/pan:optimize apply` immediately after)
|
|
15
29
|
|
|
16
30
|
**What it does:**
|
|
@@ -56,6 +70,6 @@ The optimization report in `.planning/optimization/reports/` contains:
|
|
|
56
70
|
→ Needs review: 2 prompt improvements, 1 workflow gap
|
|
57
71
|
```
|
|
58
72
|
|
|
59
|
-
**See also:** `/pan:optimize`, `/pan:exec-phase`
|
|
73
|
+
**See also:** `/pan:optimize`, `/pan:exec-phase`, `/pan:experiment` (v3.7.0+ self-improvement loop)
|
|
60
74
|
|
|
61
75
|
Follow the workflow at `.claude/workflows/learn.md` (or `pan-wizard-core/workflows/learn.md`).
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pan:links
|
|
3
|
+
group: Validation
|
|
4
|
+
description: Validate the doc-code link graph — inline wiki-style refs, source-comment anchors, and require-code-mention contracts (ADR-0027, v3.8.0+)
|
|
5
|
+
allowed-tools:
|
|
6
|
+
- Bash
|
|
7
|
+
- Read
|
|
8
|
+
- Grep
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# /pan:links
|
|
12
|
+
|
|
13
|
+
Validate the doc-code link graph. Walks `docs/`, `pan-wizard-core/`, `commands/`, and `agents/` for inline `[[<id>]]` references and `// @pan: <id>` source-comment anchors. Reports broken refs, stale anchors, and uncovered backlink contracts.
|
|
14
|
+
|
|
15
|
+
**Usage:**
|
|
16
|
+
```
|
|
17
|
+
/pan:links
|
|
18
|
+
/pan:links --strict
|
|
19
|
+
/pan:links --doc-root <path> [--doc-root <path>...]
|
|
20
|
+
/pan:links --source-root <path> [--source-root <path>...]
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
**Flags:**
|
|
24
|
+
- `--strict` — fail (exit 1) on warnings, not only errors. Default is advisory: warnings do not flip status.
|
|
25
|
+
- `--doc-root <path>` — override default doc roots. Repeatable.
|
|
26
|
+
- `--source-root <path>` — override default source roots. Repeatable.
|
|
27
|
+
- `--raw` — human-readable output instead of JSON.
|
|
28
|
+
|
|
29
|
+
**What it does:**
|
|
30
|
+
|
|
31
|
+
Three sequential passes share one walk pair:
|
|
32
|
+
|
|
33
|
+
1. **Forward links** — every `[[<id>]]` in body text and every `must_haves.key_links` entry must resolve. Section anchors (`[[ADR-0021#Decision]]`) check that the named heading exists.
|
|
34
|
+
2. **Backlink contract** — docs with `require-code-mention: true` in frontmatter must have at least one `@pan:` source anchor that resolves to them.
|
|
35
|
+
3. **Anchor-target existence** — every `// @pan: <id>` comment must point to a real doc.
|
|
36
|
+
|
|
37
|
+
**Doc-id forms accepted:**
|
|
38
|
+
|
|
39
|
+
- `ADR-NNNN` — resolves via glob to `docs/decisions/ADR-NNNN-*.md`
|
|
40
|
+
- `<path>.md` — exact path relative to repo root
|
|
41
|
+
- `<path>` (no extension) — tries `<path>.md` then `<path>/README.md`
|
|
42
|
+
- Any of the above with `#section` — verifies a heading whose slug matches
|
|
43
|
+
|
|
44
|
+
**Source-anchor grammar:**
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
// @pan: ADR-0027 (JS / TS / CJS)
|
|
48
|
+
# @pan: ADR-0027 (Python / shell)
|
|
49
|
+
<!-- @pan: ADR-0027 --> (Markdown / HTML)
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Anchors cluster at the top of a file under a single banner; comment leader must be the line's first non-whitespace token.
|
|
53
|
+
|
|
54
|
+
**Exit codes:**
|
|
55
|
+
|
|
56
|
+
- `0` — pass
|
|
57
|
+
- `1` — fail (errors present, or warnings present under `--strict`)
|
|
58
|
+
|
|
59
|
+
**Output (JSON):**
|
|
60
|
+
|
|
61
|
+
```json
|
|
62
|
+
{
|
|
63
|
+
"ok": true,
|
|
64
|
+
"summary": {
|
|
65
|
+
"total_findings": 0,
|
|
66
|
+
"errors": 0,
|
|
67
|
+
"warnings": 0,
|
|
68
|
+
"status": "pass",
|
|
69
|
+
"doc_files_scanned": 280,
|
|
70
|
+
"source_files_scanned": 170,
|
|
71
|
+
"anchors_found": 4,
|
|
72
|
+
"forward_links_found": 12,
|
|
73
|
+
"backlink_contracts_checked": 3
|
|
74
|
+
},
|
|
75
|
+
"findings": []
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
**Finding codes:**
|
|
80
|
+
|
|
81
|
+
| Code | Severity | Meaning |
|
|
82
|
+
|---|---|---|
|
|
83
|
+
| F-001 | error | Inline `[[<id>]]` does not resolve |
|
|
84
|
+
| F-002 | error | `[[<doc>#<section>]]` resolves the file but the section is missing |
|
|
85
|
+
| F-003 | warning | `must_haves.key_links` entry's `from` or `to` does not exist |
|
|
86
|
+
| F-004 | warning | `must_haves.key_links` regex pattern is invalid |
|
|
87
|
+
| B-001 | error | Doc has `require-code-mention: true` but no `@pan:` anchors resolve to it |
|
|
88
|
+
| B-002 | warning | Doc is anchored by exactly one source file (single-source informational) |
|
|
89
|
+
| A-001 | error | `@pan:` anchor target does not resolve |
|
|
90
|
+
| A-002 | warning | `@pan:` anchor section is missing in the resolved file |
|
|
91
|
+
| A-004 | warning | `@pan:` anchor has empty id |
|
|
92
|
+
|
|
93
|
+
**Composing with `validate health`:**
|
|
94
|
+
|
|
95
|
+
`validate health --links` includes the link-graph summary as a `link_graph` field in the health report. Used as a pre-flight check before release. Errors degrade the health report to a warning-level issue (`LINKS_ERR`); non-blocking unless `--strict` is added to a separate `links validate` invocation.
|
|
96
|
+
|
|
97
|
+
**See also:**
|
|
98
|
+
|
|
99
|
+
- ADR-0027 — Doc–Code Link Graph
|
|
100
|
+
- `docs/specs/doc_code_link_graph_featureai.md` — wire-level spec
|
|
101
|
+
- `pan-tools doc-lint` — frontmatter schema validator (orthogonal concern)
|
|
102
|
+
- `pan-tools verify-key-links` — legacy frontmatter-only link verifier (subsumed; both still ship)
|
package/commands/pan/optimize.md
CHANGED
|
@@ -1,3 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pan:optimize
|
|
3
|
+
group: Self-Improvement
|
|
4
|
+
description: Manage the circular optimization loop — apply recommendations, view stats, list reports, manage trace sessions
|
|
5
|
+
allowed-tools:
|
|
6
|
+
- Read
|
|
7
|
+
- Write
|
|
8
|
+
- Edit
|
|
9
|
+
- Bash
|
|
10
|
+
- Glob
|
|
11
|
+
- Grep
|
|
12
|
+
---
|
|
13
|
+
|
|
1
14
|
# /pan:optimize
|
|
2
15
|
|
|
3
16
|
Manage the circular optimization loop: apply recommendations, view stats, list reports.
|
package/commands/pan/patches.md
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
---
|
|
2
|
+
name: pan:patches
|
|
3
|
+
group: System
|
|
2
4
|
description: Reapply local modifications after a PAN update
|
|
3
|
-
allowed-tools:
|
|
5
|
+
allowed-tools:
|
|
6
|
+
- Read
|
|
7
|
+
- Write
|
|
8
|
+
- Edit
|
|
9
|
+
- Bash
|
|
10
|
+
- Glob
|
|
11
|
+
- Grep
|
|
12
|
+
- AskUserQuestion
|
|
4
13
|
---
|
|
5
14
|
|
|
6
15
|
<purpose>
|
|
@@ -12,10 +12,7 @@ allowed-tools:
|
|
|
12
12
|
- Grep
|
|
13
13
|
- Task
|
|
14
14
|
- AskUserQuestion
|
|
15
|
-
argument-instructions:
|
|
16
|
-
Parse the argument as a phase number (integer, decimal, or letter-suffix), plus optional free-text instructions.
|
|
17
|
-
Example: /pan:phase-tests 12
|
|
18
|
-
Example: /pan:phase-tests 12 focus on edge cases in the pricing module
|
|
15
|
+
argument-instructions: "Parse <phase> as a phase number (integer, decimal like 1.1, or letter-suffix like 1a) followed by optional free-text instructions. Examples: /pan:phase-tests 12 — /pan:phase-tests 12 focus on edge cases in the pricing module"
|
|
19
16
|
---
|
|
20
17
|
<objective>
|
|
21
18
|
Generate unit and E2E tests for a completed phase, using its summary.md, context.md, and verification.md as specifications.
|
package/commands/pan/todo-add.md
CHANGED
|
@@ -33,16 +33,32 @@ function buildCostRecord(data, cwd) {
|
|
|
33
33
|
// Only log actual subagent stops; ignore other Stop variants.
|
|
34
34
|
if (data.hook_event_name && data.hook_event_name !== 'SubagentStop') return null;
|
|
35
35
|
|
|
36
|
+
// P-1805 (v3.7.8): if data.usage is missing/empty (Claude Code headless mode
|
|
37
|
+
// doesn't include it in the SubagentStop payload), fall back to reading the
|
|
38
|
+
// transcript_path JSONL and summing usage across the subagent's messages.
|
|
39
|
+
// Same approach as pan-trace-logger.js for consistency.
|
|
40
|
+
let inputTokens = extractNumber(data.usage, 'input_tokens');
|
|
41
|
+
let outputTokens = extractNumber(data.usage, 'output_tokens');
|
|
42
|
+
let cacheRead = extractNumber(data.usage, 'cache_read_input_tokens');
|
|
43
|
+
let cacheWrite = extractNumber(data.usage, 'cache_creation_input_tokens');
|
|
44
|
+
if ((inputTokens + outputTokens + cacheRead + cacheWrite) === 0 && data.transcript_path) {
|
|
45
|
+
const fromTranscript = readUsageFromTranscript(data.transcript_path, data.session_id);
|
|
46
|
+
inputTokens = fromTranscript.input_tokens;
|
|
47
|
+
outputTokens = fromTranscript.output_tokens;
|
|
48
|
+
cacheRead = fromTranscript.cache_read_input_tokens;
|
|
49
|
+
cacheWrite = fromTranscript.cache_creation_input_tokens;
|
|
50
|
+
}
|
|
51
|
+
|
|
36
52
|
const record = {
|
|
37
53
|
ts: new Date().toISOString(),
|
|
38
54
|
agent: data.agent_type || data.subagent_type || null,
|
|
39
55
|
command: null,
|
|
40
56
|
model: data.model || null,
|
|
41
57
|
tier: null,
|
|
42
|
-
input_tokens:
|
|
43
|
-
output_tokens:
|
|
44
|
-
cache_read_tokens:
|
|
45
|
-
cache_write_tokens:
|
|
58
|
+
input_tokens: inputTokens,
|
|
59
|
+
output_tokens: outputTokens,
|
|
60
|
+
cache_read_tokens: cacheRead,
|
|
61
|
+
cache_write_tokens: cacheWrite,
|
|
46
62
|
cost_usd: null,
|
|
47
63
|
phase: data.phase || null,
|
|
48
64
|
session: data.session_id || null,
|
|
@@ -58,6 +74,40 @@ function extractNumber(obj, key) {
|
|
|
58
74
|
return typeof v === 'number' ? v : 0;
|
|
59
75
|
}
|
|
60
76
|
|
|
77
|
+
/**
|
|
78
|
+
* P-1805 (v3.7.8): read transcript JSONL and sum usage across all assistant
|
|
79
|
+
* messages belonging to the subagent's session. Mirrors the helper in
|
|
80
|
+
* pan-trace-logger.js. Returns zeros if transcript missing/unreadable.
|
|
81
|
+
*/
|
|
82
|
+
function readUsageFromTranscript(transcriptPath, sessionId) {
|
|
83
|
+
const totals = {
|
|
84
|
+
input_tokens: 0,
|
|
85
|
+
output_tokens: 0,
|
|
86
|
+
cache_read_input_tokens: 0,
|
|
87
|
+
cache_creation_input_tokens: 0,
|
|
88
|
+
};
|
|
89
|
+
if (!transcriptPath || typeof transcriptPath !== 'string') return totals;
|
|
90
|
+
let raw;
|
|
91
|
+
try { raw = fs.readFileSync(transcriptPath, 'utf-8'); } catch { return totals; }
|
|
92
|
+
for (const line of raw.split('\n')) {
|
|
93
|
+
if (!line) continue;
|
|
94
|
+
let entry;
|
|
95
|
+
try { entry = JSON.parse(line); } catch { continue; }
|
|
96
|
+
if (sessionId && entry.session_id && entry.session_id !== sessionId) continue;
|
|
97
|
+
const usage = entry.usage
|
|
98
|
+
|| entry.message?.usage
|
|
99
|
+
|| entry.response?.usage
|
|
100
|
+
|| (entry.type === 'assistant' && entry.message?.usage)
|
|
101
|
+
|| null;
|
|
102
|
+
if (!usage || typeof usage !== 'object') continue;
|
|
103
|
+
totals.input_tokens += extractNumber(usage, 'input_tokens');
|
|
104
|
+
totals.output_tokens += extractNumber(usage, 'output_tokens');
|
|
105
|
+
totals.cache_read_input_tokens += extractNumber(usage, 'cache_read_input_tokens');
|
|
106
|
+
totals.cache_creation_input_tokens += extractNumber(usage, 'cache_creation_input_tokens');
|
|
107
|
+
}
|
|
108
|
+
return totals;
|
|
109
|
+
}
|
|
110
|
+
|
|
61
111
|
/**
|
|
62
112
|
* Append record to .planning/metrics/tokens.jsonl. Silently succeeds
|
|
63
113
|
* even if the file or directory can't be written — hook must not block.
|