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.
@@ -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 (same 1M context at half the cost).`);
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 {
@@ -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 ceiling. |
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 ceiling for a scheduled campaign; the day's run stops when reached, resumes next day. |
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:** the per-day budget caps each day's run; the per-run `--total-budget` and the conductor caps still bound each cycle. A scheduled campaign runs the backlog down to staged, reviewed, green PRs over days — and still waits for a human at every merge.
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 · `--total-budget` exhausted · backlog empty · abort file present · context < 25% · a mission cannot pass Quality and can't be cleanly reverted (HARD STOP — preserve state, report). Always run `--clean-seal` (unless omitted) after the last item.
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, default 200)
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 points cap (5-5000) |
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.18.0",
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: 'mid', budget: 'mid' },
54
- 'pan-executor': { quality: 'reasoning', balanced: 'mid', budget: 'mid' },
55
- 'pan-phase-researcher': { quality: 'reasoning', balanced: 'mid', budget: 'fast' },
56
- 'pan-project-researcher': { quality: 'reasoning', balanced: 'mid', budget: 'fast' },
57
- 'pan-research-synthesizer': { quality: 'reasoning', balanced: 'mid', budget: 'fast' },
58
- 'pan-debugger': { quality: 'reasoning', balanced: 'mid', budget: 'mid' },
59
- 'pan-document_code': { quality: 'reasoning', balanced: 'fast', budget: 'fast' },
60
- 'pan-verifier': { quality: 'reasoning', balanced: 'mid', budget: 'fast' },
61
- 'pan-plan-checker': { quality: 'reasoning', balanced: 'mid', budget: 'fast' },
62
- 'pan-integration-checker': { quality: 'reasoning', balanced: 'mid', budget: 'fast' },
63
- 'pan-reviewer': { quality: 'reasoning', balanced: 'fast', budget: 'fast' },
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: 'mid', budget: 'mid' },
67
- 'pan-hardener': { quality: 'reasoning', balanced: 'mid', budget: 'fast' },
68
- 'pan-meta-reviewer': { quality: 'reasoning', balanced: 'mid', budget: 'fast' },
69
- 'pan-knowledge': { quality: 'reasoning', balanced: 'mid', budget: 'fast' },
70
- 'pan-previewer': { quality: 'reasoning', balanced: 'fast', budget: 'fast' },
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: 'mid', budget: 'fast' },
73
- 'pan-distiller': { quality: 'reasoning', balanced: 'fast', budget: 'fast' },
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: 'fast', budget: 'fast' },
85
+ 'pan-experiment-runner': { quality: 'reasoning', balanced: 'reasoning', budget: 'fast' },
76
86
  // ADR-0033 bot-army — Release squad
77
- 'pan-release': { quality: 'reasoning', balanced: 'mid', budget: 'fast' },
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
- if (run.totals.points_used >= run.total_budget) return 'budget_cap';
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
- const DEFAULT_CAPS = { maxCycles: 25, budget: Infinity };
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 };