pan-wizard 3.18.0 → 3.19.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/bin/install-lib.cjs +10 -1
- package/bin/install.js +1 -1
- package/commands/pan/army.md +5 -4
- package/commands/pan/focus-auto.md +3 -2
- package/package.json +1 -1
- package/pan-wizard-core/bin/lib/campaign.cjs +4 -1
- package/pan-wizard-core/bin/lib/config.cjs +4 -0
- package/pan-wizard-core/bin/lib/core.cjs +31 -21
- package/pan-wizard-core/bin/lib/focus.cjs +8 -1
- package/pan-zcode/mcp/orchestrator.cjs +4 -2
package/bin/install-lib.cjs
CHANGED
|
@@ -1016,9 +1016,18 @@ function detectModelCapabilities(modelName) {
|
|
|
1016
1016
|
const n = modelName.toLowerCase();
|
|
1017
1017
|
|
|
1018
1018
|
// Anthropic Claude family
|
|
1019
|
-
if (n.includes('fable')) {
|
|
1019
|
+
if (n.includes('fable') || n.includes('mythos')) {
|
|
1020
1020
|
return { has_1m_ctx: true, has_thinking: true, has_cache: true, tier: 'reasoning' };
|
|
1021
1021
|
}
|
|
1022
|
+
// Claude 5 family (Opus 5, Sonnet 5) — 1M context, extended thinking, prompt caching.
|
|
1023
|
+
// Without this, `claude-opus-5` falls through to `unknown` and the installer prints
|
|
1024
|
+
// a FALSE "your model lacks 1M context / extended thinking" warning on the flagship.
|
|
1025
|
+
if (n.includes('opus-5')) {
|
|
1026
|
+
return { has_1m_ctx: true, has_thinking: true, has_cache: true, tier: 'reasoning' };
|
|
1027
|
+
}
|
|
1028
|
+
if (n.includes('sonnet-5')) {
|
|
1029
|
+
return { has_1m_ctx: true, has_thinking: true, has_cache: true, tier: 'mid' };
|
|
1030
|
+
}
|
|
1022
1031
|
if (n.includes('opus-4-8') || n.includes('opus-4.8')
|
|
1023
1032
|
|| n.includes('opus-4-7') || n.includes('opus-4.7')
|
|
1024
1033
|
|| n.includes('opus-4-6') || n.includes('opus-4.6')) {
|
package/bin/install.js
CHANGED
|
@@ -2492,7 +2492,7 @@ function finishInstall(settingsPath, settings, statuslineCommand, shouldInstallS
|
|
|
2492
2492
|
console.log(`
|
|
2493
2493
|
${yellow}ℹ${reset} PAN's multi-agent workflows are tuned for frontier reasoning models. Default model "${modelField}" lacks: ${missing}.
|
|
2494
2494
|
Features degrade gracefully, but for best results select claude-fable-5 (PAN's recommended flagship — deepest
|
|
2495
|
-
long-horizon reasoning for the bot army) or claude-opus-4-8
|
|
2495
|
+
long-horizon reasoning for the bot army), or an Opus-tier model (claude-opus-5 / claude-opus-4-8) at lower cost.`);
|
|
2496
2496
|
}
|
|
2497
2497
|
}
|
|
2498
2498
|
} catch {
|
package/commands/pan/army.md
CHANGED
|
@@ -78,13 +78,14 @@ Every cap the conductor enforces applies to the campaign, scaled up:
|
|
|
78
78
|
|------|---------|--------|
|
|
79
79
|
| `--source` | `backlog` | Work selection (delegates to focus-auto): `backlog` = ranked roadmap/requirements items; `scan` = category code-scan. |
|
|
80
80
|
| `--max-cycles` | 5 | Mission items landed before stopping. |
|
|
81
|
-
| `--total-budget` | 300 | Cumulative point
|
|
81
|
+
| `--total-budget` | 300 | Cumulative point budget. **Advisory by default** — tracked/surfaced but not a hard stop unless `--enforce-budget` / config `budget.enforce: true`. |
|
|
82
|
+
| `--enforce-budget` | off | Make the point budgets hard stops again (also settable via config `budget.enforce: true`). |
|
|
82
83
|
| `--squads` | all | Restrict to a subset, e.g. `--squads architecture,build,quality`. |
|
|
83
84
|
| `--no-build-worktrees` | off | Build in the main tree instead of branch-per-agent worktrees (small/serial projects). |
|
|
84
85
|
| `--push` | off | Push approved merges to origin (still human-gated). |
|
|
85
86
|
| `--clean-seal` | off | One clean build + full verification after the last item (commands from config). |
|
|
86
87
|
| `--schedule` | off | Arm a self-resuming campaign at this cadence (`hourly`/`daily`/`weekly`/`Nh`/`Nd`) instead of running once — writes the schedule descriptor (ADR-0034). Pair with `--daily-budget`. |
|
|
87
|
-
| `--daily-budget` | 300 | Per-day point
|
|
88
|
+
| `--daily-budget` | 300 | Per-day point budget for a scheduled campaign. Advisory by default (an indicator of the day's spend); it only pauses the day's run when `budget.enforce`/`enforce_budget` is set. |
|
|
88
89
|
| `--dry-run` | off | Plan + squad delegation preview only; STOP. |
|
|
89
90
|
| `--continue` / `--stop` / `--status` | — | Resume / halt / report from `.planning/orchestration/` + focus-auto state. |
|
|
90
91
|
|
|
@@ -141,14 +142,14 @@ PAN is not a daemon — it cannot wake itself while the session is closed. `--sc
|
|
|
141
142
|
- **Arm:** `/pan:army "<goal>" --schedule daily --daily-budget 200` writes `.planning/orchestration/schedule.json` (cadence, daily budget, next-due) instead of running once.
|
|
142
143
|
- **The trigger (you wire one):** a host scheduler (Claude Code routines / cron / scheduled-tasks) or a `/loop` runs `pan-tools campaign due` and, when it reports due, invokes `/pan:army --continue`. On next session open, a due campaign is surfaced as a nudge.
|
|
143
144
|
- **Resume (`--continue`):** read the schedule + `.planning/orchestration/` + focus-auto state. If `campaign due` is true and the day's `--daily-budget` isn't spent, run the next mission(s), then `campaign record-run` (advances next-due, accrues the day's spend). If not due or budget-spent, report next-due and STOP.
|
|
144
|
-
- **Bounded spend:**
|
|
145
|
+
- **Bounded spend:** point budgets (`--total-budget`, `--daily-budget`) are **advisory indicators by default** — they're tracked and surfaced, not hard stops, unless `budget.enforce` / `--enforce-budget` is set. The real bounds are `--max-cycles`, the conductor caps, the abort file, and the human merge gate at every integrate. A scheduled campaign runs the backlog down to staged, reviewed, green PRs over days.
|
|
145
146
|
|
|
146
147
|
Manage it: `pan-tools campaign status` (active/paused, spent today, next-due), `campaign schedule --pause` / `--resume` / `--disable`.
|
|
147
148
|
|
|
148
149
|
---
|
|
149
150
|
|
|
150
151
|
## Completion contract
|
|
151
|
-
The campaign is complete when ANY holds: `--max-cycles` reached ·
|
|
152
|
+
The campaign is complete when ANY holds: `--max-cycles` reached · backlog empty · abort file present · context < 25% · a mission cannot pass Quality and can't be cleanly reverted (HARD STOP — preserve state, report). (Budget exhaustion is advisory by default — a stop condition only when `budget.enforce`/`--enforce-budget` is set.) Always run `--clean-seal` (unless omitted) after the last item.
|
|
152
153
|
|
|
153
154
|
## NEVER DO
|
|
154
155
|
- Let Mission Control write code, or let a squad agent spawn further agents (depth cap).
|
|
@@ -33,7 +33,7 @@ This command runs improvement campaigns on the **host project's source code**
|
|
|
33
33
|
<completion_contract>
|
|
34
34
|
A campaign is complete when ANY stop condition is met:
|
|
35
35
|
1. Max cycles reached (--max-cycles, default 10)
|
|
36
|
-
2. Total budget exhausted (--total-budget
|
|
36
|
+
2. Total budget exhausted (--total-budget) — **advisory by default**: tracked and surfaced but does NOT stop the run unless `--enforce-budget` (or config `budget.enforce: true`) is set
|
|
37
37
|
3. Scan returns zero items for the selected category
|
|
38
38
|
4. Context window drops below 25% (CRITICAL threshold)
|
|
39
39
|
5. User sends /pan:focus-auto --stop
|
|
@@ -100,7 +100,8 @@ Wait for the user's reply before proceeding. Do not guess or pick a default cate
|
|
|
100
100
|
| `--mode` | category-dependent | bugfix, balanced, features, full |
|
|
101
101
|
| `--budget` | category-dependent | Points per cycle (5-100) |
|
|
102
102
|
| `--max-cycles` | 10 | Maximum iterations (1-50) |
|
|
103
|
-
| `--total-budget` | 500 | Cumulative
|
|
103
|
+
| `--total-budget` | 500 | Cumulative point budget (5-5000). Advisory by default (tracked/surfaced, not a stop). |
|
|
104
|
+
| `--enforce-budget` | off | Make `--total-budget` a hard stop again (also settable via config `budget.enforce: true`). |
|
|
104
105
|
| `--continue` | — | Resume stopped/interrupted run |
|
|
105
106
|
| `--stop` | — | Gracefully stop active run |
|
|
106
107
|
| `--status` | — | Show current campaign progress |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pan-wizard",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.19.0",
|
|
4
4
|
"description": "Command a bot army for your codebase: an Opus Mission Control delegates whole-project goals to specialist squads and ships behind a human merge gate. Five AI CLIs, zero context rot.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"pan-wizard": "bin/install.js"
|
|
@@ -76,6 +76,9 @@ function writeSchedule(cwd, opts, now) {
|
|
|
76
76
|
source: opts.source ?? existing.source ?? 'backlog',
|
|
77
77
|
cadence,
|
|
78
78
|
daily_budget: opts.daily_budget != null ? Number(opts.daily_budget) : (existing.daily_budget ?? 300),
|
|
79
|
+
// Advisory by default: the daily budget is tracked + surfaced but does not block
|
|
80
|
+
// a due run unless explicitly enforced.
|
|
81
|
+
enforce_budget: opts.enforce_budget != null ? Boolean(opts.enforce_budget) : (existing.enforce_budget ?? false),
|
|
79
82
|
enabled: opts.enabled != null ? Boolean(opts.enabled) : (existing.enabled ?? true),
|
|
80
83
|
paused: opts.paused != null ? Boolean(opts.paused) : (existing.paused ?? false),
|
|
81
84
|
next_due: existing.next_due ?? at.toISOString(),
|
|
@@ -108,7 +111,7 @@ function isRunDue(schedule, now) {
|
|
|
108
111
|
const spent = spentToday(schedule, at);
|
|
109
112
|
if (!schedule.enabled) return { due: false, reason: 'disabled', next_due: schedule.next_due, spent_today: spent };
|
|
110
113
|
if (schedule.paused) return { due: false, reason: 'paused', next_due: schedule.next_due, spent_today: spent };
|
|
111
|
-
if (schedule.daily_budget != null && spent >= schedule.daily_budget) {
|
|
114
|
+
if (schedule.enforce_budget && schedule.daily_budget != null && spent >= schedule.daily_budget) {
|
|
112
115
|
return { due: false, reason: 'budget_exhausted_today', next_due: schedule.next_due, spent_today: spent };
|
|
113
116
|
}
|
|
114
117
|
const due = new Date(schedule.next_due);
|
|
@@ -62,6 +62,10 @@ function buildConfigDefaults(hasBraveSearch, userDefaults) {
|
|
|
62
62
|
default_points: 50,
|
|
63
63
|
micro_threshold_tasks: 3,
|
|
64
64
|
micro_threshold_files: 2,
|
|
65
|
+
// Budget is ADVISORY by default: point/spend caps are tracked and surfaced
|
|
66
|
+
// (HUD, telemetry) but never STOP a run. Set enforce:true (or pass
|
|
67
|
+
// --enforce-budget) to make the cap a hard stop again.
|
|
68
|
+
enforce: false,
|
|
65
69
|
},
|
|
66
70
|
commit: {
|
|
67
71
|
safety_checks: true,
|
|
@@ -47,34 +47,44 @@ const COST_MULTIPLIERS = { reasoning: 15, mid: 3, fast: 1 };
|
|
|
47
47
|
|
|
48
48
|
// ─── Model Profile Table ─────────────────────────────────────────────────────
|
|
49
49
|
|
|
50
|
+
// COST RESET (2026-07): quality + balanced (the default) both resolve to the
|
|
51
|
+
// `reasoning` tier for EVERY agent — i.e. the DEFAULT model you launched with
|
|
52
|
+
// (`inherit`). PAN no longer silently demotes agents to cheaper models; context
|
|
53
|
+
// isolation (each subagent runs in its own window), not a cheaper model, is what
|
|
54
|
+
// keeps the main conversation clean. Cheapness is now OPT-IN: choose the `budget`
|
|
55
|
+
// profile (the only column that still down-tiers) or pin a specific agent via
|
|
56
|
+
// config `model_overrides`. The 3 security agents additionally pin `model: opus`
|
|
57
|
+
// in their own frontmatter (a native, deliberate exception). resolve-model /
|
|
58
|
+
// MODEL_PROFILES is advisory + cost-estimation; native Claude Code delegation
|
|
59
|
+
// reads each agent file's static `model:` (unset → inherit).
|
|
50
60
|
const MODEL_PROFILES = {
|
|
51
61
|
// Original planning/execution agents (pre-v3.0)
|
|
52
62
|
'pan-planner': { quality: 'reasoning', balanced: 'reasoning', budget: 'mid' },
|
|
53
|
-
'pan-roadmapper': { quality: 'reasoning', balanced: '
|
|
54
|
-
'pan-executor': { quality: 'reasoning', balanced: '
|
|
55
|
-
'pan-phase-researcher': { quality: 'reasoning', balanced: '
|
|
56
|
-
'pan-project-researcher': { quality: 'reasoning', balanced: '
|
|
57
|
-
'pan-research-synthesizer': { quality: 'reasoning', balanced: '
|
|
58
|
-
'pan-debugger': { quality: 'reasoning', balanced: '
|
|
59
|
-
'pan-document_code': { quality: 'reasoning', balanced: '
|
|
60
|
-
'pan-verifier': { quality: 'reasoning', balanced: '
|
|
61
|
-
'pan-plan-checker': { quality: 'reasoning', balanced: '
|
|
62
|
-
'pan-integration-checker': { quality: 'reasoning', balanced: '
|
|
63
|
-
'pan-reviewer': { quality: 'reasoning', balanced: '
|
|
63
|
+
'pan-roadmapper': { quality: 'reasoning', balanced: 'reasoning', budget: 'mid' },
|
|
64
|
+
'pan-executor': { quality: 'reasoning', balanced: 'reasoning', budget: 'mid' },
|
|
65
|
+
'pan-phase-researcher': { quality: 'reasoning', balanced: 'reasoning', budget: 'fast' },
|
|
66
|
+
'pan-project-researcher': { quality: 'reasoning', balanced: 'reasoning', budget: 'fast' },
|
|
67
|
+
'pan-research-synthesizer': { quality: 'reasoning', balanced: 'reasoning', budget: 'fast' },
|
|
68
|
+
'pan-debugger': { quality: 'reasoning', balanced: 'reasoning', budget: 'mid' },
|
|
69
|
+
'pan-document_code': { quality: 'reasoning', balanced: 'reasoning', budget: 'fast' },
|
|
70
|
+
'pan-verifier': { quality: 'reasoning', balanced: 'reasoning', budget: 'fast' },
|
|
71
|
+
'pan-plan-checker': { quality: 'reasoning', balanced: 'reasoning', budget: 'fast' },
|
|
72
|
+
'pan-integration-checker': { quality: 'reasoning', balanced: 'reasoning', budget: 'fast' },
|
|
73
|
+
'pan-reviewer': { quality: 'reasoning', balanced: 'reasoning', budget: 'fast' },
|
|
64
74
|
// Spec B v2 agents (v3.0–v3.4) — added v3.7.5 to close MODEL_PROFILES drift
|
|
65
75
|
'pan-conductor': { quality: 'reasoning', balanced: 'reasoning', budget: 'mid' },
|
|
66
|
-
'pan-counterfactual': { quality: 'reasoning', balanced: '
|
|
67
|
-
'pan-hardener': { quality: 'reasoning', balanced: '
|
|
68
|
-
'pan-meta-reviewer': { quality: 'reasoning', balanced: '
|
|
69
|
-
'pan-knowledge': { quality: 'reasoning', balanced: '
|
|
70
|
-
'pan-previewer': { quality: 'reasoning', balanced: '
|
|
76
|
+
'pan-counterfactual': { quality: 'reasoning', balanced: 'reasoning', budget: 'mid' },
|
|
77
|
+
'pan-hardener': { quality: 'reasoning', balanced: 'reasoning', budget: 'fast' },
|
|
78
|
+
'pan-meta-reviewer': { quality: 'reasoning', balanced: 'reasoning', budget: 'fast' },
|
|
79
|
+
'pan-knowledge': { quality: 'reasoning', balanced: 'reasoning', budget: 'fast' },
|
|
80
|
+
'pan-previewer': { quality: 'reasoning', balanced: 'reasoning', budget: 'fast' },
|
|
71
81
|
// v3.5 agents
|
|
72
|
-
'pan-optimizer': { quality: 'reasoning', balanced: '
|
|
73
|
-
'pan-distiller': { quality: 'reasoning', balanced: '
|
|
82
|
+
'pan-optimizer': { quality: 'reasoning', balanced: 'reasoning', budget: 'fast' },
|
|
83
|
+
'pan-distiller': { quality: 'reasoning', balanced: 'reasoning', budget: 'fast' },
|
|
74
84
|
// v3.7.0 self-improvement loop — observation-only watchdog
|
|
75
|
-
'pan-experiment-runner': { quality: 'reasoning', balanced: '
|
|
85
|
+
'pan-experiment-runner': { quality: 'reasoning', balanced: 'reasoning', budget: 'fast' },
|
|
76
86
|
// ADR-0033 bot-army — Release squad
|
|
77
|
-
'pan-release': { quality: 'reasoning', balanced: '
|
|
87
|
+
'pan-release': { quality: 'reasoning', balanced: 'reasoning', budget: 'fast' },
|
|
78
88
|
};
|
|
79
89
|
|
|
80
90
|
// ─── Effort Profiles (2026-06, adaptive-thinking era) ───────────────────────
|
|
@@ -279,7 +289,7 @@ function loadConfig(cwd) {
|
|
|
279
289
|
verifier: get('verifier', { section: 'workflow', field: 'verifier' }) ?? defaults.verifier,
|
|
280
290
|
parallelization,
|
|
281
291
|
brave_search: get('brave_search') ?? defaults.brave_search,
|
|
282
|
-
budget: parsed.budget || { default_points: 50, micro_threshold_tasks: 3, micro_threshold_files: 2 },
|
|
292
|
+
budget: parsed.budget || { default_points: 50, micro_threshold_tasks: 3, micro_threshold_files: 2, enforce: false },
|
|
283
293
|
commit: parsed.commit || { safety_checks: true, conventional_types: true, sensitive_patterns: ['\\.env$', '\\.pem$', '\\.key$', 'credentials', 'secret', 'password', 'token'] },
|
|
284
294
|
execution: parsed.execution || { default_mode: 'wave_order', rollback_snapshots: true, error_pattern_learning: true },
|
|
285
295
|
focus: parsed.focus || { auto_commit: true },
|
|
@@ -863,7 +863,9 @@ function focusAutoCheckpointCommit(cwd, cycle, run) {
|
|
|
863
863
|
|
|
864
864
|
function determineStopReason(cycle, run) {
|
|
865
865
|
if (cycle.tests_after < cycle.tests_before) return 'regression';
|
|
866
|
-
|
|
866
|
+
// Budget is advisory by default — it only STOPS the run when explicitly enforced.
|
|
867
|
+
// Otherwise the overage is tracked/surfaced (indication) and the loop continues.
|
|
868
|
+
if (run.budget_enforce && run.totals.points_used >= run.total_budget) return 'budget_cap';
|
|
867
869
|
if (run.totals.cycles_completed >= run.max_cycles) return 'max_cycles';
|
|
868
870
|
if (cycle.items_completed === 0) {
|
|
869
871
|
// Security category gets a descriptive stop reason rather than generic zero_completed
|
|
@@ -929,6 +931,10 @@ function focusAutoInit(cwd, raw, getVal, hasFlag) {
|
|
|
929
931
|
const budget = Number(getVal('--budget', String(defaults.budget)));
|
|
930
932
|
const maxCycles = Number(getVal('--max-cycles', String(DEFAULT_MAX_CYCLES)));
|
|
931
933
|
const totalBudget = Number(getVal('--total-budget', String(DEFAULT_TOTAL_BUDGET)));
|
|
934
|
+
// Budget is advisory by default (tracked + surfaced, never a hard stop). Enforce
|
|
935
|
+
// only when the user opts in via config `budget.enforce` or `--enforce-budget`.
|
|
936
|
+
const budgetConfig = loadConfig(cwd).budget || {};
|
|
937
|
+
const budgetEnforce = hasFlag('--enforce-budget') || budgetConfig.enforce === true;
|
|
932
938
|
|
|
933
939
|
if (!FOCUS_MODES.includes(mode)) return error(`Mode must be one of: ${FOCUS_MODES.join(', ')}`);
|
|
934
940
|
if (budget < BUDGET_MIN || budget > BUDGET_MAX) return error(`Budget must be between ${BUDGET_MIN} and ${BUDGET_MAX}`);
|
|
@@ -947,6 +953,7 @@ function focusAutoInit(cwd, raw, getVal, hasFlag) {
|
|
|
947
953
|
budget_per_cycle: budget,
|
|
948
954
|
max_cycles: maxCycles,
|
|
949
955
|
total_budget: totalBudget,
|
|
956
|
+
budget_enforce: budgetEnforce,
|
|
950
957
|
priority_range: category ? CATEGORY_PRIORITY_RANGE[category] : { min: 0, max: 6 },
|
|
951
958
|
deep_review_enabled: hasFlag('--deep-review'),
|
|
952
959
|
tests_baseline: null,
|
|
@@ -15,7 +15,9 @@
|
|
|
15
15
|
* are reproducible.
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
// Budget is advisory by default (enforceBudget:false) — it never stops the loop
|
|
19
|
+
// unless the caller opts in. maxCycles remains a hard safety stop.
|
|
20
|
+
const DEFAULT_CAPS = { maxCycles: 25, budget: Infinity, enforceBudget: false };
|
|
19
21
|
const PHASE_NEXT = {
|
|
20
22
|
none: 'plan',
|
|
21
23
|
researched: 'plan',
|
|
@@ -47,7 +49,7 @@ function nextAction(state, caps) {
|
|
|
47
49
|
return { action: 'stop', reason: 'regression', done: true };
|
|
48
50
|
}
|
|
49
51
|
if ((state.cycles || 0) >= c.maxCycles) return { action: 'stop', reason: 'max_cycles', done: true };
|
|
50
|
-
if ((state.points_used || 0) >= c.budget) return { action: 'stop', reason: 'budget_cap', done: true };
|
|
52
|
+
if (c.enforceBudget && (state.points_used || 0) >= c.budget) return { action: 'stop', reason: 'budget_cap', done: true };
|
|
51
53
|
|
|
52
54
|
// The human merge gate is a barrier: while a merge awaits approval, do nothing else.
|
|
53
55
|
if (state.awaiting_approval) return { action: 'await_approval', reason: 'human_gate', done: false };
|