pan-wizard 3.8.0 → 3.10.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.
Files changed (49) hide show
  1. package/README.md +4 -1
  2. package/agents/pan-conductor.md +1 -2
  3. package/agents/pan-counterfactual.md +1 -2
  4. package/agents/pan-debugger.md +1 -2
  5. package/agents/pan-distiller.md +1 -2
  6. package/agents/pan-document_code.md +1 -0
  7. package/agents/pan-executor.md +1 -0
  8. package/agents/pan-experiment-runner.md +1 -2
  9. package/agents/pan-hardener.md +1 -2
  10. package/agents/pan-integration-checker.md +1 -2
  11. package/agents/pan-knowledge.md +1 -2
  12. package/agents/pan-meta-reviewer.md +1 -2
  13. package/agents/pan-optimizer.md +1 -0
  14. package/agents/pan-phase-researcher.md +1 -0
  15. package/agents/pan-plan-checker.md +1 -2
  16. package/agents/pan-planner.md +1 -0
  17. package/agents/pan-previewer.md +1 -2
  18. package/agents/pan-project-researcher.md +6 -0
  19. package/agents/pan-research-synthesizer.md +7 -0
  20. package/agents/pan-reviewer.md +2 -3
  21. package/agents/pan-roadmapper.md +1 -0
  22. package/agents/pan-verifier.md +1 -2
  23. package/bin/install-lib.cjs +661 -46
  24. package/bin/install.js +722 -116
  25. package/commands/pan/experiment.md +2 -0
  26. package/commands/pan/profile.md +2 -0
  27. package/hooks/dist/pan-cost-logger.js +22 -7
  28. package/package.json +5 -4
  29. package/pan-wizard-core/bin/lib/commands-learnings.cjs +544 -0
  30. package/pan-wizard-core/bin/lib/commands.cjs +12 -523
  31. package/pan-wizard-core/bin/lib/core.cjs +69 -0
  32. package/pan-wizard-core/bin/lib/cost.cjs +62 -8
  33. package/pan-wizard-core/bin/lib/git.cjs +6 -1
  34. package/pan-wizard-core/bin/lib/lock.cjs +108 -0
  35. package/pan-wizard-core/bin/lib/milestone.cjs +3 -2
  36. package/pan-wizard-core/bin/lib/phase-remove.cjs +392 -0
  37. package/pan-wizard-core/bin/lib/phase.cjs +4 -369
  38. package/pan-wizard-core/bin/lib/runner.cjs +5 -0
  39. package/pan-wizard-core/bin/lib/state.cjs +10 -1
  40. package/pan-wizard-core/bin/lib/verify-deploy.cjs +181 -0
  41. package/pan-wizard-core/bin/lib/verify-drift.cjs +255 -0
  42. package/pan-wizard-core/bin/lib/verify-preflight.cjs +261 -0
  43. package/pan-wizard-core/bin/lib/verify-retro.cjs +177 -0
  44. package/pan-wizard-core/bin/lib/verify.cjs +10 -797
  45. package/pan-wizard-core/bin/pan-tools.cjs +10 -0
  46. package/pan-wizard-core/workflows/plan-phase.md +11 -0
  47. package/scripts/build-plugin.js +105 -0
  48. package/scripts/install-git-hooks.js +64 -0
  49. package/scripts/release-check.js +13 -2
@@ -1039,6 +1039,16 @@ async function main() {
1039
1039
  break;
1040
1040
  }
1041
1041
 
1042
+ case 'models': {
1043
+ const subcommand = args[1];
1044
+ if (subcommand === 'check' || !subcommand) {
1045
+ cost.cmdModelsCheck(raw);
1046
+ } else {
1047
+ error('Unknown models subcommand. Available: check');
1048
+ }
1049
+ break;
1050
+ }
1051
+
1042
1052
  case 'bus': {
1043
1053
  const subcommand = args[1];
1044
1054
  if (subcommand === 'publish') {
@@ -511,6 +511,17 @@ Offer: 1) Force proceed, 2) Provide guidance and retry, 3) Abandon
511
511
 
512
512
  ## 13. Present Final Status
513
513
 
514
+ **Sync state.md first** — without this, state.md says "Ready to plan" until the
515
+ first plan's summary lands, and `/pan:progress`/`preflight` read a stale picture:
516
+
517
+ ```bash
518
+ node ~/.claude/pan-wizard-core/bin/pan-tools.cjs state update "Status" "Ready to execute"
519
+ node ~/.claude/pan-wizard-core/bin/pan-tools.cjs state update "Current Plan" "1"
520
+ node ~/.claude/pan-wizard-core/bin/pan-tools.cjs state update "Total Plans in Phase" "${PLAN_COUNT}"
521
+ node ~/.claude/pan-wizard-core/bin/pan-tools.cjs state update "Last Activity" "$(node ~/.claude/pan-wizard-core/bin/pan-tools.cjs current-timestamp date --raw)"
522
+ node ~/.claude/pan-wizard-core/bin/pan-tools.cjs state update "Last Activity Description" "Phase ${PHASE_NUMBER} planned — ${PLAN_COUNT} plans created"
523
+ ```
524
+
514
525
  Route to `<offer_next>` OR `auto_advance` depending on flags/config.
515
526
 
516
527
  **Circular optimization — log plan creation:**
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Build the PAN Wizard Claude Code plugin (ecosystem review item: plugin
3
+ * distribution, first slice). Emits a self-contained plugin directory at
4
+ * dist/pan-wizard-plugin/ following the verified plugin layout:
5
+ *
6
+ * .claude-plugin/plugin.json manifest (metadata; components auto-discover)
7
+ * commands/pan/*.md command markdown (Claude flavor)
8
+ * agents/pan-*.md agent definitions
9
+ * hooks/hooks.json PAN hooks with ${CLAUDE_PLUGIN_ROOT} paths
10
+ * hooks/pan-*.js hook scripts
11
+ * pan-wizard-core/ dispatcher + modules + workflows + templates
12
+ *
13
+ * Distribution status: built ALONGSIDE the loose-file installer. Marketplace
14
+ * publishing is gated on one live verification — whether ${CLAUDE_PLUGIN_ROOT}
15
+ * expands inside command markdown content (documented for hook/MCP configs
16
+ * only). Until then, content references core paths relative to the plugin
17
+ * root, which matches the documented plugin working layout.
18
+ *
19
+ * Usage: node scripts/build-plugin.js (or npm run build:plugin)
20
+ */
21
+
22
+ 'use strict';
23
+
24
+ const fs = require('fs');
25
+ const path = require('path');
26
+
27
+ const ROOT = path.join(__dirname, '..');
28
+ const OUT = path.join(ROOT, 'dist', 'pan-wizard-plugin');
29
+ const pkg = require(path.join(ROOT, 'package.json'));
30
+ const lib = require(path.join(ROOT, 'bin', 'install-lib.cjs'));
31
+
32
+ // Plugin-relative prefix used inside markdown content. Hook/MCP configs get
33
+ // the documented ${CLAUDE_PLUGIN_ROOT} form via buildPluginHooksConfig().
34
+ const CONTENT_PREFIX = '${CLAUDE_PLUGIN_ROOT}/';
35
+
36
+ function rewriteContent(content) {
37
+ return content
38
+ .replace(/~\/\.claude\/pan-wizard-core\//g, `${CONTENT_PREFIX}pan-wizard-core/`)
39
+ .replace(/\.\/\.claude\/pan-wizard-core\//g, `${CONTENT_PREFIX}pan-wizard-core/`)
40
+ .replace(/~\/\.claude\/agents\//g, `${CONTENT_PREFIX}agents/`)
41
+ .replace(/\.\/\.claude\/agents\//g, `${CONTENT_PREFIX}agents/`)
42
+ .replace(/~\/\.claude\//g, CONTENT_PREFIX)
43
+ .replace(/\.\/\.claude\//g, CONTENT_PREFIX);
44
+ }
45
+
46
+ function copyTree(srcDir, destDir, transformMd) {
47
+ fs.mkdirSync(destDir, { recursive: true });
48
+ for (const entry of fs.readdirSync(srcDir, { withFileTypes: true })) {
49
+ const srcPath = path.join(srcDir, entry.name);
50
+ const destPath = path.join(destDir, entry.name);
51
+ if (entry.isDirectory()) {
52
+ copyTree(srcPath, destPath, transformMd);
53
+ } else if (transformMd && entry.name.endsWith('.md')) {
54
+ fs.writeFileSync(destPath, transformMd(fs.readFileSync(srcPath, 'utf8')));
55
+ } else {
56
+ fs.copyFileSync(srcPath, destPath);
57
+ }
58
+ }
59
+ }
60
+
61
+ function main() {
62
+ // Clean output
63
+ fs.rmSync(OUT, { recursive: true, force: true });
64
+ fs.mkdirSync(path.join(OUT, '.claude-plugin'), { recursive: true });
65
+
66
+ // 1. Manifest
67
+ fs.writeFileSync(
68
+ path.join(OUT, '.claude-plugin', 'plugin.json'),
69
+ JSON.stringify(lib.buildPluginManifest(pkg), null, 2) + '\n'
70
+ );
71
+
72
+ // 2. Commands (Claude flavor, plugin-root-relative paths)
73
+ copyTree(path.join(ROOT, 'commands', 'pan'), path.join(OUT, 'commands', 'pan'), rewriteContent);
74
+
75
+ // 3. Agents
76
+ copyTree(path.join(ROOT, 'agents'), path.join(OUT, 'agents'), rewriteContent);
77
+
78
+ // 4. Hooks: config + scripts
79
+ fs.mkdirSync(path.join(OUT, 'hooks'), { recursive: true });
80
+ fs.writeFileSync(
81
+ path.join(OUT, 'hooks', 'hooks.json'),
82
+ JSON.stringify(lib.buildPluginHooksConfig(), null, 2) + '\n'
83
+ );
84
+ const hooksDist = path.join(ROOT, 'hooks', 'dist');
85
+ if (fs.existsSync(hooksDist)) {
86
+ for (const f of fs.readdirSync(hooksDist).filter(n => n.endsWith('.js'))) {
87
+ fs.copyFileSync(path.join(hooksDist, f), path.join(OUT, 'hooks', f));
88
+ }
89
+ }
90
+
91
+ // 5. Core (strip source-only internal learnings, same policy as the installer)
92
+ copyTree(path.join(ROOT, 'pan-wizard-core'), path.join(OUT, 'pan-wizard-core'), rewriteContent);
93
+ fs.rmSync(path.join(OUT, 'pan-wizard-core', 'learnings', 'internal'), { recursive: true, force: true });
94
+ fs.writeFileSync(path.join(OUT, 'pan-wizard-core', 'VERSION'), pkg.version);
95
+
96
+ // Sanity report
97
+ const count = (p) => { try { return fs.readdirSync(p).length; } catch { return 0; } };
98
+ console.log('PAN plugin built at', path.relative(ROOT, OUT));
99
+ console.log(' commands/pan:', count(path.join(OUT, 'commands', 'pan')));
100
+ console.log(' agents:', count(path.join(OUT, 'agents')));
101
+ console.log(' hooks:', count(path.join(OUT, 'hooks')));
102
+ console.log(' version:', pkg.version);
103
+ }
104
+
105
+ main();
@@ -0,0 +1,64 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * install-git-hooks.js
4
+ *
5
+ * Points this repo's git at `scripts/git-hooks/` instead of the per-clone
6
+ * `.git/hooks/` directory. Run automatically by the `prepare` npm script,
7
+ * which fires on `npm install` inside the source repo.
8
+ *
9
+ * Why this exists:
10
+ * `.git/hooks/` is per-clone (never committed). Without this, every fresh
11
+ * clone of PAN Wizard would have to manually `cp scripts/git-hooks/pre-commit
12
+ * .git/hooks/` to get the gitleaks pre-commit scan. With `core.hooksPath`
13
+ * set to the tracked `scripts/git-hooks/` directory, the hook is active
14
+ * the moment you finish `npm install`.
15
+ *
16
+ * No-op when not in a git working tree (e.g., the package is being installed
17
+ * as a dependency in someone else's `node_modules/`, where there's no `.git`).
18
+ *
19
+ * Safe to re-run.
20
+ */
21
+
22
+ 'use strict';
23
+
24
+ const { execFileSync } = require('child_process');
25
+ const fs = require('fs');
26
+ const path = require('path');
27
+
28
+ const REPO_ROOT = path.resolve(__dirname, '..');
29
+ const HOOKS_DIR = 'scripts/git-hooks';
30
+
31
+ // 1. Are we in a git working tree? If not, this is a downstream install —
32
+ // do nothing.
33
+ const gitDir = path.join(REPO_ROOT, '.git');
34
+ if (!fs.existsSync(gitDir)) {
35
+ // Silent no-op for downstream consumers. Their `node_modules/pan-wizard/`
36
+ // doesn't have its own .git directory.
37
+ process.exit(0);
38
+ }
39
+
40
+ // 2. Set core.hooksPath. Idempotent — overwrites any previous value.
41
+ try {
42
+ execFileSync('git', ['config', '--local', 'core.hooksPath', HOOKS_DIR], {
43
+ cwd: REPO_ROOT,
44
+ stdio: 'inherit',
45
+ });
46
+ } catch (err) {
47
+ // If `git` isn't on PATH or the config write fails, warn but don't fail
48
+ // the install. The user can run this manually later.
49
+ console.warn(`[install-git-hooks] could not set core.hooksPath: ${err.message}`);
50
+ process.exit(0);
51
+ }
52
+
53
+ // 3. Confirm the hook file is executable on Unix. On Windows the bit doesn't
54
+ // matter — Git Bash treats `.sh` and shebanged scripts as executable.
55
+ const hookFile = path.join(REPO_ROOT, HOOKS_DIR, 'pre-commit');
56
+ if (process.platform !== 'win32') {
57
+ try {
58
+ fs.chmodSync(hookFile, 0o755);
59
+ } catch {
60
+ // Best effort.
61
+ }
62
+ }
63
+
64
+ console.error(`[install-git-hooks] core.hooksPath → ${HOOKS_DIR} (gitleaks pre-commit active)`);
@@ -100,6 +100,17 @@ process.stderr.write('\n[release-check] Gate 4/6: doc-lint counts docs/\n');
100
100
  }
101
101
  }
102
102
 
103
+
104
+ // npm runs lifecycle scripts (prepare) before pack; any of their stdout noise
105
+ // lands ahead of the --json payload. npm pretty-prints the JSON array starting
106
+ // on its own line — parse from there.
107
+ function parseNpmJson(stdout) {
108
+ try { return JSON.parse(stdout); } catch { /* fall through to extraction */ }
109
+ const m = stdout.search(/^[[{]s*$/m);
110
+ if (m === -1) throw new Error('no JSON payload found in npm output');
111
+ return JSON.parse(stdout.slice(m));
112
+ }
113
+
103
114
  // Gate 5: npm pack dry-run
104
115
  process.stderr.write('\n[release-check] Gate 5/6: npm pack --dry-run\n');
105
116
  {
@@ -111,7 +122,7 @@ process.stderr.write('\n[release-check] Gate 5/6: npm pack --dry-run\n');
111
122
  }
112
123
  // Parse the JSON output to check size
113
124
  try {
114
- const parsed = JSON.parse(r.stdout);
125
+ const parsed = parseNpmJson(r.stdout);
115
126
  const entry = Array.isArray(parsed) ? parsed[0] : parsed;
116
127
  const size = entry.size || 0;
117
128
  const fileCount = entry.files ? entry.files.length : 0;
@@ -139,7 +150,7 @@ if (SKIP_SMOKE) {
139
150
  logGate('smoke install (pack)', false, `exit ${pack.status}`);
140
151
  process.exit(1);
141
152
  }
142
- const packJson = JSON.parse(pack.stdout);
153
+ const packJson = parseNpmJson(pack.stdout);
143
154
  const tarball = path.join(tmpDir, packJson[0].filename);
144
155
  if (!fs.existsSync(tarball)) {
145
156
  logGate('smoke install (pack)', false, `tarball not found at ${tarball}`);