pan-wizard 3.34.0 → 3.36.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 +16 -10
- package/agents/pan-conductor.md +2 -2
- package/agents/pan-debugger.md +3 -1
- package/agents/pan-design-checker.md +1 -0
- package/agents/pan-designer.md +1 -1
- package/agents/pan-executor.md +43 -1
- package/agents/pan-experiment-runner.md +1 -1
- package/agents/pan-hardener.md +3 -1
- package/agents/pan-meta-reviewer.md +1 -1
- package/agents/pan-phase-researcher.md +16 -2
- package/agents/pan-plan-checker.md +37 -9
- package/agents/pan-planner.md +14 -2
- package/agents/pan-previewer.md +2 -0
- package/agents/pan-project-researcher.md +9 -1
- package/agents/pan-research-synthesizer.md +1 -1
- package/agents/pan-reviewer.md +8 -2
- package/agents/pan-verifier.md +3 -3
- package/bin/install-lib.cjs +119 -16
- package/bin/install.js +34 -62
- package/commands/pan/cost.md +21 -5
- package/commands/pan/dashboard.md +0 -3
- package/commands/pan/design-phase.md +2 -2
- package/commands/pan/hud.md +1 -5
- package/commands/pan/knowledge.md +0 -1
- package/commands/pan/mcp-bridge.md +1 -3
- package/commands/pan/optimize.md +2 -0
- package/commands/pan/phase-tests.md +1 -1
- package/commands/pan/preview.md +2 -3
- package/commands/pan/report.md +1 -5
- package/commands/pan/research-phase.md +4 -4
- package/commands/pan/review-deep.md +0 -2
- package/commands/pan/what-if.md +1 -2
- package/hooks/dist/pan-context-monitor.js +12 -3
- package/hooks/dist/pan-guard.js +244 -0
- package/hooks/dist/pan-statusline.js +5 -2
- package/package.json +1 -1
- package/pan-wizard-core/bin/lib/commands.cjs +24 -2
- package/pan-wizard-core/bin/lib/config.cjs +13 -1
- package/pan-wizard-core/bin/lib/core.cjs +9 -4
- package/pan-wizard-core/bin/lib/cost.cjs +146 -0
- package/pan-wizard-core/bin/lib/doc-lint.cjs +5 -3
- package/pan-wizard-core/bin/lib/findings.cjs +239 -23
- package/pan-wizard-core/bin/lib/git.cjs +1 -1
- package/pan-wizard-core/bin/lib/hygiene.cjs +11 -5
- package/pan-wizard-core/bin/lib/init.cjs +6 -0
- package/pan-wizard-core/bin/lib/mutate.cjs +257 -0
- package/pan-wizard-core/bin/lib/optimize.cjs +13 -1
- package/pan-wizard-core/bin/lib/phase-gate.cjs +180 -0
- package/pan-wizard-core/bin/lib/phase-remove.cjs +91 -11
- package/pan-wizard-core/bin/lib/phase.cjs +61 -9
- package/pan-wizard-core/bin/lib/plan-lint.cjs +161 -0
- package/pan-wizard-core/bin/lib/preview.cjs +35 -31
- package/pan-wizard-core/bin/lib/research-lint.cjs +121 -0
- package/pan-wizard-core/bin/lib/roadmap.cjs +1 -0
- package/pan-wizard-core/bin/lib/test-gate.cjs +433 -0
- package/pan-wizard-core/bin/lib/usage.cjs +104 -0
- 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-red.cjs +138 -0
- package/pan-wizard-core/bin/lib/verify-scope.cjs +148 -6
- package/pan-wizard-core/bin/lib/verify.cjs +27 -27
- package/pan-wizard-core/bin/lib/whatif.cjs +48 -6
- package/pan-wizard-core/bin/pan-tools.cjs +106 -9
- package/pan-wizard-core/mcp/merge-gate.cjs +14 -3
- package/pan-wizard-core/mcp/native-tools.cjs +3 -3
- package/pan-wizard-core/mcp/orchestrator.cjs +4 -1
- package/pan-wizard-core/opencode/pan-wizard.js +36 -8
- package/pan-wizard-core/references/design-methodology.md +1 -1
- package/pan-wizard-core/references/handoff-decisions.md +1 -1
- package/pan-wizard-core/references/model-profiles.md +1 -1
- package/pan-wizard-core/references/planning-config.md +3 -3
- package/pan-wizard-core/references/verdict-contract.md +6 -1
- package/pan-wizard-core/templates/config.json +6 -6
- package/pan-wizard-core/templates/debug-subagent-prompt.md +2 -1
- package/pan-wizard-core/templates/design.md +5 -4
- package/pan-wizard-core/templates/phase-prompt.md +9 -0
- package/pan-wizard-core/templates/planner-subagent-prompt.md +2 -0
- package/pan-wizard-core/templates/preview-report.md +1 -1
- package/pan-wizard-core/templates/research-project/architecture.md +6 -0
- package/pan-wizard-core/templates/research-project/features.md +6 -0
- package/pan-wizard-core/templates/research-project/pitfalls.md +6 -0
- package/pan-wizard-core/templates/research-project/stack.md +6 -0
- package/pan-wizard-core/templates/research.md +10 -0
- package/pan-wizard-core/templates/state.md +4 -4
- package/pan-wizard-core/templates/summary-complex.md +5 -1
- package/pan-wizard-core/templates/summary-minimal.md +4 -0
- package/pan-wizard-core/templates/summary-standard.md +5 -1
- package/pan-wizard-core/templates/summary.md +8 -1
- package/pan-wizard-core/workflows/diagnose-issues.md +4 -4
- package/pan-wizard-core/workflows/discuss-phase.md +2 -1
- package/pan-wizard-core/workflows/exec-phase.md +92 -45
- package/pan-wizard-core/workflows/execute-plan.md +3 -1
- package/pan-wizard-core/workflows/help.md +103 -44
- package/pan-wizard-core/workflows/milestone-gaps.md +2 -2
- package/pan-wizard-core/workflows/new-project.md +8 -16
- package/pan-wizard-core/workflows/plan-phase.md +40 -8
- package/pan-wizard-core/workflows/progress.md +1 -1
- package/pan-wizard-core/workflows/quick.md +2 -2
- package/pan-wizard-core/workflows/remove-phase.md +11 -1
- package/pan-wizard-core/workflows/settings.md +17 -0
- package/pan-wizard-core/workflows/todo-check.md +3 -2
- package/pan-wizard-core/workflows/transition.md +4 -0
- package/pan-wizard-core/workflows/verify-phase.md +40 -47
- package/scripts/build-help.cjs +106 -0
- package/scripts/build-hooks.js +1 -0
- package/scripts/generate-skills-docs.py +2 -2
- package/scripts/mutation-probe.cjs +7 -80
- package/scripts/prompt-lint.cjs +167 -0
- package/scripts/test-surface.cjs +169 -6
package/bin/install-lib.cjs
CHANGED
|
@@ -1160,11 +1160,16 @@ function stripThinkingFrontmatter(content, runtime) {
|
|
|
1160
1160
|
*/
|
|
1161
1161
|
function buildCopilotHooksConfig(commands) {
|
|
1162
1162
|
const { updateCheckCommand, contextMonitorCommand, costLoggerCommand, traceLoggerCommand, stopGuardCommand,
|
|
1163
|
-
stateReinjectMarkCommand, stateReinjectInjectCommand } = commands || {};
|
|
1163
|
+
stateReinjectMarkCommand, stateReinjectInjectCommand, guardCommand } = commands || {};
|
|
1164
1164
|
const config = { version: 1, hooks: {} };
|
|
1165
1165
|
if (updateCheckCommand) {
|
|
1166
1166
|
config.hooks.sessionStart = [{ type: 'command', command: updateCheckCommand }];
|
|
1167
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
|
+
}
|
|
1168
1173
|
const postToolUse = [];
|
|
1169
1174
|
if (contextMonitorCommand) postToolUse.push({ type: 'command', command: contextMonitorCommand });
|
|
1170
1175
|
// State re-injection after a compaction (M33): preCompact leaves the marker, the
|
|
@@ -1238,10 +1243,10 @@ function buildCopilotHooksConfig(commands) {
|
|
|
1238
1243
|
* 2026-10-03, and live on Copilot CLI 1.0.88 the same day).
|
|
1239
1244
|
*/
|
|
1240
1245
|
const HOOK_EVENT_MAP = Object.freeze({
|
|
1241
|
-
claude: { surface: 'settings.json', sessionStart: 'SessionStart', postToolUse: 'PostToolUse', subagentStop: 'SubagentStop', stop: 'Stop', compact: 'SessionStart', compactMark: null, compactInject: null },
|
|
1242
|
-
gemini: { surface: 'settings.json', sessionStart: 'SessionStart', postToolUse: null, subagentStop: null, stop: 'AfterAgent', compact: null, compactMark: 'PreCompress', compactInject: 'AfterTool' },
|
|
1243
|
-
codex: { surface: 'hooks.json', sessionStart: 'SessionStart', postToolUse: 'PostToolUse', subagentStop: 'SubagentStop', stop: 'Stop', compact: 'SessionStart', compactMark: null, compactInject: null },
|
|
1244
|
-
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' },
|
|
1245
1250
|
opencode: null,
|
|
1246
1251
|
});
|
|
1247
1252
|
|
|
@@ -1253,7 +1258,7 @@ const HOOK_EVENT_MAP = Object.freeze({
|
|
|
1253
1258
|
const HOOK_SLOT_MATCHERS = Object.freeze({ compact: 'compact' });
|
|
1254
1259
|
|
|
1255
1260
|
/** The hook scripts PAN registers in a Claude-shaped settings.json `hooks` block. */
|
|
1256
|
-
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']);
|
|
1257
1262
|
|
|
1258
1263
|
/**
|
|
1259
1264
|
* Remove, from every event array of a Claude-shaped `hooks` object except
|
|
@@ -1384,10 +1389,78 @@ function mergeMcpRegistration(existing, runtime, entry, serverName = 'pan') {
|
|
|
1384
1389
|
const config = (existing && typeof existing === 'object' && !Array.isArray(existing)) ? existing : {};
|
|
1385
1390
|
const key = spec.key;
|
|
1386
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
|
+
}
|
|
1387
1400
|
config[key][serverName] = entry;
|
|
1388
1401
|
return config;
|
|
1389
1402
|
}
|
|
1390
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
|
+
|
|
1391
1464
|
/**
|
|
1392
1465
|
* Remove PAN's MCP server from a config object, preserving foreign entries.
|
|
1393
1466
|
* Empties the container key when PAN was its only member, so uninstall does not
|
|
@@ -1400,10 +1473,17 @@ function stripMcpRegistration(existing, runtime, serverName = 'pan') {
|
|
|
1400
1473
|
if (!spec) throw new Error(`stripMcpRegistration: unknown runtime "${runtime}"`);
|
|
1401
1474
|
const config = (existing && typeof existing === 'object' && !Array.isArray(existing)) ? existing : {};
|
|
1402
1475
|
const bag = config[spec.key];
|
|
1403
|
-
if (!bag || typeof bag !== 'object'
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
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 };
|
|
1407
1487
|
}
|
|
1408
1488
|
|
|
1409
1489
|
/**
|
|
@@ -1439,7 +1519,7 @@ function buildCodexMcpSnippet(serverPath, panToolsPath, projectRoot, serverName
|
|
|
1439
1519
|
* @returns {object} Merged config object to serialize back to hooks.json
|
|
1440
1520
|
*/
|
|
1441
1521
|
function mergeCodexHooksConfig(existing, commands) {
|
|
1442
|
-
const { updateCheckCommand, contextMonitorCommand, costLoggerCommand, traceLoggerCommand, stopGuardCommand, stateReinjectCommand } = commands || {};
|
|
1522
|
+
const { updateCheckCommand, contextMonitorCommand, costLoggerCommand, traceLoggerCommand, stopGuardCommand, stateReinjectCommand, guardCommand } = commands || {};
|
|
1443
1523
|
const config = (existing && typeof existing === 'object') ? existing : {};
|
|
1444
1524
|
if (!config.hooks || typeof config.hooks !== 'object') config.hooks = {};
|
|
1445
1525
|
|
|
@@ -1461,6 +1541,8 @@ function mergeCodexHooksConfig(existing, commands) {
|
|
|
1461
1541
|
// builders without reading their docs first.
|
|
1462
1542
|
const wanted = [
|
|
1463
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],
|
|
1464
1546
|
['PostToolUse', contextMonitorCommand, 'pan-context-monitor', false],
|
|
1465
1547
|
['SubagentStop', costLoggerCommand, 'pan-cost-logger', true],
|
|
1466
1548
|
['SubagentStop', traceLoggerCommand, 'pan-trace-logger', true],
|
|
@@ -1504,7 +1586,7 @@ function removeCodexPanHooks(existing) {
|
|
|
1504
1586
|
for (const event of Object.keys(existing.hooks)) {
|
|
1505
1587
|
if (!Array.isArray(existing.hooks[event])) continue;
|
|
1506
1588
|
existing.hooks[event] = existing.hooks[event].filter(group =>
|
|
1507
|
-
!(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))));
|
|
1508
1590
|
if (existing.hooks[event].length === 0) delete existing.hooks[event];
|
|
1509
1591
|
}
|
|
1510
1592
|
if (Object.keys(existing.hooks).length === 0) delete existing.hooks;
|
|
@@ -1929,15 +2011,16 @@ function buildPluginManifest(pkg) {
|
|
|
1929
2011
|
* @returns {object} hooks.json object
|
|
1930
2012
|
*/
|
|
1931
2013
|
function buildPluginHooksConfig() {
|
|
1932
|
-
const hook = (script, matcher) => ({
|
|
2014
|
+
const hook = (script, matcher, args = '') => ({
|
|
1933
2015
|
...(matcher ? { matcher } : {}),
|
|
1934
|
-
hooks: [{ type: 'command', command: `node "\${CLAUDE_PLUGIN_ROOT}/hooks/${script}"` }],
|
|
2016
|
+
hooks: [{ type: 'command', command: `node "\${CLAUDE_PLUGIN_ROOT}/hooks/${script}"${args}` }],
|
|
1935
2017
|
});
|
|
1936
2018
|
const events = HOOK_EVENT_MAP.claude;
|
|
1937
2019
|
return {
|
|
1938
2020
|
hooks: {
|
|
1939
2021
|
// compact shares SessionStart with the update check, narrowed by its matcher (M10).
|
|
1940
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')],
|
|
1941
2024
|
[events.postToolUse]: [hook('pan-context-monitor.js')],
|
|
1942
2025
|
[events.subagentStop]: [hook('pan-cost-logger.js'), hook('pan-trace-logger.js')],
|
|
1943
2026
|
[events.stop]: [hook('pan-stop-guard.js')],
|
|
@@ -2147,7 +2230,7 @@ const FINDINGS = {
|
|
|
2147
2230
|
properties: {
|
|
2148
2231
|
title: { type: 'string' },
|
|
2149
2232
|
file: { type: 'string' },
|
|
2150
|
-
severity: { type: 'string', enum: ['critical', '
|
|
2233
|
+
severity: { type: 'string', enum: ['critical', 'high', 'medium', 'low', 'info'] }, // PAN's one ladder (verdict.cjs, review-deep.cjs)
|
|
2151
2234
|
detail: { type: 'string' },
|
|
2152
2235
|
},
|
|
2153
2236
|
required: ['title', 'severity', 'detail'],
|
|
@@ -2256,6 +2339,7 @@ return { areas_mapped: maps.filter(Boolean).length, synthesis }
|
|
|
2256
2339
|
{ title: 'Index', detail: 'plan inventory with wave grouping, from the PAN engine' },
|
|
2257
2340
|
{ title: 'Execute', detail: 'one executor per plan; waves in order, plans within a wave in parallel' },
|
|
2258
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' },
|
|
2259
2343
|
],
|
|
2260
2344
|
}
|
|
2261
2345
|
// twin: pan-wizard-core/workflows/exec-phase.md
|
|
@@ -2377,7 +2461,24 @@ const verdict = await agent(
|
|
|
2377
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.',
|
|
2378
2462
|
{ agentType: 'pan-verifier', label: 'verify', phase: 'Verify', schema: VERIFY })
|
|
2379
2463
|
|
|
2380
|
-
|
|
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' }
|
|
2381
2482
|
`;
|
|
2382
2483
|
|
|
2383
2484
|
const diagnoseIssues = `export const meta = {
|
|
@@ -2559,6 +2660,8 @@ module.exports = {
|
|
|
2559
2660
|
buildMcpServerEntry,
|
|
2560
2661
|
mergeMcpRegistration,
|
|
2561
2662
|
stripMcpRegistration,
|
|
2663
|
+
addOpencodePermissions,
|
|
2664
|
+
stripOpencodePermissions,
|
|
2562
2665
|
buildCodexMcpSnippet,
|
|
2563
2666
|
removeCodexPanHooks,
|
|
2564
2667
|
buildNativeWorkflowScripts,
|
package/bin/install.js
CHANGED
|
@@ -369,13 +369,11 @@ function getCommitAttribution(runtime) {
|
|
|
369
369
|
const settings = readSettings(path.join(getGlobalDir('claude', explicitConfigDir), 'settings.json')) || {}; // unusable file = no info (read-only probe)
|
|
370
370
|
result = lib.commitAttributionFromSettings(settings);
|
|
371
371
|
} else if (runtime === 'copilot') {
|
|
372
|
-
// Copilot CLI: user
|
|
373
|
-
//
|
|
372
|
+
// Copilot CLI: user settings live in settings.json only. config.json is the CLI's
|
|
373
|
+
// internal state, and Copilot 1.0.93 ignores user settings there (R48), so a
|
|
374
|
+
// stale `attribution` left in it must not decide PAN's attribution.
|
|
374
375
|
const copilotDir = getGlobalDir('copilot', explicitConfigDir);
|
|
375
|
-
|
|
376
|
-
if (!config.attribution) {
|
|
377
|
-
config = readSettings(path.join(copilotDir, 'config.json')) || {}; // unusable file = no info (read-only probe)
|
|
378
|
-
}
|
|
376
|
+
const config = readSettings(path.join(copilotDir, 'settings.json')) || {}; // unusable file = no info (read-only probe)
|
|
379
377
|
if (!config.attribution || config.attribution.commit === undefined) {
|
|
380
378
|
result = undefined;
|
|
381
379
|
} else if (config.attribution.commit === '') {
|
|
@@ -1222,7 +1220,7 @@ function uninstall(isGlobal, runtime = 'claude') {
|
|
|
1222
1220
|
// 4. Remove PAN hooks (scripts + Copilot CLI hooks config file)
|
|
1223
1221
|
const hooksDir = path.join(targetDir, 'hooks');
|
|
1224
1222
|
if (fs.existsSync(hooksDir)) {
|
|
1225
|
-
const panHooks = ['pan-statusline.js', 'pan-check-update.js', 'pan-check-update.sh', 'pan-context-monitor.js', 'pan-cost-logger.js', 'pan-trace-logger.js', 'pan-stop-guard.js', 'pan-state-reinject.js', 'pan.json'];
|
|
1223
|
+
const panHooks = ['pan-statusline.js', 'pan-check-update.js', 'pan-check-update.sh', 'pan-guard.js', 'pan-context-monitor.js', 'pan-cost-logger.js', 'pan-trace-logger.js', 'pan-stop-guard.js', 'pan-state-reinject.js', 'pan.json'];
|
|
1226
1224
|
let hookCount = 0;
|
|
1227
1225
|
for (const hook of panHooks) {
|
|
1228
1226
|
const hookPath = path.join(hooksDir, hook);
|
|
@@ -1576,35 +1574,12 @@ function uninstall(isGlobal, runtime = 'claude') {
|
|
|
1576
1574
|
// CodeQL js/file-system-race. Same idiom as the hooks' metrics read.
|
|
1577
1575
|
try {
|
|
1578
1576
|
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
1579
|
-
let modified
|
|
1580
|
-
|
|
1581
|
-
// Remove PAN permission entries
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
const keys = Object.keys(config.permission[permType]);
|
|
1586
|
-
for (const key of keys) {
|
|
1587
|
-
// Match `pan-wizard` rather than `pan-wizard-core` so the malformed
|
|
1588
|
-
// key earlier versions wrote (`~/.config/opencode/pan-wizard/*`) is
|
|
1589
|
-
// cleaned too. Without this, machines that ran any global OpenCode
|
|
1590
|
-
// install before the glob was fixed keep that entry forever — the
|
|
1591
|
-
// uninstaller could never match it, which is what made it residue
|
|
1592
|
-
// rather than a cosmetic typo.
|
|
1593
|
-
if (key.includes('pan-wizard')) {
|
|
1594
|
-
delete config.permission[permType][key];
|
|
1595
|
-
modified = true;
|
|
1596
|
-
}
|
|
1597
|
-
}
|
|
1598
|
-
// Clean up empty objects
|
|
1599
|
-
if (Object.keys(config.permission[permType]).length === 0) {
|
|
1600
|
-
delete config.permission[permType];
|
|
1601
|
-
}
|
|
1602
|
-
}
|
|
1603
|
-
}
|
|
1604
|
-
if (Object.keys(config.permission).length === 0) {
|
|
1605
|
-
delete config.permission;
|
|
1606
|
-
}
|
|
1607
|
-
}
|
|
1577
|
+
let modified;
|
|
1578
|
+
|
|
1579
|
+
// Remove PAN permission entries, v1 `permission` keys and OpenCode 2
|
|
1580
|
+
// `permissions[]` rules alike (R47). Keys matching `pan-wizard` rather than
|
|
1581
|
+
// `pan-wizard-core` also clean the malformed key earlier versions wrote.
|
|
1582
|
+
({ modified } = lib.stripOpencodePermissions(config));
|
|
1608
1583
|
|
|
1609
1584
|
if (modified) {
|
|
1610
1585
|
// If stripping PAN permissions emptied the config, remove the file
|
|
@@ -1718,6 +1693,18 @@ function uninstall(isGlobal, runtime = 'claude') {
|
|
|
1718
1693
|
console.log(` ${yellow}⚠${reset} No PAN files found to remove.`);
|
|
1719
1694
|
}
|
|
1720
1695
|
|
|
1696
|
+
// A local install's runtime directory that the removal left empty goes too (X1).
|
|
1697
|
+
// Never a global one (~/.claude and the like are the host's own homes), and never a
|
|
1698
|
+
// directory that still holds anything: `.github` usually holds the project's files.
|
|
1699
|
+
if (!isGlobal) {
|
|
1700
|
+
try {
|
|
1701
|
+
if (fs.readdirSync(targetDir).length === 0) {
|
|
1702
|
+
fs.rmdirSync(targetDir);
|
|
1703
|
+
console.log(` ${green}✓${reset} Removed empty ${locationLabel}`);
|
|
1704
|
+
}
|
|
1705
|
+
} catch { /* already gone or unreadable: leave it */ }
|
|
1706
|
+
}
|
|
1707
|
+
|
|
1721
1708
|
console.log(`
|
|
1722
1709
|
${green}Done!${reset} PAN has been uninstalled from ${runtimeLabel}.
|
|
1723
1710
|
Your other files and settings have been preserved.
|
|
@@ -1760,10 +1747,6 @@ function configureOpencodePermissions(isGlobal = true) {
|
|
|
1760
1747
|
}
|
|
1761
1748
|
}
|
|
1762
1749
|
|
|
1763
|
-
// Ensure permission structure exists
|
|
1764
|
-
if (!config.permission) {
|
|
1765
|
-
config.permission = {};
|
|
1766
|
-
}
|
|
1767
1750
|
|
|
1768
1751
|
// Build the PAN path using the actual config directory
|
|
1769
1752
|
// Use ~ shorthand if it's in the default location, otherwise use full path
|
|
@@ -1780,25 +1763,9 @@ function configureOpencodePermissions(isGlobal = true) {
|
|
|
1780
1763
|
? '~/.config/opencode/pan-wizard-core/*'
|
|
1781
1764
|
: `${opencodeConfigDir.replace(/\\/g, '/')}/pan-wizard-core/*`;
|
|
1782
1765
|
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
if (!config.permission.read || typeof config.permission.read !== 'object') {
|
|
1787
|
-
config.permission.read = {};
|
|
1788
|
-
}
|
|
1789
|
-
if (config.permission.read[panPath] !== 'allow') {
|
|
1790
|
-
config.permission.read[panPath] = 'allow';
|
|
1791
|
-
modified = true;
|
|
1792
|
-
}
|
|
1793
|
-
|
|
1794
|
-
// Configure external_directory permission (the safety guard for paths outside project)
|
|
1795
|
-
if (!config.permission.external_directory || typeof config.permission.external_directory !== 'object') {
|
|
1796
|
-
config.permission.external_directory = {};
|
|
1797
|
-
}
|
|
1798
|
-
if (config.permission.external_directory[panPath] !== 'allow') {
|
|
1799
|
-
config.permission.external_directory[panPath] = 'allow';
|
|
1800
|
-
modified = true;
|
|
1801
|
-
}
|
|
1766
|
+
// v1 `permission` object in a new or v1 file; the native `permissions[]` array
|
|
1767
|
+
// in a file the user already converted to OpenCode 2, never both (R47).
|
|
1768
|
+
const { modified } = lib.addOpencodePermissions(config, panPath);
|
|
1802
1769
|
|
|
1803
1770
|
if (!modified) {
|
|
1804
1771
|
return; // Already configured
|
|
@@ -2785,6 +2752,10 @@ function install(isGlobal, runtime = 'claude') {
|
|
|
2785
2752
|
const stateReinjectCommand = isGlobal
|
|
2786
2753
|
? buildHookCommand(targetDir, 'pan-state-reinject.js')
|
|
2787
2754
|
: 'node ' + dirName + '/hooks/pan-state-reinject.js';
|
|
2755
|
+
// The guard names its host: payloads and the way to deny differ per runtime (A7).
|
|
2756
|
+
const guardCommand = (isGlobal
|
|
2757
|
+
? buildHookCommand(targetDir, 'pan-guard.js')
|
|
2758
|
+
: 'node ' + dirName + '/hooks/pan-guard.js') + ` --host ${runtime}`;
|
|
2788
2759
|
// Gemini and Copilot (M33): a marker before the compaction, the block on the next
|
|
2789
2760
|
// tool result. The inject mode names the host, whose output shapes differ.
|
|
2790
2761
|
const stateReinjectMarkCommand = `${stateReinjectCommand} --mark`;
|
|
@@ -2798,7 +2769,7 @@ function install(isGlobal, runtime = 'claude') {
|
|
|
2798
2769
|
if (!isOpencode) {
|
|
2799
2770
|
const entrypoints = lib.verifyHookEntrypoints([
|
|
2800
2771
|
updateCheckCommand, contextMonitorCommand, statuslineCommand, costLoggerCommand,
|
|
2801
|
-
traceLoggerCommand, stopGuardCommand, stateReinjectCommand, stateReinjectMarkCommand, stateReinjectInjectCommand,
|
|
2772
|
+
traceLoggerCommand, stopGuardCommand, stateReinjectCommand, stateReinjectMarkCommand, stateReinjectInjectCommand, guardCommand,
|
|
2802
2773
|
], process.cwd());
|
|
2803
2774
|
if (!entrypoints.ok) {
|
|
2804
2775
|
console.error(`\n ${red}✖ Hook verification FAILED — these hook commands would run a script that is not there:${reset}`);
|
|
@@ -2818,7 +2789,7 @@ function install(isGlobal, runtime = 'claude') {
|
|
|
2818
2789
|
let existing = null;
|
|
2819
2790
|
try { existing = JSON.parse(fs.readFileSync(hooksJsonPath, 'utf8')); } catch { /* absent or invalid — start fresh */ }
|
|
2820
2791
|
const merged = lib.mergeCodexHooksConfig(existing, {
|
|
2821
|
-
updateCheckCommand, contextMonitorCommand, costLoggerCommand, traceLoggerCommand, stopGuardCommand, stateReinjectCommand,
|
|
2792
|
+
updateCheckCommand, contextMonitorCommand, costLoggerCommand, traceLoggerCommand, stopGuardCommand, stateReinjectCommand, guardCommand,
|
|
2822
2793
|
});
|
|
2823
2794
|
fs.writeFileSync(hooksJsonPath, JSON.stringify(merged, null, 2) + '\n');
|
|
2824
2795
|
// Print the path we actually wrote. The hardcoded '.codex/hooks.json' was
|
|
@@ -2836,7 +2807,7 @@ function install(isGlobal, runtime = 'claude') {
|
|
|
2836
2807
|
// from any legacy config.json registration.
|
|
2837
2808
|
if (isCopilot) {
|
|
2838
2809
|
const hooksConfigPath = path.join(targetDir, 'hooks', 'pan.json');
|
|
2839
|
-
const hooksConfig = buildCopilotHooksConfig({ updateCheckCommand, contextMonitorCommand, costLoggerCommand, traceLoggerCommand, stopGuardCommand, stateReinjectMarkCommand, stateReinjectInjectCommand });
|
|
2810
|
+
const hooksConfig = buildCopilotHooksConfig({ updateCheckCommand, contextMonitorCommand, costLoggerCommand, traceLoggerCommand, stopGuardCommand, stateReinjectMarkCommand, stateReinjectInjectCommand, guardCommand });
|
|
2840
2811
|
try {
|
|
2841
2812
|
fs.mkdirSync(path.dirname(hooksConfigPath), { recursive: true });
|
|
2842
2813
|
fs.writeFileSync(hooksConfigPath, JSON.stringify(hooksConfig, null, 2) + '\n');
|
|
@@ -2930,6 +2901,7 @@ function install(isGlobal, runtime = 'claude') {
|
|
|
2930
2901
|
// unbuilt phases — fail-open and inert outside PAN projects.
|
|
2931
2902
|
const registrations = [
|
|
2932
2903
|
{ slot: 'sessionStart', hook: 'pan-check-update', command: updateCheckCommand, label: 'update check hook' },
|
|
2904
|
+
{ slot: 'preToolUse', hook: 'pan-guard', command: guardCommand, label: 'pre-tool guard hook' },
|
|
2933
2905
|
{ slot: 'postToolUse', hook: 'pan-context-monitor', command: contextMonitorCommand, label: 'context window monitor hook' },
|
|
2934
2906
|
{ slot: 'subagentStop', hook: 'pan-cost-logger', command: costLoggerCommand, label: 'cost logger hook' },
|
|
2935
2907
|
{ slot: 'subagentStop', hook: 'pan-trace-logger', command: traceLoggerCommand, label: 'trace logger hook' },
|
package/commands/pan/cost.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: pan:cost
|
|
3
3
|
group: Observability
|
|
4
4
|
description: Show token usage and estimated cost across PAN commands and agents
|
|
5
|
-
argument-hint: "[report|append|clear|rebuild|limits] [--format json|table|chart] [--since YYYY-MM-DD] [--until YYYY-MM-DD] [--apply] [--no-main-thread]"
|
|
5
|
+
argument-hint: "[report|append|clear|rebuild|limits|budget] [--format json|table|chart] [--since YYYY-MM-DD] [--until YYYY-MM-DD] [--apply] [--no-main-thread]"
|
|
6
6
|
allowed-tools:
|
|
7
7
|
- Read
|
|
8
8
|
- Bash
|
|
@@ -16,10 +16,6 @@ Reads `.planning/metrics/tokens.jsonl` — an append-only log where each line is
|
|
|
16
16
|
Default output is JSON for piping. Use `--format table` for human-readable tables or `--format chart` for an ASCII bar chart of daily spend; both print text, with or without `--raw`.
|
|
17
17
|
</objective>
|
|
18
18
|
|
|
19
|
-
<execution_context>
|
|
20
|
-
@~/.claude/pan-wizard-core/bin/lib/cost.cjs
|
|
21
|
-
</execution_context>
|
|
22
|
-
|
|
23
19
|
<subcommands>
|
|
24
20
|
|
|
25
21
|
### `report` (default)
|
|
@@ -81,6 +77,26 @@ Delete the cost log. Useful at the start of a billing cycle.
|
|
|
81
77
|
pan-tools cost clear
|
|
82
78
|
```
|
|
83
79
|
|
|
80
|
+
### `budget`
|
|
81
|
+
|
|
82
|
+
A phase's spend against its budget: `cost.phase_budget_usd` in `.planning/config.json`, **20 dollars per phase by default**, `0` to turn it off. Change it with `/pan:settings` or `pan-tools config-set cost.phase_budget_usd 50`. It only warns: `near` from 80% of the budget, `over` once spend reaches it; nothing ever stops on it. exec-phase reports it after each wave and plan-phase in its final status. On a subscription the dollars are API-equivalent (the tokens priced at the rate table).
|
|
83
|
+
|
|
84
|
+
```
|
|
85
|
+
pan-tools cost budget --phase <N> [--raw]
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Prints `{phase, budget_usd, spent_usd, pct, status, mode, warn_at_pct, unpriced}`; `status` is `off`, `ok`, `near` or `over`, and `--raw` prints it. `unpriced` counts the phase's rows with no known rate (not added to the spend).
|
|
89
|
+
|
|
90
|
+
### `usage` (census)
|
|
91
|
+
|
|
92
|
+
Which of the installed PAN commands and agents this project has used, from its own files only: the cost ledger and the trace sessions. Nothing is sent anywhere.
|
|
93
|
+
|
|
94
|
+
```
|
|
95
|
+
node ~/.claude/pan-wizard-core/bin/pan-tools.cjs usage [--raw]
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Prints `{local_only, commands: {used, never_used, unfinished, installed}, agents: {used, never_used, installed}, sources}`. Each used entry has `calls` and `last_used`, and a command also has `sessions` and `finished`. `unfinished` lists commands that were started but never finished: every trace session for them stopped without ending, the newest more than six hours ago. `--raw` prints a one-line summary. Use it to see which parts of PAN this project actually runs.
|
|
99
|
+
|
|
84
100
|
### `limits`
|
|
85
101
|
|
|
86
102
|
`pan-tools cost limits` shows Claude Code's 5-hour and 7-day usage windows as the status line last saw them, and whether the 7-day one has reached `cost.weekly_limit_stop_pct` (default 90%), where `/pan:focus-auto` and `/pan:army` stop. Interactive Claude Code sessions on a subscription only: headless runs and other runtimes have no reading.
|
|
@@ -20,6 +20,3 @@ pan-tools hud [--out <file>] [--open] [--stdout]
|
|
|
20
20
|
See **`/pan:hud`** for the full panel list, flags, JSON result shape, and runtime compatibility. The two commands are interchangeable.
|
|
21
21
|
</objective>
|
|
22
22
|
|
|
23
|
-
<execution_context>
|
|
24
|
-
@~/.claude/pan-wizard-core/bin/lib/hud.cjs
|
|
25
|
-
</execution_context>
|
|
@@ -53,7 +53,7 @@ ELSE (default):
|
|
|
53
53
|
1. **Validate phase** — error if the phase number is missing or not in `roadmap.md`.
|
|
54
54
|
2. **Prime context** — resolve the phase directory; gather `{phase}-context.md`, `{phase}-research.md`, and the phase boundary from `roadmap.md`.
|
|
55
55
|
3. **Design** — spawn `pan-designer` with a `<files_to_read>` block (context, research, roadmap boundary, `CLAUDE.md`). It fills in `templates/design.md` at the `phase` tier (`spike` if `--spike`).
|
|
56
|
-
4. **Verify (reflexion loop)** — spawn `pan-design-checker` with the drafted design + the boundary source:
|
|
56
|
+
4. **Verify (reflexion loop)** — spawn `pan-design-checker` with the drafted design + the boundary source, plus an `<open_findings>` block holding `pan-tools findings list --phase {phase} --agent pan-design-checker --status open` (empty on the first check):
|
|
57
57
|
- If it PASSES → done.
|
|
58
58
|
- If it finds gaps (iteration 1) → `pan-designer` revises (address genuine gaps only), re-check.
|
|
59
59
|
- If it finds gaps (iteration 2) → final revision, record remaining gaps as caveats.
|
|
@@ -62,7 +62,7 @@ ELSE (default):
|
|
|
62
62
|
```bash
|
|
63
63
|
node ~/.claude/pan-wizard-core/bin/pan-tools.cjs findings record --phase "{phase}" --agent pan-design-checker --file "{phase_dir}/{padded_phase}-design-check.md" --raw
|
|
64
64
|
```
|
|
65
|
-
A re-check is the next attempt and closes the
|
|
65
|
+
A re-check is the next attempt. It answers each earlier gap in `resolutions`, and the record closes the ones answered `resolved` with evidence; a gap it neither reports nor answers stays open. When the final iteration still has gaps, record them as the caveats they are before writing the design:
|
|
66
66
|
```bash
|
|
67
67
|
node ~/.claude/pan-wizard-core/bin/pan-tools.cjs findings dispose --phase "{phase}" --agent pan-design-checker --open --as deferred --reason "design caveat after 2 revision iterations"
|
|
68
68
|
```
|
package/commands/pan/hud.md
CHANGED
|
@@ -16,10 +16,6 @@ It is a *view*, not a new source of truth: every panel aggregates state PAN alre
|
|
|
16
16
|
Default output is `.planning/hud.html`. Open it in any browser. Re-run any time for a fresh snapshot.
|
|
17
17
|
</objective>
|
|
18
18
|
|
|
19
|
-
<execution_context>
|
|
20
|
-
@~/.claude/pan-wizard-core/bin/lib/hud.cjs
|
|
21
|
-
</execution_context>
|
|
22
|
-
|
|
23
19
|
<usage>
|
|
24
20
|
|
|
25
21
|
```
|
|
@@ -62,7 +58,7 @@ Panels render only when they have data — a plain (non-army) project still gets
|
|
|
62
58
|
| **Requirements & quality** | Requirements done/open + last verification artifacts | `requirements.md`, phase `*-verification.md` / `*-uat.md` |
|
|
63
59
|
| **Recent activity** | Last commits (the army's committed output) | `git log` |
|
|
64
60
|
|
|
65
|
-
*(army)* panels appear only when a campaign is scheduled or army worktrees exist — graceful degradation per ADR-0035. The *(fallback)* **Planning activity** panel appears only when there is no phase/roadmap layout, so it fills the gap for focus-auto and imported projects instead of leaving a bare page. Telemetry shows an honest advisory (never a fabricated
|
|
61
|
+
*(army)* panels appear only when a campaign is scheduled or army worktrees exist — graceful degradation per ADR-0035. The *(fallback)* **Planning activity** panel appears only when there is no phase/roadmap layout, so it fills the gap for focus-auto and imported projects instead of leaving a bare page. Telemetry shows an honest advisory (never a fabricated zero-dollar total) when the cost ledger is poisoned or every record is unpriced.
|
|
66
62
|
|
|
67
63
|
</panels>
|
|
68
64
|
|
|
@@ -23,7 +23,6 @@ Consolidates Spec B v1's X-3 converse + X-6 teach + X-10 explain into one comman
|
|
|
23
23
|
</objective>
|
|
24
24
|
|
|
25
25
|
<execution_context>
|
|
26
|
-
@~/.claude/pan-wizard-core/bin/lib/knowledge.cjs
|
|
27
26
|
@~/.claude/agents/pan-knowledge.md
|
|
28
27
|
@~/.claude/pan-wizard-core/templates/playbook.md
|
|
29
28
|
</execution_context>
|
|
@@ -15,9 +15,7 @@ Surface Model Context Protocol (MCP) tools visible to the host runtime and recom
|
|
|
15
15
|
Reduced scope from Spec B v1's X-7: **discovery and recommendation only**. Auto-injection of MCP tools into planner context and auto-invocation from executor agents are deliberately deferred and still unscheduled (the v3.5 target passed without them). This kept v3.3 narrow and avoids coupling PAN to Claude Code's MCP schema stability.
|
|
16
16
|
</objective>
|
|
17
17
|
|
|
18
|
-
<
|
|
19
|
-
@~/.claude/pan-wizard-core/bin/lib/bridge.cjs
|
|
20
|
-
</execution_context>
|
|
18
|
+
Each subcommand runs `node ~/.claude/pan-wizard-core/bin/pan-tools.cjs bridge <list|recommend|cache> [flags]`. The CLI verb is `bridge`, not `mcp-bridge`: `pan-tools mcp-bridge` is an unknown command.
|
|
21
19
|
|
|
22
20
|
<subcommands>
|
|
23
21
|
|
package/commands/pan/optimize.md
CHANGED
|
@@ -111,3 +111,5 @@ List all trace sessions, most recent first.
|
|
|
111
111
|
Each iteration puts what the last run lacked where the next run's agents read it: fewer repeated errors and gaps.
|
|
112
112
|
|
|
113
113
|
**See also:** `/pan:learn`, `/pan:exec-phase`
|
|
114
|
+
|
|
115
|
+
Follow the workflow at `~/.claude/pan-wizard-core/workflows/optimize.md`. Each subcommand runs `node ~/.claude/pan-wizard-core/bin/pan-tools.cjs optimize <subcommand> [flags]` — e.g. `optimize apply --report <path>`, `optimize revert --last`, `optimize trace init --description "..."`.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: pan:phase-tests
|
|
3
3
|
group: Phase Management
|
|
4
|
-
description: Generate tests for a completed phase
|
|
4
|
+
description: Generate tests for a completed phase from its summaries, context decisions, verification report and implementation
|
|
5
5
|
argument-hint: "<phase> [additional instructions]"
|
|
6
6
|
allowed-tools:
|
|
7
7
|
- Read
|
package/commands/pan/preview.md
CHANGED
|
@@ -19,7 +19,6 @@ Consolidates Spec B v1's architect + simulate + predict-milestone into one entry
|
|
|
19
19
|
</objective>
|
|
20
20
|
|
|
21
21
|
<execution_context>
|
|
22
|
-
@~/.claude/pan-wizard-core/bin/lib/preview.cjs
|
|
23
22
|
@~/.claude/pan-wizard-core/templates/preview-report.md
|
|
24
23
|
</execution_context>
|
|
25
24
|
|
|
@@ -32,7 +31,7 @@ Consolidates Spec B v1's architect + simulate + predict-milestone into one entry
|
|
|
32
31
|
```
|
|
33
32
|
|
|
34
33
|
**What it does:**
|
|
35
|
-
1. `pan-tools preview phase <N>` returns `{files_mentioned, test_files_mentioned, risk_signals, risk_score, plans[], status}`.
|
|
34
|
+
1. `pan-tools preview phase <N>` returns `{files_mentioned, test_files_mentioned, risk_signals, risk_score, plans[], status, cost_forecast}`. `cost_forecast` gives p10/p50/p90 dollars per plan (`per_plan`) and for the phase (`phase`) from this project's own cost ledger, or `status: insufficient` with `n` when fewer than five past runs back it.
|
|
36
35
|
2. Spawn `pan-previewer` with the payload as `<preview_input>`.
|
|
37
36
|
3. Agent writes `.planning/phases/<NN-slug>/preview.md` with files touched / tests at risk / migration steps / risk assessment / bottom line.
|
|
38
37
|
|
|
@@ -74,7 +73,7 @@ Consolidates Spec B v1's architect + simulate + predict-milestone into one entry
|
|
|
74
73
|
|
|
75
74
|
**Before committing to a milestone date externally:** run `/pan:preview milestone`. Look at `confidence_pct` and `sample_size`. If sample is <3, don't promise a date.
|
|
76
75
|
|
|
77
|
-
**Before running phases in parallel:** run `/pan:preview phases`. Parallel batches from the data layer are based on declared `
|
|
76
|
+
**Before running phases in parallel:** run `/pan:preview phases`. Parallel batches from the data layer are based on declared dependencies only — the roadmap's `**Depends on:** Phase N` line and any `phase:N` entry in a plan's `depends_on`; `hidden_coupling_count > 0` means there are cross-phase references the author should promote to explicit deps (on the roadmap's Depends on line) before parallelizing.
|
|
78
77
|
|
|
79
78
|
</workflow>
|
|
80
79
|
|
package/commands/pan/report.md
CHANGED
|
@@ -13,13 +13,9 @@ Render **self-contained HTML reports** — no server, no network, no external CS
|
|
|
13
13
|
|
|
14
14
|
Like `pan:hud`, these are *views*, not a new source of truth: every value is read from what PAN already tracks on disk (the phase's `plan`/`summary`/`verification` artifacts and their frontmatter, `roadmap.md`, and the cost ledger). The command only writes the rendered file(s), so it can never corrupt planning data. Reports reuse the HUD's visual language, so they look like part of the same product.
|
|
15
15
|
|
|
16
|
-
Reports are honest by construction: the `verify reconcile` verdict is shown beside the (rubber-stampable) self-reported verification status, status is framed as a current-disk snapshot, and any spend is gated so a poisoned or unpriced ledger never renders a fake
|
|
16
|
+
Reports are honest by construction: the `verify reconcile` verdict is shown beside the (rubber-stampable) self-reported verification status, status is framed as a current-disk snapshot, and any spend is gated so a poisoned or unpriced ledger never renders a fake zero-dollar spend.
|
|
17
17
|
</objective>
|
|
18
18
|
|
|
19
|
-
<execution_context>
|
|
20
|
-
@~/.claude/pan-wizard-core/bin/lib/phase-report.cjs
|
|
21
|
-
</execution_context>
|
|
22
|
-
|
|
23
19
|
<usage>
|
|
24
20
|
|
|
25
21
|
```
|
|
@@ -137,8 +137,8 @@ Write to: {phase_dir}/{padded_phase}-research.md
|
|
|
137
137
|
|
|
138
138
|
```
|
|
139
139
|
Task(
|
|
140
|
-
prompt=
|
|
141
|
-
subagent_type="
|
|
140
|
+
prompt=filled_prompt,
|
|
141
|
+
subagent_type="pan-phase-researcher",
|
|
142
142
|
model="{researcher_model}",
|
|
143
143
|
description="Research Phase {phase}"
|
|
144
144
|
)
|
|
@@ -171,8 +171,8 @@ Continue research for Phase {phase_number}: {phase_name}
|
|
|
171
171
|
|
|
172
172
|
```
|
|
173
173
|
Task(
|
|
174
|
-
prompt=
|
|
175
|
-
subagent_type="
|
|
174
|
+
prompt=continuation_prompt,
|
|
175
|
+
subagent_type="pan-phase-researcher",
|
|
176
176
|
model="{researcher_model}",
|
|
177
177
|
description="Continue research Phase {phase}"
|
|
178
178
|
)
|
|
@@ -24,8 +24,6 @@ Consolidates Spec B v1's X-4 (self-review) + X-12 (harden) into a single command
|
|
|
24
24
|
</objective>
|
|
25
25
|
|
|
26
26
|
<execution_context>
|
|
27
|
-
@~/.claude/pan-wizard-core/bin/lib/review-deep.cjs
|
|
28
|
-
@~/.claude/pan-wizard-core/bin/lib/bus.cjs
|
|
29
27
|
@~/.claude/agents/pan-hardener.md
|
|
30
28
|
@~/.claude/agents/pan-meta-reviewer.md
|
|
31
29
|
</execution_context>
|