@narumitw/pi-usage 0.62.0 → 0.63.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.
- package/README.md +22 -26
- package/dist/chunks/{chunk-WEXCFYZX.ts → chunk-ENCC7IBP.ts} +6 -9
- package/dist/chunks/chunk-ENCC7IBP.ts.map +7 -0
- package/dist/chunks/{openai-companion-auth-Q456G46T.ts → openai-companion-auth-6VLPFVHF.ts} +4 -6
- package/dist/chunks/openai-companion-auth-6VLPFVHF.ts.map +7 -0
- package/dist/chunks/{openai-companion-usage-Y3WTMUB2.ts → openai-companion-usage-4NOBHGP7.ts} +2 -2
- package/dist/index.ts +120 -178
- package/dist/index.ts.map +3 -3
- package/docs/providers.md +15 -12
- package/package.json +1 -1
- package/src/format.ts +15 -14
- package/src/openai-companion-auth.ts +3 -5
- package/src/providers/openai-chatgpt.ts +2 -6
- package/src/query.ts +2 -2
- package/src/settings.ts +0 -5
- package/src/types.ts +0 -1
- package/src/usage-settings-ui.ts +116 -156
- package/src/usage.ts +1 -25
- package/dist/chunks/chunk-WEXCFYZX.ts.map +0 -7
- package/dist/chunks/openai-companion-auth-Q456G46T.ts.map +0 -7
- /package/dist/chunks/{openai-companion-usage-Y3WTMUB2.ts.map → openai-companion-usage-4NOBHGP7.ts.map} +0 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/openai-companion-auth.ts"],
|
|
4
|
+
"sourcesContent": ["import type { ExtensionContext } from \"@earendil-works/pi-coding-agent\";\nimport { fingerprintResolvedAuth } from \"./core.js\";\nimport { fallbackOAuthCredentialCandidates, type OAuthCredentialCandidateReader } from \"./oauth-credential-source.js\";\nimport { openAIAuthAccessToken } from \"./providers/openai-chatgpt.js\";\nimport { adapterForProvider, resolveUsageAuth } from \"./query.js\";\nimport type { ResolvedUsageAuth } from \"./types.js\";\n\n// A native app registration is routing metadata, not cryptographic same-account proof.\n// Keep this read-only boundary separate from legacy Codex querying and reset mutation policy.\nexport async function resolveOpenAICompanionAuth(\n ctx: ExtensionContext,\n native: ResolvedUsageAuth,\n salt: Uint8Array,\n credentialReader: (providerId: string) => unknown,\n candidateReader?: OAuthCredentialCandidateReader,\n): Promise<ResolvedUsageAuth> {\n const unavailable = () => ({\n ...native,\n fingerprint: fingerprintResolvedAuth(\n { apiKey: JSON.stringify([native.fingerprint, native.openaiClientId, null]) },\n salt,\n ),\n });\n if (candidateReader?.waitUntilReady && !(await candidateReader.waitUntilReady(ctx, \"openai-codex\"))) {\n throw new Error(\"Companion Codex OAuth credential readiness failed closed.\");\n }\n const adapter = adapterForProvider(\"openai-codex\");\n if (!adapter) throw new Error(\"Companion Codex usage support is unavailable.\");\n const companion = await resolveUsageAuth(ctx, adapter, salt, credentialReader);\n if (!companion) return unavailable();\n if (companion.source !== \"OAuth\")\n throw new Error(\"Companion usage requires /login openai-codex OAuth, not an API key.\");\n // Legacy querying is more permissive. Enforce explicit Authorization removals and duplicates\n // against preserved fresh provider auth before using its normalized request headers.\n const access = openAIAuthAccessToken(companion.auth);\n if (ctx.model?.provider === \"openai-codex\") {\n const selected = await ctx.modelRegistry.getApiKeyAndHeaders(ctx.model);\n if (\n !selected.ok ||\n (selected.baseUrl && new URL(selected.baseUrl).origin !== \"https://chatgpt.com\") ||\n openAIAuthAccessToken(selected) !== access\n ) {\n throw new Error(\"Selected Codex model authorization does not match the companion OAuth credential.\");\n }\n }\n if (!access || access !== openAIAuthAccessToken(companion)) {\n throw new Error(\"Companion Codex runtime authorization did not match its OAuth credential.\");\n }\n const accountId = codexAccountId(access);\n if (!accountId) throw new Error(\"Companion Codex token did not contain a valid account ID.\");\n const offered = candidateReader\n ? await candidateReader(ctx, \"openai-codex\")\n : fallbackOAuthCredentialCandidates(\"openai-codex\", credentialReader);\n if (!offered.ok) throw new Error(\"Companion Codex OAuth credential discovery failed closed.\");\n const matches = new Set<string>();\n for (const candidate of offered.candidates) {\n const credential = object(candidate);\n if (credential?.type !== \"oauth\" || credential.access !== access) continue;\n if (\n credential.accountId !== accountId ||\n typeof credential.refresh !== \"string\" ||\n !credential.refresh ||\n typeof credential.expires !== \"number\" ||\n !Number.isFinite(credential.expires)\n ) {\n throw new Error(\"The matching companion Codex OAuth credential was incomplete or had a different account ID.\");\n }\n matches.add(credential.refresh);\n }\n if (matches.size !== 1) throw new Error(\"Companion Codex OAuth must uniquely match the fresh runtime credential.\");\n const headers = { Authorization: `Bearer ${access}`, \"ChatGPT-Account-Id\": accountId };\n return {\n ...native,\n openaiCompanion: { headers },\n fingerprint: fingerprintResolvedAuth(\n { apiKey: JSON.stringify([native.fingerprint, native.openaiClientId, companion.fingerprint, headers]) },\n salt,\n ),\n secrets: [\n ...new Set([...native.secrets, ...companion.secrets, ...matches, access, accountId, headers.Authorization]),\n ],\n };\n}\n\nfunction codexAccountId(access: string): string | undefined {\n try {\n const parts = access.split(\".\");\n if (parts.length !== 3 || !parts[1]) return undefined;\n const payload = object(JSON.parse(Buffer.from(parts[1], \"base64url\").toString(\"utf8\")));\n const account = object(payload?.[\"https://api.openai.com/auth\"])?.chatgpt_account_id;\n return typeof account === \"string\" && account.length > 0 && account.length <= 512 && /^[\\x21-\\x7e]+$/u.test(account)\n ? account\n : undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction object(value: unknown): Record<string, unknown> | undefined {\n return value && typeof value === \"object\" && !Array.isArray(value) ? (value as Record<string, unknown>) : undefined;\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/dist/chunks/{openai-companion-usage-Y3WTMUB2.ts → openai-companion-usage-4NOBHGP7.ts}
RENAMED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import {
|
|
4
4
|
CHATGPT_USAGE_SETTINGS_URL,
|
|
5
5
|
fetchProviderJson
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-ENCC7IBP.ts";
|
|
7
7
|
|
|
8
8
|
// src/providers/openai-companion-usage.ts
|
|
9
9
|
var USAGE_URL = "https://chatgpt.com/backend-api/wham/usage";
|
|
@@ -117,4 +117,4 @@ export {
|
|
|
117
117
|
matchingOpenAIAppBuckets,
|
|
118
118
|
queryOpenAICompanionUsage
|
|
119
119
|
};
|
|
120
|
-
//# sourceMappingURL=openai-companion-usage-
|
|
120
|
+
//# sourceMappingURL=openai-companion-usage-4NOBHGP7.ts.map
|
package/dist/index.ts
CHANGED
|
@@ -45,7 +45,7 @@ import {
|
|
|
45
45
|
runWithConcurrency,
|
|
46
46
|
sanitizeDisplayText,
|
|
47
47
|
usageAdapters
|
|
48
|
-
} from "./chunks/chunk-
|
|
48
|
+
} from "./chunks/chunk-ENCC7IBP.ts";
|
|
49
49
|
|
|
50
50
|
// src/codex-fast.ts
|
|
51
51
|
import { calculateCost, hasApi } from "@earendil-works/pi-ai";
|
|
@@ -422,13 +422,12 @@ function formatUsageReport(report, displayState) {
|
|
|
422
422
|
function formatUsageStatusline(report, model, now = Date.now(), showCodexResetCountdown = true, codexStatusPercentage = "remaining") {
|
|
423
423
|
if (report.providerId === "openai" && report.source === "openai-chatgpt-auth") return "chatgpt usage: web only";
|
|
424
424
|
if (report.source === "openai-chatgpt-companion") {
|
|
425
|
-
|
|
426
|
-
const
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
}).join(" \xB7 ")}`;
|
|
425
|
+
const windows = report.buckets.filter((bucket) => bucket.groupId === "chatgpt-plan").map((bucket) => {
|
|
426
|
+
const reset = formatResetCountdown(bucket.resetsAt, now);
|
|
427
|
+
const window = reset ? `\u21BB ${reset}` : formatWindowLabel(bucket.windowMinutes, "weekly", true);
|
|
428
|
+
return `${bucket.remaining === void 0 ? "unavailable" : `${bucket.remaining.toFixed(0)}%`} ${window}`;
|
|
429
|
+
});
|
|
430
|
+
return `chatgpt plan ${windows.join(" ")}`;
|
|
432
431
|
}
|
|
433
432
|
if (report.providerId === "baseten") return formatBasetenStatusline(report);
|
|
434
433
|
if (report.providerId === "openai-codex") {
|
|
@@ -840,9 +839,8 @@ function formatOpenAICompanionReport(lines, report) {
|
|
|
840
839
|
for (const group of ["chatgpt-plan", "chatgpt-app"]) {
|
|
841
840
|
lines.push(group === "chatgpt-plan" ? "Plan limits:" : "App limits:");
|
|
842
841
|
for (const bucket of report.buckets.filter((bucket2) => bucket2.groupId === group)) {
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
);
|
|
842
|
+
const value = group === "chatgpt-app" ? bucket.resetsAt === void 0 ? "Reset time unavailable" : `resets ${formatReset(bucket.resetsAt)}` : formatPercentBucket(bucket);
|
|
843
|
+
lines.push(`${formatWindowLabel(bucket.windowMinutes, "weekly", false).padEnd(VALUE_COLUMN)}${value}`);
|
|
846
844
|
}
|
|
847
845
|
}
|
|
848
846
|
for (const metric of report.metrics)
|
|
@@ -1000,7 +998,6 @@ import { getAgentDir } from "@earendil-works/pi-coding-agent";
|
|
|
1000
998
|
var USAGE_SETTINGS_FILE = "pi-usage.json";
|
|
1001
999
|
var MAX_USAGE_SETTINGS_BYTES = 64 * 1024;
|
|
1002
1000
|
var DEFAULT_USAGE_SETTINGS = Object.freeze({
|
|
1003
|
-
openaiCompanionUsage: false,
|
|
1004
1001
|
codexFastMode: false,
|
|
1005
1002
|
codexStatusResetCountdown: true,
|
|
1006
1003
|
codexStatusPercentage: "remaining",
|
|
@@ -1011,7 +1008,6 @@ function usageSettingsPath() {
|
|
|
1011
1008
|
}
|
|
1012
1009
|
function normalizeUsageSettings(value) {
|
|
1013
1010
|
if (!isRecord2(value)) return void 0;
|
|
1014
|
-
if (Object.hasOwn(value, "openaiCompanionUsage") && typeof value.openaiCompanionUsage !== "boolean") return void 0;
|
|
1015
1011
|
if (Object.hasOwn(value, "codexFastMode") && typeof value.codexFastMode !== "boolean") {
|
|
1016
1012
|
return void 0;
|
|
1017
1013
|
}
|
|
@@ -1031,7 +1027,6 @@ function normalizeUsageSettings(value) {
|
|
|
1031
1027
|
effectiveTargets.fireworks = value.fireworksAccountId;
|
|
1032
1028
|
}
|
|
1033
1029
|
return {
|
|
1034
|
-
openaiCompanionUsage: value.openaiCompanionUsage === true,
|
|
1035
1030
|
codexFastMode: typeof value.codexFastMode === "boolean" ? value.codexFastMode : DEFAULT_USAGE_SETTINGS.codexFastMode,
|
|
1036
1031
|
codexStatusResetCountdown: typeof value.codexStatusResetCountdown === "boolean" ? value.codexStatusResetCountdown : DEFAULT_USAGE_SETTINGS.codexStatusResetCountdown,
|
|
1037
1032
|
codexStatusPercentage: value.codexStatusPercentage === "used" ? "used" : DEFAULT_USAGE_SETTINGS.codexStatusPercentage,
|
|
@@ -1451,156 +1446,121 @@ async function showUsageSettings(ctx, settingsRuntime, parentSignal, isCurrent,
|
|
|
1451
1446
|
const { HorizontalRule, renderBoundedFrame } = await import("@narumitw/pi-tui-kit");
|
|
1452
1447
|
if (parentSignal.aborted || !isCurrent()) return false;
|
|
1453
1448
|
let changed = false;
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
const
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
const cancel = () => close(changed);
|
|
1501
|
-
const queueUpdate = (id, requested, display) => {
|
|
1502
|
-
saveQueue = saveQueue.then(async () => {
|
|
1503
|
-
if (signal.aborted || !isCurrent()) return;
|
|
1504
|
-
const previous = settingsRuntime.get().settings[id];
|
|
1505
|
-
if (settingsRuntime.get().kind === "invalid") {
|
|
1506
|
-
settingsList.updateValue(id, settingValueLabel(id, previous));
|
|
1507
|
-
if (!signal.aborted && isCurrent()) {
|
|
1508
|
-
ctx.ui.notify("Repair pi-usage.json and reload before changing settings.", "error");
|
|
1509
|
-
tui.requestRender();
|
|
1510
|
-
}
|
|
1511
|
-
return;
|
|
1512
|
-
}
|
|
1513
|
-
try {
|
|
1514
|
-
if (id === "openaiCompanionUsage" && requested === true && previous !== true) {
|
|
1515
|
-
selectedId = id;
|
|
1516
|
-
close("consent");
|
|
1517
|
-
return;
|
|
1518
|
-
}
|
|
1519
|
-
const patch = {};
|
|
1520
|
-
patch[id] = requested;
|
|
1521
|
-
await settingsRuntime.update(patch, signal);
|
|
1522
|
-
} catch (error) {
|
|
1523
|
-
if (signal.aborted || !isCurrent()) return;
|
|
1524
|
-
settingsList.updateValue(id, settingValueLabel(id, previous));
|
|
1525
|
-
ctx.ui.notify(`Could not save pi-usage.json: ${errorMessage(error)}`, "error");
|
|
1449
|
+
return ctx.ui.custom((tui, theme, _keybindings, done) => {
|
|
1450
|
+
const localController = new AbortController();
|
|
1451
|
+
const signal = AbortSignal.any([parentSignal, localController.signal]);
|
|
1452
|
+
let closing = false;
|
|
1453
|
+
let saveQueue = Promise.resolve();
|
|
1454
|
+
const state = settingsRuntime.get();
|
|
1455
|
+
const items = [
|
|
1456
|
+
{
|
|
1457
|
+
id: "codexFastMode",
|
|
1458
|
+
label: "Codex Fast mode",
|
|
1459
|
+
description: "Use faster Codex routing at increased plan allowance consumption.",
|
|
1460
|
+
currentValue: state.settings.codexFastMode ? ON : OFF,
|
|
1461
|
+
values: [OFF, ON]
|
|
1462
|
+
},
|
|
1463
|
+
{
|
|
1464
|
+
id: "codexStatusResetCountdown",
|
|
1465
|
+
label: "Codex reset countdown",
|
|
1466
|
+
description: "Show time remaining until each Codex usage limit resets.",
|
|
1467
|
+
currentValue: state.settings.codexStatusResetCountdown ? ON : OFF,
|
|
1468
|
+
values: [OFF, ON]
|
|
1469
|
+
},
|
|
1470
|
+
{
|
|
1471
|
+
id: "codexStatusPercentage",
|
|
1472
|
+
label: "Codex percentage",
|
|
1473
|
+
description: "Show remaining or used Codex quota in the statusline.",
|
|
1474
|
+
currentValue: settingValueLabel("codexStatusPercentage", state.settings.codexStatusPercentage),
|
|
1475
|
+
values: [REMAINING, USED]
|
|
1476
|
+
}
|
|
1477
|
+
];
|
|
1478
|
+
const rule = new HorizontalRule({ ruleStyle: (text) => theme.fg("border", text) });
|
|
1479
|
+
let settingsList;
|
|
1480
|
+
const close = (result) => {
|
|
1481
|
+
if (closing) return;
|
|
1482
|
+
closing = true;
|
|
1483
|
+
localController.abort();
|
|
1484
|
+
done(result);
|
|
1485
|
+
};
|
|
1486
|
+
const cancel = () => close(changed);
|
|
1487
|
+
const queueUpdate = (id, requested, display) => {
|
|
1488
|
+
saveQueue = saveQueue.then(async () => {
|
|
1489
|
+
if (signal.aborted || !isCurrent()) return;
|
|
1490
|
+
const previous = settingsRuntime.get().settings[id];
|
|
1491
|
+
if (settingsRuntime.get().kind === "invalid") {
|
|
1492
|
+
settingsList.updateValue(id, settingValueLabel(id, previous));
|
|
1493
|
+
if (!signal.aborted && isCurrent()) {
|
|
1494
|
+
ctx.ui.notify("Repair pi-usage.json and reload before changing settings.", "error");
|
|
1526
1495
|
tui.requestRender();
|
|
1527
|
-
return;
|
|
1528
|
-
}
|
|
1529
|
-
if (previous !== requested) {
|
|
1530
|
-
changed = true;
|
|
1531
|
-
onApplied(id);
|
|
1532
1496
|
}
|
|
1497
|
+
return;
|
|
1498
|
+
}
|
|
1499
|
+
try {
|
|
1500
|
+
const patch = {};
|
|
1501
|
+
patch[id] = requested;
|
|
1502
|
+
await settingsRuntime.update(patch, signal);
|
|
1503
|
+
} catch (error) {
|
|
1533
1504
|
if (signal.aborted || !isCurrent()) return;
|
|
1534
|
-
settingsList.updateValue(id,
|
|
1535
|
-
|
|
1536
|
-
});
|
|
1537
|
-
};
|
|
1538
|
-
settingsList = new SettingsList(
|
|
1539
|
-
items,
|
|
1540
|
-
items.length + 2,
|
|
1541
|
-
getSettingsListTheme(),
|
|
1542
|
-
(id, value) => {
|
|
1543
|
-
if (closing || signal.aborted || !isCurrent()) return;
|
|
1544
|
-
selectedId = id;
|
|
1545
|
-
if (id === "codexStatusPercentage") {
|
|
1546
|
-
queueUpdate(id, value === USED ? "used" : "remaining", value);
|
|
1547
|
-
} else if (id === "codexFastMode" || id === "codexStatusResetCountdown" || id === "openaiCompanionUsage") {
|
|
1548
|
-
queueUpdate(id, value === ON, value);
|
|
1549
|
-
}
|
|
1550
|
-
},
|
|
1551
|
-
cancel
|
|
1552
|
-
);
|
|
1553
|
-
if (selectedId) settingsList.selectItem(selectedId);
|
|
1554
|
-
parentSignal.addEventListener("abort", cancel, { once: true });
|
|
1555
|
-
return {
|
|
1556
|
-
render(width) {
|
|
1557
|
-
const title = new Text(theme.fg("accent", theme.bold("pi-usage Settings")), 1, 0).render(width);
|
|
1558
|
-
const content = settingsList.render(width);
|
|
1559
|
-
const focusedRow = content.findIndex((line) => /^[→›]\s/u.test(stripVTControlCharacters(line)));
|
|
1560
|
-
const terminalRows = Number.isFinite(tui.terminal?.rows) ? Math.floor(tui.terminal.rows) : 24;
|
|
1561
|
-
const [ruleLine = ""] = rule.render(width);
|
|
1562
|
-
return renderBoundedFrame({
|
|
1563
|
-
width,
|
|
1564
|
-
maxRows: Math.max(1, terminalRows - 3),
|
|
1565
|
-
rule: ruleLine,
|
|
1566
|
-
title,
|
|
1567
|
-
content,
|
|
1568
|
-
priorityRows: focusedRow < 0 ? [] : [focusedRow],
|
|
1569
|
-
focusedRow
|
|
1570
|
-
});
|
|
1571
|
-
},
|
|
1572
|
-
invalidate: () => settingsList.invalidate(),
|
|
1573
|
-
handleInput(data) {
|
|
1574
|
-
if (closing) return;
|
|
1575
|
-
if (matchesKey(data, Key.ctrl("c"))) cancel();
|
|
1576
|
-
else settingsList.handleInput(data);
|
|
1505
|
+
settingsList.updateValue(id, settingValueLabel(id, previous));
|
|
1506
|
+
ctx.ui.notify(`Could not save pi-usage.json: ${errorMessage(error)}`, "error");
|
|
1577
1507
|
tui.requestRender();
|
|
1578
|
-
|
|
1579
|
-
dispose() {
|
|
1580
|
-
localController.abort();
|
|
1581
|
-
parentSignal.removeEventListener("abort", cancel);
|
|
1508
|
+
return;
|
|
1582
1509
|
}
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1510
|
+
if (previous !== requested) {
|
|
1511
|
+
changed = true;
|
|
1512
|
+
onApplied(id);
|
|
1513
|
+
}
|
|
1514
|
+
if (signal.aborted || !isCurrent()) return;
|
|
1515
|
+
settingsList.updateValue(id, display);
|
|
1516
|
+
tui.requestRender();
|
|
1517
|
+
});
|
|
1518
|
+
};
|
|
1519
|
+
settingsList = new SettingsList(
|
|
1520
|
+
items,
|
|
1521
|
+
items.length + 2,
|
|
1522
|
+
getSettingsListTheme(),
|
|
1523
|
+
(id, value) => {
|
|
1524
|
+
if (closing || signal.aborted || !isCurrent()) return;
|
|
1525
|
+
if (id === "codexStatusPercentage") {
|
|
1526
|
+
queueUpdate(id, value === USED ? "used" : "remaining", value);
|
|
1527
|
+
} else if (id === "codexFastMode" || id === "codexStatusResetCountdown") {
|
|
1528
|
+
queueUpdate(id, value === ON, value);
|
|
1529
|
+
}
|
|
1530
|
+
},
|
|
1531
|
+
cancel
|
|
1532
|
+
);
|
|
1533
|
+
parentSignal.addEventListener("abort", cancel, { once: true });
|
|
1534
|
+
return {
|
|
1535
|
+
render(width) {
|
|
1536
|
+
const title = new Text(theme.fg("accent", theme.bold("pi-usage Settings")), 1, 0).render(width);
|
|
1537
|
+
const content = settingsList.render(width);
|
|
1538
|
+
const focusedRow = content.findIndex((line) => /^[→›]\s/u.test(stripVTControlCharacters(line)));
|
|
1539
|
+
const terminalRows = Number.isFinite(tui.terminal?.rows) ? Math.floor(tui.terminal.rows) : 24;
|
|
1540
|
+
const [ruleLine = ""] = rule.render(width);
|
|
1541
|
+
return renderBoundedFrame({
|
|
1542
|
+
width,
|
|
1543
|
+
maxRows: Math.max(1, terminalRows - 3),
|
|
1544
|
+
rule: ruleLine,
|
|
1545
|
+
title,
|
|
1546
|
+
content,
|
|
1547
|
+
priorityRows: focusedRow < 0 ? [] : [focusedRow],
|
|
1548
|
+
focusedRow
|
|
1549
|
+
});
|
|
1550
|
+
},
|
|
1551
|
+
invalidate: () => settingsList.invalidate(),
|
|
1552
|
+
handleInput(data) {
|
|
1553
|
+
if (closing) return;
|
|
1554
|
+
if (matchesKey(data, Key.ctrl("c"))) cancel();
|
|
1555
|
+
else settingsList.handleInput(data);
|
|
1556
|
+
tui.requestRender();
|
|
1557
|
+
},
|
|
1558
|
+
dispose() {
|
|
1559
|
+
localController.abort();
|
|
1560
|
+
parentSignal.removeEventListener("abort", cancel);
|
|
1597
1561
|
}
|
|
1598
|
-
}
|
|
1599
|
-
|
|
1600
|
-
ctx.ui.notify(`Could not enable ChatGPT companion usage: ${errorMessage(error)}`, "error");
|
|
1601
|
-
}
|
|
1602
|
-
if (parentSignal.aborted || !isCurrent()) return changed;
|
|
1603
|
-
}
|
|
1562
|
+
};
|
|
1563
|
+
});
|
|
1604
1564
|
}
|
|
1605
1565
|
|
|
1606
1566
|
// src/usage.ts
|
|
@@ -1625,14 +1585,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
1625
1585
|
const credentialCandidates = createOAuthCredentialCandidateReader(pi, credentialReader);
|
|
1626
1586
|
const createRedemptionId = dependencies.createRedemptionId ?? randomUUID2;
|
|
1627
1587
|
const settingsRuntime = dependencies.settingsRuntime ?? createUsageSettingsRuntime();
|
|
1628
|
-
const resolveUsageAuth2 =
|
|
1629
|
-
ctx,
|
|
1630
|
-
adapter,
|
|
1631
|
-
salt,
|
|
1632
|
-
reader,
|
|
1633
|
-
candidates,
|
|
1634
|
-
settingsRuntime.get().settings.openaiCompanionUsage
|
|
1635
|
-
);
|
|
1588
|
+
const resolveUsageAuth2 = resolveUsageAuth;
|
|
1636
1589
|
const cache = new UsageCache(CACHE_TTL_MS);
|
|
1637
1590
|
const failureBackoff = /* @__PURE__ */ new Map();
|
|
1638
1591
|
const latestQueries = /* @__PURE__ */ new Map();
|
|
@@ -1754,7 +1707,6 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
1754
1707
|
const expectedSessionId = ctx.sessionManager.getSessionId();
|
|
1755
1708
|
const expectedModelIdentity = modelIdentity(ctx.model);
|
|
1756
1709
|
const expectedTargetId = adapter.targets ? settingsRuntime.get().settings.selectedTargets[adapter.id] : void 0;
|
|
1757
|
-
const expectedCompanionUsage = settingsRuntime.get().settings.openaiCompanionUsage;
|
|
1758
1710
|
const providerName = providerDisplayName(ctx, adapter.id);
|
|
1759
1711
|
let auth;
|
|
1760
1712
|
try {
|
|
@@ -1795,7 +1747,7 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
1795
1747
|
"zai",
|
|
1796
1748
|
"zai-coding-cn"
|
|
1797
1749
|
].includes(adapter.id);
|
|
1798
|
-
const requestContextChanged = () => expectedSessionGeneration !== sessionGeneration || ctx.sessionManager.getSessionId() !== expectedSessionId || modelIdentity(ctx.model) !== expectedModelIdentity || adapter.
|
|
1750
|
+
const requestContextChanged = () => expectedSessionGeneration !== sessionGeneration || ctx.sessionManager.getSessionId() !== expectedSessionId || modelIdentity(ctx.model) !== expectedModelIdentity || adapter.targets !== void 0 && settingsRuntime.get().settings.selectedTargets[adapter.id] !== expectedTargetId;
|
|
1799
1751
|
if (requiresRequestBoundaryGuard && requestContextChanged()) throw abortError();
|
|
1800
1752
|
if (!auth) {
|
|
1801
1753
|
if (adapter.id === "openai") invalidateProviderState(adapter.id);
|
|
@@ -2444,16 +2396,6 @@ function usageExtension(pi, dependencies = {}) {
|
|
|
2444
2396
|
controller.signal,
|
|
2445
2397
|
() => statusGeneration === menuGeneration && !controller.signal.aborted,
|
|
2446
2398
|
(id) => {
|
|
2447
|
-
if (id === "openaiCompanionUsage" && statusGeneration === menuGeneration && !controller.signal.aborted) {
|
|
2448
|
-
for (const active of nativeQueryControllers) active.abort();
|
|
2449
|
-
invalidateProviderState("openai");
|
|
2450
|
-
if (ctx.model?.provider === "openai") {
|
|
2451
|
-
statusController?.abort();
|
|
2452
|
-
statusController = void 0;
|
|
2453
|
-
clearStatusTimers();
|
|
2454
|
-
safeSetStatus(ctx, void 0);
|
|
2455
|
-
}
|
|
2456
|
-
}
|
|
2457
2399
|
if ((id === "codexStatusResetCountdown" || id === "codexStatusPercentage") && stableCurrent && statusGeneration === menuGeneration && !controller.signal.aborted) {
|
|
2458
2400
|
publishStableCurrent(ctx, stableCurrent);
|
|
2459
2401
|
}
|