@danypops/pi-jittor 0.2.0 → 0.2.1

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.
@@ -1,6 +1,6 @@
1
+ import { USAGE_PERIODS, type UsagePeriod } from "@danypops/jittor";
1
2
  import type { ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
2
3
  import { matchesKey, truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
3
- import { USAGE_PERIODS, type UsagePeriod } from "@danypops/jittor";
4
4
  import type { CodexRecoveryControl, EnforcementControl, UsageBudgetControl } from "./settings.ts";
5
5
 
6
6
  export interface SettingsSnapshot {
@@ -24,12 +24,7 @@ export interface SettingsEffects {
24
24
  setRecovery(enabled: boolean): void | Promise<void>;
25
25
  }
26
26
 
27
- const SETTINGS_KEYS: SettingsKey[] = [
28
- "enforcement",
29
- "footer",
30
- "recovery",
31
- ...USAGE_PERIODS.map(({ id }) => `budget-${id}` as const),
32
- ];
27
+ const SETTINGS_KEYS: SettingsKey[] = ["enforcement", "footer", "recovery", ...USAGE_PERIODS.map(({ id }) => `budget-${id}` as const)];
33
28
 
34
29
  function state(enabled: boolean, theme: SettingsTheme): string {
35
30
  return enabled ? theme.fg("success", "ON") : theme.fg("muted", "OFF");
@@ -63,18 +58,14 @@ export function settingsSnapshot(
63
58
 
64
59
  export function renderSettingsView(snapshot: SettingsSnapshot, selected: number, width: number, theme: SettingsTheme): string[] {
65
60
  const safeWidth = Math.max(20, width);
66
- const lines = [
67
- theme.bold("Jittor Settings"),
68
- theme.fg("dim", "Token budgets are user values; provider quotas remain separate."),
69
- "",
70
- ];
61
+ const lines = [theme.bold("Jittor Settings"), theme.fg("dim", "Token budgets are user values; provider quotas remain separate."), ""];
71
62
  for (let index = 0; index < SETTINGS_KEYS.length; index += 1) {
72
63
  const selectedRow = index === selected;
73
64
  const prefix = selectedRow ? theme.fg("accent", "› ") : " ";
74
65
  lines.push(`${prefix}${rowText(SETTINGS_KEYS[index]!, snapshot, theme)}`);
75
66
  }
76
67
  lines.push("", theme.fg("dim", "↑/↓ select · Enter edit · Esc close"));
77
- return lines.map((line) => visibleWidth(line) <= safeWidth ? line : truncateToWidth(line, safeWidth, "…"));
68
+ return lines.map((line) => (visibleWidth(line) <= safeWidth ? line : truncateToWidth(line, safeWidth, "…")));
78
69
  }
79
70
 
80
71
  function plainTheme(): SettingsTheme {
@@ -113,7 +104,12 @@ export async function showSettingsPanel(
113
104
  },
114
105
  ): Promise<void> {
115
106
  if (ctx.mode !== "tui") {
116
- ctx.ui.notify(renderSettingsView(settingsSnapshot(enforcement, recovery, budgets), -1, 100, plainTheme()).slice(0, -2).join("\n"), "info");
107
+ ctx.ui.notify(
108
+ renderSettingsView(settingsSnapshot(enforcement, recovery, budgets), -1, 100, plainTheme())
109
+ .slice(0, -2)
110
+ .join("\n"),
111
+ "info",
112
+ );
117
113
  return;
118
114
  }
119
115
  for (;;) {
@@ -122,19 +118,32 @@ export async function showSettingsPanel(
122
118
  let selected = 0;
123
119
  return {
124
120
  invalidate() {},
125
- render(width: number): string[] { return renderSettingsView(snapshot, selected, width, theme); },
121
+ render(width: number): string[] {
122
+ return renderSettingsView(snapshot, selected, width, theme);
123
+ },
126
124
  handleInput(data: string): void {
127
125
  if (matchesKey(data, "escape") || matchesKey(data, "ctrl+c") || data === "q") done({ kind: "close" });
128
- else if (matchesKey(data, "up")) { selected = (selected - 1 + SETTINGS_KEYS.length) % SETTINGS_KEYS.length; tui.requestRender(); }
129
- else if (matchesKey(data, "down")) { selected = (selected + 1) % SETTINGS_KEYS.length; tui.requestRender(); }
130
- else if (matchesKey(data, "return") || matchesKey(data, "enter") || matchesKey(data, "space")) done({ kind: "activate", key: SETTINGS_KEYS[selected]! });
126
+ else if (matchesKey(data, "up")) {
127
+ selected = (selected - 1 + SETTINGS_KEYS.length) % SETTINGS_KEYS.length;
128
+ tui.requestRender();
129
+ } else if (matchesKey(data, "down")) {
130
+ selected = (selected + 1) % SETTINGS_KEYS.length;
131
+ tui.requestRender();
132
+ } else if (matchesKey(data, "return") || matchesKey(data, "enter") || matchesKey(data, "space"))
133
+ done({ kind: "activate", key: SETTINGS_KEYS[selected]! });
131
134
  },
132
135
  };
133
136
  });
134
137
  if (!action || action.kind === "close") return;
135
138
  if (action.key === "enforcement") {
136
139
  if (enforcement.isEnabled()) {
137
- if (await ctx.ui.confirm("Disable routing enforcement?", "Jittor will remain monitor-only and will no longer block unsafe provider requests.")) await effects.setEnforcement(false);
140
+ if (
141
+ await ctx.ui.confirm(
142
+ "Disable routing enforcement?",
143
+ "Jittor will remain monitor-only and will no longer block unsafe provider requests.",
144
+ )
145
+ )
146
+ await effects.setEnforcement(false);
138
147
  } else await effects.setEnforcement(true);
139
148
  continue;
140
149
  }
@@ -144,7 +153,13 @@ export async function showSettingsPanel(
144
153
  }
145
154
  if (action.key === "recovery") {
146
155
  if (!recovery.isCodexRecoveryEnabled()) {
147
- if (await ctx.ui.confirm("Enable Codex recovery?", "Jittor may start bounded hidden retries only after transient Codex failures fully settle.")) await effects.setRecovery(true);
156
+ if (
157
+ await ctx.ui.confirm(
158
+ "Enable Codex recovery?",
159
+ "Jittor may start bounded hidden retries only after transient Codex failures fully settle.",
160
+ )
161
+ )
162
+ await effects.setRecovery(true);
148
163
  } else await effects.setRecovery(false);
149
164
  continue;
150
165
  }
@@ -35,14 +35,16 @@ function defaultSettings(): ExtensionSettings {
35
35
  function parseUsageTokenBudgets(value: unknown): Partial<Record<UsagePeriod, number>> {
36
36
  if (typeof value !== "object" || value === null || Array.isArray(value)) return {};
37
37
  const record = value as Record<string, unknown>;
38
- return Object.fromEntries(USAGE_PERIODS.flatMap(({ id }) => {
39
- const tokens = record[id];
40
- return typeof tokens === "number" && Number.isFinite(tokens) && tokens > 0 ? [[id, tokens]] : [];
41
- })) as Partial<Record<UsagePeriod, number>>;
38
+ return Object.fromEntries(
39
+ USAGE_PERIODS.flatMap(({ id }) => {
40
+ const tokens = record[id];
41
+ return typeof tokens === "number" && Number.isFinite(tokens) && tokens > 0 ? [[id, tokens]] : [];
42
+ }),
43
+ ) as Partial<Record<UsagePeriod, number>>;
42
44
  }
43
45
 
44
46
  function settingsPath(env: Record<string, string | undefined> = process.env): string {
45
- const config = env["XDG_CONFIG_HOME"] ?? join(env["HOME"] ?? ".", ".config");
47
+ const config = env.XDG_CONFIG_HOME ?? join(env.HOME ?? ".", ".config");
46
48
  return join(config, JITTOR_STATE_DIRECTORY, JITTOR_EXTENSION_SETTINGS_FILENAME);
47
49
  }
48
50
 
@@ -52,10 +54,10 @@ function loadSettings(path: string): ExtensionSettings {
52
54
  if (typeof value !== "object" || value === null || Array.isArray(value)) return defaultSettings();
53
55
  const record = value as Record<string, unknown>;
54
56
  return {
55
- enforcementEnabled: record["enforcementEnabled"] !== false,
56
- footerEnabled: record["footerEnabled"] !== false,
57
- codexRecoveryEnabled: record["codexRecoveryEnabled"] === true,
58
- usageTokenBudgets: parseUsageTokenBudgets(record["usageTokenBudgets"]),
57
+ enforcementEnabled: record.enforcementEnabled !== false,
58
+ footerEnabled: record.footerEnabled !== false,
59
+ codexRecoveryEnabled: record.codexRecoveryEnabled === true,
60
+ usageTokenBudgets: parseUsageTokenBudgets(record.usageTokenBudgets),
59
61
  };
60
62
  } catch {
61
63
  return defaultSettings();
@@ -93,7 +95,8 @@ export function persistentEnforcementControl(env: Record<string, string | undefi
93
95
  return settings.usageTokenBudgets[period];
94
96
  },
95
97
  setUsageTokenBudget(period, tokens): void {
96
- if (tokens !== undefined && (!Number.isFinite(tokens) || tokens <= 0)) throw new Error("usage token budget must be a positive finite number");
98
+ if (tokens !== undefined && (!Number.isFinite(tokens) || tokens <= 0))
99
+ throw new Error("usage token budget must be a positive finite number");
97
100
  if (tokens === undefined) delete settings.usageTokenBudgets[period];
98
101
  else settings.usageTokenBudgets[period] = tokens;
99
102
  persistSettings(path, settings);
@@ -1,5 +1,3 @@
1
- import type { ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
2
- import { matchesKey, truncateToWidth } from "@earendil-works/pi-tui";
3
1
  import {
4
2
  HUMAN_STATUS_MAX_SOURCES,
5
3
  HUMAN_TEXT_FIELD_MAX_CHARACTERS,
@@ -9,6 +7,8 @@ import {
9
7
  type RouterStatus,
10
8
  type StoredMetricObservation,
11
9
  } from "@danypops/jittor";
10
+ import type { ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
11
+ import { matchesKey, truncateToWidth } from "@earendil-works/pi-tui";
12
12
  import type { ProviderBudget } from "./footer.ts";
13
13
  import { sessionSecretField } from "./session-identity.ts";
14
14
 
@@ -18,22 +18,34 @@ export interface JittorPanelClient {
18
18
 
19
19
  export function providerBudgetMetricQuery(status: RouterStatus): MetricQuery | null {
20
20
  switch (status.currentRoute?.provider) {
21
- case "openai-codex": return { source: "codex-subscription", metric: "used-fraction", order: "desc", limit: 100 };
22
- case "openrouter": return { source: "openrouter", order: "desc", limit: 20 };
23
- case "anthropic": return { source: "anthropic", metric: "used-fraction", order: "desc", limit: 20 };
24
- case "anthropic-vertex": return { source: "anthropic-vertex", metric: "used-fraction", order: "desc", limit: 20 };
25
- default: return null;
21
+ case "openai-codex":
22
+ return { source: "codex-subscription", metric: "used-fraction", order: "desc", limit: 100 };
23
+ case "openrouter":
24
+ return { source: "openrouter", order: "desc", limit: 20 };
25
+ case "anthropic":
26
+ return { source: "anthropic", metric: "used-fraction", order: "desc", limit: 20 };
27
+ case "anthropic-vertex":
28
+ return { source: "anthropic-vertex", metric: "used-fraction", order: "desc", limit: 20 };
29
+ default:
30
+ return null;
26
31
  }
27
32
  }
28
33
 
29
34
  type PanelAction = "pause" | "resume" | "refresh" | "override" | "clear-override" | "close";
30
35
 
31
- function latest(rows: StoredMetricObservation[], predicate: (row: StoredMetricObservation) => boolean): StoredMetricObservation | undefined {
36
+ function latest(
37
+ rows: StoredMetricObservation[],
38
+ predicate: (row: StoredMetricObservation) => boolean,
39
+ ): StoredMetricObservation | undefined {
32
40
  return rows.filter(predicate).sort((left, right) => right.observedAt - left.observedAt || right.id - left.id)[0];
33
41
  }
34
42
 
35
43
  function sanitizedText(value: string): string {
36
- return value.replace(/[\r\n\t]/g, " ").replace(/ +/g, " ").trim().slice(0, HUMAN_TEXT_FIELD_MAX_CHARACTERS);
44
+ return value
45
+ .replace(/[\r\n\t]/g, " ")
46
+ .replace(/ +/g, " ")
47
+ .trim()
48
+ .slice(0, HUMAN_TEXT_FIELD_MAX_CHARACTERS);
37
49
  }
38
50
 
39
51
  function routeText(route: Route): string {
@@ -45,26 +57,31 @@ function normalizedIdentity(value: unknown): string {
45
57
  }
46
58
 
47
59
  function longestWindow(rows: StoredMetricObservation[]): StoredMetricObservation | undefined {
48
- return [...rows].sort((left, right) =>
49
- Number(right.attributes["windowSeconds"] ?? 0) - Number(left.attributes["windowSeconds"] ?? 0)
50
- || right.observedAt - left.observedAt
51
- || right.id - left.id,
60
+ return [...rows].sort(
61
+ (left, right) =>
62
+ Number(right.attributes.windowSeconds ?? 0) - Number(left.attributes.windowSeconds ?? 0) ||
63
+ right.observedAt - left.observedAt ||
64
+ right.id - left.id,
52
65
  )[0];
53
66
  }
54
67
 
55
68
  function codexWindowForModel(rows: StoredMetricObservation[], model: string): StoredMetricObservation | undefined {
56
- const codexRows = rows.filter((row) => row.source === "codex-subscription" && row.metric === "used-fraction" && typeof row.value === "number");
69
+ const codexRows = rows.filter(
70
+ (row) => row.source === "codex-subscription" && row.metric === "used-fraction" && typeof row.value === "number",
71
+ );
57
72
  const modelIdentity = normalizedIdentity(model);
58
73
  const matchingAdditional = codexRows.filter((row) => {
59
- const limitId = normalizedIdentity(row.attributes["limitId"]);
60
- const limitName = normalizedIdentity(row.attributes["limitName"]);
74
+ const limitId = normalizedIdentity(row.attributes.limitId);
75
+ const limitName = normalizedIdentity(row.attributes.limitName);
61
76
  return limitId !== "codex" && limitName.length > 0 && limitName === modelIdentity;
62
77
  });
63
78
  if (matchingAdditional.length > 0) return longestWindow(matchingAdditional);
64
- return longestWindow(codexRows.filter((row) => {
65
- const limitId = normalizedIdentity(row.attributes["limitId"]);
66
- return limitId === "codex" || (limitId.length === 0 && row.scope.startsWith("codex:"));
67
- }));
79
+ return longestWindow(
80
+ codexRows.filter((row) => {
81
+ const limitId = normalizedIdentity(row.attributes.limitId);
82
+ return limitId === "codex" || (limitId.length === 0 && row.scope.startsWith("codex:"));
83
+ }),
84
+ );
68
85
  }
69
86
 
70
87
  function compactWindowName(seconds: number): string {
@@ -92,20 +109,27 @@ export function buildFooterBudget(status: RouterStatus, metrics: StoredMetricObs
92
109
  if (status.currentRoute.provider === "openai-codex") {
93
110
  const codex = codexWindowForModel(metrics, status.currentRoute.model);
94
111
  if (!codex || typeof codex.value !== "number") return null;
95
- const resetsAtSeconds = Number(codex.attributes["resetsAt"]);
112
+ const resetsAtSeconds = Number(codex.attributes.resetsAt);
96
113
  return {
97
114
  kind: "bounded",
98
- label: compactWindowName(Number(codex.attributes["windowSeconds"] ?? 0)),
115
+ label: compactWindowName(Number(codex.attributes.windowSeconds ?? 0)),
99
116
  remainingFraction: 1 - codex.value,
100
117
  observedAt: codex.observedAt,
101
118
  ...(Number.isFinite(resetsAtSeconds) && resetsAtSeconds > 0 ? { resetsAt: resetsAtSeconds * 1_000 } : {}),
102
119
  };
103
120
  }
104
121
  if (status.currentRoute.provider === "anthropic") {
105
- const anthropic = latest(metrics, (row) => row.source === "anthropic" && row.metric === "used-fraction" && row.scope === "tokens" && typeof row.value === "number")
106
- ?? latest(metrics, (row) => row.source === "anthropic" && row.metric === "used-fraction" && row.scope === "requests" && typeof row.value === "number");
122
+ const anthropic =
123
+ latest(
124
+ metrics,
125
+ (row) => row.source === "anthropic" && row.metric === "used-fraction" && row.scope === "tokens" && typeof row.value === "number",
126
+ ) ??
127
+ latest(
128
+ metrics,
129
+ (row) => row.source === "anthropic" && row.metric === "used-fraction" && row.scope === "requests" && typeof row.value === "number",
130
+ );
107
131
  if (!anthropic || typeof anthropic.value !== "number") return null;
108
- const resetsAt = Number(anthropic.attributes["resetsAt"]);
132
+ const resetsAt = Number(anthropic.attributes.resetsAt);
109
133
  return {
110
134
  kind: "bounded",
111
135
  label: anthropic.scope === "tokens" ? "tok" : "req",
@@ -121,10 +145,19 @@ export function buildFooterBudget(status: RouterStatus, metrics: StoredMetricObs
121
145
  // pool even if the header shape is identical. If nothing was ever observed, this stays null
122
146
  // (may still resolve later), not undefined (never possible) -- unlike google-vertex, this
123
147
  // provider's transport has not been shown to structurally lack the signal.
124
- const anthropicVertex = latest(metrics, (row) => row.source === "anthropic-vertex" && row.metric === "used-fraction" && row.scope === "tokens" && typeof row.value === "number")
125
- ?? latest(metrics, (row) => row.source === "anthropic-vertex" && row.metric === "used-fraction" && row.scope === "requests" && typeof row.value === "number");
148
+ const anthropicVertex =
149
+ latest(
150
+ metrics,
151
+ (row) =>
152
+ row.source === "anthropic-vertex" && row.metric === "used-fraction" && row.scope === "tokens" && typeof row.value === "number",
153
+ ) ??
154
+ latest(
155
+ metrics,
156
+ (row) =>
157
+ row.source === "anthropic-vertex" && row.metric === "used-fraction" && row.scope === "requests" && typeof row.value === "number",
158
+ );
126
159
  if (!anthropicVertex || typeof anthropicVertex.value !== "number") return null;
127
- const resetsAt = Number(anthropicVertex.attributes["resetsAt"]);
160
+ const resetsAt = Number(anthropicVertex.attributes.resetsAt);
128
161
  return {
129
162
  kind: "bounded",
130
163
  label: anthropicVertex.scope === "tokens" ? "vtok" : "vreq",
@@ -135,9 +168,12 @@ export function buildFooterBudget(status: RouterStatus, metrics: StoredMetricObs
135
168
  }
136
169
  if (status.currentRoute.provider === "openrouter") {
137
170
  const openRouter = latest(metrics, (row) => row.source === "openrouter" && row.metric === "usage" && typeof row.value === "number");
138
- const remaining = latest(metrics, (row) => row.source === "openrouter" && row.metric === "remaining-fraction" && typeof row.value === "number");
171
+ const remaining = latest(
172
+ metrics,
173
+ (row) => row.source === "openrouter" && row.metric === "remaining-fraction" && typeof row.value === "number",
174
+ );
139
175
  if (remaining && typeof remaining.value === "number" && (!openRouter || remaining.observedAt >= openRouter.observedAt)) {
140
- const reset = typeof remaining.attributes["reset"] === "string" ? sanitizedText(remaining.attributes["reset"]) : undefined;
176
+ const reset = typeof remaining.attributes.reset === "string" ? sanitizedText(remaining.attributes.reset) : undefined;
141
177
  return {
142
178
  kind: "bounded",
143
179
  label: "OR",
@@ -160,27 +196,42 @@ export function formatFooterStatus(status: RouterStatus, metrics: StoredMetricOb
160
196
 
161
197
  function nextAction(action: PolicyAction | undefined): string {
162
198
  switch (action) {
163
- case "continue": return "throttle";
164
- case "throttle": return "lower thinking";
165
- case "lower-thinking": return "switch model";
166
- case "switch-model": return "switch provider";
167
- case "switch-provider": return "halt";
168
- case "halt": return "halted";
169
- default: return "waiting for decision";
199
+ case "continue":
200
+ return "throttle";
201
+ case "throttle":
202
+ return "lower thinking";
203
+ case "lower-thinking":
204
+ return "switch model";
205
+ case "switch-model":
206
+ return "switch provider";
207
+ case "switch-provider":
208
+ return "halt";
209
+ case "halt":
210
+ return "halted";
211
+ default:
212
+ return "waiting for decision";
170
213
  }
171
214
  }
172
215
 
173
216
  function burnLine(rows: StoredMetricObservation[], current: StoredMetricObservation, now: number): string {
174
217
  const previous = rows
175
- .filter((row) => row.source === current.source && row.scope === current.scope && row.metric === current.metric && row.id !== current.id && row.observedAt < current.observedAt)
218
+ .filter(
219
+ (row) =>
220
+ row.source === current.source &&
221
+ row.scope === current.scope &&
222
+ row.metric === current.metric &&
223
+ row.id !== current.id &&
224
+ row.observedAt < current.observedAt,
225
+ )
176
226
  .sort((left, right) => right.observedAt - left.observedAt)[0];
177
- const resetsAt = Number(current.attributes["resetsAt"] ?? 0) * 1_000;
227
+ const resetsAt = Number(current.attributes.resetsAt ?? 0) * 1_000;
178
228
  const remainingSeconds = (resetsAt - now) / 1_000;
179
229
  const sustainable = typeof current.value === "number" && remainingSeconds > 0 ? (1 - current.value) / remainingSeconds : null;
180
- const observed = previous && typeof previous.value === "number" && typeof current.value === "number" && current.observedAt > previous.observedAt
181
- ? (current.value - previous.value) / ((current.observedAt - previous.observedAt) / 1_000)
182
- : null;
183
- const perHour = (rate: number | null) => rate === null ? "n/a" : `${(rate * 3_600 * 100).toFixed(2)}%/h`;
230
+ const observed =
231
+ previous && typeof previous.value === "number" && typeof current.value === "number" && current.observedAt > previous.observedAt
232
+ ? (current.value - previous.value) / ((current.observedAt - previous.observedAt) / 1_000)
233
+ : null;
234
+ const perHour = (rate: number | null) => (rate === null ? "n/a" : `${(rate * 3_600 * 100).toFixed(2)}%/h`);
184
235
  return `Burn: observed ${perHour(observed)} · sustainable ${perHour(sustainable)}`;
185
236
  }
186
237
 
@@ -188,21 +239,34 @@ export function buildStatusView(status: RouterStatus, metrics: StoredMetricObser
188
239
  const lines = [status.ready ? "Ready" : "Not ready"];
189
240
  const codex = status.currentRoute?.provider === "openai-codex" ? codexWindowForModel(metrics, status.currentRoute.model) : undefined;
190
241
  if (codex && typeof codex.value === "number") {
191
- const seconds = Number(codex.attributes["windowSeconds"] ?? 0);
242
+ const seconds = Number(codex.attributes.windowSeconds ?? 0);
192
243
  lines.push(`Codex ${windowName(seconds)}: ${((1 - codex.value) * 100).toFixed(1)}% left`);
193
244
  lines.push(burnLine(metrics, codex, now));
194
245
  }
195
- const openRouter = status.currentRoute?.provider === "openrouter"
196
- ? latest(metrics, (row) => row.source === "openrouter" && row.metric === "usage" && typeof row.value === "number")
197
- : undefined;
246
+ const openRouter =
247
+ status.currentRoute?.provider === "openrouter"
248
+ ? latest(metrics, (row) => row.source === "openrouter" && row.metric === "usage" && typeof row.value === "number")
249
+ : undefined;
198
250
  if (openRouter && typeof openRouter.value === "number") lines.push(`OpenRouter spend: $${openRouter.value.toFixed(3)}`);
199
- const anthropic = status.currentRoute?.provider === "anthropic"
200
- ? latest(metrics, (row) => row.source === "anthropic" && row.metric === "used-fraction" && row.scope === "tokens" && typeof row.value === "number")
201
- ?? latest(metrics, (row) => row.source === "anthropic" && row.metric === "used-fraction" && row.scope === "requests" && typeof row.value === "number")
202
- : undefined;
203
- if (anthropic && typeof anthropic.value === "number") lines.push(`Anthropic ${anthropic.scope}: ${((1 - anthropic.value) * 100).toFixed(1)}% left`);
251
+ const anthropic =
252
+ status.currentRoute?.provider === "anthropic"
253
+ ? (latest(
254
+ metrics,
255
+ (row) => row.source === "anthropic" && row.metric === "used-fraction" && row.scope === "tokens" && typeof row.value === "number",
256
+ ) ??
257
+ latest(
258
+ metrics,
259
+ (row) =>
260
+ row.source === "anthropic" && row.metric === "used-fraction" && row.scope === "requests" && typeof row.value === "number",
261
+ ))
262
+ : undefined;
263
+ if (anthropic && typeof anthropic.value === "number")
264
+ lines.push(`Anthropic ${anthropic.scope}: ${((1 - anthropic.value) * 100).toFixed(1)}% left`);
204
265
  if (status.currentRoute) lines.push(`Route: ${routeText(status.currentRoute)}`);
205
- if (status.lastDecision) lines.push(`Pressure: ${Number.isFinite(status.lastDecision.pressure) ? status.lastDecision.pressure.toFixed(3) : "∞"} · ${status.lastDecision.action}`);
266
+ if (status.lastDecision)
267
+ lines.push(
268
+ `Pressure: ${Number.isFinite(status.lastDecision.pressure) ? status.lastDecision.pressure.toFixed(3) : "∞"} · ${status.lastDecision.action}`,
269
+ );
206
270
  lines.push(`Next: ${nextAction(status.lastDecision?.action)}`);
207
271
  lines.push("Telemetry:");
208
272
  const providerSources = status.sources.filter((source) => source.provider === status.currentRoute?.provider);
@@ -210,21 +274,28 @@ export function buildStatusView(status: RouterStatus, metrics: StoredMetricObser
210
274
  const freshness = !source.ok ? "failed" : source.observedAt !== undefined && now - source.observedAt > 120_000 ? "stale" : "fresh";
211
275
  lines.push(` ${sanitizedText(source.id)}: ${freshness} · ${source.metrics} metrics`);
212
276
  }
213
- if (providerSources.length > HUMAN_STATUS_MAX_SOURCES) lines.push(` … ${providerSources.length - HUMAN_STATUS_MAX_SOURCES} more telemetry sources omitted`);
277
+ if (providerSources.length > HUMAN_STATUS_MAX_SOURCES)
278
+ lines.push(` … ${providerSources.length - HUMAN_STATUS_MAX_SOURCES} more telemetry sources omitted`);
214
279
  if (status.override) lines.push(`Override: ${routeText(status.override.route)}`);
215
280
  if (status.paused) lines.push("Emergency halt is active");
216
281
  return lines;
217
282
  }
218
283
 
219
- async function snapshot(client: JittorPanelClient, sessionId: string): Promise<{ status: RouterStatus; metrics: StoredMetricObservation[] }> {
220
- const status = await client.call("router.status", { session_id: sessionId }) as RouterStatus;
284
+ async function snapshot(
285
+ client: JittorPanelClient,
286
+ sessionId: string,
287
+ ): Promise<{ status: RouterStatus; metrics: StoredMetricObservation[] }> {
288
+ const status = (await client.call("router.status", { session_id: sessionId })) as RouterStatus;
221
289
  const query = providerBudgetMetricQuery(status);
222
- const metrics = query ? await client.call("metrics.query", query) as StoredMetricObservation[] : [];
290
+ const metrics = query ? ((await client.call("metrics.query", query)) as StoredMetricObservation[]) : [];
223
291
  return { status, metrics };
224
292
  }
225
293
 
226
294
  async function chooseOverride(ctx: ExtensionCommandContext, routes: Route[]): Promise<Route | undefined> {
227
- if (routes.length === 0) { ctx.ui.notify("Pi reports no authenticated routes for the current provider.", "warning"); return undefined; }
295
+ if (routes.length === 0) {
296
+ ctx.ui.notify("Pi reports no authenticated routes for the current provider.", "warning");
297
+ return undefined;
298
+ }
228
299
  const labels = routes.map(routeText);
229
300
  const selected = await ctx.ui.select("Override route", labels);
230
301
  const index = selected ? labels.indexOf(selected) : -1;
@@ -265,20 +336,34 @@ export async function showJittorPanel(ctx: ExtensionCommandContext, client: Jitt
265
336
  },
266
337
  }));
267
338
  if (!action || action === "close") return;
268
- if (action === "refresh") { await client.call("telemetry.poll", {}); continue; }
339
+ if (action === "refresh") {
340
+ await client.call("telemetry.poll", {});
341
+ continue;
342
+ }
269
343
  if (action === "pause" || action === "resume") {
270
- if (await ctx.ui.confirm(action === "pause" ? "Emergency-halt provider requests?" : "Release emergency halt?", "This changes provider-request enforcement. Use /jittor off to disable blocking entirely.")) {
344
+ if (
345
+ await ctx.ui.confirm(
346
+ action === "pause" ? "Emergency-halt provider requests?" : "Release emergency halt?",
347
+ "This changes provider-request enforcement. Use /jittor off to disable blocking entirely.",
348
+ )
349
+ ) {
271
350
  await client.call(action === "pause" ? "router.pause" : "router.resume", { session_id, ...sessionSecretField(session_id) });
272
351
  }
273
352
  continue;
274
353
  }
275
354
  if (action === "clear-override") {
276
- if (await ctx.ui.confirm("Clear route override?", "Policy-controlled routing will resume.")) await client.call("router.clear_override", { session_id, ...sessionSecretField(session_id) });
355
+ if (await ctx.ui.confirm("Clear route override?", "Policy-controlled routing will resume."))
356
+ await client.call("router.clear_override", { session_id, ...sessionSecretField(session_id) });
277
357
  continue;
278
358
  }
279
359
  const route = await chooseOverride(ctx, current.status.availableRoutes);
280
- if (route && await ctx.ui.confirm("Apply route override?", `${routeText(route)} for one hour`)) {
281
- await client.call("router.override", { route, expiresAt: Date.now() + 60 * 60 * 1_000, session_id, ...sessionSecretField(session_id) });
360
+ if (route && (await ctx.ui.confirm("Apply route override?", `${routeText(route)} for one hour`))) {
361
+ await client.call("router.override", {
362
+ route,
363
+ expiresAt: Date.now() + 60 * 60 * 1_000,
364
+ session_id,
365
+ ...sessionSecretField(session_id),
366
+ });
282
367
  }
283
368
  }
284
369
  }