pan-wizard 3.33.0 → 3.35.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 +29 -26
- package/agents/pan-conductor.md +18 -17
- package/agents/pan-counterfactual.md +2 -2
- package/agents/pan-debugger.md +30 -9
- package/agents/pan-design-checker.md +2 -1
- package/agents/pan-designer.md +2 -2
- package/agents/pan-distiller.md +3 -3
- package/agents/pan-document_code.md +14 -14
- package/agents/pan-executor.md +30 -9
- package/agents/pan-experiment-runner.md +9 -8
- package/agents/pan-hardener.md +1 -1
- package/agents/pan-integration-checker.md +2 -2
- package/agents/pan-knowledge.md +1 -1
- package/agents/pan-meta-reviewer.md +4 -4
- package/agents/pan-optimizer.md +39 -43
- package/agents/pan-phase-researcher.md +10 -10
- package/agents/pan-plan-checker.md +37 -34
- package/agents/pan-planner.md +57 -44
- package/agents/pan-previewer.md +1 -1
- package/agents/pan-project-researcher.md +12 -12
- package/agents/pan-release.md +1 -1
- package/agents/pan-research-synthesizer.md +3 -3
- package/agents/pan-reviewer.md +26 -3
- package/agents/pan-roadmapper.md +15 -14
- package/agents/pan-verifier.md +33 -25
- package/bin/install-lib.cjs +176 -38
- package/bin/install.js +81 -63
- package/commands/pan/army.md +15 -11
- package/commands/pan/assumptions.md +2 -2
- package/commands/pan/audit-deployment.md +11 -12
- package/commands/pan/cost.md +8 -8
- package/commands/pan/dashboard.md +0 -3
- package/commands/pan/debug.md +10 -7
- package/commands/pan/design-phase.md +5 -5
- package/commands/pan/discuss-phase.md +2 -0
- package/commands/pan/exec-phase.md +21 -37
- package/commands/pan/experiment.md +9 -8
- package/commands/pan/focus-auto.md +22 -20
- package/commands/pan/focus-design.md +7 -6
- package/commands/pan/focus-doc-audit.md +4 -3
- package/commands/pan/focus-drift-walking.md +4 -3
- package/commands/pan/focus-exec.md +6 -6
- package/commands/pan/focus-plan.md +12 -11
- package/commands/pan/focus-scan.md +5 -3
- package/commands/pan/focus-sync.md +3 -2
- package/commands/pan/git.md +8 -8
- package/commands/pan/health.md +2 -2
- package/commands/pan/hud.md +4 -7
- package/commands/pan/hygiene.md +14 -7
- package/commands/pan/knowledge.md +9 -10
- package/commands/pan/learn.md +10 -7
- package/commands/pan/links.md +4 -1
- package/commands/pan/map-codebase.md +1 -1
- package/commands/pan/mcp-bridge.md +19 -21
- package/commands/pan/milestone-done.md +6 -3
- package/commands/pan/milestone-new.md +1 -1
- package/commands/pan/new-project.md +10 -10
- package/commands/pan/optimize.md +18 -14
- package/commands/pan/patches.md +2 -6
- package/commands/pan/pause.md +1 -1
- package/commands/pan/phase-tests.md +3 -2
- package/commands/pan/plan-phase.md +9 -19
- package/commands/pan/preview.md +2 -3
- package/commands/pan/profile.md +2 -2
- package/commands/pan/quick.md +1 -1
- package/commands/pan/remove-phase.md +1 -1
- package/commands/pan/report.md +3 -7
- package/commands/pan/research-phase.md +16 -15
- package/commands/pan/resume.md +9 -11
- package/commands/pan/retro.md +5 -3
- package/commands/pan/review-deep.md +7 -9
- package/commands/pan/settings.md +1 -1
- package/commands/pan/verify-phase.md +0 -11
- package/commands/pan/what-if.md +3 -4
- package/hooks/dist/pan-context-monitor.js +352 -44
- package/hooks/dist/pan-cost-logger.js +30 -0
- package/hooks/dist/pan-guard.js +244 -0
- package/hooks/dist/pan-statusline.js +73 -24
- package/hooks/dist/pan-stop-guard.js +7 -2
- package/package.json +1 -1
- package/pan-wizard-core/bin/lib/agents-md.cjs +44 -6
- package/pan-wizard-core/bin/lib/bridge.cjs +6 -5
- package/pan-wizard-core/bin/lib/campaign.cjs +4 -2
- package/pan-wizard-core/bin/lib/commands-learnings.cjs +19 -2
- package/pan-wizard-core/bin/lib/commands.cjs +57 -6
- package/pan-wizard-core/bin/lib/config.cjs +7 -1
- package/pan-wizard-core/bin/lib/constants.cjs +18 -6
- package/pan-wizard-core/bin/lib/context-budget.cjs +12 -9
- package/pan-wizard-core/bin/lib/core.cjs +53 -19
- package/pan-wizard-core/bin/lib/cost-rebuild.cjs +13 -1
- package/pan-wizard-core/bin/lib/cost.cjs +142 -13
- package/pan-wizard-core/bin/lib/distill.cjs +6 -3
- package/pan-wizard-core/bin/lib/doc-lint.cjs +30 -11
- package/pan-wizard-core/bin/lib/findings.cjs +135 -21
- package/pan-wizard-core/bin/lib/focus.cjs +13 -4
- package/pan-wizard-core/bin/lib/frontmatter.cjs +105 -26
- package/pan-wizard-core/bin/lib/hygiene.cjs +184 -17
- package/pan-wizard-core/bin/lib/init.cjs +13 -4
- package/pan-wizard-core/bin/lib/knowledge.cjs +17 -1
- package/pan-wizard-core/bin/lib/learn-index.cjs +111 -10
- package/pan-wizard-core/bin/lib/learn-lint.cjs +30 -3
- package/pan-wizard-core/bin/lib/memory-optimize.cjs +8 -4
- package/pan-wizard-core/bin/lib/memory.cjs +508 -54
- package/pan-wizard-core/bin/lib/milestone.cjs +8 -3
- package/pan-wizard-core/bin/lib/optimize.cjs +97 -17
- package/pan-wizard-core/bin/lib/phase-gate.cjs +174 -0
- package/pan-wizard-core/bin/lib/phase-remove.cjs +85 -21
- package/pan-wizard-core/bin/lib/phase-report.cjs +8 -2
- package/pan-wizard-core/bin/lib/phase.cjs +39 -13
- package/pan-wizard-core/bin/lib/preview.cjs +34 -31
- package/pan-wizard-core/bin/lib/roadmap-compact.cjs +267 -0
- package/pan-wizard-core/bin/lib/roadmap.cjs +243 -9
- package/pan-wizard-core/bin/lib/runner.cjs +2 -1
- package/pan-wizard-core/bin/lib/state-compact.cjs +11 -6
- package/pan-wizard-core/bin/lib/state.cjs +43 -28
- package/pan-wizard-core/bin/lib/template.cjs +11 -4
- package/pan-wizard-core/bin/lib/verdict.cjs +140 -10
- package/pan-wizard-core/bin/lib/verify-integrity.cjs +181 -0
- package/pan-wizard-core/bin/lib/verify-plan-set.cjs +230 -0
- package/pan-wizard-core/bin/lib/verify-preflight.cjs +4 -13
- package/pan-wizard-core/bin/lib/verify-retro.cjs +5 -3
- package/pan-wizard-core/bin/lib/verify-scope.cjs +11 -7
- package/pan-wizard-core/bin/lib/verify.cjs +30 -28
- package/pan-wizard-core/bin/lib/whatif.cjs +53 -9
- package/pan-wizard-core/bin/pan-tools.cjs +114 -19
- package/pan-wizard-core/learnings/index.json +5 -5
- package/pan-wizard-core/mcp/merge-gate.cjs +14 -3
- package/pan-wizard-core/mcp/native-tools.cjs +3 -3
- package/pan-wizard-core/opencode/pan-wizard.js +139 -0
- package/pan-wizard-core/references/checkpoints.md +3 -3
- package/pan-wizard-core/references/continuation-format.md +3 -3
- package/pan-wizard-core/references/decimal-phase-calculation.md +2 -3
- package/pan-wizard-core/references/design-methodology.md +1 -1
- package/pan-wizard-core/references/git-integration.md +4 -6
- package/pan-wizard-core/references/git-planning-commit.md +2 -2
- package/pan-wizard-core/references/guardrails.md +2 -2
- package/pan-wizard-core/references/handoff-decisions.md +3 -3
- package/pan-wizard-core/references/model-profile-resolution.md +5 -5
- package/pan-wizard-core/references/model-profiles.md +15 -10
- package/pan-wizard-core/references/phase-argument-parsing.md +7 -7
- package/pan-wizard-core/references/planning-config.md +7 -7
- package/pan-wizard-core/references/tdd.md +10 -1
- package/pan-wizard-core/references/verdict-contract.md +6 -1
- package/pan-wizard-core/references/verification-patterns.md +5 -5
- package/pan-wizard-core/templates/codebase/architecture.md +2 -2
- package/pan-wizard-core/templates/codebase/best-practices.md +2 -2
- package/pan-wizard-core/templates/codebase/concerns.md +3 -3
- package/pan-wizard-core/templates/codebase/integrations.md +6 -6
- package/pan-wizard-core/templates/codebase/relationships.md +2 -2
- package/pan-wizard-core/templates/codebase/stack.md +2 -2
- package/pan-wizard-core/templates/codebase/structure.md +4 -4
- package/pan-wizard-core/templates/codebase/testing.md +4 -4
- package/pan-wizard-core/templates/config.json +2 -6
- package/pan-wizard-core/templates/continue-here.md +1 -1
- package/pan-wizard-core/templates/debug-subagent-prompt.md +5 -3
- package/pan-wizard-core/templates/debug.md +15 -1
- package/pan-wizard-core/templates/milestone-archive.md +6 -6
- package/pan-wizard-core/templates/milestone.md +1 -1
- package/pan-wizard-core/templates/phase-prompt.md +31 -17
- package/pan-wizard-core/templates/planner-subagent-prompt.md +5 -5
- package/pan-wizard-core/templates/preview-report.md +1 -1
- package/pan-wizard-core/templates/research-project/architecture.md +3 -3
- package/pan-wizard-core/templates/research-project/features.md +1 -1
- package/pan-wizard-core/templates/research-project/pitfalls.md +1 -1
- package/pan-wizard-core/templates/research-project/stack.md +3 -3
- package/pan-wizard-core/templates/research.md +5 -5
- package/pan-wizard-core/templates/retrospective.md +1 -1
- package/pan-wizard-core/templates/roadmap.md +15 -15
- package/pan-wizard-core/templates/state.md +4 -4
- package/pan-wizard-core/templates/summary-complex.md +1 -0
- package/pan-wizard-core/templates/summary-minimal.md +1 -0
- package/pan-wizard-core/templates/summary-standard.md +2 -1
- package/pan-wizard-core/templates/summary.md +18 -2
- package/pan-wizard-core/templates/uat.md +3 -3
- package/pan-wizard-core/templates/user-setup.md +8 -8
- package/pan-wizard-core/templates/verification-report.md +53 -8
- package/pan-wizard-core/workflows/add-phase.md +1 -1
- package/pan-wizard-core/workflows/assumptions.md +1 -1
- package/pan-wizard-core/workflows/diagnose-issues.md +4 -4
- package/pan-wizard-core/workflows/discuss-phase.md +10 -8
- package/pan-wizard-core/workflows/exec-phase.md +75 -95
- package/pan-wizard-core/workflows/execute-plan.md +8 -7
- package/pan-wizard-core/workflows/health.md +13 -12
- package/pan-wizard-core/workflows/help.md +8 -9
- package/pan-wizard-core/workflows/learn.md +13 -11
- package/pan-wizard-core/workflows/map-codebase.md +10 -10
- package/pan-wizard-core/workflows/milestone-audit.md +10 -10
- package/pan-wizard-core/workflows/milestone-gaps.md +18 -25
- package/pan-wizard-core/workflows/milestone-new.md +7 -6
- package/pan-wizard-core/workflows/new-project.md +17 -25
- package/pan-wizard-core/workflows/optimize.md +11 -9
- package/pan-wizard-core/workflows/pause.md +6 -1
- package/pan-wizard-core/workflows/phase-tests.md +4 -4
- package/pan-wizard-core/workflows/plan-phase.md +53 -42
- package/pan-wizard-core/workflows/profile.md +2 -2
- package/pan-wizard-core/workflows/progress.md +6 -8
- package/pan-wizard-core/workflows/quick.md +7 -5
- package/pan-wizard-core/workflows/remove-phase.md +1 -1
- package/pan-wizard-core/workflows/research-phase.md +9 -5
- package/pan-wizard-core/workflows/resume-project.md +4 -6
- package/pan-wizard-core/workflows/retro.md +3 -1
- package/pan-wizard-core/workflows/settings.md +16 -24
- package/pan-wizard-core/workflows/todo-check.md +4 -3
- package/pan-wizard-core/workflows/transition.md +16 -12
- package/pan-wizard-core/workflows/update.md +25 -17
- package/pan-wizard-core/workflows/verify-phase.md +22 -20
- package/pan-zcode/KNOWN-BETA-RISKS.md +2 -2
- package/pan-zcode/README.md +7 -7
- package/pan-zcode/bin/install-zcode.js +1 -1
- package/scripts/build-hooks.js +1 -0
- package/scripts/build-plugin.js +3 -1
- package/scripts/generate-skills-docs.py +15 -6
- package/scripts/prompt-lint.cjs +167 -0
- package/scripts/test-surface.cjs +1 -0
package/bin/install-lib.cjs
CHANGED
|
@@ -564,6 +564,8 @@ function rewriteSharedCoreMarkdown(content, { corePrefix, pathPrefix, projectDir
|
|
|
564
564
|
content = content.replace(/\.\/\.claude\/agents\//g, `${corePrefix}pan-wizard-core/agents/`);
|
|
565
565
|
content = content.replace(/~\/\.claude\//g, pathPrefix);
|
|
566
566
|
content = content.replace(/\.\/\.claude\//g, projectDirPrefix);
|
|
567
|
+
// No `pan-tools` bin is on PATH: invoke it via node, as the skill rewrite does.
|
|
568
|
+
content = content.replace(/\bpan-tools\b(?=\s+[a-z])/g, `node ${corePrefix}pan-wizard-core/bin/pan-tools.cjs`);
|
|
567
569
|
content = processAttribution(content, attribution);
|
|
568
570
|
return convertSlashCommandsToCopilotSkillMentions(content);
|
|
569
571
|
}
|
|
@@ -573,9 +575,29 @@ function rewriteSharedCoreMarkdown(content, { corePrefix, pathPrefix, projectDir
|
|
|
573
575
|
* under `<shared core>/agents/` — reading material for agents, not a runtime
|
|
574
576
|
* registration (ADR-0028 agent-ref canonicalization).
|
|
575
577
|
*/
|
|
578
|
+
/**
|
|
579
|
+
* Name the agent file this runtime actually installs. A prompt that says "read
|
|
580
|
+
* ~/.claude/agents/pan-planner.md for your role" becomes `<prefix>agents/pan-planner.md`
|
|
581
|
+
* after the prefix rewrite, but Codex installs agents as `pan-planner.toml` and Copilot
|
|
582
|
+
* as `pan-planner.agent.md`, so the spawned agent read nothing and ran with no role.
|
|
583
|
+
* Idempotent; other runtimes keep `.md`.
|
|
584
|
+
* @param {string} content
|
|
585
|
+
* @param {string} runtime - claude | codex | gemini | opencode | copilot
|
|
586
|
+
* @param {string} pathPrefix - the runtime's rewritten config-dir prefix (ends in `/`)
|
|
587
|
+
* @returns {string}
|
|
588
|
+
*/
|
|
589
|
+
function rewriteAgentFileRefs(content, runtime, pathPrefix) {
|
|
590
|
+
const ext = runtime === 'codex' ? '.toml' : runtime === 'copilot' ? '.agent.md' : null;
|
|
591
|
+
if (!ext || !pathPrefix) return content;
|
|
592
|
+
const prefix = pathPrefix.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
593
|
+
return content.replace(new RegExp(`(${prefix}agents/pan-[a-z0-9_-]+)\\.md\\b`, 'g'), (_, base) => base + ext);
|
|
594
|
+
}
|
|
595
|
+
|
|
576
596
|
function rewriteAgentReferenceCopy(content, corePrefix) {
|
|
577
597
|
content = content.replace(/~\/\.claude\/pan-wizard-core\//g, `${corePrefix}pan-wizard-core/`);
|
|
578
598
|
content = content.replace(/\.\/\.claude\/pan-wizard-core\//g, `${corePrefix}pan-wizard-core/`);
|
|
599
|
+
// No `pan-tools` bin is on PATH: invoke it via node, as the skill rewrite does.
|
|
600
|
+
content = content.replace(/\bpan-tools\b(?=\s+[a-z])/g, `node ${corePrefix}pan-wizard-core/bin/pan-tools.cjs`);
|
|
579
601
|
return convertSlashCommandsToCopilotSkillMentions(content);
|
|
580
602
|
}
|
|
581
603
|
|
|
@@ -1138,11 +1160,16 @@ function stripThinkingFrontmatter(content, runtime) {
|
|
|
1138
1160
|
*/
|
|
1139
1161
|
function buildCopilotHooksConfig(commands) {
|
|
1140
1162
|
const { updateCheckCommand, contextMonitorCommand, costLoggerCommand, traceLoggerCommand, stopGuardCommand,
|
|
1141
|
-
stateReinjectMarkCommand, stateReinjectInjectCommand } = commands || {};
|
|
1163
|
+
stateReinjectMarkCommand, stateReinjectInjectCommand, guardCommand } = commands || {};
|
|
1142
1164
|
const config = { version: 1, hooks: {} };
|
|
1143
1165
|
if (updateCheckCommand) {
|
|
1144
1166
|
config.hooks.sessionStart = [{ type: 'command', command: updateCheckCommand }];
|
|
1145
1167
|
}
|
|
1168
|
+
// preToolUse: the PAN guard (A7). Copilot denies a call on the JSON
|
|
1169
|
+
// `permissionDecision: "deny"` output, which pan-guard.js prints under `--host copilot`.
|
|
1170
|
+
if (guardCommand) {
|
|
1171
|
+
config.hooks.preToolUse = [{ type: 'command', command: guardCommand }];
|
|
1172
|
+
}
|
|
1146
1173
|
const postToolUse = [];
|
|
1147
1174
|
if (contextMonitorCommand) postToolUse.push({ type: 'command', command: contextMonitorCommand });
|
|
1148
1175
|
// State re-injection after a compaction (M33): preCompact leaves the marker, the
|
|
@@ -1216,10 +1243,10 @@ function buildCopilotHooksConfig(commands) {
|
|
|
1216
1243
|
* 2026-10-03, and live on Copilot CLI 1.0.88 the same day).
|
|
1217
1244
|
*/
|
|
1218
1245
|
const HOOK_EVENT_MAP = Object.freeze({
|
|
1219
|
-
claude: { surface: 'settings.json', sessionStart: 'SessionStart', postToolUse: 'PostToolUse', subagentStop: 'SubagentStop', stop: 'Stop', compact: 'SessionStart', compactMark: null, compactInject: null },
|
|
1220
|
-
gemini: { surface: 'settings.json', sessionStart: 'SessionStart', postToolUse: null, subagentStop: null, stop: 'AfterAgent', compact: null, compactMark: 'PreCompress', compactInject: 'AfterTool' },
|
|
1221
|
-
codex: { surface: 'hooks.json', sessionStart: 'SessionStart', postToolUse: 'PostToolUse', subagentStop: 'SubagentStop', stop: 'Stop', compact: 'SessionStart', compactMark: null, compactInject: null },
|
|
1222
|
-
copilot: { surface: 'hooks/pan.json', sessionStart: 'sessionStart', postToolUse: 'postToolUse', subagentStop: 'subagentStop', stop: 'agentStop', compact: null, compactMark: 'preCompact', compactInject: 'postToolUse' },
|
|
1246
|
+
claude: { surface: 'settings.json', sessionStart: 'SessionStart', preToolUse: 'PreToolUse', postToolUse: 'PostToolUse', subagentStop: 'SubagentStop', stop: 'Stop', compact: 'SessionStart', compactMark: null, compactInject: null },
|
|
1247
|
+
gemini: { surface: 'settings.json', sessionStart: 'SessionStart', preToolUse: 'BeforeTool', postToolUse: null, subagentStop: null, stop: 'AfterAgent', compact: null, compactMark: 'PreCompress', compactInject: 'AfterTool' },
|
|
1248
|
+
codex: { surface: 'hooks.json', sessionStart: 'SessionStart', preToolUse: 'PreToolUse', postToolUse: 'PostToolUse', subagentStop: 'SubagentStop', stop: 'Stop', compact: 'SessionStart', compactMark: null, compactInject: null },
|
|
1249
|
+
copilot: { surface: 'hooks/pan.json', sessionStart: 'sessionStart', preToolUse: 'preToolUse', postToolUse: 'postToolUse', subagentStop: 'subagentStop', stop: 'agentStop', compact: null, compactMark: 'preCompact', compactInject: 'postToolUse' },
|
|
1223
1250
|
opencode: null,
|
|
1224
1251
|
});
|
|
1225
1252
|
|
|
@@ -1231,7 +1258,7 @@ const HOOK_EVENT_MAP = Object.freeze({
|
|
|
1231
1258
|
const HOOK_SLOT_MATCHERS = Object.freeze({ compact: 'compact' });
|
|
1232
1259
|
|
|
1233
1260
|
/** The hook scripts PAN registers in a Claude-shaped settings.json `hooks` block. */
|
|
1234
|
-
const PAN_SETTINGS_HOOKS = Object.freeze(['pan-check-update', 'pan-context-monitor', 'pan-cost-logger', 'pan-trace-logger', 'pan-stop-guard', 'pan-state-reinject']);
|
|
1261
|
+
const PAN_SETTINGS_HOOKS = Object.freeze(['pan-check-update', 'pan-guard', 'pan-context-monitor', 'pan-cost-logger', 'pan-trace-logger', 'pan-stop-guard', 'pan-state-reinject']);
|
|
1235
1262
|
|
|
1236
1263
|
/**
|
|
1237
1264
|
* Remove, from every event array of a Claude-shaped `hooks` object except
|
|
@@ -1362,10 +1389,78 @@ function mergeMcpRegistration(existing, runtime, entry, serverName = 'pan') {
|
|
|
1362
1389
|
const config = (existing && typeof existing === 'object' && !Array.isArray(existing)) ? existing : {};
|
|
1363
1390
|
const key = spec.key;
|
|
1364
1391
|
if (!config[key] || typeof config[key] !== 'object' || Array.isArray(config[key])) config[key] = {};
|
|
1392
|
+
// OpenCode 2 nests servers under `mcp.servers` (R47). PAN keeps writing the v1
|
|
1393
|
+
// shape, but in a file the user already converted it updates the native entry and
|
|
1394
|
+
// never leaves a legacy `mcp.pan` beside it: the native one would win, stale.
|
|
1395
|
+
if (runtime === 'opencode' && isOpencodeV2Servers(config[key].servers)) {
|
|
1396
|
+
config[key].servers[serverName] = entry;
|
|
1397
|
+
delete config[key][serverName];
|
|
1398
|
+
return config;
|
|
1399
|
+
}
|
|
1365
1400
|
config[key][serverName] = entry;
|
|
1366
1401
|
return config;
|
|
1367
1402
|
}
|
|
1368
1403
|
|
|
1404
|
+
/** OpenCode 2's `mcp.servers` container: an object of server entries, not a v1 server named "servers". */
|
|
1405
|
+
function isOpencodeV2Servers(v) {
|
|
1406
|
+
return !!v && typeof v === 'object' && !Array.isArray(v) && !('type' in v) && !('command' in v);
|
|
1407
|
+
}
|
|
1408
|
+
|
|
1409
|
+
/**
|
|
1410
|
+
* Add PAN's OpenCode read and external_directory allowances for `panPath`.
|
|
1411
|
+
* v1 (or a new file): the `permission` object PAN has always written. v2 (the file
|
|
1412
|
+
* already has an ordered `permissions[]` of {action, resource, effect}): PAN's rules
|
|
1413
|
+
* go into that array, and no legacy `permission` object is added beside it (R47).
|
|
1414
|
+
* @returns {{config: object, modified: boolean, shape: 'v1'|'v2'}}
|
|
1415
|
+
*/
|
|
1416
|
+
function addOpencodePermissions(existing, panPath) {
|
|
1417
|
+
const config = (existing && typeof existing === 'object' && !Array.isArray(existing)) ? existing : {};
|
|
1418
|
+
let modified = false;
|
|
1419
|
+
if (Array.isArray(config.permissions)) {
|
|
1420
|
+
for (const action of ['read', 'external_directory']) {
|
|
1421
|
+
const has = config.permissions.some((r) => r && r.action === action && r.resource === panPath && r.effect === 'allow');
|
|
1422
|
+
if (!has) { config.permissions.push({ action, resource: panPath, effect: 'allow' }); modified = true; }
|
|
1423
|
+
}
|
|
1424
|
+
return { config, modified, shape: 'v2' };
|
|
1425
|
+
}
|
|
1426
|
+
if (!config.permission || typeof config.permission !== 'object' || Array.isArray(config.permission)) config.permission = {};
|
|
1427
|
+
for (const type of ['read', 'external_directory']) {
|
|
1428
|
+
if (!config.permission[type] || typeof config.permission[type] !== 'object') config.permission[type] = {};
|
|
1429
|
+
if (config.permission[type][panPath] !== 'allow') { config.permission[type][panPath] = 'allow'; modified = true; }
|
|
1430
|
+
}
|
|
1431
|
+
return { config, modified, shape: 'v1' };
|
|
1432
|
+
}
|
|
1433
|
+
|
|
1434
|
+
/**
|
|
1435
|
+
* Remove every PAN allowance from an OpenCode config, in either shape: keys of the
|
|
1436
|
+
* v1 `permission.read` / `permission.external_directory` objects and v2
|
|
1437
|
+
* `permissions[]` rules whose path names `pan-wizard` (which also catches the
|
|
1438
|
+
* malformed `~/.config/opencode/pan-wizard/*` key early versions wrote). Containers
|
|
1439
|
+
* PAN emptied are removed.
|
|
1440
|
+
* @returns {{config: object, modified: boolean}}
|
|
1441
|
+
*/
|
|
1442
|
+
function stripOpencodePermissions(existing) {
|
|
1443
|
+
const config = (existing && typeof existing === 'object' && !Array.isArray(existing)) ? existing : {};
|
|
1444
|
+
let modified = false;
|
|
1445
|
+
if (config.permission && typeof config.permission === 'object' && !Array.isArray(config.permission)) {
|
|
1446
|
+
for (const type of ['read', 'external_directory']) {
|
|
1447
|
+
const bag = config.permission[type];
|
|
1448
|
+
if (!bag || typeof bag !== 'object') continue;
|
|
1449
|
+
for (const key of Object.keys(bag)) if (key.includes('pan-wizard')) { delete bag[key]; modified = true; }
|
|
1450
|
+
if (Object.keys(bag).length === 0) delete config.permission[type];
|
|
1451
|
+
}
|
|
1452
|
+
if (Object.keys(config.permission).length === 0) delete config.permission;
|
|
1453
|
+
}
|
|
1454
|
+
if (Array.isArray(config.permissions)) {
|
|
1455
|
+
const kept = config.permissions.filter((r) => !(r && typeof r.resource === 'string' && r.resource.includes('pan-wizard')));
|
|
1456
|
+
if (kept.length !== config.permissions.length) {
|
|
1457
|
+
modified = true;
|
|
1458
|
+
if (kept.length) config.permissions = kept; else delete config.permissions;
|
|
1459
|
+
}
|
|
1460
|
+
}
|
|
1461
|
+
return { config, modified };
|
|
1462
|
+
}
|
|
1463
|
+
|
|
1369
1464
|
/**
|
|
1370
1465
|
* Remove PAN's MCP server from a config object, preserving foreign entries.
|
|
1371
1466
|
* Empties the container key when PAN was its only member, so uninstall does not
|
|
@@ -1378,10 +1473,17 @@ function stripMcpRegistration(existing, runtime, serverName = 'pan') {
|
|
|
1378
1473
|
if (!spec) throw new Error(`stripMcpRegistration: unknown runtime "${runtime}"`);
|
|
1379
1474
|
const config = (existing && typeof existing === 'object' && !Array.isArray(existing)) ? existing : {};
|
|
1380
1475
|
const bag = config[spec.key];
|
|
1381
|
-
if (!bag || typeof bag !== 'object'
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1476
|
+
if (!bag || typeof bag !== 'object') return { config, removed: false };
|
|
1477
|
+
let removed = false;
|
|
1478
|
+
// OpenCode 2's `mcp.servers.pan` as well as the v1 `mcp.pan` (R47).
|
|
1479
|
+
if (runtime === 'opencode' && isOpencodeV2Servers(bag.servers) && serverName in bag.servers) {
|
|
1480
|
+
delete bag.servers[serverName];
|
|
1481
|
+
if (Object.keys(bag.servers).length === 0) delete bag.servers;
|
|
1482
|
+
removed = true;
|
|
1483
|
+
}
|
|
1484
|
+
if (serverName in bag) { delete bag[serverName]; removed = true; }
|
|
1485
|
+
if (removed && Object.keys(bag).length === 0) delete config[spec.key];
|
|
1486
|
+
return { config, removed };
|
|
1385
1487
|
}
|
|
1386
1488
|
|
|
1387
1489
|
/**
|
|
@@ -1417,7 +1519,7 @@ function buildCodexMcpSnippet(serverPath, panToolsPath, projectRoot, serverName
|
|
|
1417
1519
|
* @returns {object} Merged config object to serialize back to hooks.json
|
|
1418
1520
|
*/
|
|
1419
1521
|
function mergeCodexHooksConfig(existing, commands) {
|
|
1420
|
-
const { updateCheckCommand, contextMonitorCommand, costLoggerCommand, traceLoggerCommand, stopGuardCommand, stateReinjectCommand } = commands || {};
|
|
1522
|
+
const { updateCheckCommand, contextMonitorCommand, costLoggerCommand, traceLoggerCommand, stopGuardCommand, stateReinjectCommand, guardCommand } = commands || {};
|
|
1421
1523
|
const config = (existing && typeof existing === 'object') ? existing : {};
|
|
1422
1524
|
if (!config.hooks || typeof config.hooks !== 'object') config.hooks = {};
|
|
1423
1525
|
|
|
@@ -1439,6 +1541,8 @@ function mergeCodexHooksConfig(existing, commands) {
|
|
|
1439
1541
|
// builders without reading their docs first.
|
|
1440
1542
|
const wanted = [
|
|
1441
1543
|
['SessionStart', updateCheckCommand, 'pan-check-update', true],
|
|
1544
|
+
// The guard decides whether a call may run, which an async handler cannot (A7).
|
|
1545
|
+
['PreToolUse', guardCommand, 'pan-guard', false],
|
|
1442
1546
|
['PostToolUse', contextMonitorCommand, 'pan-context-monitor', false],
|
|
1443
1547
|
['SubagentStop', costLoggerCommand, 'pan-cost-logger', true],
|
|
1444
1548
|
['SubagentStop', traceLoggerCommand, 'pan-trace-logger', true],
|
|
@@ -1482,7 +1586,7 @@ function removeCodexPanHooks(existing) {
|
|
|
1482
1586
|
for (const event of Object.keys(existing.hooks)) {
|
|
1483
1587
|
if (!Array.isArray(existing.hooks[event])) continue;
|
|
1484
1588
|
existing.hooks[event] = existing.hooks[event].filter(group =>
|
|
1485
|
-
!(Array.isArray(group.hooks) && group.hooks.some(h => h.command && /pan-(check-update|context-monitor|cost-logger|trace-logger|stop-guard|state-reinject)/.test(h.command))));
|
|
1589
|
+
!(Array.isArray(group.hooks) && group.hooks.some(h => h.command && /pan-(check-update|guard|context-monitor|cost-logger|trace-logger|stop-guard|state-reinject)/.test(h.command))));
|
|
1486
1590
|
if (existing.hooks[event].length === 0) delete existing.hooks[event];
|
|
1487
1591
|
}
|
|
1488
1592
|
if (Object.keys(existing.hooks).length === 0) delete existing.hooks;
|
|
@@ -1654,6 +1758,12 @@ function detectModelCapabilities(modelName) {
|
|
|
1654
1758
|
if (n.includes('sonnet-5')) {
|
|
1655
1759
|
return { has_1m_ctx: true, has_thinking: true, has_cache: true, tier: 'mid' };
|
|
1656
1760
|
}
|
|
1761
|
+
// Haiku 5 family (Haiku 5.5): 1M context and adaptive thinking (pricing page and
|
|
1762
|
+
// Claude Code 2.1.293 changelog, read 2026-10-10). It is a forward release, so
|
|
1763
|
+
// without this it took the fallback's Haiku profile, which is Haiku 4's.
|
|
1764
|
+
if (n.includes('haiku-5')) {
|
|
1765
|
+
return { has_1m_ctx: true, has_thinking: true, has_cache: true, tier: 'fast' };
|
|
1766
|
+
}
|
|
1657
1767
|
if (n.includes('opus-4-8') || n.includes('opus-4.8')
|
|
1658
1768
|
|| n.includes('opus-4-7') || n.includes('opus-4.7')
|
|
1659
1769
|
|| n.includes('opus-4-6') || n.includes('opus-4.6')) {
|
|
@@ -1673,10 +1783,9 @@ function detectModelCapabilities(modelName) {
|
|
|
1673
1783
|
if (n.includes('sonnet-4') && !isForwardRelease) {
|
|
1674
1784
|
return { has_1m_ctx: false, has_thinking: true, has_cache: true, tier: 'mid' };
|
|
1675
1785
|
}
|
|
1676
|
-
// Haiku 4.x — fast tier, no extended thinking. Guarded for the same reason
|
|
1677
|
-
//
|
|
1678
|
-
//
|
|
1679
|
-
// either way. The guard is here so that stops being true only deliberately.
|
|
1786
|
+
// Haiku 4.x — fast tier, no extended thinking. Guarded for the same reason: a
|
|
1787
|
+
// Haiku release newer than 4.5 takes the fallback's modern Haiku profile, which
|
|
1788
|
+
// since Haiku 5.5 has 1M context and thinking.
|
|
1680
1789
|
if ((n.includes('haiku-4-5') || n.includes('haiku-4.5') || n.includes('haiku-4')) && !isForwardRelease) {
|
|
1681
1790
|
return { has_1m_ctx: false, has_thinking: false, has_cache: true, tier: 'fast' };
|
|
1682
1791
|
}
|
|
@@ -1749,7 +1858,8 @@ function detectModelCapabilities(modelName) {
|
|
|
1749
1858
|
const MODERN = {
|
|
1750
1859
|
opus: { has_1m_ctx: true, has_thinking: true, has_cache: true, tier: 'reasoning' },
|
|
1751
1860
|
sonnet: { has_1m_ctx: true, has_thinking: true, has_cache: true, tier: 'mid' },
|
|
1752
|
-
|
|
1861
|
+
// Haiku 5.5 (the branch above) is the newest Haiku with known capabilities.
|
|
1862
|
+
haiku: { has_1m_ctx: true, has_thinking: true, has_cache: true, tier: 'fast' },
|
|
1753
1863
|
};
|
|
1754
1864
|
return { ...MODERN[family] };
|
|
1755
1865
|
}
|
|
@@ -1901,15 +2011,16 @@ function buildPluginManifest(pkg) {
|
|
|
1901
2011
|
* @returns {object} hooks.json object
|
|
1902
2012
|
*/
|
|
1903
2013
|
function buildPluginHooksConfig() {
|
|
1904
|
-
const hook = (script, matcher) => ({
|
|
2014
|
+
const hook = (script, matcher, args = '') => ({
|
|
1905
2015
|
...(matcher ? { matcher } : {}),
|
|
1906
|
-
hooks: [{ type: 'command', command: `node "\${CLAUDE_PLUGIN_ROOT}/hooks/${script}"` }],
|
|
2016
|
+
hooks: [{ type: 'command', command: `node "\${CLAUDE_PLUGIN_ROOT}/hooks/${script}"${args}` }],
|
|
1907
2017
|
});
|
|
1908
2018
|
const events = HOOK_EVENT_MAP.claude;
|
|
1909
2019
|
return {
|
|
1910
2020
|
hooks: {
|
|
1911
2021
|
// compact shares SessionStart with the update check, narrowed by its matcher (M10).
|
|
1912
2022
|
[events.sessionStart]: [hook('pan-check-update.js'), hook('pan-state-reinject.js', HOOK_SLOT_MATCHERS.compact)],
|
|
2023
|
+
[events.preToolUse]: [hook('pan-guard.js', null, ' --host claude')],
|
|
1913
2024
|
[events.postToolUse]: [hook('pan-context-monitor.js')],
|
|
1914
2025
|
[events.subagentStop]: [hook('pan-cost-logger.js'), hook('pan-trace-logger.js')],
|
|
1915
2026
|
[events.stop]: [hook('pan-stop-guard.js')],
|
|
@@ -2035,11 +2146,11 @@ so the result is greppable out of the transcript.
|
|
|
2035
2146
|
/**
|
|
2036
2147
|
* Build the plugin's MCP registration (`.mcp.json` at the plugin root).
|
|
2037
2148
|
*
|
|
2038
|
-
* Plugins may declare MCP servers in a plugin-root `.mcp.json
|
|
2039
|
-
*
|
|
2040
|
-
*
|
|
2041
|
-
*
|
|
2042
|
-
*
|
|
2149
|
+
* Plugins may declare MCP servers in a plugin-root `.mcp.json`. Hook and MCP
|
|
2150
|
+
* *configs* are the documented place `${CLAUDE_PLUGIN_ROOT}` is substituted (it
|
|
2151
|
+
* expands in plugin command markdown too: measured 2026-08-14, which lifted the
|
|
2152
|
+
* marketplace-publishing gate). So the same form `buildPluginHooksConfig()` relies
|
|
2153
|
+
* on is correct here.
|
|
2043
2154
|
*
|
|
2044
2155
|
* No `env` block: a plugin serves whatever project the session is in, so pinning
|
|
2045
2156
|
* PAN_PROJECT_ROOT would be wrong, and the server resolves its engine from its
|
|
@@ -2097,7 +2208,7 @@ function buildNativeWorkflowScripts() {
|
|
|
2097
2208
|
const reviewPipeline = `export const meta = {
|
|
2098
2209
|
name: 'pan-review-pipeline',
|
|
2099
2210
|
description: 'PAN deep review: reviewer + hardener fan-out, meta-reviewer merge',
|
|
2100
|
-
whenToUse: 'Deterministic version of the /pan
|
|
2211
|
+
whenToUse: 'Deterministic version of the /pan:review-deep fan-out. Pass the phase number or a description of the change set as args.',
|
|
2101
2212
|
phases: [
|
|
2102
2213
|
{ title: 'Find', detail: 'reviewer + security hardener in parallel' },
|
|
2103
2214
|
{ title: 'Merge', detail: 'meta-reviewer dedupes, disputes, and issues the verdict' },
|
|
@@ -2119,7 +2230,7 @@ const FINDINGS = {
|
|
|
2119
2230
|
properties: {
|
|
2120
2231
|
title: { type: 'string' },
|
|
2121
2232
|
file: { type: 'string' },
|
|
2122
|
-
severity: { type: 'string', enum: ['critical', '
|
|
2233
|
+
severity: { type: 'string', enum: ['critical', 'high', 'medium', 'low', 'info'] }, // PAN's one ladder (verdict.cjs, review-deep.cjs)
|
|
2123
2234
|
detail: { type: 'string' },
|
|
2124
2235
|
},
|
|
2125
2236
|
required: ['title', 'severity', 'detail'],
|
|
@@ -2162,7 +2273,7 @@ return merged
|
|
|
2162
2273
|
const mapCodebase = `export const meta = {
|
|
2163
2274
|
name: 'pan-map-codebase',
|
|
2164
2275
|
description: 'PAN codebase mapping: shard fan-out per top-level area, then synthesis',
|
|
2165
|
-
whenToUse: 'Deterministic version of the /pan
|
|
2276
|
+
whenToUse: 'Deterministic version of the /pan:map-codebase shard pattern for repositories too large for a single pass.',
|
|
2166
2277
|
phases: [
|
|
2167
2278
|
{ title: 'Scan', detail: 'discover top-level areas worth documenting' },
|
|
2168
2279
|
{ title: 'Map', detail: 'one documenter per area, in parallel' },
|
|
@@ -2223,11 +2334,12 @@ return { areas_mapped: maps.filter(Boolean).length, synthesis }
|
|
|
2223
2334
|
const execWaves = `export const meta = {
|
|
2224
2335
|
name: 'pan-exec-waves',
|
|
2225
2336
|
description: 'PAN phase execution: wave-grouped executor fan-out for a checkpoint-free phase, then verification',
|
|
2226
|
-
whenToUse: 'Deterministic version of the /pan
|
|
2337
|
+
whenToUse: 'Deterministic version of the /pan:exec-phase wave dispatch. Pass the phase number as args. Refuses a phase that contains checkpoint plans (a workflow cannot pause for a human) — run /pan:exec-phase for those.',
|
|
2227
2338
|
phases: [
|
|
2228
2339
|
{ title: 'Index', detail: 'plan inventory with wave grouping, from the PAN engine' },
|
|
2229
2340
|
{ title: 'Execute', detail: 'one executor per plan; waves in order, plans within a wave in parallel' },
|
|
2230
2341
|
{ title: 'Verify', detail: 'the phase verifier over the completed plans' },
|
|
2342
|
+
{ title: 'Gate', detail: 'the PAN phase gate: stops when the phase may not be completed' },
|
|
2231
2343
|
],
|
|
2232
2344
|
}
|
|
2233
2345
|
// twin: pan-wizard-core/workflows/exec-phase.md
|
|
@@ -2249,6 +2361,7 @@ const INDEX = {
|
|
|
2249
2361
|
phase_name: { type: 'string' },
|
|
2250
2362
|
phase_dir: { type: 'string' },
|
|
2251
2363
|
parallelization: { type: 'boolean' },
|
|
2364
|
+
verifier_enabled: { type: 'boolean' },
|
|
2252
2365
|
has_checkpoints: { type: 'boolean' },
|
|
2253
2366
|
plans: {
|
|
2254
2367
|
type: 'array',
|
|
@@ -2269,11 +2382,11 @@ const INDEX = {
|
|
|
2269
2382
|
required: ['phase_found', 'has_checkpoints', 'plans'],
|
|
2270
2383
|
}
|
|
2271
2384
|
const index = await agent(
|
|
2272
|
-
'Index phase ' + phaseArg + ' for execution using the ' + PAN_TOOLS + ' Run two verbs and merge their JSON: (1) init execute-phase ' + phaseArg + ' — take phase_found, phase_number, phase_name, phase_dir, parallelization; (2) phase-plan-index ' + phaseArg + ' — take has_checkpoints and plans[] (id, wave, autonomous, has_summary, objective; include each plan file path as file). Do not execute anything; return only the merged index.',
|
|
2385
|
+
'Index phase ' + phaseArg + ' for execution using the ' + PAN_TOOLS + ' Run two verbs and merge their JSON: (1) init execute-phase ' + phaseArg + ' — take phase_found, phase_number, phase_name, phase_dir, parallelization, verifier_enabled; (2) phase-plan-index ' + phaseArg + ' — take has_checkpoints and plans[] (id, wave, autonomous, has_summary, objective; include each plan file path as file). Do not execute anything; return only the merged index.',
|
|
2273
2386
|
{ label: 'index', phase: 'Index', schema: INDEX })
|
|
2274
2387
|
if (!index || !index.phase_found) return { error: 'phase ' + phaseArg + ' not found' }
|
|
2275
2388
|
if (index.has_checkpoints) {
|
|
2276
|
-
return { error: 'phase ' + phaseArg + ' contains checkpoint plans (autonomous: false). A workflow cannot pause for a human — run /pan
|
|
2389
|
+
return { error: 'phase ' + phaseArg + ' contains checkpoint plans (autonomous: false). A workflow cannot pause for a human — run /pan:exec-phase ' + phaseArg + ' instead.', plans: index.plans.map(p => p.id) }
|
|
2277
2390
|
}
|
|
2278
2391
|
const pending = index.plans.filter(p => !p.has_summary)
|
|
2279
2392
|
if (pending.length === 0) return { phase: phaseArg, done: true, message: 'every plan already has a summary — nothing to execute' }
|
|
@@ -2297,7 +2410,7 @@ const EXEC_RESULT = {
|
|
|
2297
2410
|
const executorPrompt = (p) =>
|
|
2298
2411
|
'Execute plan ' + p.id + ' of phase ' + (index.phase_number || phaseArg) + (index.phase_name ? '-' + index.phase_name : '') + '. Commit each task atomically. Create summary.md. Update state.md and roadmap.md (via roadmap update-plan-progress).\\n\\n'
|
|
2299
2412
|
+ 'Read first, in this order: ' + CORE_DOCS + '\\n\\n'
|
|
2300
|
-
+ 'Then read: ' + (p.file || (index.phase_dir + '/' + p.id)) + ' (the plan), .planning/state.md, .planning/config.json (if present), ./CLAUDE.md (if present — follow its conventions), .agents/skills/ (if present — follow relevant skills)
|
|
2413
|
+
+ 'Then read: ' + (p.file || (index.phase_dir + '/' + p.id)) + ' (the plan), .planning/state.md, .planning/config.json (if present), ./CLAUDE.md (if present — follow its conventions), and .agents/skills/ (if present — follow relevant skills).\\n\\n'
|
|
2301
2414
|
+ 'Report plan_id, status (complete | failed | checkpoint), summary_path, the number of commits you made, and self_check (passed if your summary carries no "Self-Check: FAILED" marker).'
|
|
2302
2415
|
const executed = []
|
|
2303
2416
|
let halted = null
|
|
@@ -2326,7 +2439,11 @@ for (const w of waveNumbers) {
|
|
|
2326
2439
|
}
|
|
2327
2440
|
}
|
|
2328
2441
|
if (halted) {
|
|
2329
|
-
return { phase: phaseArg, halted, executed, next: 'Inspect the failed plan(s), then re-run /pan-exec-waves ' + phaseArg + ' (completed plans are skipped) or fall back to /pan
|
|
2442
|
+
return { phase: phaseArg, halted, executed, next: 'Inspect the failed plan(s), then re-run /pan-exec-waves ' + phaseArg + ' (completed plans are skipped) or fall back to /pan:exec-phase ' + phaseArg }
|
|
2443
|
+
}
|
|
2444
|
+
// workflow.verifier: false (/pan:settings) turns the phase verifier off, as in exec-phase.
|
|
2445
|
+
if (index.verifier_enabled === false) {
|
|
2446
|
+
return { phase: phaseArg, waves_run: waveNumbers.length, plans_complete: executed.length, verification: null, next: 'Verification skipped: workflow.verifier is off. /pan:verify-phase ' + phaseArg + ' verifies on demand; then continue with /pan:exec-phase ' + phaseArg + ' (transition)' }
|
|
2330
2447
|
}
|
|
2331
2448
|
|
|
2332
2449
|
phase('Verify')
|
|
@@ -2344,13 +2461,30 @@ const verdict = await agent(
|
|
|
2344
2461
|
'Verify phase ' + phaseArg + ' following the PAN verify-phase protocol (PAN core: workflows/verify-phase.md — ' + PAN_TOOLS + '). Check the phase goals against what the plans delivered, write the verification file the protocol prescribes, and report status (passed | gaps_found | human_needed | failed), the verification file path, any gaps, and a summary. Do not mark the phase complete or advance state — that decision stays with the user.',
|
|
2345
2462
|
{ agentType: 'pan-verifier', label: 'verify', phase: 'Verify', schema: VERIFY })
|
|
2346
2463
|
|
|
2347
|
-
|
|
2464
|
+
phase('Gate')
|
|
2465
|
+
const GATE = {
|
|
2466
|
+
type: 'object',
|
|
2467
|
+
properties: {
|
|
2468
|
+
ok: { type: 'boolean' },
|
|
2469
|
+
mode: { type: 'string' },
|
|
2470
|
+
reasons: { type: 'array', items: { type: 'object', properties: { code: { type: 'string' }, detail: { type: 'string' } }, required: ['code'] } },
|
|
2471
|
+
},
|
|
2472
|
+
required: ['ok', 'reasons'],
|
|
2473
|
+
}
|
|
2474
|
+
const gate = await agent(
|
|
2475
|
+
'Run the PAN phase gate for phase ' + phaseArg + ' with the ' + PAN_TOOLS + ' Run exactly: phase gate ' + phaseArg + ' (it exits 1 when it refuses; that is a result, not an error). Return its JSON fields ok, mode and reasons (each code and detail) unchanged. Do not fix anything and do not mark the phase complete.',
|
|
2476
|
+
{ label: 'gate', phase: 'Gate', schema: GATE })
|
|
2477
|
+
const gateReasons = gate && Array.isArray(gate.reasons) ? gate.reasons : []
|
|
2478
|
+
if (!gate || gate.ok !== true) {
|
|
2479
|
+
return { phase: phaseArg, waves_run: waveNumbers.length, plans_complete: executed.length, verification: verdict, gate, halted: 'phase_gate', next: 'The phase gate refused: ' + (gateReasons.map((r) => r.code).join(', ') || 'the gate step returned no verdict') + '. Fix each reason (or close the gaps with /pan:plan-phase ' + phaseArg + ' --gaps), then re-run /pan:exec-phase ' + phaseArg + '. Do not mark the phase complete until the gate passes.' }
|
|
2480
|
+
}
|
|
2481
|
+
return { phase: phaseArg, waves_run: waveNumbers.length, plans_complete: executed.length, verification: verdict, gate, next: 'The phase gate passes. Continue with /pan:exec-phase ' + phaseArg + ' (transition) or /pan:plan-phase for the next phase' }
|
|
2348
2482
|
`;
|
|
2349
2483
|
|
|
2350
2484
|
const diagnoseIssues = `export const meta = {
|
|
2351
2485
|
name: 'pan-diagnose-issues',
|
|
2352
2486
|
description: 'PAN UAT diagnosis: one debugger per failed UAT truth, in parallel, then root causes written back',
|
|
2353
|
-
whenToUse: 'Deterministic version of
|
|
2487
|
+
whenToUse: 'Deterministic version of the diagnose-issues workflow. Pass the phase number as args. Investigates only — fixes come from /pan:plan-phase --gaps.',
|
|
2354
2488
|
phases: [
|
|
2355
2489
|
{ title: 'Gaps', detail: 'read the phase UAT file and list the failed truths' },
|
|
2356
2490
|
{ title: 'Diagnose', detail: 'one pan-debugger per gap, in parallel, root cause only' },
|
|
@@ -2404,6 +2538,7 @@ const DIAGNOSIS = {
|
|
|
2404
2538
|
issue_id: { type: 'string' },
|
|
2405
2539
|
status: { type: 'string', enum: ['root_cause_found', 'inconclusive'] },
|
|
2406
2540
|
root_cause: { type: 'string' },
|
|
2541
|
+
reproduction: { type: 'string' },
|
|
2407
2542
|
evidence: { type: 'array', items: { type: 'string' } },
|
|
2408
2543
|
files: { type: 'array', items: { type: 'string' } },
|
|
2409
2544
|
suggested_fix: { type: 'string' },
|
|
@@ -2413,9 +2548,9 @@ const DIAGNOSIS = {
|
|
|
2413
2548
|
required: ['issue_id', 'status'],
|
|
2414
2549
|
}
|
|
2415
2550
|
const diagnoses = await parallel(gaps.map(g => () => agent(
|
|
2416
|
-
'Debug issue UAT-' + g.test_num + ' for phase ' + phaseArg + ' — root cause ONLY, do not fix (fixes come from /pan
|
|
2551
|
+
'Debug issue UAT-' + g.test_num + ' for phase ' + phaseArg + ' — root cause ONLY, do not fix (fixes come from /pan:plan-phase --gaps).\\n\\n'
|
|
2417
2552
|
+ 'Symptoms (pre-filled from UAT, treat as given): expected: ' + (g.expected || g.truth) + '. actual: ' + (g.reason || 'not recorded') + '. reproduction: test ' + g.test_num + ' in ' + found.uat_path + '. severity: ' + g.severity + '.\\n\\n'
|
|
2418
|
-
+ 'Follow the PAN debugger protocol: create the debug session file under .planning/debug/ named from the issue, investigate autonomously (read code, form hypotheses, test them), and report issue_id, status (root_cause_found | inconclusive), root_cause with evidence, files involved, a suggested fix direction, and the debug session path. If inconclusive, list the remaining possibilities. Also read ' + found.uat_path + ' and .planning/state.md for context.',
|
|
2553
|
+
+ 'Follow the PAN debugger protocol: create the debug session file under .planning/debug/ named from the issue, build and run a command that fails on the symptom before forming any hypothesis, investigate autonomously (read code, form hypotheses, test them), and report issue_id, status (root_cause_found | inconclusive), the reproduction command (or none, with what you tried), root_cause with evidence, files involved, a suggested fix direction, and the debug session path. If inconclusive, list the remaining possibilities. Also read ' + found.uat_path + ' and .planning/state.md for context.',
|
|
2419
2554
|
{ agentType: 'pan-debugger', label: 'debug:UAT-' + g.test_num, phase: 'Diagnose', schema: DIAGNOSIS })))
|
|
2420
2555
|
const results = diagnoses.filter(Boolean)
|
|
2421
2556
|
log(results.filter(r => r.status === 'root_cause_found').length + ' root cause(s) found, ' + results.filter(r => r.status === 'inconclusive').length + ' inconclusive')
|
|
@@ -2427,10 +2562,10 @@ const RECORDED = {
|
|
|
2427
2562
|
required: ['uat_path', 'gaps_updated'],
|
|
2428
2563
|
}
|
|
2429
2564
|
const recorded = await agent(
|
|
2430
|
-
'Update the Gaps section of ' + found.uat_path + ' with these diagnoses, following the PAN diagnose-issues protocol: for each gap add root_cause, artifacts (
|
|
2565
|
+
'Update the Gaps section of ' + found.uat_path + ' with these diagnoses, following the PAN diagnose-issues protocol: for each gap add root_cause, artifacts (each file involved, with its issue), missing (the suggested fix direction) and debug_session (the debug session path); mark inconclusive ones as needing manual review with their remaining possibilities. Edit the Gaps section in place and set the frontmatter status to diagnosed (the --gaps mode of pan-planner reads UAT gaps only from a diagnosed file); do not rewrite other content. Report the path and how many gaps you updated.\\n\\nDiagnoses:\\n' + JSON.stringify(results, null, 2),
|
|
2431
2566
|
{ label: 'record', phase: 'Record', schema: RECORDED })
|
|
2432
2567
|
|
|
2433
|
-
return { phase: phaseArg, uat_path: found.uat_path, gaps: gaps.length, root_causes_found: results.filter(r => r.status === 'root_cause_found').length, inconclusive: results.filter(r => r.status === 'inconclusive').length, recorded, next: 'Run /pan
|
|
2568
|
+
return { phase: phaseArg, uat_path: found.uat_path, gaps: gaps.length, root_causes_found: results.filter(r => r.status === 'root_cause_found').length, inconclusive: results.filter(r => r.status === 'inconclusive').length, recorded, next: 'Run /pan:plan-phase ' + phaseArg + ' --gaps to plan the fixes' }
|
|
2434
2569
|
`;
|
|
2435
2570
|
|
|
2436
2571
|
return [
|
|
@@ -2525,6 +2660,8 @@ module.exports = {
|
|
|
2525
2660
|
buildMcpServerEntry,
|
|
2526
2661
|
mergeMcpRegistration,
|
|
2527
2662
|
stripMcpRegistration,
|
|
2663
|
+
addOpencodePermissions,
|
|
2664
|
+
stripOpencodePermissions,
|
|
2528
2665
|
buildCodexMcpSnippet,
|
|
2529
2666
|
removeCodexPanHooks,
|
|
2530
2667
|
buildNativeWorkflowScripts,
|
|
@@ -2532,6 +2669,7 @@ module.exports = {
|
|
|
2532
2669
|
rewriteUnifiedSkillCommandContent,
|
|
2533
2670
|
rewriteSharedCoreMarkdown,
|
|
2534
2671
|
rewriteAgentReferenceCopy,
|
|
2672
|
+
rewriteAgentFileRefs,
|
|
2535
2673
|
stripInternalLearningsTopics,
|
|
2536
2674
|
AGENT_PLUGINS_VERSION,
|
|
2537
2675
|
AGENT_PLUGIN_MANIFEST_SCHEMA,
|