pi-crew 0.9.27 → 0.9.28

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/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.9.28] — maxTokens cap + real-time steering + provider-per-model (2026-07-09)
4
+
5
+ ### Features
6
+ - **maxTokens cap for background workers**: agent config `maxTokens: N` sets `PI_CREW_MAX_OUTPUT` env var; prompt-runtime hooks `before_provider_request` to cap `payload.max_tokens`
7
+ - **Real-time child steering**: team tool writes steers to JSONL file in real-time; child's prompt-runtime polls file every 500ms and injects via `pi.sendMessage({deliverAs:"steer"})`
8
+ - **Provider quota follows selected model**: `fetchProviderUsage()` now takes a provider parameter; quota section shows data for the current model's provider only, hides for unsupported providers
9
+ - **Minimax provider quota**: fetches from `https://www.minimax.io/v1/token_plan/remains` (interval + weekly usage with reset timers)
10
+
11
+ ### Fixes
12
+ - **currentProvider not initialized**: quota bar was always hidden because `model_select` only fires on manual switch; now reads `ctx.model.provider` at `session_start`
13
+ - **Animation stability**: PUA cat frames for native terminals, braille fallback for web terminals (gotty/wetty). Removed unstable cat widget and isWebTerminal detection for default behavior
14
+ - **PI_CREW_MAX_OUTPUT_TOKENS → PI_CREW_MAX_OUTPUT**: renamed to avoid `isSecretKey` detection ("TOKEN" pattern)
15
+ - **BASE_ALLOWLIST**: added `PI_CREW_MAX_OUTPUT` and `PI_CREW_STEERING_FILE` so `sanitizeEnvSecrets` passes them through
16
+ - **parseAgentFile**: now parses `maxTokens` from agent definition frontmatter
17
+
3
18
  ## [0.9.27] — crew-vibes provider usage + animation fixes (2026-07-08)
4
19
 
5
20
  ### Features
@@ -7077,7 +7077,7 @@
7077
7077
  "format": "esm"
7078
7078
  },
7079
7079
  "src/agents/agent-config.ts": {
7080
- "bytes": 8253,
7080
+ "bytes": 8365,
7081
7081
  "imports": [
7082
7082
  {
7083
7083
  "path": "src/config/role-tools.ts",
@@ -7088,7 +7088,7 @@
7088
7088
  "format": "esm"
7089
7089
  },
7090
7090
  "src/runtime/pi-args.ts": {
7091
- "bytes": 27311,
7091
+ "bytes": 27494,
7092
7092
  "imports": [
7093
7093
  {
7094
7094
  "path": "node:fs",
@@ -7341,7 +7341,7 @@
7341
7341
  "format": "esm"
7342
7342
  },
7343
7343
  "src/runtime/child-pi.ts": {
7344
- "bytes": 65598,
7344
+ "bytes": 65884,
7345
7345
  "imports": [
7346
7346
  {
7347
7347
  "path": "node:child_process",
@@ -8003,7 +8003,7 @@
8003
8003
  "format": "esm"
8004
8004
  },
8005
8005
  "src/agents/discover-agents.ts": {
8006
- "bytes": 25500,
8006
+ "bytes": 25646,
8007
8007
  "imports": [
8008
8008
  {
8009
8009
  "path": "node:fs",
@@ -14815,7 +14815,7 @@
14815
14815
  "format": "esm"
14816
14816
  },
14817
14817
  "src/runtime/task-runner.ts": {
14818
- "bytes": 54735,
14818
+ "bytes": 54809,
14819
14819
  "imports": [
14820
14820
  {
14821
14821
  "path": "node:fs",
@@ -15975,7 +15975,7 @@
15975
15975
  "format": "esm"
15976
15976
  },
15977
15977
  "src/extension/team-tool.ts": {
15978
- "bytes": 40639,
15978
+ "bytes": 41087,
15979
15979
  "imports": [
15980
15980
  {
15981
15981
  "path": "node:fs",
@@ -17160,7 +17160,7 @@
17160
17160
  "format": "esm"
17161
17161
  },
17162
17162
  "src/extension/crew-vibes/provider-usage.ts": {
17163
- "bytes": 10862,
17163
+ "bytes": 13202,
17164
17164
  "imports": [
17165
17165
  {
17166
17166
  "path": "node:fs",
@@ -17181,7 +17181,7 @@
17181
17181
  "format": "esm"
17182
17182
  },
17183
17183
  "src/extension/crew-vibes/figures.ts": {
17184
- "bytes": 3595,
17184
+ "bytes": 3603,
17185
17185
  "imports": [
17186
17186
  {
17187
17187
  "path": "src/extension/crew-vibes/font-detect.ts",
@@ -17212,24 +17212,14 @@
17212
17212
  "imports": [],
17213
17213
  "format": "esm"
17214
17214
  },
17215
- "src/extension/crew-vibes/cat-frames.ts": {
17216
- "bytes": 847,
17217
- "imports": [],
17218
- "format": "esm"
17219
- },
17220
17215
  "src/extension/crew-vibes/index.ts": {
17221
- "bytes": 13189,
17216
+ "bytes": 12760,
17222
17217
  "imports": [
17223
17218
  {
17224
17219
  "path": "src/extension/crew-vibes/config.ts",
17225
17220
  "kind": "import-statement",
17226
17221
  "original": "./config.ts"
17227
17222
  },
17228
- {
17229
- "path": "src/extension/crew-vibes/font-detect.ts",
17230
- "kind": "import-statement",
17231
- "original": "./font-detect.ts"
17232
- },
17233
17223
  {
17234
17224
  "path": "src/extension/crew-vibes/provider-usage.ts",
17235
17225
  "kind": "import-statement",
@@ -17249,11 +17239,6 @@
17249
17239
  "path": "src/extension/crew-vibes/speed.ts",
17250
17240
  "kind": "import-statement",
17251
17241
  "original": "./speed.ts"
17252
- },
17253
- {
17254
- "path": "src/extension/crew-vibes/cat-frames.ts",
17255
- "kind": "import-statement",
17256
- "original": "./cat-frames.ts"
17257
17242
  }
17258
17243
  ],
17259
17244
  "format": "esm"
@@ -18349,7 +18334,7 @@
18349
18334
  "imports": [],
18350
18335
  "exports": [],
18351
18336
  "inputs": {},
18352
- "bytes": 6596483
18337
+ "bytes": 6599888
18353
18338
  },
18354
18339
  "dist/index.mjs": {
18355
18340
  "imports": [
@@ -20657,7 +20642,7 @@
20657
20642
  "bytesInOutput": 1291
20658
20643
  },
20659
20644
  "src/runtime/pi-args.ts": {
20660
- "bytesInOutput": 14908
20645
+ "bytesInOutput": 15095
20661
20646
  },
20662
20647
  "src/runtime/runtime-warmup.ts": {
20663
20648
  "bytesInOutput": 1998
@@ -20720,7 +20705,7 @@
20720
20705
  "bytesInOutput": 1642
20721
20706
  },
20722
20707
  "src/runtime/child-pi.ts": {
20723
- "bytesInOutput": 45261
20708
+ "bytesInOutput": 45400
20724
20709
  },
20725
20710
  "src/runtime/heartbeat-gradient.ts": {
20726
20711
  "bytesInOutput": 953
@@ -20798,7 +20783,7 @@
20798
20783
  "bytesInOutput": 5482
20799
20784
  },
20800
20785
  "src/agents/discover-agents.ts": {
20801
- "bytesInOutput": 15168
20786
+ "bytesInOutput": 15325
20802
20787
  },
20803
20788
  "src/utils/git.ts": {
20804
20789
  "bytesInOutput": 5972
@@ -21725,7 +21710,7 @@
21725
21710
  "bytesInOutput": 6123
21726
21711
  },
21727
21712
  "src/runtime/task-runner.ts": {
21728
- "bytesInOutput": 42475
21713
+ "bytesInOutput": 42554
21729
21714
  },
21730
21715
  "src/runtime/workflow-state.ts": {
21731
21716
  "bytesInOutput": 2471
@@ -21803,7 +21788,7 @@
21803
21788
  "bytesInOutput": 34875
21804
21789
  },
21805
21790
  "src/extension/team-tool.ts": {
21806
- "bytesInOutput": 35293
21791
+ "bytesInOutput": 35616
21807
21792
  },
21808
21793
  "src/ui/run-action-dispatcher.ts": {
21809
21794
  "bytesInOutput": 4137
@@ -21995,7 +21980,7 @@
21995
21980
  "bytesInOutput": 1467
21996
21981
  },
21997
21982
  "src/extension/crew-vibes/provider-usage.ts": {
21998
- "bytesInOutput": 7211
21983
+ "bytesInOutput": 9012
21999
21984
  },
22000
21985
  "src/extension/crew-vibes/figures.ts": {
22001
21986
  "bytesInOutput": 1218
@@ -22006,11 +21991,8 @@
22006
21991
  "src/extension/crew-vibes/speed.ts": {
22007
21992
  "bytesInOutput": 6470
22008
21993
  },
22009
- "src/extension/crew-vibes/cat-frames.ts": {
22010
- "bytesInOutput": 855
22011
- },
22012
21994
  "src/extension/crew-vibes/index.ts": {
22013
- "bytesInOutput": 11101
21995
+ "bytesInOutput": 10666
22014
21996
  },
22015
21997
  "src/extension/cross-extension-rpc.ts": {
22016
21998
  "bytesInOutput": 8532
@@ -22046,7 +22028,7 @@
22046
22028
  "bytesInOutput": 81
22047
22029
  }
22048
22030
  },
22049
- "bytes": 3145843
22031
+ "bytes": 3147196
22050
22032
  }
22051
22033
  }
22052
22034
  }
package/dist/index.mjs CHANGED
@@ -16490,7 +16490,9 @@ function buildPiWorkerArgs(input) {
16490
16490
  PI_TEAMS_INHERIT_SKILLS: input.agent.inheritSkills ? "1" : "0",
16491
16491
  PI_TEAMS_DEPTH: String(parentDepth + 1),
16492
16492
  PI_TEAMS_MAX_DEPTH: String(maxDepth),
16493
- PI_TEAMS_ROLE: input.agent.name
16493
+ PI_TEAMS_ROLE: input.agent.name,
16494
+ // maxTokens cap for background workers — prompt-runtime reads this to cap API output
16495
+ ...input.agent.maxTokens ? { PI_CREW_MAX_OUTPUT: String(input.agent.maxTokens) } : {}
16494
16496
  },
16495
16497
  tempDir
16496
16498
  };
@@ -18713,6 +18715,7 @@ ${JSON.stringify({ type: "message_end", usage: { input: 10, output: 5, cost: 1e-
18713
18715
  skillPaths: input.skillPaths,
18714
18716
  role: input.role
18715
18717
  });
18718
+ if (input.steeringFile) built.env.PI_CREW_STEERING_FILE = input.steeringFile;
18716
18719
  const spawnSpec = getPiSpawnCommand(built.args);
18717
18720
  try {
18718
18721
  return await new Promise((resolve21) => {
@@ -19348,7 +19351,9 @@ var init_child_pi = __esm({
19348
19351
  "PI_TEAMS_INHERIT_SKILLS",
19349
19352
  "PI_TEAMS_PI_BIN",
19350
19353
  "PI_TEAMS_MOCK_CHILD_PI",
19351
- "PI_CREW_ALLOW_MOCK"
19354
+ "PI_CREW_ALLOW_MOCK",
19355
+ "PI_CREW_MAX_OUTPUT",
19356
+ "PI_CREW_STEERING_FILE"
19352
19357
  ];
19353
19358
  ChildPiLineObserver = class _ChildPiLineObserver {
19354
19359
  buffer = "";
@@ -22157,6 +22162,10 @@ function parseAgentFile(filePath, source) {
22157
22162
  const n = Number.parseInt(frontmatter.maxTurns, 10);
22158
22163
  return Number.isFinite(n) && n > 0 ? n : void 0;
22159
22164
  })(),
22165
+ maxTokens: (() => {
22166
+ const n = Number.parseInt(frontmatter.maxTokens, 10);
22167
+ return Number.isFinite(n) && n > 0 ? n : void 0;
22168
+ })(),
22160
22169
  effort: frontmatter.effort === "low" || frontmatter.effort === "medium" || frontmatter.effort === "high" ? frontmatter.effort : void 0,
22161
22170
  disabled: frontmatter.disabled === "true" || frontmatter.enabled === "false",
22162
22171
  routing: triggers || useWhen || avoidWhen || cost || category ? { triggers, useWhen, avoidWhen, cost, category } : void 0
@@ -58134,6 +58143,7 @@ async function runTeamTask(input) {
58134
58143
  runId: manifest.runId,
58135
58144
  agentId: task.id,
58136
58145
  artifactsRoot: manifest.artifactsRoot,
58146
+ steeringFile: `${manifest.artifactsRoot}/steering/${task.id}.jsonl`,
58137
58147
  onSpawn: (pid) => {
58138
58148
  try {
58139
58149
  ({ task, tasks } = checkpointTask(manifest, tasks, task, "child-spawned", pid));
@@ -71196,6 +71206,15 @@ function handleSteer(params, ctx) {
71196
71206
  }
71197
71207
  task.pendingSteers.push(message);
71198
71208
  saveRunTasks(loaded.manifest, loaded.tasks);
71209
+ try {
71210
+ const steeringDir = `${loaded.manifest.artifactsRoot}/steering`;
71211
+ fs91.mkdirSync(steeringDir, { recursive: true });
71212
+ fs91.appendFileSync(
71213
+ `${steeringDir}/${taskId}.jsonl`,
71214
+ JSON.stringify({ type: "steer", message, ts: (/* @__PURE__ */ new Date()).toISOString() }) + "\n"
71215
+ );
71216
+ } catch {
71217
+ }
71199
71218
  appendEvent(loaded.manifest.eventsPath, {
71200
71219
  type: "task.steer_queued",
71201
71220
  runId,
@@ -81684,7 +81703,7 @@ function registerCrewShortcuts(pi) {
81684
81703
  var CREW_SHORTCUT_KEYS = CREW_SHORTCUTS.map((s) => s.key);
81685
81704
 
81686
81705
  // src/extension/crew-vibes/config.ts
81687
- import { existsSync as existsSync76, mkdirSync as mkdirSync44, readFileSync as readFileSync75, writeFileSync as writeFileSync33 } from "node:fs";
81706
+ import { existsSync as existsSync76, mkdirSync as mkdirSync45, readFileSync as readFileSync75, writeFileSync as writeFileSync33 } from "node:fs";
81688
81707
  import { dirname as dirname39, join as join76 } from "node:path";
81689
81708
 
81690
81709
  // src/extension/crew-vibes/font-detect.ts
@@ -81857,7 +81876,7 @@ function loadConfig2() {
81857
81876
  }
81858
81877
  function saveConfig(config) {
81859
81878
  const path81 = configPath2();
81860
- mkdirSync44(dirname39(path81), { recursive: true });
81879
+ mkdirSync45(dirname39(path81), { recursive: true });
81861
81880
  writeFileSync33(path81, `${JSON.stringify(normalizeConfig(config), null, 2)}
81862
81881
  `);
81863
81882
  }
@@ -81896,6 +81915,17 @@ function loadZaiToken() {
81896
81915
  return void 0;
81897
81916
  }
81898
81917
  }
81918
+ function loadMinimaxToken() {
81919
+ const envKey = process.env.MINIMAX_API_KEY?.trim();
81920
+ if (envKey) return envKey;
81921
+ try {
81922
+ const data2 = JSON.parse(readFileSync76(piAuthPath(), "utf8"));
81923
+ const key = data2.minimax?.key;
81924
+ return typeof key === "string" && key.length > 0 ? key : void 0;
81925
+ } catch {
81926
+ return void 0;
81927
+ }
81928
+ }
81899
81929
  var COPILOT_TOKEN_KEYS = ["oauth_token", "user_token", "github_token", "token"];
81900
81930
  function tokenFromHostEntry(entry) {
81901
81931
  if (!entry) return void 0;
@@ -82020,51 +82050,86 @@ function clearProviderUsageCache() {
82020
82050
  cachedUsage = null;
82021
82051
  cachedAt = 0;
82022
82052
  }
82023
- async function fetchProviderUsage(maxAgeMs = 3e5) {
82053
+ async function fetchMinimaxUsage(token) {
82054
+ const data2 = await withTimeout(1e4, async (signal) => {
82055
+ const res = await fetch("https://www.minimax.io/v1/token_plan/remains", {
82056
+ headers: { Authorization: `Bearer ${token}`, Accept: "application/json" },
82057
+ signal
82058
+ });
82059
+ if (!res.ok) throw new Error(`minimax usage HTTP ${res.status}`);
82060
+ return await res.json();
82061
+ });
82062
+ if (data2.base_resp?.status_code !== 0) throw new Error(data2.base_resp?.status_msg || "minimax API error");
82063
+ const models = data2.model_remains ?? [];
82064
+ const general = models.find((m) => m.model_name === "general") ?? models[0];
82065
+ if (!general) throw new Error("minimax: no model data");
82066
+ const intervalUsed = 100 - (general.current_interval_remaining_percent ?? 100);
82067
+ const weeklyUsed = 100 - (general.current_weekly_remaining_percent ?? 100);
82068
+ const intervalReset = typeof general.end_time === "number" ? new Date(general.end_time).toISOString() : null;
82069
+ const weeklyReset = typeof general.weekly_end_time === "number" ? new Date(general.weekly_end_time).toISOString() : null;
82070
+ return {
82071
+ providerName: "Minimax",
82072
+ fiveHourPercent: intervalUsed,
82073
+ fiveHourResetAt: intervalReset,
82074
+ weeklyPercent: weeklyUsed,
82075
+ weeklyResetAt: weeklyReset
82076
+ };
82077
+ }
82078
+ var QUOTA_PROVIDERS = /* @__PURE__ */ new Set(["anthropic", "minimax", "minimax-cn", "zai", "github-copilot"]);
82079
+ async function fetchForProvider(provider) {
82080
+ switch (provider) {
82081
+ case "anthropic": {
82082
+ const token = loadAnthropicToken();
82083
+ if (!token) return null;
82084
+ const base = await fetchAnthropicUsage(token);
82085
+ return { providerName: "Claude", ...base };
82086
+ }
82087
+ case "minimax":
82088
+ case "minimax-cn": {
82089
+ const token = loadMinimaxToken();
82090
+ if (!token) return null;
82091
+ return await fetchMinimaxUsage(token);
82092
+ }
82093
+ case "zai": {
82094
+ const token = loadZaiToken();
82095
+ if (!token) return null;
82096
+ const usage = await fetchZaiUsage(token);
82097
+ usage.providerName = "z.ai";
82098
+ return usage;
82099
+ }
82100
+ case "github-copilot": {
82101
+ const token = loadCopilotToken();
82102
+ if (!token) return null;
82103
+ const pct = await fetchCopilotMonthlyPercent(token);
82104
+ if (pct === void 0) return null;
82105
+ return {
82106
+ providerName: "Copilot",
82107
+ fiveHourPercent: 0,
82108
+ fiveHourResetAt: null,
82109
+ weeklyPercent: pct,
82110
+ weeklyResetAt: null,
82111
+ copilotMonthlyPercent: pct
82112
+ };
82113
+ }
82114
+ default:
82115
+ return null;
82116
+ }
82117
+ }
82118
+ async function fetchProviderUsage(maxAgeMs = 3e5, provider) {
82119
+ if (!provider || !QUOTA_PROVIDERS.has(provider)) {
82120
+ cachedUsage = null;
82121
+ return null;
82122
+ }
82024
82123
  if (cachedUsage !== null && Date.now() - cachedAt < maxAgeMs) {
82025
82124
  return cachedUsage;
82026
82125
  }
82027
82126
  try {
82028
- const anthropicToken = loadAnthropicToken();
82029
- if (anthropicToken) {
82030
- const base = await fetchAnthropicUsage(anthropicToken);
82031
- const usage = {
82032
- providerName: "Claude",
82033
- fiveHourPercent: base.fiveHourPercent,
82034
- fiveHourResetAt: base.fiveHourResetAt,
82035
- weeklyPercent: base.weeklyPercent,
82036
- weeklyResetAt: base.weeklyResetAt
82037
- };
82127
+ const usage = await fetchForProvider(provider);
82128
+ if (usage) {
82038
82129
  cachedUsage = usage;
82039
82130
  cachedAt = Date.now();
82040
- return usage;
82041
82131
  }
82042
- const zaiToken = loadZaiToken();
82043
- if (zaiToken) {
82044
- const usage = await fetchZaiUsage(zaiToken);
82045
- usage.providerName = "z.ai";
82046
- cachedUsage = usage;
82047
- cachedAt = Date.now();
82048
- return usage;
82049
- }
82050
- const copilotToken = loadCopilotToken();
82051
- if (copilotToken) {
82052
- const monthlyPercent = await fetchCopilotMonthlyPercent(copilotToken);
82053
- if (monthlyPercent !== void 0) {
82054
- const usage = {
82055
- providerName: "Copilot",
82056
- fiveHourPercent: 0,
82057
- fiveHourResetAt: null,
82058
- weeklyPercent: monthlyPercent,
82059
- weeklyResetAt: null,
82060
- copilotMonthlyPercent: monthlyPercent
82061
- };
82062
- cachedUsage = usage;
82063
- cachedAt = Date.now();
82064
- return usage;
82065
- }
82066
- }
82067
- return null;
82132
+ return usage;
82068
82133
  } catch {
82069
82134
  return null;
82070
82135
  }
@@ -82473,19 +82538,6 @@ var SpeedAnimator = class {
82473
82538
  }
82474
82539
  };
82475
82540
 
82476
- // src/extension/crew-vibes/cat-frames.ts
82477
- var CAT_FRAMES2 = [
82478
- // Frame 0 — standing
82479
- ["\u2584\u2584 \u2588\u2588\u2588\u2584 ", "\u2580\u2580\u2588\u2588\u2588\u2588\u2588\u2584", " \u2588\u2588\u2580\u2588\u2588 ", " \u2580\u2580 \u2580\u2580"],
82480
- // Frame 1 — step 1
82481
- [" \u2588\u2588\u2588\u2588 ", " \u2588\u2588\u2588\u2588\u2588\u2584", "\u2584\u2588\u2588\u2588\u2588\u2588\u2588\u2580", " \u2588\u2588 \u2580\u2588\u2584"],
82482
- // Frame 2 — step 2
82483
- [" \u2584\u2588\u2588\u2588\u2588\u2588\u2588", " \u2588\u2588\u2588\u2588\u2588\u2580 ", "\u2588\u2588\u2588\u2588\u2588\u2588\u2588 ", "\u2580\u2588\u2588\u2588\u2588\u2588\u2588 "],
82484
- // Frame 3 — step 3
82485
- [" \u2588\u2588\u2588\u2588 ", "\u2584\u2588\u2588\u2588\u2588\u2588\u2584 ", "\u2580\u2588\u2588\u2588\u2588\u2588\u2588\u2584", "\u2584\u2588\u2580 \u2588\u2588 "]
82486
- ];
82487
- var CAT_FRAME_COUNT = CAT_FRAMES2.length;
82488
-
82489
82541
  // src/extension/crew-vibes/index.ts
82490
82542
  function isAssistantMessage(message) {
82491
82543
  return typeof message === "object" && message !== null && message.role === "assistant";
@@ -82513,7 +82565,7 @@ function registerCrewVibes(pi) {
82513
82565
  let capacityTimer;
82514
82566
  let providerTimer;
82515
82567
  let lastProviderText;
82516
- let catFrameIndex = 0;
82568
+ let currentProvider;
82517
82569
  function visibleLen(text) {
82518
82570
  return text.replace(/\x1b\[[0-9;]*m/g, "").length;
82519
82571
  }
@@ -82590,10 +82642,6 @@ function registerCrewVibes(pi) {
82590
82642
  const speed = speedTracker.liveTokS();
82591
82643
  applyIndicator(ctx, speed);
82592
82644
  renderWorking(ctx, speed);
82593
- if (isWebTerminal()) {
82594
- catFrameIndex = (catFrameIndex + 1) % CAT_FRAMES2.length;
82595
- ctx.ui.setWidget("crew-vibes-cat", [...CAT_FRAMES2[catFrameIndex]], { placement: "aboveEditor" });
82596
- }
82597
82645
  }, config.speed.renderIntervalMs);
82598
82646
  liveTimer.unref?.();
82599
82647
  }
@@ -82625,7 +82673,7 @@ function registerCrewVibes(pi) {
82625
82673
  return;
82626
82674
  }
82627
82675
  try {
82628
- const usage = await fetchProviderUsage(config.capacity.providerRefreshMs);
82676
+ const usage = await fetchProviderUsage(config.capacity.providerRefreshMs, currentProvider);
82629
82677
  lastProviderText = renderProviderUsage(themeOf(ctx), usage);
82630
82678
  publishCapacity(ctx);
82631
82679
  } catch {
@@ -82668,6 +82716,7 @@ function registerCrewVibes(pi) {
82668
82716
  speedTracker.resetSession();
82669
82717
  footerAnimator.reset(null);
82670
82718
  clearProviderUsageCache();
82719
+ currentProvider = ctx.model?.provider;
82671
82720
  if (!config.enabled) {
82672
82721
  clearVibesStatus(ctx);
82673
82722
  return;
@@ -82692,9 +82741,6 @@ function registerCrewVibes(pi) {
82692
82741
  footerAnimator.reset(speedTracker.lastTokS);
82693
82742
  startLiveTimer(ctx);
82694
82743
  lastRenderedAt = 0;
82695
- if (isWebTerminal() && ctx.hasUI) {
82696
- ctx.ui.setWidget("crew-vibes-cat", [...CAT_FRAMES2[0]], { placement: "aboveEditor" });
82697
- }
82698
82744
  });
82699
82745
  pi.on("message_update", (event, ctx) => {
82700
82746
  if (!config.enabled || !config.speed.enabled || !isAssistantMessage(event.message) || !speedTracker.isStreaming) return;
@@ -82722,9 +82768,6 @@ function registerCrewVibes(pi) {
82722
82768
  publishSpeedFooter(ctx);
82723
82769
  startFooterTimer(ctx);
82724
82770
  applyIndicator(ctx, speedTracker.lastTokS);
82725
- if (isWebTerminal() && ctx.hasUI) {
82726
- ctx.ui.setWidget("crew-vibes-cat", void 0);
82727
- }
82728
82771
  });
82729
82772
  pi.on("turn_end", () => {
82730
82773
  speedTracker.stopMessage();
@@ -82736,10 +82779,13 @@ function registerCrewVibes(pi) {
82736
82779
  if (ctx && config.enabled && ctx.hasUI) {
82737
82780
  applyIndicator(ctx, speedTracker.lastTokS);
82738
82781
  ctx.ui.setWorkingMessage();
82739
- if (isWebTerminal()) ctx.ui.setWidget("crew-vibes-cat", void 0);
82740
82782
  }
82741
82783
  });
82742
- pi.on("model_select", (_event, ctx) => publishCapacity(ctx));
82784
+ pi.on("model_select", (event, ctx) => {
82785
+ currentProvider = event.model?.provider;
82786
+ clearProviderUsageCache();
82787
+ publishCapacity(ctx);
82788
+ });
82743
82789
  pi.on("session_compact", (_event, ctx) => publishCapacity(ctx));
82744
82790
  pi.on("session_tree", (_event, ctx) => publishCapacity(ctx));
82745
82791
  pi.on("session_shutdown", (_event, ctx) => {
@@ -82748,7 +82794,6 @@ function registerCrewVibes(pi) {
82748
82794
  stopCapacityTimer();
82749
82795
  stopProviderTimer();
82750
82796
  clearVibesStatus(ctx);
82751
- if (ctx.hasUI) ctx.ui.setWidget("crew-vibes-cat", void 0);
82752
82797
  });
82753
82798
  async function handleCommand(args, ctx) {
82754
82799
  const tokens = args.trim().split(/\s+/).filter(Boolean);