@danypops/pi-jittor 0.2.0 → 0.3.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.
Files changed (25) hide show
  1. package/README.md +19 -3
  2. package/docs/USAGE_PRIOR_ART.md +1 -1
  3. package/extension/src/index.ts +379 -118
  4. package/extension/src/{context-breakdown.ts → observability/context-breakdown.ts} +251 -47
  5. package/extension/src/observability/context-growth.ts +26 -0
  6. package/extension/src/{capabilities → observability}/context-hub.ts +1 -5
  7. package/extension/src/observability/context-report.ts +92 -0
  8. package/extension/src/observability/context-view.ts +264 -0
  9. package/extension/src/{footer.ts → observability/footer.ts} +63 -26
  10. package/extension/src/{capabilities/local-run-telemetry.ts → observability/model-run.ts} +14 -10
  11. package/extension/src/observability/provider-context-snapshot.ts +246 -0
  12. package/extension/src/{capabilities/provider-response-telemetry.ts → observability/provider-response.ts} +21 -7
  13. package/extension/src/{tui.ts → observability/status.ts} +202 -72
  14. package/extension/src/observability/usage.ts +314 -0
  15. package/extension/src/optimization/model-selection-panel.ts +160 -0
  16. package/extension/src/{capabilities/codex-recovery.ts → optimization/recovery/codex.ts} +41 -25
  17. package/extension/src/service-client.ts +49 -2
  18. package/extension/src/settings-tui.ts +73 -33
  19. package/extension/src/settings.ts +40 -29
  20. package/package.json +11 -5
  21. package/extension/src/benchmark-tui.ts +0 -113
  22. package/extension/src/context-report.ts +0 -49
  23. package/extension/src/context-view.ts +0 -108
  24. package/extension/src/usage.ts +0 -324
  25. /package/extension/src/{capabilities → observability}/http-headers.ts +0 -0
@@ -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,
@@ -8,9 +6,12 @@ import {
8
6
  type Route,
9
7
  type RouterStatus,
10
8
  type StoredMetricObservation,
9
+ TELEMETRY_STALE_AFTER_MS,
11
10
  } from "@danypops/jittor";
11
+ import type { ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
12
+ import { matchesKey, truncateToWidth } from "@earendil-works/pi-tui";
13
+ import { sessionSecretField } from "../session-identity.ts";
12
14
  import type { ProviderBudget } from "./footer.ts";
13
- import { sessionSecretField } from "./session-identity.ts";
14
15
 
15
16
  export interface JittorPanelClient {
16
17
  call(operation: string, input: unknown): Promise<any>;
@@ -18,22 +19,34 @@ export interface JittorPanelClient {
18
19
 
19
20
  export function providerBudgetMetricQuery(status: RouterStatus): MetricQuery | null {
20
21
  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;
22
+ case "openai-codex":
23
+ return { source: "codex-subscription", metric: "used-fraction", order: "desc", limit: 100 };
24
+ case "openrouter":
25
+ return { source: "openrouter", order: "desc", limit: 20 };
26
+ case "anthropic":
27
+ return { source: "anthropic", metric: "used-fraction", order: "desc", limit: 20 };
28
+ case "anthropic-vertex":
29
+ return { source: "anthropic-vertex", metric: "used-fraction", order: "desc", limit: 20 };
30
+ default:
31
+ return null;
26
32
  }
27
33
  }
28
34
 
29
35
  type PanelAction = "pause" | "resume" | "refresh" | "override" | "clear-override" | "close";
30
36
 
31
- function latest(rows: StoredMetricObservation[], predicate: (row: StoredMetricObservation) => boolean): StoredMetricObservation | undefined {
37
+ function latest(
38
+ rows: StoredMetricObservation[],
39
+ predicate: (row: StoredMetricObservation) => boolean,
40
+ ): StoredMetricObservation | undefined {
32
41
  return rows.filter(predicate).sort((left, right) => right.observedAt - left.observedAt || right.id - left.id)[0];
33
42
  }
34
43
 
35
44
  function sanitizedText(value: string): string {
36
- return value.replace(/[\r\n\t]/g, " ").replace(/ +/g, " ").trim().slice(0, HUMAN_TEXT_FIELD_MAX_CHARACTERS);
45
+ return value
46
+ .replace(/[\r\n\t]/g, " ")
47
+ .replace(/ +/g, " ")
48
+ .trim()
49
+ .slice(0, HUMAN_TEXT_FIELD_MAX_CHARACTERS);
37
50
  }
38
51
 
39
52
  function routeText(route: Route): string {
@@ -45,26 +58,31 @@ function normalizedIdentity(value: unknown): string {
45
58
  }
46
59
 
47
60
  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,
61
+ return [...rows].sort(
62
+ (left, right) =>
63
+ Number(right.attributes.windowSeconds ?? 0) - Number(left.attributes.windowSeconds ?? 0) ||
64
+ right.observedAt - left.observedAt ||
65
+ right.id - left.id,
52
66
  )[0];
53
67
  }
54
68
 
55
69
  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");
70
+ const codexRows = rows.filter(
71
+ (row) => row.source === "codex-subscription" && row.metric === "used-fraction" && typeof row.value === "number",
72
+ );
57
73
  const modelIdentity = normalizedIdentity(model);
58
74
  const matchingAdditional = codexRows.filter((row) => {
59
- const limitId = normalizedIdentity(row.attributes["limitId"]);
60
- const limitName = normalizedIdentity(row.attributes["limitName"]);
75
+ const limitId = normalizedIdentity(row.attributes.limitId);
76
+ const limitName = normalizedIdentity(row.attributes.limitName);
61
77
  return limitId !== "codex" && limitName.length > 0 && limitName === modelIdentity;
62
78
  });
63
79
  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
- }));
80
+ return longestWindow(
81
+ codexRows.filter((row) => {
82
+ const limitId = normalizedIdentity(row.attributes.limitId);
83
+ return limitId === "codex" || (limitId.length === 0 && row.scope.startsWith("codex:"));
84
+ }),
85
+ );
68
86
  }
69
87
 
70
88
  function compactWindowName(seconds: number): string {
@@ -87,25 +105,68 @@ function windowName(seconds: number): string {
87
105
  * could ever read -- see google-vertex-contracts.ts); the footer omits the segment entirely rather
88
106
  * than showing a `?` that can never resolve.
89
107
  */
90
- export function buildFooterBudget(status: RouterStatus, metrics: StoredMetricObservation[]): ProviderBudget | null | undefined {
91
- if (!status.ready || !status.currentRoute) return null;
108
+ type CodexTelemetryState = "available" | "missing" | "failed" | "stale";
109
+
110
+ function codexTelemetryState(status: RouterStatus, now: number): CodexTelemetryState {
111
+ const source = status.sources.find((candidate) => candidate.id === "codex-subscription");
112
+ if (!source) return "missing";
113
+ if (!source.ok) return "failed";
114
+ if (source.observedAt !== undefined && now - source.observedAt > TELEMETRY_STALE_AFTER_MS) return "stale";
115
+ return "available";
116
+ }
117
+
118
+ function unavailableCodexBudget(
119
+ label: string,
120
+ reason: "reset pending" | "telemetry unavailable" | "telemetry failed" | "telemetry stale",
121
+ ): ProviderBudget {
122
+ return { kind: "unavailable", label, valueText: reason };
123
+ }
124
+
125
+ export function buildFooterBudget(
126
+ status: RouterStatus,
127
+ metrics: StoredMetricObservation[],
128
+ now = Date.now(),
129
+ ): ProviderBudget | null | undefined {
130
+ if (!status.currentRoute) return null;
92
131
  if (status.currentRoute.provider === "openai-codex") {
93
132
  const codex = codexWindowForModel(metrics, status.currentRoute.model);
94
- if (!codex || typeof codex.value !== "number") return null;
95
- const resetsAtSeconds = Number(codex.attributes["resetsAt"]);
133
+ const sourceState = codexTelemetryState(status, now);
134
+ if (!codex || typeof codex.value !== "number") {
135
+ if (sourceState === "missing") return unavailableCodexBudget("Codex", "telemetry unavailable");
136
+ if (sourceState === "failed") return unavailableCodexBudget("Codex", "telemetry failed");
137
+ if (sourceState === "stale") return unavailableCodexBudget("Codex", "telemetry stale");
138
+ return null;
139
+ }
140
+ const label = compactWindowName(Number(codex.attributes.windowSeconds ?? 0));
141
+ const resetsAtSeconds = Number(codex.attributes.resetsAt);
142
+ const resetsAt = Number.isFinite(resetsAtSeconds) && resetsAtSeconds > 0 ? resetsAtSeconds * 1_000 : undefined;
143
+ if (resetsAt !== undefined && resetsAt <= now) return unavailableCodexBudget(label, "reset pending");
144
+ if (now - codex.observedAt > TELEMETRY_STALE_AFTER_MS) {
145
+ if (sourceState === "missing") return unavailableCodexBudget(label, "telemetry unavailable");
146
+ if (sourceState === "failed") return unavailableCodexBudget(label, "telemetry failed");
147
+ return unavailableCodexBudget(label, "telemetry stale");
148
+ }
96
149
  return {
97
150
  kind: "bounded",
98
- label: compactWindowName(Number(codex.attributes["windowSeconds"] ?? 0)),
151
+ label,
99
152
  remainingFraction: 1 - codex.value,
100
153
  observedAt: codex.observedAt,
101
- ...(Number.isFinite(resetsAtSeconds) && resetsAtSeconds > 0 ? { resetsAt: resetsAtSeconds * 1_000 } : {}),
154
+ ...(resetsAt !== undefined ? { resetsAt } : {}),
102
155
  };
103
156
  }
157
+ if (!status.ready) return null;
104
158
  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");
159
+ const anthropic =
160
+ latest(
161
+ metrics,
162
+ (row) => row.source === "anthropic" && row.metric === "used-fraction" && row.scope === "tokens" && typeof row.value === "number",
163
+ ) ??
164
+ latest(
165
+ metrics,
166
+ (row) => row.source === "anthropic" && row.metric === "used-fraction" && row.scope === "requests" && typeof row.value === "number",
167
+ );
107
168
  if (!anthropic || typeof anthropic.value !== "number") return null;
108
- const resetsAt = Number(anthropic.attributes["resetsAt"]);
169
+ const resetsAt = Number(anthropic.attributes.resetsAt);
109
170
  return {
110
171
  kind: "bounded",
111
172
  label: anthropic.scope === "tokens" ? "tok" : "req",
@@ -121,10 +182,19 @@ export function buildFooterBudget(status: RouterStatus, metrics: StoredMetricObs
121
182
  // pool even if the header shape is identical. If nothing was ever observed, this stays null
122
183
  // (may still resolve later), not undefined (never possible) -- unlike google-vertex, this
123
184
  // 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");
185
+ const anthropicVertex =
186
+ latest(
187
+ metrics,
188
+ (row) =>
189
+ row.source === "anthropic-vertex" && row.metric === "used-fraction" && row.scope === "tokens" && typeof row.value === "number",
190
+ ) ??
191
+ latest(
192
+ metrics,
193
+ (row) =>
194
+ row.source === "anthropic-vertex" && row.metric === "used-fraction" && row.scope === "requests" && typeof row.value === "number",
195
+ );
126
196
  if (!anthropicVertex || typeof anthropicVertex.value !== "number") return null;
127
- const resetsAt = Number(anthropicVertex.attributes["resetsAt"]);
197
+ const resetsAt = Number(anthropicVertex.attributes.resetsAt);
128
198
  return {
129
199
  kind: "bounded",
130
200
  label: anthropicVertex.scope === "tokens" ? "vtok" : "vreq",
@@ -135,9 +205,12 @@ export function buildFooterBudget(status: RouterStatus, metrics: StoredMetricObs
135
205
  }
136
206
  if (status.currentRoute.provider === "openrouter") {
137
207
  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");
208
+ const remaining = latest(
209
+ metrics,
210
+ (row) => row.source === "openrouter" && row.metric === "remaining-fraction" && typeof row.value === "number",
211
+ );
139
212
  if (remaining && typeof remaining.value === "number" && (!openRouter || remaining.observedAt >= openRouter.observedAt)) {
140
- const reset = typeof remaining.attributes["reset"] === "string" ? sanitizedText(remaining.attributes["reset"]) : undefined;
213
+ const reset = typeof remaining.attributes.reset === "string" ? sanitizedText(remaining.attributes.reset) : undefined;
141
214
  return {
142
215
  kind: "bounded",
143
216
  label: "OR",
@@ -152,79 +225,122 @@ export function buildFooterBudget(status: RouterStatus, metrics: StoredMetricObs
152
225
  return undefined;
153
226
  }
154
227
 
155
- export function formatFooterStatus(status: RouterStatus, metrics: StoredMetricObservation[]): string {
156
- const budget = buildFooterBudget(status, metrics);
228
+ export function formatFooterStatus(status: RouterStatus, metrics: StoredMetricObservation[], now = Date.now()): string {
229
+ const budget = buildFooterBudget(status, metrics, now);
157
230
  if (!budget) return "";
158
- return budget.kind === "unbounded" ? budget.valueText : `${budget.label} ${(budget.remainingFraction * 100).toFixed(1)}% left`;
231
+ if (budget.kind === "unbounded") return budget.valueText;
232
+ if (budget.kind === "unavailable") return `${budget.label} ${budget.valueText}`;
233
+ return `${budget.label} ${(budget.remainingFraction * 100).toFixed(1)}% left`;
159
234
  }
160
235
 
161
236
  function nextAction(action: PolicyAction | undefined): string {
162
237
  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";
238
+ case "continue":
239
+ return "throttle";
240
+ case "throttle":
241
+ return "lower thinking";
242
+ case "lower-thinking":
243
+ return "switch model";
244
+ case "switch-model":
245
+ return "switch provider";
246
+ case "switch-provider":
247
+ return "halt";
248
+ case "halt":
249
+ return "halted";
250
+ default:
251
+ return "waiting for decision";
170
252
  }
171
253
  }
172
254
 
173
255
  function burnLine(rows: StoredMetricObservation[], current: StoredMetricObservation, now: number): string {
174
256
  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)
257
+ .filter(
258
+ (row) =>
259
+ row.source === current.source &&
260
+ row.scope === current.scope &&
261
+ row.metric === current.metric &&
262
+ row.id !== current.id &&
263
+ row.observedAt < current.observedAt,
264
+ )
176
265
  .sort((left, right) => right.observedAt - left.observedAt)[0];
177
- const resetsAt = Number(current.attributes["resetsAt"] ?? 0) * 1_000;
266
+ const resetsAt = Number(current.attributes.resetsAt ?? 0) * 1_000;
178
267
  const remainingSeconds = (resetsAt - now) / 1_000;
179
268
  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`;
269
+ const observed =
270
+ previous && typeof previous.value === "number" && typeof current.value === "number" && current.observedAt > previous.observedAt
271
+ ? (current.value - previous.value) / ((current.observedAt - previous.observedAt) / 1_000)
272
+ : null;
273
+ const perHour = (rate: number | null) => (rate === null ? "n/a" : `${(rate * 3_600 * 100).toFixed(2)}%/h`);
184
274
  return `Burn: observed ${perHour(observed)} · sustainable ${perHour(sustainable)}`;
185
275
  }
186
276
 
187
277
  export function buildStatusView(status: RouterStatus, metrics: StoredMetricObservation[], now = Date.now()): string[] {
188
278
  const lines = [status.ready ? "Ready" : "Not ready"];
189
279
  const codex = status.currentRoute?.provider === "openai-codex" ? codexWindowForModel(metrics, status.currentRoute.model) : undefined;
190
- if (codex && typeof codex.value === "number") {
191
- const seconds = Number(codex.attributes["windowSeconds"] ?? 0);
280
+ const budget = buildFooterBudget(status, metrics, now);
281
+ if (codex && typeof codex.value === "number" && budget?.kind === "bounded") {
282
+ const seconds = Number(codex.attributes.windowSeconds ?? 0);
192
283
  lines.push(`Codex ${windowName(seconds)}: ${((1 - codex.value) * 100).toFixed(1)}% left`);
193
284
  lines.push(burnLine(metrics, codex, now));
285
+ } else if (status.currentRoute?.provider === "openai-codex" && budget?.kind === "unavailable") {
286
+ const seconds = Number(codex?.attributes.windowSeconds ?? 0);
287
+ lines.push(`Codex ${codex ? windowName(seconds) : "subscription"}: ${budget.valueText}`);
194
288
  }
195
- const openRouter = status.currentRoute?.provider === "openrouter"
196
- ? latest(metrics, (row) => row.source === "openrouter" && row.metric === "usage" && typeof row.value === "number")
197
- : undefined;
289
+ const openRouter =
290
+ status.currentRoute?.provider === "openrouter"
291
+ ? latest(metrics, (row) => row.source === "openrouter" && row.metric === "usage" && typeof row.value === "number")
292
+ : undefined;
198
293
  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`);
294
+ const anthropic =
295
+ status.currentRoute?.provider === "anthropic"
296
+ ? (latest(
297
+ metrics,
298
+ (row) => row.source === "anthropic" && row.metric === "used-fraction" && row.scope === "tokens" && typeof row.value === "number",
299
+ ) ??
300
+ latest(
301
+ metrics,
302
+ (row) =>
303
+ row.source === "anthropic" && row.metric === "used-fraction" && row.scope === "requests" && typeof row.value === "number",
304
+ ))
305
+ : undefined;
306
+ if (anthropic && typeof anthropic.value === "number")
307
+ lines.push(`Anthropic ${anthropic.scope}: ${((1 - anthropic.value) * 100).toFixed(1)}% left`);
204
308
  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}`);
309
+ if (status.lastDecision)
310
+ lines.push(
311
+ `Pressure: ${Number.isFinite(status.lastDecision.pressure) ? status.lastDecision.pressure.toFixed(3) : "∞"} · ${status.lastDecision.action}`,
312
+ );
206
313
  lines.push(`Next: ${nextAction(status.lastDecision?.action)}`);
207
314
  lines.push("Telemetry:");
208
315
  const providerSources = status.sources.filter((source) => source.provider === status.currentRoute?.provider);
316
+ if (status.currentRoute?.provider === "openai-codex" && providerSources.length === 0)
317
+ lines.push(" codex-subscription: unavailable · not configured by active daemon");
209
318
  for (const source of providerSources.slice(0, HUMAN_STATUS_MAX_SOURCES)) {
210
319
  const freshness = !source.ok ? "failed" : source.observedAt !== undefined && now - source.observedAt > 120_000 ? "stale" : "fresh";
211
320
  lines.push(` ${sanitizedText(source.id)}: ${freshness} · ${source.metrics} metrics`);
212
321
  }
213
- if (providerSources.length > HUMAN_STATUS_MAX_SOURCES) lines.push(` … ${providerSources.length - HUMAN_STATUS_MAX_SOURCES} more telemetry sources omitted`);
322
+ if (providerSources.length > HUMAN_STATUS_MAX_SOURCES)
323
+ lines.push(` … ${providerSources.length - HUMAN_STATUS_MAX_SOURCES} more telemetry sources omitted`);
214
324
  if (status.override) lines.push(`Override: ${routeText(status.override.route)}`);
215
325
  if (status.paused) lines.push("Emergency halt is active");
216
326
  return lines;
217
327
  }
218
328
 
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;
329
+ async function snapshot(
330
+ client: JittorPanelClient,
331
+ sessionId: string,
332
+ ): Promise<{ status: RouterStatus; metrics: StoredMetricObservation[] }> {
333
+ const status = (await client.call("router.status", { session_id: sessionId })) as RouterStatus;
221
334
  const query = providerBudgetMetricQuery(status);
222
- const metrics = query ? await client.call("metrics.query", query) as StoredMetricObservation[] : [];
335
+ const metrics = query ? ((await client.call("metrics.query", query)) as StoredMetricObservation[]) : [];
223
336
  return { status, metrics };
224
337
  }
225
338
 
226
339
  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; }
340
+ if (routes.length === 0) {
341
+ ctx.ui.notify("Pi reports no authenticated routes for the current provider.", "warning");
342
+ return undefined;
343
+ }
228
344
  const labels = routes.map(routeText);
229
345
  const selected = await ctx.ui.select("Override route", labels);
230
346
  const index = selected ? labels.indexOf(selected) : -1;
@@ -265,20 +381,34 @@ export async function showJittorPanel(ctx: ExtensionCommandContext, client: Jitt
265
381
  },
266
382
  }));
267
383
  if (!action || action === "close") return;
268
- if (action === "refresh") { await client.call("telemetry.poll", {}); continue; }
384
+ if (action === "refresh") {
385
+ await client.call("telemetry.poll", {});
386
+ continue;
387
+ }
269
388
  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.")) {
389
+ if (
390
+ await ctx.ui.confirm(
391
+ action === "pause" ? "Emergency-halt provider requests?" : "Release emergency halt?",
392
+ "This changes provider-request enforcement. Use /jittor off to disable blocking entirely.",
393
+ )
394
+ ) {
271
395
  await client.call(action === "pause" ? "router.pause" : "router.resume", { session_id, ...sessionSecretField(session_id) });
272
396
  }
273
397
  continue;
274
398
  }
275
399
  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) });
400
+ if (await ctx.ui.confirm("Clear route override?", "Policy-controlled routing will resume."))
401
+ await client.call("router.clear_override", { session_id, ...sessionSecretField(session_id) });
277
402
  continue;
278
403
  }
279
404
  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) });
405
+ if (route && (await ctx.ui.confirm("Apply route override?", `${routeText(route)} for one hour`))) {
406
+ await client.call("router.override", {
407
+ route,
408
+ expiresAt: Date.now() + 60 * 60 * 1_000,
409
+ session_id,
410
+ ...sessionSecretField(session_id),
411
+ });
282
412
  }
283
413
  }
284
414
  }