@eddyskywalker/dsh-chatgpt-subscription 0.12.6 → 0.13.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.
- package/CHANGELOG.md +637 -619
- package/lib/client.js +3975 -4521
- package/lib/client.js.map +1 -1
- package/lib/index.js +1146 -299
- package/lib/types/client/CodexComposerQuota.d.ts.map +1 -1
- package/lib/types/client/CodexSubscriptionSection.d.ts +1 -3
- package/lib/types/client/CodexSubscriptionSection.d.ts.map +1 -1
- package/lib/types/client/ProviderHubSection.d.ts +6 -5
- package/lib/types/client/ProviderHubSection.d.ts.map +1 -1
- package/lib/types/client/antigravity/AntigravityComposerQuota.d.ts +22 -1
- package/lib/types/client/antigravity/AntigravityComposerQuota.d.ts.map +1 -1
- package/lib/types/client/antigravity/AntigravitySection.d.ts +0 -2
- package/lib/types/client/antigravity/AntigravitySection.d.ts.map +1 -1
- package/lib/types/client/antigravity/locales.d.ts +33 -26
- package/lib/types/client/antigravity/locales.d.ts.map +1 -1
- package/lib/types/client/antigravity/styles.d.ts.map +1 -1
- package/lib/types/client/claude/ClaudeComposerQuota.d.ts +3 -7
- package/lib/types/client/claude/ClaudeComposerQuota.d.ts.map +1 -1
- package/lib/types/client/claude/ClaudeSection.d.ts +10 -9
- package/lib/types/client/claude/ClaudeSection.d.ts.map +1 -1
- package/lib/types/client/claude/locales.d.ts +29 -29
- package/lib/types/client/claude/locales.d.ts.map +1 -1
- package/lib/types/client/claude/useClaudeSection.d.ts +93 -0
- package/lib/types/client/claude/useClaudeSection.d.ts.map +1 -0
- package/lib/types/client/command-code/CommandCodeComposerQuota.d.ts +3 -7
- package/lib/types/client/command-code/CommandCodeComposerQuota.d.ts.map +1 -1
- package/lib/types/client/command-code/CommandCodeSection.d.ts +0 -3
- package/lib/types/client/command-code/CommandCodeSection.d.ts.map +1 -1
- package/lib/types/client/command-code/locales.d.ts +32 -29
- package/lib/types/client/command-code/locales.d.ts.map +1 -1
- package/lib/types/client/common/AccountPoolSection.d.ts +16 -4
- package/lib/types/client/common/AccountPoolSection.d.ts.map +1 -1
- package/lib/types/client/common/ComposerQuotaBadge.d.ts +35 -0
- package/lib/types/client/common/ComposerQuotaBadge.d.ts.map +1 -0
- package/lib/types/client/common/ContextWindowEditor.d.ts +69 -0
- package/lib/types/client/common/ContextWindowEditor.d.ts.map +1 -0
- package/lib/types/client/common/ModelChecklist.d.ts +29 -0
- package/lib/types/client/common/ModelChecklist.d.ts.map +1 -0
- package/lib/types/client/common/account-pool-labels.d.ts +18 -2
- package/lib/types/client/common/account-pool-labels.d.ts.map +1 -1
- package/lib/types/client/common/account-quota.d.ts +60 -0
- package/lib/types/client/common/account-quota.d.ts.map +1 -0
- package/lib/types/client/common/format.d.ts +30 -0
- package/lib/types/client/common/format.d.ts.map +1 -0
- package/lib/types/client/common/line-api.d.ts +8 -0
- package/lib/types/client/common/line-api.d.ts.map +1 -0
- package/lib/types/client/common/model-checklist-styles.d.ts +2 -0
- package/lib/types/client/common/model-checklist-styles.d.ts.map +1 -0
- package/lib/types/client/common/styles.d.ts.map +1 -1
- package/lib/types/client/common/use-store.d.ts +3 -0
- package/lib/types/client/common/use-store.d.ts.map +1 -0
- package/lib/types/client/hub/HubOverview.d.ts +14 -0
- package/lib/types/client/hub/HubOverview.d.ts.map +1 -0
- package/lib/types/client/hub/brand-icons.d.ts +46 -0
- package/lib/types/client/hub/brand-icons.d.ts.map +1 -0
- package/lib/types/client/hub/brand-svg.d.ts +51 -0
- package/lib/types/client/hub/brand-svg.d.ts.map +1 -0
- package/lib/types/client/hub/hub-styles.d.ts +2 -0
- package/lib/types/client/hub/hub-styles.d.ts.map +1 -0
- package/lib/types/client/hub/providers.d.ts +38 -0
- package/lib/types/client/hub/providers.d.ts.map +1 -0
- package/lib/types/client/index.d.ts +20 -6
- package/lib/types/client/index.d.ts.map +1 -1
- package/lib/types/client/kimi-code/KimiCodeComposerQuota.d.ts +3 -7
- package/lib/types/client/kimi-code/KimiCodeComposerQuota.d.ts.map +1 -1
- package/lib/types/client/kimi-code/KimiCodeSection.d.ts +0 -3
- package/lib/types/client/kimi-code/KimiCodeSection.d.ts.map +1 -1
- package/lib/types/client/kimi-code/locales.d.ts +32 -32
- package/lib/types/client/kimi-code/locales.d.ts.map +1 -1
- package/lib/types/client/kimi-code/styles.d.ts.map +1 -1
- package/lib/types/client/locales.d.ts +45 -35
- package/lib/types/client/locales.d.ts.map +1 -1
- package/lib/types/client/minimax-code/MinimaxCodeComposerQuota.d.ts +4 -8
- package/lib/types/client/minimax-code/MinimaxCodeComposerQuota.d.ts.map +1 -1
- package/lib/types/client/minimax-code/MinimaxCodeSection.d.ts +8 -37
- package/lib/types/client/minimax-code/MinimaxCodeSection.d.ts.map +1 -1
- package/lib/types/client/minimax-code/api.d.ts +3 -3
- package/lib/types/client/minimax-code/api.d.ts.map +1 -1
- package/lib/types/client/minimax-code/locales.d.ts +29 -56
- package/lib/types/client/minimax-code/locales.d.ts.map +1 -1
- package/lib/types/client/minimax-code/useMinimaxCodeSection.d.ts +115 -0
- package/lib/types/client/minimax-code/useMinimaxCodeSection.d.ts.map +1 -0
- package/lib/types/client/ollama/OllamaSection.d.ts +2 -2
- package/lib/types/client/ollama/OllamaSection.d.ts.map +1 -1
- package/lib/types/client/ollama/locales.d.ts +54 -24
- package/lib/types/client/ollama/locales.d.ts.map +1 -1
- package/lib/types/client/styles.d.ts.map +1 -1
- package/lib/types/client/workbuddy/WorkBuddyComposerQuota.d.ts +3 -7
- package/lib/types/client/workbuddy/WorkBuddyComposerQuota.d.ts.map +1 -1
- package/lib/types/client/workbuddy/WorkBuddySection.d.ts +10 -37
- package/lib/types/client/workbuddy/WorkBuddySection.d.ts.map +1 -1
- package/lib/types/client/workbuddy/locales.d.ts +0 -66
- package/lib/types/client/workbuddy/locales.d.ts.map +1 -1
- package/lib/types/client/workbuddy/useWorkBuddySection.d.ts +141 -0
- package/lib/types/client/workbuddy/useWorkBuddySection.d.ts.map +1 -0
- package/lib/types/host/antigravity/account-pool.d.ts +18 -1
- package/lib/types/host/antigravity/account-pool.d.ts.map +1 -1
- package/lib/types/host/antigravity/client.d.ts.map +1 -1
- package/lib/types/host/claude/account-pool.d.ts +22 -2
- package/lib/types/host/claude/account-pool.d.ts.map +1 -1
- package/lib/types/host/claude/client.d.ts +37 -5
- package/lib/types/host/claude/client.d.ts.map +1 -1
- package/lib/types/host/claude/routes.d.ts.map +1 -1
- package/lib/types/host/codex-account-pool.d.ts +26 -1
- package/lib/types/host/codex-account-pool.d.ts.map +1 -1
- package/lib/types/host/command-code/account-pool.d.ts +13 -1
- package/lib/types/host/command-code/account-pool.d.ts.map +1 -1
- package/lib/types/host/command-code/client.d.ts +2 -1
- package/lib/types/host/command-code/client.d.ts.map +1 -1
- package/lib/types/host/common/account-quota.d.ts +44 -0
- package/lib/types/host/common/account-quota.d.ts.map +1 -0
- package/lib/types/host/common/catalog-snapshot.d.ts +9 -0
- package/lib/types/host/common/catalog-snapshot.d.ts.map +1 -1
- package/lib/types/host/common/provider-route.d.ts +56 -0
- package/lib/types/host/common/provider-route.d.ts.map +1 -0
- package/lib/types/host/hub-overview.d.ts +26 -0
- package/lib/types/host/hub-overview.d.ts.map +1 -0
- package/lib/types/host/kimi-code/account-pool.d.ts +24 -1
- package/lib/types/host/kimi-code/account-pool.d.ts.map +1 -1
- package/lib/types/host/kimi-code/client.d.ts +23 -2
- package/lib/types/host/kimi-code/client.d.ts.map +1 -1
- package/lib/types/host/minimax-code/account-pool.d.ts +34 -2
- package/lib/types/host/minimax-code/account-pool.d.ts.map +1 -1
- package/lib/types/host/minimax-code/client.d.ts +23 -0
- package/lib/types/host/minimax-code/client.d.ts.map +1 -1
- package/lib/types/host/minimax-code/routes.d.ts.map +1 -1
- package/lib/types/host/oauth-service.d.ts +16 -0
- package/lib/types/host/oauth-service.d.ts.map +1 -1
- package/lib/types/host/usage-service.d.ts +27 -2
- package/lib/types/host/usage-service.d.ts.map +1 -1
- package/lib/types/host/workbuddy/account-pool.d.ts +13 -1
- package/lib/types/host/workbuddy/account-pool.d.ts.map +1 -1
- package/lib/types/host/workbuddy/client.d.ts +15 -0
- package/lib/types/host/workbuddy/client.d.ts.map +1 -1
- package/lib/types/host/workbuddy/routes.d.ts.map +1 -1
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/shared/account-pool-contracts.d.ts +44 -0
- package/lib/types/shared/account-pool-contracts.d.ts.map +1 -1
- package/lib/types/shared/antigravity-contracts.d.ts +9 -3
- package/lib/types/shared/antigravity-contracts.d.ts.map +1 -1
- package/lib/types/shared/hub-contracts.d.ts +37 -0
- package/lib/types/shared/hub-contracts.d.ts.map +1 -0
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -516,6 +516,17 @@ function catalogSnapshotPath(name) {
|
|
|
516
516
|
return path.join(dshHomeDir(), "storages", `${name}-catalog.json`);
|
|
517
517
|
}
|
|
518
518
|
/**
|
|
519
|
+
* How many models one line's catalog holds, for the hub overview's "N/M models".
|
|
520
|
+
*
|
|
521
|
+
* An empty catalog is reported as `null` rather than `0`: "this line has synced
|
|
522
|
+
* nothing yet" and "this line offers no models" are different statements, and
|
|
523
|
+
* only the second one is a fact. The overview hides the model count for a null,
|
|
524
|
+
* which is what a line that has never synced should show.
|
|
525
|
+
*/
|
|
526
|
+
function catalogTotal(count) {
|
|
527
|
+
return count === 0 ? null : count;
|
|
528
|
+
}
|
|
529
|
+
/**
|
|
519
530
|
* Snapshot name for one catalog *and* one credential scope.
|
|
520
531
|
*
|
|
521
532
|
* A persisted snapshot answers before any credential is read — that is the whole
|
|
@@ -681,7 +692,7 @@ let snapshotRehydrated = null;
|
|
|
681
692
|
* directly; returning it here under a different entry type would force every
|
|
682
693
|
* one of them to convert it.
|
|
683
694
|
*/
|
|
684
|
-
function getCachedCatalog() {
|
|
695
|
+
function getCachedCatalog$2() {
|
|
685
696
|
return catalogCache$2?.models;
|
|
686
697
|
}
|
|
687
698
|
/**
|
|
@@ -740,7 +751,7 @@ async function performCatalogLoad$1(credentials, options) {
|
|
|
740
751
|
live = true;
|
|
741
752
|
writeCatalogSnapshot(catalogSnapshotName(SNAPSHOT_SCOPE, key), [...models], Date.now());
|
|
742
753
|
} catch {
|
|
743
|
-
models = getCachedCatalog() ?? [];
|
|
754
|
+
models = getCachedCatalog$2() ?? [];
|
|
744
755
|
live = false;
|
|
745
756
|
}
|
|
746
757
|
catalogCache$2 = {
|
|
@@ -2521,13 +2532,31 @@ var OAuthService = class {
|
|
|
2521
2532
|
* "credentials are required" on every web search.
|
|
2522
2533
|
*/
|
|
2523
2534
|
async credentials(forceRefresh = false, access = {}) {
|
|
2535
|
+
return (await this.credentialSelection(forceRefresh, access)).credentials;
|
|
2536
|
+
}
|
|
2537
|
+
/**
|
|
2538
|
+
* The credential to use next, together with the pool row that owns it.
|
|
2539
|
+
*
|
|
2540
|
+
* The settings card keys each account's quota snapshot by the row the reading
|
|
2541
|
+
* was made for, and the credential cannot do that job: a refresh rotates its
|
|
2542
|
+
* tokens, and an account may state no id of its own. Callers that care about
|
|
2543
|
+
* identity ask here; every other caller keeps using {@link credentials} and
|
|
2544
|
+
* sees no difference.
|
|
2545
|
+
*
|
|
2546
|
+
* @param forceRefresh - refresh even a token that is not close to expiry.
|
|
2547
|
+
* @param access - who is asking; see {@link credentials}.
|
|
2548
|
+
*/
|
|
2549
|
+
async credentialSelection(forceRefresh = false, access = {}) {
|
|
2524
2550
|
if (this.pool !== null) {
|
|
2525
|
-
|
|
2526
|
-
return
|
|
2551
|
+
const picked = access.purpose === "tool" ? await this.pool.getCredentialAccount(this.fetchFn, forceRefresh) : await this.pool.getEffectiveAccount(void 0, this.fetchFn, forceRefresh);
|
|
2552
|
+
return {
|
|
2553
|
+
accountId: picked.account.id,
|
|
2554
|
+
credentials: picked.credentials
|
|
2555
|
+
};
|
|
2527
2556
|
}
|
|
2528
2557
|
const stored = await this.loadAuthenticated();
|
|
2529
|
-
if (forceRefresh || stored.expiresAt - this.now() <= 6e4) return this.refreshCredentials(stored);
|
|
2530
|
-
return stored;
|
|
2558
|
+
if (forceRefresh || stored.expiresAt - this.now() <= 6e4) return { credentials: await this.refreshCredentials(stored) };
|
|
2559
|
+
return { credentials: stored };
|
|
2531
2560
|
}
|
|
2532
2561
|
dispose() {
|
|
2533
2562
|
if (this.disposed) return;
|
|
@@ -2823,6 +2852,49 @@ async function oauthErrorIdentifier(response) {
|
|
|
2823
2852
|
return null;
|
|
2824
2853
|
}
|
|
2825
2854
|
//#endregion
|
|
2855
|
+
//#region src/host/common/account-quota.ts
|
|
2856
|
+
/**
|
|
2857
|
+
* A reset instant as Unix milliseconds.
|
|
2858
|
+
*
|
|
2859
|
+
* Providers state this in seconds, in milliseconds, or not at all, and the two
|
|
2860
|
+
* numeric forms are told apart by magnitude rather than by a flag: 10^10
|
|
2861
|
+
* seconds is the year 2286, so anything larger is already milliseconds.
|
|
2862
|
+
*/
|
|
2863
|
+
function quotaResetMs(value) {
|
|
2864
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) return null;
|
|
2865
|
+
return value > 1e10 ? value : value * 1e3;
|
|
2866
|
+
}
|
|
2867
|
+
/**
|
|
2868
|
+
* One window, or null when its consumed share was never measured.
|
|
2869
|
+
*
|
|
2870
|
+
* `label` may be empty: the card names an unlabeled window from its length, and
|
|
2871
|
+
* only falls back to a generic name when the line stated neither.
|
|
2872
|
+
*/
|
|
2873
|
+
function quotaWindow$1(label, usedPercent, options = {}) {
|
|
2874
|
+
if (typeof usedPercent !== "number" || !Number.isFinite(usedPercent)) return null;
|
|
2875
|
+
const windowDurationMins = typeof options.windowDurationMins === "number" && Number.isFinite(options.windowDurationMins) ? options.windowDurationMins : null;
|
|
2876
|
+
return {
|
|
2877
|
+
label,
|
|
2878
|
+
usedPercent: Math.min(100, Math.max(0, usedPercent)),
|
|
2879
|
+
windowDurationMins,
|
|
2880
|
+
resetsAt: quotaResetMs(options.resetsAt)
|
|
2881
|
+
};
|
|
2882
|
+
}
|
|
2883
|
+
/**
|
|
2884
|
+
* The snapshot to publish for one account, or undefined when there is none.
|
|
2885
|
+
*
|
|
2886
|
+
* Undefined is the honest answer for "never read" and for "read before this
|
|
2887
|
+
* process started": both mean the card has nothing to show, and neither means
|
|
2888
|
+
* the account is unspent.
|
|
2889
|
+
*/
|
|
2890
|
+
function poolQuota(fetchedAt, windows) {
|
|
2891
|
+
if (typeof fetchedAt !== "number" || !Number.isFinite(fetchedAt) || fetchedAt <= 0) return void 0;
|
|
2892
|
+
return {
|
|
2893
|
+
windows: windows.filter((window) => window !== null),
|
|
2894
|
+
fetchedAt
|
|
2895
|
+
};
|
|
2896
|
+
}
|
|
2897
|
+
//#endregion
|
|
2826
2898
|
//#region src/host/codex-account-pool.ts
|
|
2827
2899
|
/** Encrypted pool file the ChatGPT line owns; the single-credential store stays the mirror. */
|
|
2828
2900
|
function codexPoolPath() {
|
|
@@ -2891,13 +2963,32 @@ const concurrency = new ConcurrencyGate();
|
|
|
2891
2963
|
function chatGPTConcurrency() {
|
|
2892
2964
|
return concurrency;
|
|
2893
2965
|
}
|
|
2966
|
+
/**
|
|
2967
|
+
* One ChatGPT usage snapshot as the account card's per-account quota.
|
|
2968
|
+
*
|
|
2969
|
+
* A bucket lists its windows either in `windows` or, on older payloads, only as
|
|
2970
|
+
* the `primary`/`secondary` pair — the same fallback the quota card itself
|
|
2971
|
+
* applies, so the account row cannot show fewer windows than the card does. The
|
|
2972
|
+
* label stays empty on purpose: a ChatGPT window is named by its length, and
|
|
2973
|
+
* the card localizes that length in the reader's own language.
|
|
2974
|
+
*/
|
|
2975
|
+
function codexAccountQuota(snapshot) {
|
|
2976
|
+
return poolQuota(snapshot.fetchedAt, snapshot.usage.buckets.flatMap((bucket) => {
|
|
2977
|
+
return (bucket.windows.length > 0 ? bucket.windows : [bucket.primary, bucket.secondary].filter((window) => window !== null)).map((window) => quotaWindow$1("", window.usedPercent, {
|
|
2978
|
+
windowDurationMins: window.windowDurationMins,
|
|
2979
|
+
resetsAt: window.resetsAt
|
|
2980
|
+
}));
|
|
2981
|
+
}));
|
|
2982
|
+
}
|
|
2894
2983
|
var CodexAccountPool = class extends AccountPoolCore {
|
|
2895
2984
|
refresherRef;
|
|
2896
2985
|
store;
|
|
2986
|
+
quotaSnapshotRef;
|
|
2897
2987
|
quotaBlockedUntil;
|
|
2898
2988
|
constructor(options = {}) {
|
|
2899
2989
|
const store = options.store ?? createPlatformTokenStore();
|
|
2900
2990
|
const ref = {};
|
|
2991
|
+
const quotaSnapshotRef = {};
|
|
2901
2992
|
const hooks = {
|
|
2902
2993
|
providerId: "codex-chatgpt",
|
|
2903
2994
|
displayName: "ChatGPT",
|
|
@@ -2948,7 +3039,11 @@ var CodexAccountPool = class extends AccountPoolCore {
|
|
|
2948
3039
|
extendSummary: (account, base) => ({
|
|
2949
3040
|
...base,
|
|
2950
3041
|
...account.email === void 0 ? {} : { email: account.email },
|
|
2951
|
-
...account.planType === void 0 ? {} : { planLabel: account.planType }
|
|
3042
|
+
...account.planType === void 0 ? {} : { planLabel: account.planType },
|
|
3043
|
+
...(() => {
|
|
3044
|
+
const quota = quotaSnapshotRef.current?.(account);
|
|
3045
|
+
return quota === void 0 ? {} : { quota };
|
|
3046
|
+
})()
|
|
2952
3047
|
}),
|
|
2953
3048
|
emptyMessage: "未登录 ChatGPT 账号,请在「设置 → 订阅服务 → ChatGPT」中添加并登录账号。",
|
|
2954
3049
|
...options.backend === void 0 ? {} : { backend: options.backend },
|
|
@@ -2956,6 +3051,7 @@ var CodexAccountPool = class extends AccountPoolCore {
|
|
|
2956
3051
|
};
|
|
2957
3052
|
super(hooks);
|
|
2958
3053
|
this.refresherRef = ref;
|
|
3054
|
+
this.quotaSnapshotRef = quotaSnapshotRef;
|
|
2959
3055
|
this.store = store;
|
|
2960
3056
|
}
|
|
2961
3057
|
/** Hand the pool the OAuth service's per-account refresh implementation. */
|
|
@@ -2973,6 +3069,18 @@ var CodexAccountPool = class extends AccountPoolCore {
|
|
|
2973
3069
|
setQuotaBlockedUntil(lookup) {
|
|
2974
3070
|
this.quotaBlockedUntil = lookup;
|
|
2975
3071
|
}
|
|
3072
|
+
/**
|
|
3073
|
+
* Wire in the account's own newest quota snapshot, for display only.
|
|
3074
|
+
*
|
|
3075
|
+
* The same map that already spares an exhausted account a wasted request also
|
|
3076
|
+
* answers "what did this account's window look like last time we read it".
|
|
3077
|
+
* The lookup must be a memory read: it runs while the settings card builds
|
|
3078
|
+
* its account list, and that page must never fan out an upstream request per
|
|
3079
|
+
* pooled account.
|
|
3080
|
+
*/
|
|
3081
|
+
setQuotaSnapshot(lookup) {
|
|
3082
|
+
this.quotaSnapshotRef.current = lookup;
|
|
3083
|
+
}
|
|
2976
3084
|
isEligible(account, now, triedAccountIds) {
|
|
2977
3085
|
if (!super.isEligible(account, now, triedAccountIds)) return false;
|
|
2978
3086
|
const blockedUntil = this.quotaBlockedUntil?.(account, now);
|
|
@@ -4088,6 +4196,56 @@ function createControlledModelFetch(baseFetch, options) {
|
|
|
4088
4196
|
};
|
|
4089
4197
|
}
|
|
4090
4198
|
//#endregion
|
|
4199
|
+
//#region src/host/common/provider-route.ts
|
|
4200
|
+
/**
|
|
4201
|
+
* Claim one provider route for this plugin and keep claiming it.
|
|
4202
|
+
*
|
|
4203
|
+
* The route is taken immediately, and every `llm/adapters-updated` reports the
|
|
4204
|
+
* claim again — it is a no-op while the registration is held, and takes the
|
|
4205
|
+
* route back once another owner releases it. A rejected claim is remembered
|
|
4206
|
+
* rather than thrown, because the line whose route table asks through
|
|
4207
|
+
* {@link ProviderRouteClaim.conflict} still has to render.
|
|
4208
|
+
* @param ctx - The plugin context owning the `llm` service and the event seam.
|
|
4209
|
+
* @param options - The route id, the display label the two log lines name, and the adapter serving it.
|
|
4210
|
+
* @returns The claim's state and its disposer.
|
|
4211
|
+
*/
|
|
4212
|
+
function claimProviderRoute(ctx, options) {
|
|
4213
|
+
let registration;
|
|
4214
|
+
let conflict = null;
|
|
4215
|
+
const claim = () => {
|
|
4216
|
+
if (registration !== void 0) return;
|
|
4217
|
+
try {
|
|
4218
|
+
registration = ctx.llm.registerAdapter([options.providerId], options.adapter);
|
|
4219
|
+
if (conflict !== null) ctx.logger.info(`[dsh-chatgpt-subscription] ${options.label} route "${options.providerId}" is now served by this plugin`);
|
|
4220
|
+
conflict = null;
|
|
4221
|
+
} catch (error) {
|
|
4222
|
+
conflict = error instanceof Error ? error.message : String(error);
|
|
4223
|
+
ctx.logger.warn(`[dsh-chatgpt-subscription] provider route "${options.providerId}" is already owned by another adapter; ${options.label} models keep being served by that one until its configuration is removed (${conflict})`);
|
|
4224
|
+
}
|
|
4225
|
+
};
|
|
4226
|
+
claim();
|
|
4227
|
+
const watch = options.watch === false || typeof ctx.on !== "function" ? void 0 : ctx.on("llm/adapters-updated", () => {
|
|
4228
|
+
claim();
|
|
4229
|
+
});
|
|
4230
|
+
return {
|
|
4231
|
+
serving: () => registration !== void 0,
|
|
4232
|
+
conflict: () => conflict,
|
|
4233
|
+
dispose: () => {
|
|
4234
|
+
releaseHandle(watch);
|
|
4235
|
+
registration?.();
|
|
4236
|
+
registration = void 0;
|
|
4237
|
+
}
|
|
4238
|
+
};
|
|
4239
|
+
}
|
|
4240
|
+
/** Cordis event handles are either a disposer function or a disposable object. */
|
|
4241
|
+
function releaseHandle(handle) {
|
|
4242
|
+
if (typeof handle === "function") {
|
|
4243
|
+
handle();
|
|
4244
|
+
return;
|
|
4245
|
+
}
|
|
4246
|
+
handle?.dispose?.();
|
|
4247
|
+
}
|
|
4248
|
+
//#endregion
|
|
4091
4249
|
//#region src/host/common/request-diagnostics.ts
|
|
4092
4250
|
/**
|
|
4093
4251
|
* Reusable request diagnostics wrapper for model provider calls.
|
|
@@ -6239,6 +6397,72 @@ function acceptIdentity(current, incoming) {
|
|
|
6239
6397
|
return typeof incoming === "string" && incoming.length > 0 ? incoming : current;
|
|
6240
6398
|
}
|
|
6241
6399
|
//#endregion
|
|
6400
|
+
//#region src/shared/hub-contracts.ts
|
|
6401
|
+
/**
|
|
6402
|
+
* Wire contracts for the subscription hub's overview route.
|
|
6403
|
+
*
|
|
6404
|
+
* The overview is the settings page's opening screen: one card per provider
|
|
6405
|
+
* line, annotated with how many accounts it holds and whether it is enabled.
|
|
6406
|
+
* Everything here is a non-secret fact a settings card may render; no
|
|
6407
|
+
* credential, quota figure, or upstream call ever crosses this boundary.
|
|
6408
|
+
*/
|
|
6409
|
+
/** The aggregated, read-only overview the hub's opening screen renders. */
|
|
6410
|
+
const HUB_OVERVIEW_PATH = `${ROUTE_PREFIX$5}/hub/overview`;
|
|
6411
|
+
//#endregion
|
|
6412
|
+
//#region src/host/hub-overview.ts
|
|
6413
|
+
function registerHubOverviewRoutes(ctx, sources) {
|
|
6414
|
+
const handler = async (request, response) => {
|
|
6415
|
+
if (request.method !== "GET") {
|
|
6416
|
+
response.writeHead(405, {
|
|
6417
|
+
allow: "GET",
|
|
6418
|
+
"content-type": "application/json; charset=utf-8"
|
|
6419
|
+
});
|
|
6420
|
+
response.end(JSON.stringify({
|
|
6421
|
+
ok: false,
|
|
6422
|
+
error: {
|
|
6423
|
+
code: "bad-request",
|
|
6424
|
+
message: "Method not allowed."
|
|
6425
|
+
}
|
|
6426
|
+
}));
|
|
6427
|
+
return;
|
|
6428
|
+
}
|
|
6429
|
+
const envelope = {
|
|
6430
|
+
ok: true,
|
|
6431
|
+
value: { providers: (await Promise.allSettled(sources.map(async (source) => ({
|
|
6432
|
+
id: source.id,
|
|
6433
|
+
providerId: source.providerId,
|
|
6434
|
+
canToggle: source.canToggle,
|
|
6435
|
+
...await source.read()
|
|
6436
|
+
})))).map((result, index) => {
|
|
6437
|
+
if (result.status === "fulfilled") return result.value;
|
|
6438
|
+
const source = sources[index];
|
|
6439
|
+
return {
|
|
6440
|
+
id: source.id,
|
|
6441
|
+
providerId: source.providerId,
|
|
6442
|
+
canToggle: source.canToggle,
|
|
6443
|
+
enabled: !source.canToggle,
|
|
6444
|
+
accountCount: 0,
|
|
6445
|
+
authenticated: false,
|
|
6446
|
+
enabledModelCount: null,
|
|
6447
|
+
totalModelCount: null,
|
|
6448
|
+
error: true
|
|
6449
|
+
};
|
|
6450
|
+
}) }
|
|
6451
|
+
};
|
|
6452
|
+
response.writeHead(200, {
|
|
6453
|
+
"content-type": "application/json; charset=utf-8",
|
|
6454
|
+
"cache-control": "no-store",
|
|
6455
|
+
"x-content-type-options": "nosniff"
|
|
6456
|
+
});
|
|
6457
|
+
response.end(JSON.stringify(envelope));
|
|
6458
|
+
};
|
|
6459
|
+
return ctx.webServer.register({
|
|
6460
|
+
kind: "exact",
|
|
6461
|
+
path: HUB_OVERVIEW_PATH,
|
|
6462
|
+
handler
|
|
6463
|
+
});
|
|
6464
|
+
}
|
|
6465
|
+
//#endregion
|
|
6242
6466
|
//#region src/host/common/same-origin.ts
|
|
6243
6467
|
/**
|
|
6244
6468
|
* Whether one mutation request comes from this application's own document.
|
|
@@ -6346,9 +6570,9 @@ var UsageService = class {
|
|
|
6346
6570
|
};
|
|
6347
6571
|
const now = this.now();
|
|
6348
6572
|
if (!force && !this.invalidated && this.cache !== null && now - this.cache.fetchedAt < 6e4 && this.cacheIdentityRevision === this.oauth.currentIdentityRevision()) return this.fromCache(false);
|
|
6349
|
-
let
|
|
6573
|
+
let selection;
|
|
6350
6574
|
try {
|
|
6351
|
-
|
|
6575
|
+
selection = await this.oauth.credentialSelection(false, USAGE_CREDENTIAL_ACCESS);
|
|
6352
6576
|
} catch (error) {
|
|
6353
6577
|
const reason = error instanceof Error && error.message !== "" ? ` (${error.message})` : "";
|
|
6354
6578
|
return this.failure({
|
|
@@ -6356,7 +6580,8 @@ var UsageService = class {
|
|
|
6356
6580
|
message: `ChatGPT credentials could not be refreshed.${reason}`
|
|
6357
6581
|
});
|
|
6358
6582
|
}
|
|
6359
|
-
const
|
|
6583
|
+
const credentials = selection.credentials;
|
|
6584
|
+
const accountKey = this.snapshotKeyFor(selection.accountId, credentials);
|
|
6360
6585
|
if (this.cache !== null && this.cache.accountKey !== accountKey) this.clear();
|
|
6361
6586
|
if (!force && !this.invalidated && this.cache !== null && now - this.cache.fetchedAt < 6e4) return this.fromCache(false);
|
|
6362
6587
|
if (this.cache !== null && now - this.lastUpstreamAt < 15e3) return this.fromCache(this.invalidated || now - this.cache.fetchedAt >= 6e4);
|
|
@@ -6384,9 +6609,9 @@ var UsageService = class {
|
|
|
6384
6609
|
* The rejection is absorbed here: this refresh has no caller to receive it,
|
|
6385
6610
|
* and {@link fromCache} keeps serving the snapshot it failed to replace.
|
|
6386
6611
|
*/
|
|
6387
|
-
startBackgroundRefresh(credentials,
|
|
6612
|
+
startBackgroundRefresh(credentials, snapshotKey) {
|
|
6388
6613
|
if (this.inFlight !== null) return;
|
|
6389
|
-
const task = this.refreshUpstream(credentials,
|
|
6614
|
+
const task = this.refreshUpstream(credentials, snapshotKey).finally(() => {
|
|
6390
6615
|
if (this.inFlight === task) this.inFlight = null;
|
|
6391
6616
|
});
|
|
6392
6617
|
this.inFlight = task;
|
|
@@ -6403,8 +6628,8 @@ var UsageService = class {
|
|
|
6403
6628
|
* cooldown rather than forever, so a missing upstream field cannot strand an
|
|
6404
6629
|
* account permanently.
|
|
6405
6630
|
*/
|
|
6406
|
-
blockedUntilFor(credentials, now) {
|
|
6407
|
-
const snapshot = this.snapshots.get(
|
|
6631
|
+
blockedUntilFor(accountId, credentials, now) {
|
|
6632
|
+
const snapshot = this.snapshots.get(this.snapshotKeyFor(accountId, credentials));
|
|
6408
6633
|
if (snapshot === void 0) return void 0;
|
|
6409
6634
|
let reopen;
|
|
6410
6635
|
for (const bucket of snapshot.usage.buckets) {
|
|
@@ -6417,6 +6642,32 @@ var UsageService = class {
|
|
|
6417
6642
|
}
|
|
6418
6643
|
return reopen !== void 0 && reopen > now ? reopen : void 0;
|
|
6419
6644
|
}
|
|
6645
|
+
/**
|
|
6646
|
+
* The newest quota snapshot held for one account, if any.
|
|
6647
|
+
*
|
|
6648
|
+
* Quota follows the account, so the settings card shows each account its own
|
|
6649
|
+
* progress. The pool asks here with the row id it addresses the account by —
|
|
6650
|
+
* the identity that survives a token refresh — while its credentials answer
|
|
6651
|
+
* for a composition without a pool. This reads the remembered map only, never
|
|
6652
|
+
* the network, because opening the settings page must not cost one upstream
|
|
6653
|
+
* request per pooled account.
|
|
6654
|
+
*/
|
|
6655
|
+
snapshotFor(accountId, credentials) {
|
|
6656
|
+
return this.snapshots.get(this.snapshotKeyFor(accountId, credentials));
|
|
6657
|
+
}
|
|
6658
|
+
/**
|
|
6659
|
+
* Key one account's remembered snapshot is filed under.
|
|
6660
|
+
*
|
|
6661
|
+
* A pool row id when the caller names one, prefixed so it can never be
|
|
6662
|
+
* confused with the credential-derived key, and otherwise the credential
|
|
6663
|
+
* identity — which is all a composition without a pool has. Two pooled accounts
|
|
6664
|
+
* that state neither an account id nor an email would otherwise collapse onto
|
|
6665
|
+
* one key and show each other's numbers, so the row id is the answer wherever
|
|
6666
|
+
* a pool is in charge.
|
|
6667
|
+
*/
|
|
6668
|
+
snapshotKeyFor(accountId, credentials) {
|
|
6669
|
+
return accountId === void 0 || accountId === "" ? identityKey(credentials) : `row:${accountId}`;
|
|
6670
|
+
}
|
|
6420
6671
|
/** Remember the newest snapshot for one account, bounded to the accounts in use. */
|
|
6421
6672
|
rememberSnapshot(accountKey, usage, fetchedAt) {
|
|
6422
6673
|
this.snapshots.set(accountKey, {
|
|
@@ -6436,8 +6687,8 @@ var UsageService = class {
|
|
|
6436
6687
|
this.invalidated = false;
|
|
6437
6688
|
}
|
|
6438
6689
|
/** Drop the remembered snapshot of one account, after its window is known to have reset. */
|
|
6439
|
-
forgetSnapshot(credentials) {
|
|
6440
|
-
this.snapshots.delete(
|
|
6690
|
+
forgetSnapshot(accountId, credentials) {
|
|
6691
|
+
this.snapshots.delete(this.snapshotKeyFor(accountId, credentials));
|
|
6441
6692
|
}
|
|
6442
6693
|
async consumeResetCredit() {
|
|
6443
6694
|
if (this.resetConsumeInFlight !== null) return this.resetConsumeInFlight;
|
|
@@ -6448,12 +6699,17 @@ var UsageService = class {
|
|
|
6448
6699
|
}
|
|
6449
6700
|
async consumeResetCreditUpstream() {
|
|
6450
6701
|
let credentials;
|
|
6702
|
+
let accountId;
|
|
6451
6703
|
try {
|
|
6452
|
-
|
|
6704
|
+
const selection = await this.oauth.credentialSelection(false, USAGE_CREDENTIAL_ACCESS);
|
|
6705
|
+
credentials = selection.credentials;
|
|
6706
|
+
accountId = selection.accountId;
|
|
6453
6707
|
let creditsResponse = await this.fetchResetCredits(credentials);
|
|
6454
6708
|
if (creditsResponse.status === 401) {
|
|
6455
6709
|
await creditsResponse.body?.cancel().catch(() => void 0);
|
|
6456
|
-
|
|
6710
|
+
const renewed = await this.oauth.credentialSelection(true, USAGE_CREDENTIAL_ACCESS);
|
|
6711
|
+
credentials = renewed.credentials;
|
|
6712
|
+
accountId = renewed.accountId;
|
|
6457
6713
|
creditsResponse = await this.fetchResetCredits(credentials);
|
|
6458
6714
|
}
|
|
6459
6715
|
if (!creditsResponse.ok) {
|
|
@@ -6484,7 +6740,9 @@ var UsageService = class {
|
|
|
6484
6740
|
});
|
|
6485
6741
|
if (consumeResponse.status === 401) {
|
|
6486
6742
|
await consumeResponse.body?.cancel().catch(() => void 0);
|
|
6487
|
-
|
|
6743
|
+
const renewed = await this.oauth.credentialSelection(true, USAGE_CREDENTIAL_ACCESS);
|
|
6744
|
+
credentials = renewed.credentials;
|
|
6745
|
+
accountId = renewed.accountId;
|
|
6488
6746
|
consumeResponse = await this.fetchFn(CODEX_RESET_CREDITS_CONSUME_URL, {
|
|
6489
6747
|
method: "POST",
|
|
6490
6748
|
headers: {
|
|
@@ -6508,7 +6766,7 @@ var UsageService = class {
|
|
|
6508
6766
|
}
|
|
6509
6767
|
await consumeResponse.body?.cancel().catch(() => void 0);
|
|
6510
6768
|
this.clear();
|
|
6511
|
-
const refreshed = await this.refreshUpstream(credentials,
|
|
6769
|
+
const refreshed = await this.refreshUpstream(credentials, this.snapshotKeyFor(accountId, credentials));
|
|
6512
6770
|
if (refreshed.error !== void 0) throw new UsageServiceError({
|
|
6513
6771
|
code: "quota-failed",
|
|
6514
6772
|
message: "The reset credit was used, but usage could not be refreshed."
|
|
@@ -6535,16 +6793,17 @@ var UsageService = class {
|
|
|
6535
6793
|
checkedAt: Math.floor(this.now() / 1e3)
|
|
6536
6794
|
};
|
|
6537
6795
|
}
|
|
6538
|
-
async refreshUpstream(initialCredentials,
|
|
6796
|
+
async refreshUpstream(initialCredentials, initialSnapshotKey) {
|
|
6539
6797
|
this.lastUpstreamAt = this.now();
|
|
6540
6798
|
try {
|
|
6541
6799
|
let credentials = initialCredentials;
|
|
6542
|
-
let
|
|
6800
|
+
let snapshotKey = initialSnapshotKey;
|
|
6543
6801
|
let response = await this.fetch(credentials);
|
|
6544
6802
|
if (response.status === 401) {
|
|
6545
6803
|
await response.body?.cancel().catch(() => void 0);
|
|
6546
|
-
|
|
6547
|
-
|
|
6804
|
+
const renewed = await this.oauth.credentialSelection(true, USAGE_CREDENTIAL_ACCESS);
|
|
6805
|
+
credentials = renewed.credentials;
|
|
6806
|
+
snapshotKey = this.snapshotKeyFor(renewed.accountId, credentials);
|
|
6548
6807
|
response = await this.fetch(credentials);
|
|
6549
6808
|
}
|
|
6550
6809
|
if (response.status === 429) {
|
|
@@ -6577,10 +6836,10 @@ var UsageService = class {
|
|
|
6577
6836
|
this.cache = {
|
|
6578
6837
|
usage,
|
|
6579
6838
|
fetchedAt: this.now(),
|
|
6580
|
-
accountKey
|
|
6839
|
+
accountKey: snapshotKey
|
|
6581
6840
|
};
|
|
6582
6841
|
this.cacheIdentityRevision = this.oauth.currentIdentityRevision();
|
|
6583
|
-
this.rememberSnapshot(
|
|
6842
|
+
this.rememberSnapshot(snapshotKey, usage, this.cache.fetchedAt);
|
|
6584
6843
|
this.invalidated = false;
|
|
6585
6844
|
return this.fromCache(false);
|
|
6586
6845
|
} catch (error) {
|
|
@@ -7919,7 +8178,7 @@ var FileModelSettingsStore$2 = class {
|
|
|
7919
8178
|
*/
|
|
7920
8179
|
/** Default loopback port the Antigravity CLI's own flow uses. */
|
|
7921
8180
|
const DEFAULT_CALLBACK_PORT$2 = 51121;
|
|
7922
|
-
let cachedQuota
|
|
8181
|
+
let cachedQuota;
|
|
7923
8182
|
let quotaFetchInFlight = null;
|
|
7924
8183
|
/** Bumped by every cache clear so an in-flight fetch cannot publish stale state. */
|
|
7925
8184
|
let quotaCacheEpoch$2 = 0;
|
|
@@ -8096,7 +8355,7 @@ function parseQuotaSummary(data) {
|
|
|
8096
8355
|
for (const bucket of rawBuckets) {
|
|
8097
8356
|
if (typeof bucket !== "object" || bucket === null) continue;
|
|
8098
8357
|
const bRec = bucket;
|
|
8099
|
-
const remaining = typeof bRec.remainingFraction === "number" ? Math.max(0, Math.min(1, bRec.remainingFraction)) :
|
|
8358
|
+
const remaining = typeof bRec.remainingFraction === "number" && Number.isFinite(bRec.remainingFraction) ? Math.max(0, Math.min(1, bRec.remainingFraction)) : null;
|
|
8100
8359
|
buckets.push({
|
|
8101
8360
|
bucketId: String(bRec.bucketId || bRec.displayName || "limit"),
|
|
8102
8361
|
displayName: String(bRec.displayName || bRec.bucketId || "Limit"),
|
|
@@ -8159,7 +8418,7 @@ function mergeCatalogSelection(stored, storedCatalog) {
|
|
|
8159
8418
|
return stored.filter((id) => known.has(id));
|
|
8160
8419
|
}
|
|
8161
8420
|
async function fetchAccountQuota(store = new FileCredentialStore$2(), modelSettings, fetchFn = fetch, force = false) {
|
|
8162
|
-
if (!force && cachedQuota
|
|
8421
|
+
if (!force && cachedQuota && Date.now() - (cachedQuota.fetchedAt || 0) < 12e4) return cachedQuota;
|
|
8163
8422
|
if (quotaFetchInFlight) return quotaFetchInFlight;
|
|
8164
8423
|
const epoch = quotaCacheEpoch$2;
|
|
8165
8424
|
const request = (async () => {
|
|
@@ -8195,7 +8454,7 @@ async function fetchAccountQuota(store = new FileCredentialStore$2(), modelSetti
|
|
|
8195
8454
|
fetchedAt: Date.now()
|
|
8196
8455
|
};
|
|
8197
8456
|
if (epoch !== quotaCacheEpoch$2) return snapshot;
|
|
8198
|
-
cachedQuota
|
|
8457
|
+
cachedQuota = snapshot;
|
|
8199
8458
|
if (modelSettings && catalogModels.length > 0) {
|
|
8200
8459
|
const current = await modelSettings.read();
|
|
8201
8460
|
const mergedEnabled = mergeCatalogSelection(current.enabledModelIds, current.catalogModels);
|
|
@@ -8211,11 +8470,11 @@ async function fetchAccountQuota(store = new FileCredentialStore$2(), modelSetti
|
|
|
8211
8470
|
}
|
|
8212
8471
|
}
|
|
8213
8472
|
function getCachedQuota() {
|
|
8214
|
-
return cachedQuota
|
|
8473
|
+
return cachedQuota;
|
|
8215
8474
|
}
|
|
8216
8475
|
function clearCachedQuota() {
|
|
8217
8476
|
quotaCacheEpoch$2 += 1;
|
|
8218
|
-
cachedQuota
|
|
8477
|
+
cachedQuota = void 0;
|
|
8219
8478
|
quotaFetchInFlight = null;
|
|
8220
8479
|
}
|
|
8221
8480
|
//#endregion
|
|
@@ -9595,6 +9854,54 @@ function createPoolCredentialBackend(filePath) {
|
|
|
9595
9854
|
throw new Error("Antigravity pool encrypted storage requires Windows, macOS, or Linux.");
|
|
9596
9855
|
}
|
|
9597
9856
|
/**
|
|
9857
|
+
* One bucket's reset moment as Unix milliseconds, when it parses as a date.
|
|
9858
|
+
*
|
|
9859
|
+
* The service states it as an ISO-ish string; anything `Date.parse` refuses is
|
|
9860
|
+
* dropped rather than guessed at, because a wrong instant on the card is worse
|
|
9861
|
+
* than none.
|
|
9862
|
+
*/
|
|
9863
|
+
function resetTimeMs(resetTime) {
|
|
9864
|
+
if (resetTime === void 0 || resetTime === "") return null;
|
|
9865
|
+
const parsed = Date.parse(resetTime);
|
|
9866
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : null;
|
|
9867
|
+
}
|
|
9868
|
+
/**
|
|
9869
|
+
* One cached Antigravity snapshot as the shared account card renders it.
|
|
9870
|
+
*
|
|
9871
|
+
* One window per bucket. The service states what is LEFT, and the card draws what
|
|
9872
|
+
* is SPENT, so the used share is the complement. A bucket whose fraction is
|
|
9873
|
+
* `null` (never measured) or outside 0-1 is dropped rather than drawn as 0% or
|
|
9874
|
+
* 100%: "not stated" and "nothing used" are different claims and only one of
|
|
9875
|
+
* them is true. A stated 0 is a real measurement — the allowance is exhausted —
|
|
9876
|
+
* and is published as 100% used.
|
|
9877
|
+
*
|
|
9878
|
+
* `windowDurationMins` is deliberately absent. The bucket's `window` field is
|
|
9879
|
+
* carried through this line's cache verbatim and nothing in the line interprets
|
|
9880
|
+
* it as a duration, so naming a window from it would be a guess; the card names
|
|
9881
|
+
* each window from the label below instead.
|
|
9882
|
+
*/
|
|
9883
|
+
function antigravityPoolQuota(quota) {
|
|
9884
|
+
if (quota === void 0) return void 0;
|
|
9885
|
+
const nameCounts = /* @__PURE__ */ new Map();
|
|
9886
|
+
for (const group of quota.groups) for (const bucket of group.buckets) {
|
|
9887
|
+
const name = bucket.displayName.trim();
|
|
9888
|
+
if (name === "") continue;
|
|
9889
|
+
nameCounts.set(name, (nameCounts.get(name) ?? 0) + 1);
|
|
9890
|
+
}
|
|
9891
|
+
const windows = [];
|
|
9892
|
+
for (const group of quota.groups) {
|
|
9893
|
+
const groupName = group.displayName.trim();
|
|
9894
|
+
for (const bucket of group.buckets) {
|
|
9895
|
+
const remaining = bucket.remainingFraction;
|
|
9896
|
+
if (remaining === null || !Number.isFinite(remaining) || remaining < 0 || remaining > 1) continue;
|
|
9897
|
+
const name = bucket.displayName.trim();
|
|
9898
|
+
const label = (name === "" || (nameCounts.get(name) ?? 0) > 1) && groupName !== "" ? name === "" ? groupName : groupName + " · " + name : name;
|
|
9899
|
+
windows.push(quotaWindow$1(label, (1 - remaining) * 100, { resetsAt: resetTimeMs(bucket.resetTime) }));
|
|
9900
|
+
}
|
|
9901
|
+
}
|
|
9902
|
+
return poolQuota(quota.fetchedAt, windows);
|
|
9903
|
+
}
|
|
9904
|
+
/**
|
|
9598
9905
|
* Antigravity's account pool.
|
|
9599
9906
|
*
|
|
9600
9907
|
* The storage, eligibility, rotation and cooldown rules live in the shared
|
|
@@ -9658,7 +9965,11 @@ var AccountPoolStore = class {
|
|
|
9658
9965
|
...base,
|
|
9659
9966
|
...projectId === void 0 ? {} : { projectId },
|
|
9660
9967
|
...email === void 0 ? {} : { email },
|
|
9661
|
-
...account.planLabel === void 0 ? {} : { planLabel: account.planLabel }
|
|
9968
|
+
...account.planLabel === void 0 ? {} : { planLabel: account.planLabel },
|
|
9969
|
+
...account.isPrimary === true ? (() => {
|
|
9970
|
+
const quota = antigravityPoolQuota(getCachedQuota());
|
|
9971
|
+
return quota === void 0 ? {} : { quota };
|
|
9972
|
+
})() : {}
|
|
9662
9973
|
};
|
|
9663
9974
|
},
|
|
9664
9975
|
emptyMessage: "未登录 Antigravity 账号,请在「设置 → Antigravity」中添加并登录账号。",
|
|
@@ -12569,7 +12880,41 @@ function whoami(apiKey, options = {}) {
|
|
|
12569
12880
|
async function verifyApiKey(apiKey, options = {}) {
|
|
12570
12881
|
return parseWhoami(await whoami(apiKey, options), { authenticatedAt: Date.now() });
|
|
12571
12882
|
}
|
|
12572
|
-
|
|
12883
|
+
/**
|
|
12884
|
+
* One newest snapshot PER ACCOUNT.
|
|
12885
|
+
*
|
|
12886
|
+
* Quota follows the account: rotation decides which key spends the next
|
|
12887
|
+
* request, so a single slot only ever described whichever key was read last.
|
|
12888
|
+
* The pool's card draws every account its own reading, so each account keeps
|
|
12889
|
+
* its own entry; past the cap the oldest read is evicted.
|
|
12890
|
+
*
|
|
12891
|
+
* This map is a memory read only. Nothing here fetches — the settings card
|
|
12892
|
+
* builds its account list from it, and that must never cost one upstream
|
|
12893
|
+
* request per pooled key.
|
|
12894
|
+
*/
|
|
12895
|
+
const cachedQuotaEntries$1 = /* @__PURE__ */ new Map();
|
|
12896
|
+
/** How many accounts' snapshots are remembered; mirrors the Codex usage service. */
|
|
12897
|
+
const QUOTA_CACHE_LIMIT$1 = 20;
|
|
12898
|
+
/** Key of a snapshot whose caller named no account. */
|
|
12899
|
+
const UNNAMED_ACCOUNT_KEY$1 = "";
|
|
12900
|
+
function quotaCacheKey(accountId) {
|
|
12901
|
+
return accountId ?? UNNAMED_ACCOUNT_KEY$1;
|
|
12902
|
+
}
|
|
12903
|
+
/** The entry read most recently, whichever account it belongs to. */
|
|
12904
|
+
function newestQuotaEntry$2() {
|
|
12905
|
+
let newest;
|
|
12906
|
+
for (const entry of cachedQuotaEntries$1.values()) if (newest === void 0 || entry.fetchedAt > newest.fetchedAt) newest = entry;
|
|
12907
|
+
return newest;
|
|
12908
|
+
}
|
|
12909
|
+
/** Remember one account's newest snapshot, bounded to the accounts in use. */
|
|
12910
|
+
function rememberQuotaEntry(entry) {
|
|
12911
|
+
cachedQuotaEntries$1.set(quotaCacheKey(entry.accountId), entry);
|
|
12912
|
+
while (cachedQuotaEntries$1.size > QUOTA_CACHE_LIMIT$1) {
|
|
12913
|
+
const oldest = [...cachedQuotaEntries$1.entries()].sort((left, right) => left[1].fetchedAt - right[1].fetchedAt)[0];
|
|
12914
|
+
if (oldest === void 0) break;
|
|
12915
|
+
cachedQuotaEntries$1.delete(oldest[0]);
|
|
12916
|
+
}
|
|
12917
|
+
}
|
|
12573
12918
|
let quotaInFlight$2 = null;
|
|
12574
12919
|
let quotaInFlightAccountId$1;
|
|
12575
12920
|
let quotaCacheEpoch$1 = 0;
|
|
@@ -12578,21 +12923,22 @@ let quotaCacheEpoch$1 = 0;
|
|
|
12578
12923
|
* Kept with a no-argument signature for backward compatibility.
|
|
12579
12924
|
*/
|
|
12580
12925
|
function getCachedQuota$2() {
|
|
12581
|
-
return
|
|
12926
|
+
return newestQuotaEntry$2()?.quota;
|
|
12582
12927
|
}
|
|
12583
12928
|
/**
|
|
12584
12929
|
* The cached snapshot only when it belongs to this account.
|
|
12585
12930
|
*
|
|
12586
12931
|
* Passing no account keeps the pre-pool behavior of returning whatever was
|
|
12587
|
-
* fetched last.
|
|
12932
|
+
* fetched last. This is the lookup the account pool calls while it builds its
|
|
12933
|
+
* summaries: a pure memory read, never a fetch.
|
|
12588
12934
|
*/
|
|
12589
|
-
function getCachedQuotaFor$
|
|
12590
|
-
if (accountId === void 0 || accountId === null) return
|
|
12591
|
-
return
|
|
12935
|
+
function getCachedQuotaFor$3(accountId) {
|
|
12936
|
+
if (accountId === void 0 || accountId === null) return newestQuotaEntry$2()?.quota;
|
|
12937
|
+
return cachedQuotaEntries$1.get(accountId)?.quota;
|
|
12592
12938
|
}
|
|
12593
12939
|
function clearCachedQuota$2() {
|
|
12594
12940
|
quotaCacheEpoch$1 += 1;
|
|
12595
|
-
|
|
12941
|
+
cachedQuotaEntries$1.clear();
|
|
12596
12942
|
quotaInFlight$2 = null;
|
|
12597
12943
|
quotaInFlightAccountId$1 = void 0;
|
|
12598
12944
|
}
|
|
@@ -12607,8 +12953,8 @@ async function fetchAccountQuota$2(store = new FileCredentialStore$1(), fetchFnO
|
|
|
12607
12953
|
const fetchFn = typeof fetchFnOrOptions === "function" ? fetchFnOrOptions : fetchFnOrOptions?.fetchFn ?? fetch;
|
|
12608
12954
|
const effectiveForce = isOptionsObj ? fetchFnOrOptions.force ?? force : force;
|
|
12609
12955
|
const effectiveAccountId = isOptionsObj ? fetchFnOrOptions.accountId ?? accountId : accountId;
|
|
12610
|
-
const
|
|
12611
|
-
if (!effectiveForce &&
|
|
12956
|
+
const cached = getCachedQuotaFor$3(effectiveAccountId);
|
|
12957
|
+
if (!effectiveForce && cached !== void 0 && Date.now() - (cached.fetchedAt || 0) < 12e4) return cached;
|
|
12612
12958
|
if (quotaInFlight$2 !== null && (effectiveAccountId === void 0 || quotaInFlightAccountId$1 === effectiveAccountId)) return quotaInFlight$2;
|
|
12613
12959
|
const epoch = quotaCacheEpoch$1;
|
|
12614
12960
|
const request = (async () => {
|
|
@@ -12664,11 +13010,11 @@ async function fetchAccountQuota$2(store = new FileCredentialStore$1(), fetchFnO
|
|
|
12664
13010
|
sources
|
|
12665
13011
|
};
|
|
12666
13012
|
if (epoch !== quotaCacheEpoch$1) return snapshot;
|
|
12667
|
-
|
|
13013
|
+
rememberQuotaEntry({
|
|
12668
13014
|
accountId: effectiveAccountId,
|
|
12669
13015
|
quota: snapshot,
|
|
12670
13016
|
fetchedAt: snapshot.fetchedAt
|
|
12671
|
-
};
|
|
13017
|
+
});
|
|
12672
13018
|
return snapshot;
|
|
12673
13019
|
})();
|
|
12674
13020
|
quotaInFlight$2 = request;
|
|
@@ -14758,6 +15104,34 @@ function processLine$1(line, state, wire) {
|
|
|
14758
15104
|
}
|
|
14759
15105
|
//#endregion
|
|
14760
15106
|
//#region src/host/command-code/account-pool.ts
|
|
15107
|
+
/**
|
|
15108
|
+
* One cached snapshot as the shared account card renders it.
|
|
15109
|
+
*
|
|
15110
|
+
* A usage window states its own consumed share, so it maps straight across; a
|
|
15111
|
+
* window whose share nobody measured is dropped rather than drawn at 0, which
|
|
15112
|
+
* would claim an unspent window no reading supports.
|
|
15113
|
+
*
|
|
15114
|
+
* Exported for the pool's regression tests; the card only reaches it through
|
|
15115
|
+
* the summary hook.
|
|
15116
|
+
*/
|
|
15117
|
+
function commandCodePoolQuota(cached) {
|
|
15118
|
+
return poolQuota(cached.fetchedAt, cached.windows.map((window) => quotaWindow$1(window.label, window.usedPercent, {
|
|
15119
|
+
windowDurationMins: window.windowDurationMins,
|
|
15120
|
+
resetsAt: window.resetsAt
|
|
15121
|
+
})));
|
|
15122
|
+
}
|
|
15123
|
+
/**
|
|
15124
|
+
* This key's own newest snapshot, ready for the account card.
|
|
15125
|
+
*
|
|
15126
|
+
* Quota follows the account, so the pool reports what the line already
|
|
15127
|
+
* remembered for THIS account id. The lookup is a pure memory read: the card
|
|
15128
|
+
* builds its account list here, and that must never cost one upstream request
|
|
15129
|
+
* per pooled key.
|
|
15130
|
+
*/
|
|
15131
|
+
function quotaFor$1(accountId) {
|
|
15132
|
+
const cached = getCachedQuotaFor$3(accountId);
|
|
15133
|
+
return cached === void 0 ? void 0 : commandCodePoolQuota(cached);
|
|
15134
|
+
}
|
|
14761
15135
|
/** Encrypted pool file this line owns; the pre-pool credential file stays the mirror. */
|
|
14762
15136
|
function commandCodePoolPath() {
|
|
14763
15137
|
return path.join(dshHomeDir(), "storages", "command-code-pool.json");
|
|
@@ -14895,7 +15269,11 @@ var CommandCodeAccountPool = class extends AccountPoolCore {
|
|
|
14895
15269
|
...account.userName === void 0 ? {} : { userName: account.userName },
|
|
14896
15270
|
...account.organizationName === void 0 ? {} : { organizationName: account.organizationName },
|
|
14897
15271
|
...account.planId === void 0 ? {} : { planId: account.planId },
|
|
14898
|
-
...account.userId === void 0 ? {} : { userId: account.userId }
|
|
15272
|
+
...account.userId === void 0 ? {} : { userId: account.userId },
|
|
15273
|
+
...(() => {
|
|
15274
|
+
const quota = quotaFor$1(account.id);
|
|
15275
|
+
return quota === void 0 ? {} : { quota };
|
|
15276
|
+
})()
|
|
14899
15277
|
};
|
|
14900
15278
|
},
|
|
14901
15279
|
emptyMessage: "Not signed in to Command Code. 请在「设置 → 订阅服务 → Command Code」中添加账号或粘贴 API Key。",
|
|
@@ -15450,7 +15828,7 @@ async function getCommandCodeWebStatus(store, modelSettings, preferences, option
|
|
|
15450
15828
|
const catalog = live.length > 0 ? live : fallbackCatalog$1();
|
|
15451
15829
|
const enabled = settings.enabled !== false;
|
|
15452
15830
|
const models = buildModelOptions$2(catalog, resolveEnabledModelIds$4(settings.enabledModelIds, catalog, enabled), settings.contextWindowOverrides);
|
|
15453
|
-
const quota = getCachedQuotaFor$
|
|
15831
|
+
const quota = getCachedQuotaFor$3(activeAccount?.id ?? null);
|
|
15454
15832
|
const activeAccountView = activePoolAccount === void 0 ? null : {
|
|
15455
15833
|
userId: activePoolAccount.userId ?? activePoolAccount.credentials.userId ?? null,
|
|
15456
15834
|
userName: activePoolAccount.userName ?? activePoolAccount.credentials.userName ?? null,
|
|
@@ -15523,7 +15901,7 @@ function registerCommandCodeRoutes(ctx, store, modelSettings, preferences, optio
|
|
|
15523
15901
|
if (method !== "GET") return sendMethodNotAllowed$5(response);
|
|
15524
15902
|
const credentials = await store.read();
|
|
15525
15903
|
const targetId = await activeAccountId();
|
|
15526
|
-
const cached = getCachedQuotaFor$
|
|
15904
|
+
const cached = getCachedQuotaFor$3(targetId);
|
|
15527
15905
|
if ((credentials !== null || targetId !== void 0) && (cached === void 0 || Date.now() - (cached.fetchedAt || 0) > 12e4)) {
|
|
15528
15906
|
const refresh = () => fetchAccountQuota$2(quotaStore, fetchFn, false, targetId);
|
|
15529
15907
|
if (cached === void 0) await quotaRefresh.run(refresh);
|
|
@@ -19336,19 +19714,89 @@ function buildModelOptions$1(catalog, enabledModelIds, contextWindowOverrides) {
|
|
|
19336
19714
|
};
|
|
19337
19715
|
});
|
|
19338
19716
|
}
|
|
19339
|
-
|
|
19340
|
-
|
|
19717
|
+
/**
|
|
19718
|
+
* How many accounts' snapshots are remembered.
|
|
19719
|
+
*
|
|
19720
|
+
* Mirrors the bound the ChatGPT line's usage service applies to its own
|
|
19721
|
+
* per-account map: room for every account a user is likely to pool, and no way
|
|
19722
|
+
* for a long-lived process to accumulate one snapshot per account it has seen.
|
|
19723
|
+
*/
|
|
19724
|
+
const QUOTA_ACCOUNT_LIMIT$1 = 20;
|
|
19725
|
+
/** Key of a snapshot whose caller named no account: the single-credential read. */
|
|
19726
|
+
const UNNAMED_ACCOUNT_KEY = "";
|
|
19727
|
+
/**
|
|
19728
|
+
* One newest snapshot PER ACCOUNT, keyed by the account id the caller stated.
|
|
19729
|
+
*
|
|
19730
|
+
* Quota follows the account: rotation decides which account spends the next
|
|
19731
|
+
* request, so a single slot could only ever describe whichever account was read
|
|
19732
|
+
* last. The pool's card draws every account its own reading, so each account
|
|
19733
|
+
* keeps its own entry; past the cap the oldest read is evicted.
|
|
19734
|
+
*
|
|
19735
|
+
* This map is a memory read only. Nothing here fetches — the settings card
|
|
19736
|
+
* builds its account list from it, and that must never cost one upstream
|
|
19737
|
+
* request per pooled account.
|
|
19738
|
+
*/
|
|
19739
|
+
const quotaCache$1 = /* @__PURE__ */ new Map();
|
|
19740
|
+
/**
|
|
19741
|
+
* Key of the entry written most recently.
|
|
19742
|
+
*
|
|
19743
|
+
* The pre-pool card asks "whatever was fetched last"; the last WRITE answers
|
|
19744
|
+
* that exactly, where a scan by `fetchedAt` would break a tie between two
|
|
19745
|
+
* accounts read inside the same millisecond by map order.
|
|
19746
|
+
*/
|
|
19747
|
+
let quotaLastKey$1 = UNNAMED_ACCOUNT_KEY;
|
|
19748
|
+
function quotaCacheKeyFor(accountId) {
|
|
19749
|
+
return accountId ?? UNNAMED_ACCOUNT_KEY;
|
|
19750
|
+
}
|
|
19751
|
+
/** The entry read most recently, whichever account it belongs to. */
|
|
19752
|
+
function newestQuotaEntry$1() {
|
|
19753
|
+
return quotaCache$1.get(quotaLastKey$1);
|
|
19754
|
+
}
|
|
19755
|
+
/** Remember one account's newest snapshot, bounded to the accounts in use. */
|
|
19756
|
+
function rememberQuota$1(accountId, snapshot) {
|
|
19757
|
+
const key = quotaCacheKeyFor(accountId);
|
|
19758
|
+
quotaCache$1.set(key, snapshot);
|
|
19759
|
+
quotaLastKey$1 = key;
|
|
19760
|
+
while (quotaCache$1.size > QUOTA_ACCOUNT_LIMIT$1) {
|
|
19761
|
+
const oldest = [...quotaCache$1.entries()].sort((left, right) => left[1].fetchedAt - right[1].fetchedAt)[0];
|
|
19762
|
+
if (oldest === void 0) break;
|
|
19763
|
+
quotaCache$1.delete(oldest[0]);
|
|
19764
|
+
if (quotaLastKey$1 === oldest[0]) quotaLastKey$1 = UNNAMED_ACCOUNT_KEY;
|
|
19765
|
+
}
|
|
19766
|
+
}
|
|
19767
|
+
/**
|
|
19768
|
+
* The snapshot read most recently, whichever account it belongs to.
|
|
19769
|
+
*
|
|
19770
|
+
* Kept for the pre-pool single-credential card, which has no account id to ask
|
|
19771
|
+
* with. A pooled caller asks {@link getCachedQuotaFor} instead.
|
|
19772
|
+
*/
|
|
19341
19773
|
function getCachedQuota$3() {
|
|
19342
|
-
return
|
|
19774
|
+
return newestQuotaEntry$1() ?? null;
|
|
19343
19775
|
}
|
|
19344
|
-
/**
|
|
19345
|
-
|
|
19346
|
-
|
|
19347
|
-
|
|
19776
|
+
/**
|
|
19777
|
+
* The cached snapshot only when it belongs to this account.
|
|
19778
|
+
*
|
|
19779
|
+
* Passing no account keeps the pre-pool behavior of returning whatever was
|
|
19780
|
+
* fetched last. Passing one answers that account's own newest snapshot, or null
|
|
19781
|
+
* when this line has never read it — null is "never read", which is a different
|
|
19782
|
+
* statement from a snapshot whose windows are all at zero.
|
|
19783
|
+
*/
|
|
19784
|
+
function getCachedQuotaFor$2(accountId) {
|
|
19785
|
+
if (accountId === void 0 || accountId === null) return newestQuotaEntry$1() ?? null;
|
|
19786
|
+
return cachedQuotaFor$1(accountId);
|
|
19787
|
+
}
|
|
19788
|
+
/**
|
|
19789
|
+
* The newest snapshot held for one account, for display only.
|
|
19790
|
+
*
|
|
19791
|
+
* The pool asks here while it builds the account list for the settings card, so
|
|
19792
|
+
* this is a pure memory read: it never fetches.
|
|
19793
|
+
*/
|
|
19794
|
+
function cachedQuotaFor$1(accountId) {
|
|
19795
|
+
return quotaCache$1.get(accountId) ?? null;
|
|
19348
19796
|
}
|
|
19349
19797
|
function clearCachedQuota$3() {
|
|
19350
|
-
quotaCache$1
|
|
19351
|
-
|
|
19798
|
+
quotaCache$1.clear();
|
|
19799
|
+
quotaLastKey$1 = UNNAMED_ACCOUNT_KEY;
|
|
19352
19800
|
}
|
|
19353
19801
|
/**
|
|
19354
19802
|
* Display name and nominal length for each window key the service reports.
|
|
@@ -19595,8 +20043,8 @@ function parsePlanLevel(payload) {
|
|
|
19595
20043
|
* account's real usage.
|
|
19596
20044
|
*/
|
|
19597
20045
|
async function fetchAccountQuota$3(store, options = {}) {
|
|
19598
|
-
const
|
|
19599
|
-
if (options.force !== true &&
|
|
20046
|
+
const cached = quotaCache$1.get(quotaCacheKeyFor(options.accountId));
|
|
20047
|
+
if (options.force !== true && cached !== void 0 && Date.now() - cached.fetchedAt < 12e4) return cached;
|
|
19600
20048
|
const fetchFn = options.fetchFn ?? fetch;
|
|
19601
20049
|
const pooled = options.credentials !== void 0;
|
|
19602
20050
|
let credentials;
|
|
@@ -19645,8 +20093,7 @@ async function fetchAccountQuota$3(store, options = {}) {
|
|
|
19645
20093
|
fetchedAt: Date.now(),
|
|
19646
20094
|
sources: [openAIUrl(USAGES_PATH, credentials.region)]
|
|
19647
20095
|
};
|
|
19648
|
-
|
|
19649
|
-
quotaAccountId = options.accountId;
|
|
20096
|
+
rememberQuota$1(options.accountId, snapshot);
|
|
19650
20097
|
return snapshot;
|
|
19651
20098
|
}
|
|
19652
20099
|
/**
|
|
@@ -22547,6 +22994,34 @@ function parseKimiCodePoolData(value) {
|
|
|
22547
22994
|
return result;
|
|
22548
22995
|
}
|
|
22549
22996
|
/**
|
|
22997
|
+
* One account's own newest quota snapshot, in the shape the account card draws.
|
|
22998
|
+
*
|
|
22999
|
+
* The snapshot comes from 'client.ts''s per-account cache keyed by the pool
|
|
23000
|
+
* account id, and this is where this line's own numbers are translated into the
|
|
23001
|
+
* shared shape. Every judgement below trades a possibly-nice-looking bar for an
|
|
23002
|
+
* honest one:
|
|
23003
|
+
*
|
|
23004
|
+
* - a window whose consumed share nobody measured is DROPPED (`quotaWindow`
|
|
23005
|
+
* returns null), because "0% used" and "not stated" are different claims. This
|
|
23006
|
+
* parser only mints a window once it has a ratio, so a window that states none
|
|
23007
|
+
* never reaches here at all — the drop is the second line of defence;
|
|
23008
|
+
* - `resetsAt` is already Unix MILLISECONDS on this line, so it is passed
|
|
23009
|
+
* through and normalized rather than multiplied;
|
|
23010
|
+
* - the read time is the snapshot's own `fetchedAt`, which this line always
|
|
23011
|
+
* sets. A snapshot with no read time is not a snapshot, and `poolQuota`
|
|
23012
|
+
* reports that as undefined.
|
|
23013
|
+
*
|
|
23014
|
+
* A null snapshot means "this account was never read", which the card renders as
|
|
23015
|
+
* exactly that instead of drawing a zero.
|
|
23016
|
+
*/
|
|
23017
|
+
function kimiCodePoolQuota(snapshot) {
|
|
23018
|
+
if (snapshot === null) return void 0;
|
|
23019
|
+
return poolQuota(snapshot.fetchedAt, snapshot.windows.map((window) => quotaWindow$1(window.label, window.usedPercent, {
|
|
23020
|
+
windowDurationMins: window.windowDurationMins,
|
|
23021
|
+
resetsAt: window.resetsAt
|
|
23022
|
+
})));
|
|
23023
|
+
}
|
|
23024
|
+
/**
|
|
22550
23025
|
* Kimi Code's account pool.
|
|
22551
23026
|
*
|
|
22552
23027
|
* The credential is an OAuth pair whose refresh token rotates, so the pool owns
|
|
@@ -22625,6 +23100,7 @@ var KimiCodeAccountPool = class extends AccountPoolCore {
|
|
|
22625
23100
|
const nickname = account.nickname ?? account.credentials.nickname;
|
|
22626
23101
|
const planName = account.planName ?? account.credentials.planName;
|
|
22627
23102
|
const region = account.region ?? account.credentials.region;
|
|
23103
|
+
const quota = kimiCodePoolQuota(cachedQuotaFor$1(account.id));
|
|
22628
23104
|
return {
|
|
22629
23105
|
...base,
|
|
22630
23106
|
...email === void 0 ? {} : { email },
|
|
@@ -22634,7 +23110,8 @@ var KimiCodeAccountPool = class extends AccountPoolCore {
|
|
|
22634
23110
|
planLabel: planName
|
|
22635
23111
|
},
|
|
22636
23112
|
...region === void 0 ? {} : { region },
|
|
22637
|
-
...account.userId === void 0 ? {} : { userId: account.userId }
|
|
23113
|
+
...account.userId === void 0 ? {} : { userId: account.userId },
|
|
23114
|
+
...quota === void 0 ? {} : { quota }
|
|
22638
23115
|
};
|
|
22639
23116
|
},
|
|
22640
23117
|
emptyMessage: "Not signed in to Kimi Code. Sign in from Settings > Kimi Code.",
|
|
@@ -22748,7 +23225,7 @@ async function getKimiCodeWebStatus(store, modelSettings, preferences, options =
|
|
|
22748
23225
|
const catalog = live.length > 0 ? live : fallbackCatalog();
|
|
22749
23226
|
const enabled = settings.enabled !== false;
|
|
22750
23227
|
const models = buildModelOptions$1(catalog, resolveEnabledModelIds$3(settings.enabledModelIds, catalog, enabled), settings.contextWindowOverrides);
|
|
22751
|
-
const quota = getCachedQuotaFor(activeAccount?.id ?? null);
|
|
23228
|
+
const quota = getCachedQuotaFor$2(activeAccount?.id ?? null);
|
|
22752
23229
|
const account = quota?.account ?? (active === null || active === void 0 ? null : accountFromCredentials$2(active));
|
|
22753
23230
|
return {
|
|
22754
23231
|
enabled,
|
|
@@ -22882,7 +23359,7 @@ function registerKimiCodeRoutes(ctx, store, modelSettings, preferences, options
|
|
|
22882
23359
|
if (path === "" || path === "status") {
|
|
22883
23360
|
if (method !== "GET") return sendMethodNotAllowed$3(response);
|
|
22884
23361
|
const poolActive = await activeAccount();
|
|
22885
|
-
const cached = getCachedQuotaFor(poolActive.id ?? null);
|
|
23362
|
+
const cached = getCachedQuotaFor$2(poolActive.id ?? null);
|
|
22886
23363
|
if (poolActive.credentials !== void 0 && (cached === null || Date.now() - (cached.fetchedAt || 0) > 12e4)) {
|
|
22887
23364
|
const refresh = async () => {
|
|
22888
23365
|
const credentials = await effectiveCredentials(poolActive);
|
|
@@ -26725,29 +27202,75 @@ const QUOTA_FAILURE_CACHE_MS = 10 * 6e4;
|
|
|
26725
27202
|
const QUOTA_TIMEOUT_MS = 8e3;
|
|
26726
27203
|
let quotaHostInForce = null;
|
|
26727
27204
|
/**
|
|
26728
|
-
*
|
|
27205
|
+
* How many accounts' snapshots are remembered.
|
|
27206
|
+
*
|
|
27207
|
+
* Bounded like the ChatGPT line's own per-account map: the pool accepts a
|
|
27208
|
+
* handful of accounts, and a long-lived process must not accumulate one entry
|
|
27209
|
+
* per id it has ever seen. The oldest WRITE is evicted, which is also the read
|
|
27210
|
+
* least likely to be looked at again.
|
|
27211
|
+
*/
|
|
27212
|
+
const QUOTA_SNAPSHOT_ACCOUNT_LIMIT = 20;
|
|
27213
|
+
/**
|
|
27214
|
+
* The newest read, whichever account it belonged to.
|
|
26729
27215
|
*
|
|
26730
|
-
*
|
|
26731
|
-
*
|
|
26732
|
-
*
|
|
26733
|
-
* visible disappearance of the quota box; `quotaLastGood` lets the card keep
|
|
26734
|
-
* showing the last known numbers while saying they are old.
|
|
27216
|
+
* Kept beside the per-account map because the page-level block and the
|
|
27217
|
+
* "is a read even worth starting" test are about the line's latest reading,
|
|
27218
|
+
* not about one account.
|
|
26735
27219
|
*/
|
|
26736
27220
|
let quotaSnapshot = null;
|
|
26737
|
-
/**
|
|
26738
|
-
|
|
27221
|
+
/** Per-account snapshots, so an account is never shown the numbers read for another. */
|
|
27222
|
+
const quotaByAccount = /* @__PURE__ */ new Map();
|
|
26739
27223
|
/** How long a refused credential is remembered before asking again. */
|
|
26740
27224
|
const QUOTA_REJECTED_CACHE_MS = 30 * 6e4;
|
|
26741
27225
|
/** Forget the cached usage snapshot (a sign-out, a sign-in, a test). */
|
|
26742
27226
|
function clearCachedQuota$4() {
|
|
26743
27227
|
quotaSnapshot = null;
|
|
26744
|
-
|
|
27228
|
+
quotaByAccount.clear();
|
|
26745
27229
|
quotaHostInForce = null;
|
|
26746
27230
|
}
|
|
26747
27231
|
/** The last usage snapshot without touching the network. */
|
|
26748
27232
|
function getCachedQuota$4() {
|
|
26749
27233
|
return quotaSnapshot?.value ?? null;
|
|
26750
27234
|
}
|
|
27235
|
+
/**
|
|
27236
|
+
* The cached snapshot only when it belongs to this account, without touching the
|
|
27237
|
+
* network.
|
|
27238
|
+
*
|
|
27239
|
+
* Quota follows the account: a rotation decides whose credential is spent next,
|
|
27240
|
+
* so the snapshot a read produced describes the row it was made for. The pool
|
|
27241
|
+
* asks here while it builds the settings card's account list, which must never
|
|
27242
|
+
* wait on — or trigger — an upstream read.
|
|
27243
|
+
*
|
|
27244
|
+
* An absent, empty or null id keeps the pre-pool behaviour and answers with the
|
|
27245
|
+
* newest read, which is what the page-level block wants.
|
|
27246
|
+
*/
|
|
27247
|
+
function getCachedQuotaFor$1(accountId) {
|
|
27248
|
+
if (accountId === void 0 || accountId === null || accountId === "") return getCachedQuota$4();
|
|
27249
|
+
return quotaByAccount.get(accountId)?.value ?? null;
|
|
27250
|
+
}
|
|
27251
|
+
/** The entry a read for this account should consult, when there is one. */
|
|
27252
|
+
function quotaEntryFor(accountId) {
|
|
27253
|
+
if (accountId === void 0 || accountId === "") return quotaSnapshot;
|
|
27254
|
+
return quotaByAccount.get(accountId) ?? null;
|
|
27255
|
+
}
|
|
27256
|
+
/**
|
|
27257
|
+
* Remember one read against the account it was made for.
|
|
27258
|
+
*
|
|
27259
|
+
* Re-inserting an id moves it to the newest position, so the map's first key is
|
|
27260
|
+
* always the least recently written entry and eviction is a single delete.
|
|
27261
|
+
*/
|
|
27262
|
+
function rememberQuotaSnapshot(entry) {
|
|
27263
|
+
quotaSnapshot = entry;
|
|
27264
|
+
const accountId = entry.accountId;
|
|
27265
|
+
if (accountId === void 0 || accountId === "") return;
|
|
27266
|
+
quotaByAccount.delete(accountId);
|
|
27267
|
+
quotaByAccount.set(accountId, entry);
|
|
27268
|
+
while (quotaByAccount.size > QUOTA_SNAPSHOT_ACCOUNT_LIMIT) {
|
|
27269
|
+
const oldest = quotaByAccount.keys().next().value;
|
|
27270
|
+
if (oldest === void 0) break;
|
|
27271
|
+
quotaByAccount.delete(oldest);
|
|
27272
|
+
}
|
|
27273
|
+
}
|
|
26751
27274
|
/** Why the last read produced no snapshot, or null when it produced one. */
|
|
26752
27275
|
function getQuotaUnavailable() {
|
|
26753
27276
|
return quotaSnapshot?.reason ?? null;
|
|
@@ -26869,9 +27392,10 @@ function parseTokenPlanQuota(payload, now = Date.now()) {
|
|
|
26869
27392
|
async function fetchTokenPlanQuota(credentials, options = {}) {
|
|
26870
27393
|
const fetchFn = options.fetchFn ?? fetch;
|
|
26871
27394
|
const now = Date.now();
|
|
26872
|
-
|
|
26873
|
-
|
|
26874
|
-
|
|
27395
|
+
const cached = quotaEntryFor(options.accountId);
|
|
27396
|
+
if (options.force !== true && cached !== null) {
|
|
27397
|
+
const ttl = cached.reason === "credential-not-accepted" ? QUOTA_REJECTED_CACHE_MS : cached.reason === "token-expired" && cached.value === null ? QUOTA_FAILURE_CACHE_MS : cached.value === null ? QUOTA_FAILURE_CACHE_MS : QUOTA_CACHE_MS;
|
|
27398
|
+
if (now - cached.at < ttl) return cached.value;
|
|
26875
27399
|
}
|
|
26876
27400
|
const candidates = quotaHostCandidates(credentials.region);
|
|
26877
27401
|
const ordered = quotaHostInForce === null ? candidates : [quotaHostInForce, ...candidates.filter((host) => host !== quotaHostInForce)];
|
|
@@ -26911,19 +27435,19 @@ async function fetchTokenPlanQuota(credentials, options = {}) {
|
|
|
26911
27435
|
});
|
|
26912
27436
|
}
|
|
26913
27437
|
if (value === null && reason === null) reason = authRefused ? "token-expired" : "unreachable";
|
|
26914
|
-
if (value
|
|
26915
|
-
|
|
26916
|
-
|
|
26917
|
-
|
|
26918
|
-
|
|
26919
|
-
|
|
26920
|
-
reason = "stale";
|
|
27438
|
+
if (value === null) {
|
|
27439
|
+
const previous = quotaEntryFor(options.accountId);
|
|
27440
|
+
if (previous !== null && previous.value !== null) {
|
|
27441
|
+
value = previous.value;
|
|
27442
|
+
reason = "stale";
|
|
27443
|
+
}
|
|
26921
27444
|
}
|
|
26922
|
-
|
|
27445
|
+
rememberQuotaSnapshot({
|
|
27446
|
+
accountId: options.accountId,
|
|
26923
27447
|
at: Date.now(),
|
|
26924
27448
|
value,
|
|
26925
27449
|
reason
|
|
26926
|
-
};
|
|
27450
|
+
});
|
|
26927
27451
|
return value;
|
|
26928
27452
|
}
|
|
26929
27453
|
/**
|
|
@@ -27961,6 +28485,38 @@ function parseMinimaxCodePoolData(value) {
|
|
|
27961
28485
|
return result;
|
|
27962
28486
|
}
|
|
27963
28487
|
/**
|
|
28488
|
+
* Nominal length of the two windows the Token Plan reports, in minutes.
|
|
28489
|
+
*
|
|
28490
|
+
* The line's own card names these two keys (`quotaWindowInterval` = 5 小时窗口,
|
|
28491
|
+
* `quotaWindowWeekly` = 每周窗口), and 5 hours / 7 days is what those words mean,
|
|
28492
|
+
* so the shared account card can name an unlabeled window from its length
|
|
28493
|
+
* instead of showing a generic one. The same two numbers label the equivalent
|
|
28494
|
+
* windows on the Command Code and Kimi Code lines.
|
|
28495
|
+
*/
|
|
28496
|
+
const WINDOW_MINUTES = {
|
|
28497
|
+
interval: 300,
|
|
28498
|
+
weekly: 10080
|
|
28499
|
+
};
|
|
28500
|
+
/**
|
|
28501
|
+
* One cached read as the shared account card renders it.
|
|
28502
|
+
*
|
|
28503
|
+
* Every window is labeled through its LENGTH rather than with a string: the
|
|
28504
|
+
* canonical window names live in the client's dictionary, and the host has no
|
|
28505
|
+
* business shipping display text. A window whose consumed share nobody measured
|
|
28506
|
+
* is dropped by {@link quotaWindow} — a null percentage is not 0%, it is
|
|
28507
|
+
* "not stated", and a bar would lie about it. An `unlimited` window states no
|
|
28508
|
+
* consumed share at all and the per-account shape has no way to say
|
|
28509
|
+
* "unlimited", so it is dropped too rather than drawn as an empty bar.
|
|
28510
|
+
*/
|
|
28511
|
+
function minimaxCodePoolQuota(quota) {
|
|
28512
|
+
if (quota === null || quota === void 0) return void 0;
|
|
28513
|
+
const windows = quota.windows === void 0 || quota.windows.length === 0 ? [quotaWindow$1("", quota.usedPercent, { resetsAt: quota.resetsAtMs })] : quota.windows.map((window) => quotaWindow$1("", window.usedPercent, {
|
|
28514
|
+
windowDurationMins: WINDOW_MINUTES[window.key],
|
|
28515
|
+
resetsAt: window.resetsAtMs
|
|
28516
|
+
}));
|
|
28517
|
+
return poolQuota(quota.fetchedAtMs, windows);
|
|
28518
|
+
}
|
|
28519
|
+
/**
|
|
27964
28520
|
* MiniMax Code's account pool.
|
|
27965
28521
|
*
|
|
27966
28522
|
* It owns rotation and the write-back, exactly like the sibling lines, with one
|
|
@@ -28041,7 +28597,11 @@ var MinimaxCodeAccountPool = class extends AccountPoolCore {
|
|
|
28041
28597
|
...planName === void 0 ? {} : {
|
|
28042
28598
|
planName,
|
|
28043
28599
|
planLabel: planName
|
|
28044
|
-
}
|
|
28600
|
+
},
|
|
28601
|
+
...(() => {
|
|
28602
|
+
const quota = minimaxCodePoolQuota(getCachedQuotaFor$1(account.id));
|
|
28603
|
+
return quota === void 0 ? {} : { quota };
|
|
28604
|
+
})()
|
|
28045
28605
|
};
|
|
28046
28606
|
},
|
|
28047
28607
|
liveCredentialsFor: (account) => this.nativeAuthority(account),
|
|
@@ -28128,6 +28688,34 @@ var MinimaxCodeAccountPool = class extends AccountPoolCore {
|
|
|
28128
28688
|
});
|
|
28129
28689
|
}
|
|
28130
28690
|
/**
|
|
28691
|
+
* The account a usage read belongs to, together with the credential to read it
|
|
28692
|
+
* with.
|
|
28693
|
+
*
|
|
28694
|
+
* Authored here rather than in the routes because it is provider-shaped: the
|
|
28695
|
+
* routes need a credential and the ACCOUNT it was read for, so a snapshot can
|
|
28696
|
+
* be remembered against the row whose numbers it describes. The selection is
|
|
28697
|
+
* the core's own rule for a caller that names no account — the active one, then
|
|
28698
|
+
* the primary, then the first — repeated in these three lines because the core
|
|
28699
|
+
* exposes it only through `getFreshCredential`, which returns the credential
|
|
28700
|
+
* alone; the credential (and its single-flight refresh, write-back and
|
|
28701
|
+
* bookkeeping) still comes from the core, so no rotation rule lives here.
|
|
28702
|
+
*
|
|
28703
|
+
* No upstream request is made for the selection itself, and none of this moves
|
|
28704
|
+
* the rotation: reading quota is not serving a request.
|
|
28705
|
+
*/
|
|
28706
|
+
async getQuotaReadTarget(fetchFn = fetch) {
|
|
28707
|
+
const data = await this.read();
|
|
28708
|
+
const target = data.accounts.find((account) => account.id === data.activeAccountId) ?? data.accounts.find((account) => account.isPrimary) ?? data.accounts[0];
|
|
28709
|
+
if (target === void 0) {
|
|
28710
|
+
await this.getFreshCredential(void 0, fetchFn);
|
|
28711
|
+
throw new Error("MiniMax Code 号池中没有账号。");
|
|
28712
|
+
}
|
|
28713
|
+
return {
|
|
28714
|
+
accountId: target.id,
|
|
28715
|
+
credentials: await this.getFreshCredential(target.id, fetchFn)
|
|
28716
|
+
};
|
|
28717
|
+
}
|
|
28718
|
+
/**
|
|
28131
28719
|
* Pick the account for the next request.
|
|
28132
28720
|
*
|
|
28133
28721
|
* The returned credential carries its own region and record key, so a caller
|
|
@@ -28461,8 +29049,12 @@ function registerMinimaxCodeRoutes(ctx, store = new MinimaxCodeCredentialStore()
|
|
|
28461
29049
|
* network, and the status route reads the snapshot through the cache instead.
|
|
28462
29050
|
*/
|
|
28463
29051
|
const refreshQuota = async (force) => {
|
|
28464
|
-
const
|
|
28465
|
-
|
|
29052
|
+
const target = await (options.accountPool === void 0 ? ensureAccessToken$2(store, { fetchFn }).then((credentials) => ({
|
|
29053
|
+
accountId: void 0,
|
|
29054
|
+
credentials
|
|
29055
|
+
})).catch(() => null) : options.accountPool.getQuotaReadTarget(fetchFn).catch(() => null));
|
|
29056
|
+
if (target === null) return null;
|
|
29057
|
+
const credentials = target.credentials;
|
|
28466
29058
|
const readToken = credentials.refreshToken;
|
|
28467
29059
|
const isCredentialStale = async () => {
|
|
28468
29060
|
const live = await store.readFresh().catch(() => null);
|
|
@@ -28472,10 +29064,11 @@ function registerMinimaxCodeRoutes(ctx, store = new MinimaxCodeCredentialStore()
|
|
|
28472
29064
|
fetchFn,
|
|
28473
29065
|
force,
|
|
28474
29066
|
isCredentialStale,
|
|
29067
|
+
...target.accountId === void 0 ? {} : { accountId: target.accountId },
|
|
28475
29068
|
renewCredential: async () => await (options.accountPool === void 0 ? ensureAccessToken$2(store, {
|
|
28476
29069
|
fetchFn,
|
|
28477
29070
|
force: true
|
|
28478
|
-
}) : options.accountPool.renewCredential(
|
|
29071
|
+
}) : options.accountPool.renewCredential(target.accountId, fetchFn)).catch(() => null)
|
|
28479
29072
|
}).catch(() => null);
|
|
28480
29073
|
};
|
|
28481
29074
|
/**
|
|
@@ -30540,6 +31133,9 @@ const CATALOG_CACHE_TTL_MS$1 = 1800 * 1e3;
|
|
|
30540
31133
|
* every cache miss.
|
|
30541
31134
|
*/
|
|
30542
31135
|
const catalogSnapshotScopesLoaded = /* @__PURE__ */ new Set();
|
|
31136
|
+
function getCachedCatalog$1() {
|
|
31137
|
+
return cachedCatalog?.models ?? [];
|
|
31138
|
+
}
|
|
30543
31139
|
function clearCachedCatalog$1() {
|
|
30544
31140
|
cachedCatalog = void 0;
|
|
30545
31141
|
catalogCacheEpoch += 1;
|
|
@@ -30731,16 +31327,64 @@ function billingMeters(billing) {
|
|
|
30731
31327
|
}
|
|
30732
31328
|
return meters;
|
|
30733
31329
|
}
|
|
30734
|
-
|
|
31330
|
+
/**
|
|
31331
|
+
* One newest snapshot PER ACCOUNT, keyed by the snapshot's own `account.id` —
|
|
31332
|
+
* the same public key the pool addresses an account with.
|
|
31333
|
+
*
|
|
31334
|
+
* Quota follows the account: rotation decides which account spends the next
|
|
31335
|
+
* request, so a single slot only ever described whichever account was read
|
|
31336
|
+
* last. The pool's card draws every account its own reading, so each account
|
|
31337
|
+
* keeps its own entry; past the cap the oldest read is evicted.
|
|
31338
|
+
*
|
|
31339
|
+
* This map is a memory read only. Nothing here fetches — the settings card
|
|
31340
|
+
* builds its account list from it, and that must never cost one upstream
|
|
31341
|
+
* request per pooled account.
|
|
31342
|
+
*/
|
|
31343
|
+
const cachedQuotaEntries = /* @__PURE__ */ new Map();
|
|
31344
|
+
/** How many accounts' snapshots are remembered; mirrors the Codex usage service. */
|
|
31345
|
+
const QUOTA_CACHE_LIMIT = 20;
|
|
31346
|
+
/** The entry read most recently, whichever account it belongs to. */
|
|
31347
|
+
function newestCachedQuota() {
|
|
31348
|
+
let newest;
|
|
31349
|
+
for (const snapshot of cachedQuotaEntries.values()) if (newest === void 0 || (snapshot.fetchedAt || 0) > (newest.fetchedAt || 0)) newest = snapshot;
|
|
31350
|
+
return newest;
|
|
31351
|
+
}
|
|
31352
|
+
/** Remember one account's newest snapshot, bounded to the accounts in use. */
|
|
31353
|
+
function rememberCachedQuota(snapshot) {
|
|
31354
|
+
cachedQuotaEntries.set(snapshot.account.id, snapshot);
|
|
31355
|
+
while (cachedQuotaEntries.size > QUOTA_CACHE_LIMIT) {
|
|
31356
|
+
const oldest = [...cachedQuotaEntries.entries()].sort((left, right) => (left[1].fetchedAt || 0) - (right[1].fetchedAt || 0))[0];
|
|
31357
|
+
if (oldest === void 0) break;
|
|
31358
|
+
cachedQuotaEntries.delete(oldest[0]);
|
|
31359
|
+
}
|
|
31360
|
+
}
|
|
30735
31361
|
let quotaInFlight$1 = null;
|
|
30736
31362
|
let quotaInFlightAccountId = null;
|
|
30737
31363
|
let quotaCacheEpoch = 0;
|
|
31364
|
+
/**
|
|
31365
|
+
* The snapshot read most recently, whichever account it belongs to.
|
|
31366
|
+
*
|
|
31367
|
+
* Kept with a no-argument signature for backward compatibility; the page-level
|
|
31368
|
+
* facts use {@link getCachedQuotaFor} instead, because they describe one
|
|
31369
|
+
* account and must never be another account's numbers.
|
|
31370
|
+
*/
|
|
30738
31371
|
function getCachedQuota$5() {
|
|
30739
|
-
return
|
|
31372
|
+
return newestCachedQuota();
|
|
31373
|
+
}
|
|
31374
|
+
/**
|
|
31375
|
+
* The snapshot remembered for one account, if it was read before.
|
|
31376
|
+
*
|
|
31377
|
+
* This is the lookup the account pool calls while it builds its summaries: a
|
|
31378
|
+
* pure memory read, never a fetch. Passing no account keeps the pre-pool
|
|
31379
|
+
* behavior of returning whatever was fetched last.
|
|
31380
|
+
*/
|
|
31381
|
+
function getCachedQuotaFor(accountId) {
|
|
31382
|
+
if (accountId === void 0 || accountId === null) return newestCachedQuota();
|
|
31383
|
+
return cachedQuotaEntries.get(accountId);
|
|
30740
31384
|
}
|
|
30741
31385
|
function clearCachedQuota$5() {
|
|
30742
31386
|
quotaCacheEpoch += 1;
|
|
30743
|
-
|
|
31387
|
+
cachedQuotaEntries.clear();
|
|
30744
31388
|
quotaInFlight$1 = null;
|
|
30745
31389
|
quotaInFlightAccountId = null;
|
|
30746
31390
|
}
|
|
@@ -30757,7 +31401,8 @@ async function fetchAccountQuota$4(store = new FileCredentialStore$4(), fetchFn
|
|
|
30757
31401
|
});
|
|
30758
31402
|
if (credentials === null) throw new Error(`Not signed in to ${PROVIDER_NAME$1}.`);
|
|
30759
31403
|
const requestedAccountId = workBuddyAccountId(credentials);
|
|
30760
|
-
|
|
31404
|
+
const cached = cachedQuotaEntries.get(requestedAccountId);
|
|
31405
|
+
if (!force && cached !== void 0 && Date.now() - (cached.fetchedAt || 0) < 12e4) return cached;
|
|
30761
31406
|
if (quotaInFlight$1 && quotaInFlightAccountId === requestedAccountId) return quotaInFlight$1;
|
|
30762
31407
|
const epoch = quotaCacheEpoch;
|
|
30763
31408
|
const request = (async () => {
|
|
@@ -30793,7 +31438,7 @@ async function fetchAccountQuota$4(store = new FileCredentialStore$4(), fetchFn
|
|
|
30793
31438
|
sources: ["billing/meter/get-user-resource"]
|
|
30794
31439
|
};
|
|
30795
31440
|
if (epoch !== quotaCacheEpoch) return snapshot;
|
|
30796
|
-
|
|
31441
|
+
rememberCachedQuota(snapshot);
|
|
30797
31442
|
return snapshot;
|
|
30798
31443
|
})();
|
|
30799
31444
|
quotaInFlight$1 = request;
|
|
@@ -31108,7 +31753,7 @@ async function getWorkBuddyWebStatus(store, modelSettings, preferences, options
|
|
|
31108
31753
|
const catalog = live.length > 0 ? live : FALLBACK_MODELS$1;
|
|
31109
31754
|
const available = modelsForRegion(credentials?.region ?? "intl", catalog).map((model) => model.id);
|
|
31110
31755
|
const models = buildModelOptions(catalog, available, resolveEnabledModelIds$2(settings.enabledModelIds, available, enabled), settings.contextWindowOverrides);
|
|
31111
|
-
const quota =
|
|
31756
|
+
const quota = getCachedQuotaFor(credentials === null ? null : accountFromCredentials$1(credentials).id);
|
|
31112
31757
|
const poolData = options.accountPool === void 0 ? null : await options.accountPool.read().catch(() => null);
|
|
31113
31758
|
const poolAccounts = options.accountPool === void 0 ? [] : await options.accountPool.listAccounts().catch(() => []);
|
|
31114
31759
|
const hiddenIds = new Set(settings.hiddenAccountIds);
|
|
@@ -31167,12 +31812,10 @@ function registerWorkBuddyRoutes(ctx, store, modelSettings, preferences, options
|
|
|
31167
31812
|
accountId: settings.selectedAccountId,
|
|
31168
31813
|
hiddenAccountIds: settings.hiddenAccountIds
|
|
31169
31814
|
});
|
|
31170
|
-
const cached =
|
|
31171
|
-
|
|
31172
|
-
if (credentials !== null && (!quotaMatches || cached === void 0 || Date.now() - (cached.fetchedAt || 0) > 12e4)) {
|
|
31173
|
-
if (!quotaMatches) clearCachedQuota$5();
|
|
31815
|
+
const cached = getCachedQuotaFor(credentials === null ? null : accountFromCredentials$1(credentials).id);
|
|
31816
|
+
if (credentials !== null && (cached === void 0 || Date.now() - (cached.fetchedAt || 0) > 12e4)) {
|
|
31174
31817
|
const refresh = () => fetchAccountQuota$4(store, fetchFn, false, settings.selectedAccountId, settings.hiddenAccountIds);
|
|
31175
|
-
if (cached === void 0
|
|
31818
|
+
if (cached === void 0) await quotaRefresh.run(refresh);
|
|
31176
31819
|
else quotaRefresh.start(refresh);
|
|
31177
31820
|
}
|
|
31178
31821
|
return sendJson$1(response, 200, {
|
|
@@ -32658,6 +33301,47 @@ function defaultAliasFor(credentials, position) {
|
|
|
32658
33301
|
return credentials.nickname || credentials.uin || credentials.uid || `账号 ${position}`;
|
|
32659
33302
|
}
|
|
32660
33303
|
/**
|
|
33304
|
+
* A meter's consumed share, from whichever fraction this line measured.
|
|
33305
|
+
*
|
|
33306
|
+
* `usedFraction` is the DTO's own "share consumed"; `remainingFraction` is the
|
|
33307
|
+
* same statement read from the other end, and is the one the rest of the card
|
|
33308
|
+
* renders. A meter that states neither is dropped (null) rather than drawn at
|
|
33309
|
+
* 0, which would claim a full window no reading supports.
|
|
33310
|
+
*/
|
|
33311
|
+
function meterUsedPercent(meter) {
|
|
33312
|
+
if (typeof meter.usedFraction === "number" && Number.isFinite(meter.usedFraction)) return meter.usedFraction * 100;
|
|
33313
|
+
if (typeof meter.remainingFraction === "number" && Number.isFinite(meter.remainingFraction)) return (1 - meter.remainingFraction) * 100;
|
|
33314
|
+
return null;
|
|
33315
|
+
}
|
|
33316
|
+
/**
|
|
33317
|
+
* One cached snapshot as the shared account card renders it.
|
|
33318
|
+
*
|
|
33319
|
+
* Only what the DTO states is published: every meter that measured a share
|
|
33320
|
+
* becomes a window, and a meter that measured none is dropped rather than drawn
|
|
33321
|
+
* at 0 — which would claim an unspent allowance no reading supports.
|
|
33322
|
+
*
|
|
33323
|
+
* Exported for the pool's regression tests; the card only reaches it through
|
|
33324
|
+
* the summary hook.
|
|
33325
|
+
*/
|
|
33326
|
+
function workBuddyPoolQuota(snapshot) {
|
|
33327
|
+
const windows = snapshot.meters.map((meter) => quotaWindow$1(meter.label, meterUsedPercent(meter), { resetsAt: meter.resetsAt }));
|
|
33328
|
+
if (!snapshot.meters.some((meter) => meter.id === "cycle") && snapshot.cycleCredits !== null && snapshot.cycleCredits > 0 && snapshot.cycleUsedCredits !== null) windows.push(quotaWindow$1(snapshot.packageName ?? "Billing cycle", snapshot.cycleUsedCredits / snapshot.cycleCredits * 100, { resetsAt: snapshot.cycleEndsAt }));
|
|
33329
|
+
return poolQuota(snapshot.fetchedAt, windows);
|
|
33330
|
+
}
|
|
33331
|
+
/**
|
|
33332
|
+
* This account's own newest snapshot, ready for the account card.
|
|
33333
|
+
*
|
|
33334
|
+
* Quota follows the account, so the pool reports the snapshot the line already
|
|
33335
|
+
* remembered for THIS account id. The lookup is a pure memory read: the card
|
|
33336
|
+
* builds its account list here, and that must never cost one upstream request
|
|
33337
|
+
* per pooled account. Undefined means exactly that — never read — which is not
|
|
33338
|
+
* the same statement as "nothing used".
|
|
33339
|
+
*/
|
|
33340
|
+
function quotaFor(accountId) {
|
|
33341
|
+
const snapshot = getCachedQuotaFor(accountId);
|
|
33342
|
+
return snapshot === void 0 ? void 0 : workBuddyPoolQuota(snapshot);
|
|
33343
|
+
}
|
|
33344
|
+
/**
|
|
32661
33345
|
* WorkBuddy's account pool.
|
|
32662
33346
|
*
|
|
32663
33347
|
* Desktop accounts are adopted into the pool so they can be scheduled and
|
|
@@ -32718,7 +33402,11 @@ var WorkBuddyAccountPool = class extends AccountPoolCore {
|
|
|
32718
33402
|
...account.credentials.domain === "" ? {} : { domain: account.credentials.domain },
|
|
32719
33403
|
...account.credentials.backend === "" ? {} : { backend: account.credentials.backend },
|
|
32720
33404
|
...account.credentials.accountType === void 0 ? {} : { accountType: account.credentials.accountType },
|
|
32721
|
-
...account.credentials.expiresAt > 0 ? {} : { expiresAt: void 0 }
|
|
33405
|
+
...account.credentials.expiresAt > 0 ? {} : { expiresAt: void 0 },
|
|
33406
|
+
...(() => {
|
|
33407
|
+
const quota = quotaFor(account.id);
|
|
33408
|
+
return quota === void 0 ? {} : { quota };
|
|
33409
|
+
})()
|
|
32722
33410
|
}),
|
|
32723
33411
|
preferAccountId: () => this.resolveSelectionId(options.selection?.().selectedAccountId ?? null),
|
|
32724
33412
|
emptyMessage: `Not signed in to ${PROVIDER_NAME$1}. Sign in with the CodeBuddy desktop client, or add an account from Settings > WorkBuddy.`,
|
|
@@ -34727,6 +35415,10 @@ const catalogInFlight = /* @__PURE__ */ new Map();
|
|
|
34727
35415
|
function clearCachedCatalog() {
|
|
34728
35416
|
catalogCache = null;
|
|
34729
35417
|
}
|
|
35418
|
+
/** The listing currently held, or an empty array before the first load. */
|
|
35419
|
+
function getCachedCatalog() {
|
|
35420
|
+
return catalogCache?.models ?? [];
|
|
35421
|
+
}
|
|
34730
35422
|
/**
|
|
34731
35423
|
* Read one entry of the live listing.
|
|
34732
35424
|
*
|
|
@@ -35022,22 +35714,108 @@ function parseQuotaHeaders(headers) {
|
|
|
35022
35714
|
}
|
|
35023
35715
|
};
|
|
35024
35716
|
}
|
|
35025
|
-
|
|
35717
|
+
/**
|
|
35718
|
+
* Cache key of one account's snapshot.
|
|
35719
|
+
*
|
|
35720
|
+
* A pool row id when the caller names one — that is the identity that survives a
|
|
35721
|
+
* token refresh and the one the account card asks with — and otherwise the
|
|
35722
|
+
* credential's token tail, which is all a single-credential process has. The
|
|
35723
|
+
* `acc:` prefix keeps the two apart, so no row id can ever be answered with an
|
|
35724
|
+
* entry written under a token tail.
|
|
35725
|
+
*/
|
|
35726
|
+
function quotaEntryKey(accountId, credentials) {
|
|
35727
|
+
return accountId === void 0 || accountId === "" ? accountKeyFor(credentials) : `acc:${accountId}`;
|
|
35728
|
+
}
|
|
35729
|
+
/**
|
|
35730
|
+
* How many accounts' snapshots are remembered.
|
|
35731
|
+
*
|
|
35732
|
+
* Mirrors the bound the ChatGPT line's usage service applies to its own
|
|
35733
|
+
* per-account map: room for every account a user is likely to pool, and no way
|
|
35734
|
+
* for a long-lived process to accumulate one snapshot per token it has seen.
|
|
35735
|
+
*/
|
|
35736
|
+
const QUOTA_ACCOUNT_LIMIT = 20;
|
|
35737
|
+
/**
|
|
35738
|
+
* The newest snapshot of each account, keyed by {@link quotaEntryKey}.
|
|
35739
|
+
*
|
|
35740
|
+
* ONE ENTRY PER ACCOUNT rather than one slot for the line: quota follows the
|
|
35741
|
+
* account, and rotation decides which account spends the next request, so a
|
|
35742
|
+
* single slot could only ever describe whichever account was read last. This is
|
|
35743
|
+
* a memory read only — the settings card builds its account list from it, and
|
|
35744
|
+
* that must never cost one upstream request per pooled account.
|
|
35745
|
+
*/
|
|
35746
|
+
const quotaCache = /* @__PURE__ */ new Map();
|
|
35747
|
+
/**
|
|
35748
|
+
* Key of the entry written most recently.
|
|
35749
|
+
*
|
|
35750
|
+
* The pre-pool card asks "whatever was read last", and a header reading that
|
|
35751
|
+
* names no account may only merge into the snapshot it was read beside. Both
|
|
35752
|
+
* need the last WRITE rather than a scan: two accounts can be written inside one
|
|
35753
|
+
* millisecond, and a tie would otherwise be broken by map order.
|
|
35754
|
+
*/
|
|
35755
|
+
let quotaLastKey = null;
|
|
35026
35756
|
const quotaInFlight = /* @__PURE__ */ new Map();
|
|
35027
|
-
/** Drop
|
|
35757
|
+
/** Drop every cached snapshot. Called on sign-out and after a credential change. */
|
|
35028
35758
|
function clearCachedQuota$1() {
|
|
35029
|
-
quotaCache
|
|
35759
|
+
quotaCache.clear();
|
|
35760
|
+
quotaLastKey = null;
|
|
35761
|
+
}
|
|
35762
|
+
/** The entry written most recently, whichever account it belongs to. */
|
|
35763
|
+
function newestQuotaEntry() {
|
|
35764
|
+
return quotaLastKey === null ? null : quotaCache.get(quotaLastKey) ?? null;
|
|
35765
|
+
}
|
|
35766
|
+
/**
|
|
35767
|
+
* Remember one account's newest snapshot, bounded to the accounts in use.
|
|
35768
|
+
*
|
|
35769
|
+
* The oldest entry is measured by {@link QuotaCacheEntry.observedAt} rather than
|
|
35770
|
+
* by `fetchedAt`: a snapshot kept warm by response headers has no full read
|
|
35771
|
+
* behind it at all, and it is still the newest thing known about that account.
|
|
35772
|
+
*/
|
|
35773
|
+
function rememberQuota(entry) {
|
|
35774
|
+
quotaCache.set(entry.key, entry);
|
|
35775
|
+
quotaLastKey = entry.key;
|
|
35776
|
+
while (quotaCache.size > QUOTA_ACCOUNT_LIMIT) {
|
|
35777
|
+
const oldest = [...quotaCache.entries()].sort((left, right) => left[1].observedAt - right[1].observedAt)[0];
|
|
35778
|
+
if (oldest === void 0) break;
|
|
35779
|
+
quotaCache.delete(oldest[0]);
|
|
35780
|
+
if (quotaLastKey === oldest[0]) quotaLastKey = null;
|
|
35781
|
+
}
|
|
35030
35782
|
}
|
|
35031
35783
|
/**
|
|
35032
35784
|
* The cached snapshot, optionally only when it belongs to this credential.
|
|
35033
35785
|
*
|
|
35034
35786
|
* With one stored account the argument is unnecessary; it exists so a later
|
|
35035
35787
|
* pool chunk cannot render one account's usage under another account's name.
|
|
35788
|
+
* Given a credential the answer is THAT account's own newest snapshot, which is
|
|
35789
|
+
* what keeps two pooled accounts apart: a later read of a different account
|
|
35790
|
+
* cannot displace it. Without one the pre-pool answer is kept — whatever was
|
|
35791
|
+
* written last — because the single-account card has no identity to ask with.
|
|
35036
35792
|
*/
|
|
35037
35793
|
function getCachedQuota$1(credentials) {
|
|
35038
|
-
if (
|
|
35039
|
-
|
|
35040
|
-
|
|
35794
|
+
if (credentials === void 0) return newestQuotaEntry()?.quota ?? null;
|
|
35795
|
+
return cachedQuotaFor(credentials);
|
|
35796
|
+
}
|
|
35797
|
+
/**
|
|
35798
|
+
* The newest snapshot held for one credential's account, for display only.
|
|
35799
|
+
*
|
|
35800
|
+
* The token-tail form, kept for a composition with a single stored credential.
|
|
35801
|
+
* A pooled caller asks {@link cachedQuotaForPool} with the row id instead: a
|
|
35802
|
+
* token is rotated by every refresh, so an entry filed under a tail is lost the
|
|
35803
|
+
* moment the account renews.
|
|
35804
|
+
*/
|
|
35805
|
+
function cachedQuotaFor(credentials) {
|
|
35806
|
+
return quotaCache.get(accountKeyFor(credentials))?.quota ?? null;
|
|
35807
|
+
}
|
|
35808
|
+
/**
|
|
35809
|
+
* The newest snapshot held for one pool row, for display only.
|
|
35810
|
+
*
|
|
35811
|
+
* The pool asks here while it builds the account list for the settings card, so
|
|
35812
|
+
* this is a pure memory read: it never fetches. Null means nothing was ever read
|
|
35813
|
+
* for this account, which is a different statement from "nothing used". A row id
|
|
35814
|
+
* that is undefined falls back to the credential's own tail, which is what a
|
|
35815
|
+
* composition without a pool has.
|
|
35816
|
+
*/
|
|
35817
|
+
function cachedQuotaForPool(accountId, credentials) {
|
|
35818
|
+
return quotaCache.get(quotaEntryKey(accountId, credentials))?.quota ?? null;
|
|
35041
35819
|
}
|
|
35042
35820
|
/**
|
|
35043
35821
|
* Read the account's usage meters.
|
|
@@ -35055,12 +35833,13 @@ function getCachedQuota$1(credentials) {
|
|
|
35055
35833
|
* up staring at a card that claims they are fine.
|
|
35056
35834
|
*/
|
|
35057
35835
|
function fetchAccountQuota$1(credentials, options = {}) {
|
|
35058
|
-
const key =
|
|
35836
|
+
const key = quotaEntryKey(options.accountId, credentials);
|
|
35059
35837
|
const at = now();
|
|
35060
|
-
|
|
35061
|
-
|
|
35062
|
-
const
|
|
35063
|
-
|
|
35838
|
+
const cached = quotaCache.get(key);
|
|
35839
|
+
if (options.force !== true && cached !== void 0) {
|
|
35840
|
+
const warm = at - cached.observedAt < QUOTA_CACHE_TTL_MS;
|
|
35841
|
+
const freshFullRead = cached.fullReadAt !== null && at - cached.fullReadAt < 3e5;
|
|
35842
|
+
if (warm && freshFullRead) return Promise.resolve(cached.quota);
|
|
35064
35843
|
}
|
|
35065
35844
|
const pending = quotaInFlight.get(key);
|
|
35066
35845
|
if (pending !== void 0) return pending;
|
|
@@ -35075,9 +35854,9 @@ function fetchAccountQuota$1(credentials, options = {}) {
|
|
|
35075
35854
|
return run;
|
|
35076
35855
|
}
|
|
35077
35856
|
async function performQuotaFetch(credentials, options) {
|
|
35078
|
-
const key =
|
|
35857
|
+
const key = quotaEntryKey(options.accountId, credentials);
|
|
35079
35858
|
const fetchFn = options.fetchFn ?? fetch;
|
|
35080
|
-
const previous = quotaCache
|
|
35859
|
+
const previous = quotaCache.get(key)?.quota ?? null;
|
|
35081
35860
|
let response;
|
|
35082
35861
|
try {
|
|
35083
35862
|
response = await fetchFn("https://api.anthropic.com/api/oauth/usage", {
|
|
@@ -35115,12 +35894,12 @@ async function performQuotaFetch(credentials, options) {
|
|
|
35115
35894
|
status: null,
|
|
35116
35895
|
representativeClaim: null
|
|
35117
35896
|
};
|
|
35118
|
-
|
|
35897
|
+
rememberQuota({
|
|
35119
35898
|
quota,
|
|
35120
35899
|
key,
|
|
35121
35900
|
fullReadAt: at,
|
|
35122
35901
|
observedAt: at
|
|
35123
|
-
};
|
|
35902
|
+
});
|
|
35124
35903
|
return quota;
|
|
35125
35904
|
}
|
|
35126
35905
|
/**
|
|
@@ -39747,6 +40526,32 @@ async function refreshClaudeCredential(credentials, fetchFn) {
|
|
|
39747
40526
|
};
|
|
39748
40527
|
}
|
|
39749
40528
|
/**
|
|
40529
|
+
* One account's own newest quota snapshot, in the shape the account card draws.
|
|
40530
|
+
*
|
|
40531
|
+
* The snapshot comes from 'client.ts''s per-account cache, and this is where
|
|
40532
|
+
* this line's own numbers are translated into the shared shape. Every judgement
|
|
40533
|
+
* below trades a possibly-nice-looking bar for an honest one:
|
|
40534
|
+
*
|
|
40535
|
+
* - a window whose consumed share nobody measured is DROPPED (`quotaWindow`
|
|
40536
|
+
* returns null), because "0% used" and "not stated" are different claims;
|
|
40537
|
+
* - the share falls back to `100 - remainingPercent` only when that field was
|
|
40538
|
+
* stated; when the payload stated NEITHER share there is nothing to draw;
|
|
40539
|
+
* - the read time is the full read's own `fetchedAt`, or — for a snapshot that
|
|
40540
|
+
* only response headers ever kept warm, which performed no full read — the
|
|
40541
|
+
* `observedAt` instant those numbers arrived. Either way it is when this line
|
|
40542
|
+
* saw the numbers, never when upstream served them.
|
|
40543
|
+
*
|
|
40544
|
+
* A null snapshot means "this account was never read", which `poolQuota` reports
|
|
40545
|
+
* as undefined so the card can say exactly that instead of drawing a zero.
|
|
40546
|
+
*/
|
|
40547
|
+
function claudePoolQuota(snapshot) {
|
|
40548
|
+
if (snapshot === null) return void 0;
|
|
40549
|
+
return poolQuota(snapshot.fetchedAt ?? snapshot.observedAt, snapshot.windows.map((window) => quotaWindow$1(window.label, window.usedPercent ?? (window.remainingPercent === null ? null : 100 - window.remainingPercent), {
|
|
40550
|
+
windowDurationMins: window.windowMinutes,
|
|
40551
|
+
resetsAt: typeof window.resetsAt === "string" ? Date.parse(window.resetsAt) : null
|
|
40552
|
+
})));
|
|
40553
|
+
}
|
|
40554
|
+
/**
|
|
39750
40555
|
* The Claude subscription account pool.
|
|
39751
40556
|
*
|
|
39752
40557
|
* Read the module comment first: it carries the two rules this class exists to
|
|
@@ -39844,6 +40649,7 @@ var ClaudeAccountPool = class extends AccountPoolCore {
|
|
|
39844
40649
|
const subscriptionType = account.subscriptionType ?? credentials.subscriptionType;
|
|
39845
40650
|
const adopted = account.adopted === true;
|
|
39846
40651
|
const expired = adopted && adoptedCredentialExpired(credentials);
|
|
40652
|
+
const quota = claudePoolQuota(cachedQuotaForPool(account.id, credentials));
|
|
39847
40653
|
return {
|
|
39848
40654
|
...base,
|
|
39849
40655
|
...email === void 0 ? {} : { email },
|
|
@@ -39855,6 +40661,7 @@ var ClaudeAccountPool = class extends AccountPoolCore {
|
|
|
39855
40661
|
source: account.source,
|
|
39856
40662
|
removable: !adopted,
|
|
39857
40663
|
...account.sourcePath === void 0 ? {} : { sourcePath: account.sourcePath },
|
|
40664
|
+
...quota === void 0 ? {} : { quota },
|
|
39858
40665
|
...expired ? {
|
|
39859
40666
|
authStatus: "expired",
|
|
39860
40667
|
authFailedReason: ADOPTED_CREDENTIAL_EXPIRED_HINT
|
|
@@ -40421,7 +41228,7 @@ async function getClaudeWebStatus(store, modelSettings, preferences, options = {
|
|
|
40421
41228
|
const catalog = live.length > 0 ? live : FALLBACK_MODELS;
|
|
40422
41229
|
const available = catalog.map((model) => model.id);
|
|
40423
41230
|
const models = buildClaudeModelOptions(catalog, available, resolveEnabledModelIds(settings.enabledModelIds, available, enabled), settings.contextWindowOverrides);
|
|
40424
|
-
const quota = credential === void 0 ? getCachedQuota$1() :
|
|
41231
|
+
const quota = credential === void 0 ? getCachedQuota$1() : cachedQuotaForPool(active.id, credential);
|
|
40425
41232
|
const poolData = options.accountPool === void 0 ? null : await options.accountPool.read().catch(() => null);
|
|
40426
41233
|
const poolAccounts = options.accountPool === void 0 ? [] : await options.accountPool.listAccounts().catch(() => []);
|
|
40427
41234
|
const presence = await claudeCodeCredentialPresence(options.adoptPaths ?? claudeCodeCredentialPaths()).catch(() => ({
|
|
@@ -40555,13 +41362,14 @@ function registerClaudeRoutes(ctx, store, modelSettings, preferences, options =
|
|
|
40555
41362
|
if (path === "" || path === "status") {
|
|
40556
41363
|
if (method !== "GET") return sendMethodNotAllowed(response);
|
|
40557
41364
|
const active = await activeAccount();
|
|
40558
|
-
const cached = active.credentials === void 0 ? null :
|
|
41365
|
+
const cached = active.credentials === void 0 ? null : cachedQuotaForPool(active.id, active.credentials);
|
|
40559
41366
|
const stale = cached === null || Date.now() - (cached.fetchedAt || 0) > 12e4;
|
|
40560
41367
|
if (active.credentials !== void 0 && stale) {
|
|
40561
41368
|
const credentials = active.credentials;
|
|
40562
41369
|
const refresh = () => fetchAccountQuota$1(credentials, {
|
|
40563
41370
|
fetchFn,
|
|
40564
|
-
signal: quotaAbort.signal
|
|
41371
|
+
signal: quotaAbort.signal,
|
|
41372
|
+
accountId: active.id
|
|
40565
41373
|
});
|
|
40566
41374
|
if (cached === null) await quotaRefresh.run(refresh);
|
|
40567
41375
|
else quotaRefresh.start(refresh);
|
|
@@ -40683,7 +41491,8 @@ function registerClaudeRoutes(ctx, store, modelSettings, preferences, options =
|
|
|
40683
41491
|
await fetchAccountQuota$1(credentials, {
|
|
40684
41492
|
fetchFn,
|
|
40685
41493
|
force: method === "POST",
|
|
40686
|
-
signal: quotaAbort.signal
|
|
41494
|
+
signal: quotaAbort.signal,
|
|
41495
|
+
accountId: active.id
|
|
40687
41496
|
});
|
|
40688
41497
|
} catch (error) {
|
|
40689
41498
|
quotaError = error instanceof Error ? error.message : String(error);
|
|
@@ -44299,39 +45108,24 @@ function apply(ctx, pluginConfig = {}) {
|
|
|
44299
45108
|
provider,
|
|
44300
45109
|
limits: providerLimits
|
|
44301
45110
|
})]));
|
|
44302
|
-
const
|
|
44303
|
-
|
|
44304
|
-
|
|
44305
|
-
|
|
44306
|
-
|
|
44307
|
-
|
|
44308
|
-
|
|
44309
|
-
|
|
44310
|
-
try {
|
|
44311
|
-
antigravityRegistration = ctx.llm.registerAdapter([PROVIDER_ID$6], antigravityAdapter);
|
|
44312
|
-
if (antigravityConflict !== null) ctx.logger.info(`[dsh-chatgpt-subscription] Antigravity route "${PROVIDER_ID$6}" is now served by this plugin`);
|
|
44313
|
-
antigravityConflict = null;
|
|
44314
|
-
} catch (error) {
|
|
44315
|
-
antigravityConflict = error instanceof Error ? error.message : String(error);
|
|
44316
|
-
ctx.logger.warn(`[dsh-chatgpt-subscription] provider route "${PROVIDER_ID$6}" is already owned by another adapter; Antigravity models keep being served by that one until its configuration is removed (${antigravityConflict})`);
|
|
44317
|
-
}
|
|
44318
|
-
};
|
|
44319
|
-
claimAntigravityRoute();
|
|
44320
|
-
const antigravityRouteWatch = typeof ctx.on === "function" ? ctx.on("llm/adapters-updated", () => {
|
|
44321
|
-
claimAntigravityRoute();
|
|
44322
|
-
}) : void 0;
|
|
45111
|
+
const antigravityClaim = claimProviderRoute(ctx, {
|
|
45112
|
+
providerId: PROVIDER_ID$6,
|
|
45113
|
+
label: PROVIDER_NAME$6,
|
|
45114
|
+
adapter: new AntigravityAdapter(antigravityStore, antigravityModelSettings, antigravityPreferences, {
|
|
45115
|
+
fetchFn: modelFetch.antigravity,
|
|
45116
|
+
attachments: ctx.attachments
|
|
45117
|
+
}, antigravityAccountPool)
|
|
45118
|
+
});
|
|
44323
45119
|
const disposeAntigravityRoutes = registerAntigravityRoutes(ctx, antigravityStore, antigravityModelSettings, antigravityPreferences, proxyFetch, antigravityAccountPool);
|
|
44324
45120
|
const disposeCommandCodeRoutes = registerCommandCodeRoutes(ctx, commandCodeStore, commandCodeModelSettings, commandCodePreferences, {
|
|
44325
45121
|
fetchFn: proxyFetch,
|
|
44326
|
-
serving: () =>
|
|
44327
|
-
conflict: () =>
|
|
45122
|
+
serving: () => commandCodeClaim.serving(),
|
|
45123
|
+
conflict: () => commandCodeClaim.conflict()
|
|
44328
45124
|
}, commandCodeAccountPool);
|
|
44329
45125
|
const commandCodeAdapter = new CommandCodeAdapter(commandCodeStore, commandCodeModelSettings, commandCodePreferences, {
|
|
44330
45126
|
fetchFn: modelFetch["command-code"],
|
|
44331
45127
|
attachments: ctx.attachments
|
|
44332
45128
|
}, commandCodeAccountPool);
|
|
44333
|
-
let commandCodeRegistration;
|
|
44334
|
-
let commandCodeConflict = null;
|
|
44335
45129
|
const ollamaStore = new FileCredentialStore$5();
|
|
44336
45130
|
const ollamaModelSettings = new FileModelSettingsStore$5();
|
|
44337
45131
|
const ollamaAccountPool = new OllamaAccountPool({ store: ollamaStore });
|
|
@@ -44339,92 +45133,48 @@ function apply(ctx, pluginConfig = {}) {
|
|
|
44339
45133
|
fetchFn: modelFetch.ollama,
|
|
44340
45134
|
attachments: ctx.attachments
|
|
44341
45135
|
}, ollamaAccountPool);
|
|
44342
|
-
|
|
44343
|
-
|
|
44344
|
-
|
|
44345
|
-
|
|
44346
|
-
|
|
44347
|
-
|
|
44348
|
-
|
|
44349
|
-
|
|
44350
|
-
|
|
44351
|
-
|
|
44352
|
-
|
|
44353
|
-
|
|
44354
|
-
const
|
|
44355
|
-
|
|
44356
|
-
|
|
44357
|
-
|
|
44358
|
-
|
|
44359
|
-
|
|
44360
|
-
} catch (error) {
|
|
44361
|
-
kimiCodeConflict = error instanceof Error ? error.message : String(error);
|
|
44362
|
-
ctx.logger.warn(`[dsh-chatgpt-subscription] provider route "${PROVIDER_ID$3}" is already owned by another adapter; ${PROVIDER_NAME$3} models keep being served by that one until its configuration is removed (${kimiCodeConflict})`);
|
|
44363
|
-
}
|
|
44364
|
-
};
|
|
44365
|
-
claimKimiCodeRoute();
|
|
44366
|
-
const kimiCodeRouteWatch = typeof ctx.on === "function" ? ctx.on("llm/adapters-updated", () => {
|
|
44367
|
-
claimKimiCodeRoute();
|
|
44368
|
-
}) : void 0;
|
|
44369
|
-
const claimOllamaRoute = () => {
|
|
44370
|
-
if (ollamaRegistration !== void 0) return;
|
|
44371
|
-
try {
|
|
44372
|
-
ollamaRegistration = ctx.llm.registerAdapter([PROVIDER_ID$4], ollamaAdapter);
|
|
44373
|
-
if (ollamaConflict !== null) ctx.logger.info(`[dsh-chatgpt-subscription] ${PROVIDER_NAME$4} route "${PROVIDER_ID$4}" is now served by this plugin`);
|
|
44374
|
-
ollamaConflict = null;
|
|
44375
|
-
} catch (error) {
|
|
44376
|
-
ollamaConflict = error instanceof Error ? error.message : String(error);
|
|
44377
|
-
ctx.logger.warn(`[dsh-chatgpt-subscription] provider route "${PROVIDER_ID$4}" is already owned by another adapter; ${PROVIDER_NAME$4} models keep being served by that one until its configuration is removed (${ollamaConflict})`);
|
|
44378
|
-
}
|
|
44379
|
-
};
|
|
44380
|
-
claimOllamaRoute();
|
|
45136
|
+
const kimiCodeClaim = claimProviderRoute(ctx, {
|
|
45137
|
+
providerId: PROVIDER_ID$3,
|
|
45138
|
+
label: PROVIDER_NAME$3,
|
|
45139
|
+
adapter: new KimiCodeAdapter(kimiCodeStore, kimiCodeModelSettings, kimiCodePreferences, {
|
|
45140
|
+
fetchFn: modelFetch["kimi-code"],
|
|
45141
|
+
attachments: ctx.attachments,
|
|
45142
|
+
videos: { readVideo: async (ref) => ({
|
|
45143
|
+
data: await readVideoBytes(ref),
|
|
45144
|
+
mediaType: ref.mediaType
|
|
45145
|
+
}) }
|
|
45146
|
+
}, kimiCodeAccountPool)
|
|
45147
|
+
});
|
|
45148
|
+
const ollamaClaim = claimProviderRoute(ctx, {
|
|
45149
|
+
providerId: PROVIDER_ID$4,
|
|
45150
|
+
label: PROVIDER_NAME$4,
|
|
45151
|
+
adapter: ollamaAdapter,
|
|
45152
|
+
watch: false
|
|
45153
|
+
});
|
|
44381
45154
|
const disposeOllamaRoutes = registerOllamaRoutes(ctx, {
|
|
44382
45155
|
accountPool: ollamaAccountPool,
|
|
44383
45156
|
modelSettings: ollamaModelSettings,
|
|
44384
45157
|
fetchFn: proxyFetch
|
|
44385
45158
|
});
|
|
44386
|
-
const
|
|
44387
|
-
|
|
44388
|
-
|
|
44389
|
-
|
|
44390
|
-
|
|
44391
|
-
commandCodeConflict = null;
|
|
44392
|
-
} catch (error) {
|
|
44393
|
-
commandCodeConflict = error instanceof Error ? error.message : String(error);
|
|
44394
|
-
ctx.logger.warn(`[dsh-chatgpt-subscription] provider route "${PROVIDER_ID$5}" is already owned by another adapter; ${PROVIDER_NAME$5} models keep being served by that one until its configuration is removed (${commandCodeConflict})`);
|
|
44395
|
-
}
|
|
44396
|
-
};
|
|
44397
|
-
claimCommandCodeRoute();
|
|
44398
|
-
const commandCodeRouteWatch = typeof ctx.on === "function" ? ctx.on("llm/adapters-updated", () => {
|
|
44399
|
-
claimCommandCodeRoute();
|
|
44400
|
-
}) : void 0;
|
|
45159
|
+
const commandCodeClaim = claimProviderRoute(ctx, {
|
|
45160
|
+
providerId: PROVIDER_ID$5,
|
|
45161
|
+
label: PROVIDER_NAME$5,
|
|
45162
|
+
adapter: commandCodeAdapter
|
|
45163
|
+
});
|
|
44401
45164
|
const disposeKimiCodeRoutes = registerKimiCodeRoutes(ctx, kimiCodeStore, kimiCodeModelSettings, kimiCodePreferences, {
|
|
44402
45165
|
fetchFn: proxyFetch,
|
|
44403
|
-
serving: () =>
|
|
44404
|
-
conflict: () =>
|
|
45166
|
+
serving: () => kimiCodeClaim.serving(),
|
|
45167
|
+
conflict: () => kimiCodeClaim.conflict()
|
|
44405
45168
|
}, kimiCodeAccountPool);
|
|
44406
|
-
const
|
|
44407
|
-
|
|
44408
|
-
|
|
44409
|
-
|
|
44410
|
-
|
|
44411
|
-
|
|
44412
|
-
|
|
44413
|
-
|
|
44414
|
-
|
|
44415
|
-
try {
|
|
44416
|
-
minimaxCodeRegistration = ctx.llm.registerAdapter([PROVIDER_ID$2], minimaxCodeAdapter);
|
|
44417
|
-
if (minimaxCodeConflict !== null) ctx.logger.info(`[dsh-chatgpt-subscription] ${PROVIDER_NAME$2} route "${PROVIDER_ID$2}" is now served by this plugin`);
|
|
44418
|
-
minimaxCodeConflict = null;
|
|
44419
|
-
} catch (error) {
|
|
44420
|
-
minimaxCodeConflict = error instanceof Error ? error.message : String(error);
|
|
44421
|
-
ctx.logger.warn(`[dsh-chatgpt-subscription] provider route "${PROVIDER_ID$2}" is already owned by another adapter; ${PROVIDER_NAME$2} models keep being served by that one until its configuration is removed (${minimaxCodeConflict})`);
|
|
44422
|
-
}
|
|
44423
|
-
};
|
|
44424
|
-
claimMinimaxCodeRoute();
|
|
44425
|
-
const minimaxCodeRouteWatch = typeof ctx.on === "function" ? ctx.on("llm/adapters-updated", () => {
|
|
44426
|
-
claimMinimaxCodeRoute();
|
|
44427
|
-
}) : void 0;
|
|
45169
|
+
const minimaxCodeClaim = claimProviderRoute(ctx, {
|
|
45170
|
+
providerId: PROVIDER_ID$2,
|
|
45171
|
+
label: PROVIDER_NAME$2,
|
|
45172
|
+
adapter: new MinimaxCodeAdapter(minimaxCodeStore, {
|
|
45173
|
+
fetchFn: modelFetch["minimax-code"],
|
|
45174
|
+
attachments: ctx.attachments,
|
|
45175
|
+
accountPool: minimaxCodeAccountPool
|
|
45176
|
+
}, minimaxCodeModelSettings, minimaxCodePreferences)
|
|
45177
|
+
});
|
|
44428
45178
|
let minimaxCodeAppVersion;
|
|
44429
45179
|
try {
|
|
44430
45180
|
const manifest = createRequire(import.meta.url)("../package.json");
|
|
@@ -44448,33 +45198,20 @@ function apply(ctx, pluginConfig = {}) {
|
|
|
44448
45198
|
minimaxCodeCheckinTick();
|
|
44449
45199
|
const disposeMinimaxCodeRoutes = registerMinimaxCodeRoutes(ctx, minimaxCodeStore, {
|
|
44450
45200
|
fetchFn: proxyFetch,
|
|
44451
|
-
serving: () =>
|
|
44452
|
-
conflict: () =>
|
|
45201
|
+
serving: () => minimaxCodeClaim.serving(),
|
|
45202
|
+
conflict: () => minimaxCodeClaim.conflict(),
|
|
44453
45203
|
accountPool: minimaxCodeAccountPool,
|
|
44454
45204
|
checkin: minimaxCodeCheckin
|
|
44455
45205
|
}, minimaxCodeModelSettings, minimaxCodePreferences);
|
|
44456
|
-
const
|
|
44457
|
-
|
|
44458
|
-
|
|
44459
|
-
|
|
45206
|
+
const workBuddyClaim = claimProviderRoute(ctx, {
|
|
45207
|
+
providerId: PROVIDER_ID$1,
|
|
45208
|
+
label: PROVIDER_NAME$1,
|
|
45209
|
+
adapter: new WorkBuddyAdapter(workBuddyStore, workBuddyModelSettings, workBuddyPreferences, {
|
|
45210
|
+
fetchFn: modelFetch.workbuddy,
|
|
45211
|
+
attachments: ctx.attachments,
|
|
45212
|
+
accountPool: workBuddyAccountPool
|
|
45213
|
+
})
|
|
44460
45214
|
});
|
|
44461
|
-
let workBuddyRegistration;
|
|
44462
|
-
let workBuddyConflict = null;
|
|
44463
|
-
const claimWorkBuddyRoute = () => {
|
|
44464
|
-
if (workBuddyRegistration !== void 0) return;
|
|
44465
|
-
try {
|
|
44466
|
-
workBuddyRegistration = ctx.llm.registerAdapter([PROVIDER_ID$1], workBuddyAdapter);
|
|
44467
|
-
if (workBuddyConflict !== null) ctx.logger.info(`[dsh-chatgpt-subscription] ${PROVIDER_NAME$1} route "${PROVIDER_ID$1}" is now served by this plugin`);
|
|
44468
|
-
workBuddyConflict = null;
|
|
44469
|
-
} catch (error) {
|
|
44470
|
-
workBuddyConflict = error instanceof Error ? error.message : String(error);
|
|
44471
|
-
ctx.logger.warn(`[dsh-chatgpt-subscription] provider route "${PROVIDER_ID$1}" is already owned by another adapter; ${PROVIDER_NAME$1} models keep being served by that one until its configuration is removed (${workBuddyConflict})`);
|
|
44472
|
-
}
|
|
44473
|
-
};
|
|
44474
|
-
claimWorkBuddyRoute();
|
|
44475
|
-
const workBuddyRouteWatch = typeof ctx.on === "function" ? ctx.on("llm/adapters-updated", () => {
|
|
44476
|
-
claimWorkBuddyRoute();
|
|
44477
|
-
}) : void 0;
|
|
44478
45215
|
const workBuddyCheckin = new WorkBuddyCheckinService(workBuddyStore, {
|
|
44479
45216
|
fetchFn: proxyFetch,
|
|
44480
45217
|
settings: () => workBuddyPreferences.status().checkin,
|
|
@@ -44490,37 +45227,24 @@ function apply(ctx, pluginConfig = {}) {
|
|
|
44490
45227
|
checkinTick();
|
|
44491
45228
|
const disposeWorkBuddyRoutes = registerWorkBuddyRoutes(ctx, workBuddyStore, workBuddyModelSettings, workBuddyPreferences, {
|
|
44492
45229
|
fetchFn: proxyFetch,
|
|
44493
|
-
serving: () =>
|
|
44494
|
-
conflict: () =>
|
|
45230
|
+
serving: () => workBuddyClaim.serving(),
|
|
45231
|
+
conflict: () => workBuddyClaim.conflict(),
|
|
44495
45232
|
accountPool: workBuddyAccountPool,
|
|
44496
45233
|
checkin: workBuddyCheckin
|
|
44497
45234
|
});
|
|
44498
|
-
const
|
|
44499
|
-
|
|
44500
|
-
|
|
44501
|
-
|
|
45235
|
+
const claudeClaim = claimProviderRoute(ctx, {
|
|
45236
|
+
providerId: PROVIDER_ID,
|
|
45237
|
+
label: PROVIDER_NAME,
|
|
45238
|
+
adapter: new ClaudeAdapter(claudeStore, claudeModelSettings, claudePreferences, {
|
|
45239
|
+
fetchFn: modelFetch.claude,
|
|
45240
|
+
attachments: ctx.attachments,
|
|
45241
|
+
accountPool: claudeAccountPool
|
|
45242
|
+
})
|
|
44502
45243
|
});
|
|
44503
|
-
let claudeRegistration;
|
|
44504
|
-
let claudeConflict = null;
|
|
44505
|
-
const claimClaudeRoute = () => {
|
|
44506
|
-
if (claudeRegistration !== void 0) return;
|
|
44507
|
-
try {
|
|
44508
|
-
claudeRegistration = ctx.llm.registerAdapter([PROVIDER_ID], claudeAdapter);
|
|
44509
|
-
if (claudeConflict !== null) ctx.logger.info(`[dsh-chatgpt-subscription] ${PROVIDER_NAME} route "${PROVIDER_ID}" is now served by this plugin`);
|
|
44510
|
-
claudeConflict = null;
|
|
44511
|
-
} catch (error) {
|
|
44512
|
-
claudeConflict = error instanceof Error ? error.message : String(error);
|
|
44513
|
-
ctx.logger.warn(`[dsh-chatgpt-subscription] provider route "${PROVIDER_ID}" is already owned by another adapter; ${PROVIDER_NAME} models keep being served by that one until its configuration is removed (${claudeConflict})`);
|
|
44514
|
-
}
|
|
44515
|
-
};
|
|
44516
|
-
claimClaudeRoute();
|
|
44517
|
-
const claudeRouteWatch = typeof ctx.on === "function" ? ctx.on("llm/adapters-updated", () => {
|
|
44518
|
-
claimClaudeRoute();
|
|
44519
|
-
}) : void 0;
|
|
44520
45244
|
const disposeClaudeRoutes = registerClaudeRoutes(ctx, claudeStore, claudeModelSettings, claudePreferences, {
|
|
44521
45245
|
fetchFn: proxyFetch,
|
|
44522
|
-
serving: () =>
|
|
44523
|
-
conflict: () =>
|
|
45246
|
+
serving: () => claudeClaim.serving(),
|
|
45247
|
+
conflict: () => claudeClaim.conflict(),
|
|
44524
45248
|
accountPool: claudeAccountPool
|
|
44525
45249
|
});
|
|
44526
45250
|
workBuddyAccountPool.syncDesktopAccounts().catch(() => void 0);
|
|
@@ -44531,7 +45255,11 @@ function apply(ctx, pluginConfig = {}) {
|
|
|
44531
45255
|
pool: codexAccountPool
|
|
44532
45256
|
});
|
|
44533
45257
|
const usage = new UsageService(oauth, { fetchFn: proxyFetch });
|
|
44534
|
-
codexAccountPool.setQuotaBlockedUntil((account, now) => usage.blockedUntilFor(account.credentials, now));
|
|
45258
|
+
codexAccountPool.setQuotaBlockedUntil((account, now) => usage.blockedUntilFor(account.id, account.credentials, now));
|
|
45259
|
+
codexAccountPool.setQuotaSnapshot((account) => {
|
|
45260
|
+
const snapshot = usage.snapshotFor(account.id, account.credentials);
|
|
45261
|
+
return snapshot === void 0 ? void 0 : codexAccountQuota(snapshot);
|
|
45262
|
+
});
|
|
44535
45263
|
const adapter = new CodexChatGptAdapter(new ResponsesClient(oauth, ctx.attachments, {
|
|
44536
45264
|
fetchFn: modelFetch["codex-chatgpt"],
|
|
44537
45265
|
accountPool: codexAccountPool,
|
|
@@ -44587,6 +45315,145 @@ function apply(ctx, pluginConfig = {}) {
|
|
|
44587
45315
|
});
|
|
44588
45316
|
};
|
|
44589
45317
|
const disposeRoutes = registerRoutes(ctx, oauth, usage, preferences, proxyManager, searchSwitcher, readRouteAudit, codexAccountPool, fetchConfiguration);
|
|
45318
|
+
const routable = (accounts) => accounts.some((account) => account.authStatus === void 0 || account.authStatus === "ok");
|
|
45319
|
+
const disposeHubOverview = registerHubOverviewRoutes(ctx, [
|
|
45320
|
+
{
|
|
45321
|
+
id: "chatgpt",
|
|
45322
|
+
providerId: PROVIDER_ID$7,
|
|
45323
|
+
canToggle: true,
|
|
45324
|
+
read: async () => {
|
|
45325
|
+
const current = preferences.status();
|
|
45326
|
+
const accounts = await codexAccountPool.listAccounts().catch(() => []);
|
|
45327
|
+
return {
|
|
45328
|
+
enabled: current.enabled !== false,
|
|
45329
|
+
accountCount: accounts.length,
|
|
45330
|
+
authenticated: routable(accounts),
|
|
45331
|
+
enabledModelCount: current.visibleModelIds.length,
|
|
45332
|
+
totalModelCount: CODEX_MODEL_CATALOG.length
|
|
45333
|
+
};
|
|
45334
|
+
}
|
|
45335
|
+
},
|
|
45336
|
+
{
|
|
45337
|
+
id: "antigravity",
|
|
45338
|
+
providerId: PROVIDER_ID$6,
|
|
45339
|
+
canToggle: true,
|
|
45340
|
+
read: async () => {
|
|
45341
|
+
const current = antigravityPreferences.status();
|
|
45342
|
+
const accounts = await antigravityAccountPool.listAccounts().catch(() => []);
|
|
45343
|
+
const total = catalogTotal((await antigravityModelSettings.read()).catalogModels.length);
|
|
45344
|
+
return {
|
|
45345
|
+
enabled: current.enabled !== false,
|
|
45346
|
+
accountCount: accounts.length,
|
|
45347
|
+
authenticated: routable(accounts),
|
|
45348
|
+
enabledModelCount: total === null ? null : Math.min(current.enabledModelIds?.length ?? 0, total),
|
|
45349
|
+
totalModelCount: total
|
|
45350
|
+
};
|
|
45351
|
+
}
|
|
45352
|
+
},
|
|
45353
|
+
{
|
|
45354
|
+
id: "command-code",
|
|
45355
|
+
providerId: PROVIDER_ID$5,
|
|
45356
|
+
canToggle: true,
|
|
45357
|
+
read: async () => {
|
|
45358
|
+
const current = commandCodePreferences.status();
|
|
45359
|
+
const accounts = await commandCodeAccountPool.listAccounts().catch(() => []);
|
|
45360
|
+
const total = catalogTotal((await commandCodeModelSettings.read()).catalogModels.length);
|
|
45361
|
+
return {
|
|
45362
|
+
enabled: current.enabled !== false,
|
|
45363
|
+
accountCount: accounts.length,
|
|
45364
|
+
authenticated: routable(accounts),
|
|
45365
|
+
enabledModelCount: total === null ? null : Math.min(current.enabledModelIds?.length ?? 0, total),
|
|
45366
|
+
totalModelCount: total
|
|
45367
|
+
};
|
|
45368
|
+
}
|
|
45369
|
+
},
|
|
45370
|
+
{
|
|
45371
|
+
id: "kimi-code",
|
|
45372
|
+
providerId: PROVIDER_ID$3,
|
|
45373
|
+
canToggle: true,
|
|
45374
|
+
read: async () => {
|
|
45375
|
+
const current = kimiCodePreferences.status();
|
|
45376
|
+
const accounts = await kimiCodeAccountPool.listAccounts().catch(() => []);
|
|
45377
|
+
const total = catalogTotal((await kimiCodeModelSettings.read()).catalogModels.length);
|
|
45378
|
+
return {
|
|
45379
|
+
enabled: current.enabled !== false,
|
|
45380
|
+
accountCount: accounts.length,
|
|
45381
|
+
authenticated: routable(accounts),
|
|
45382
|
+
enabledModelCount: total === null ? null : Math.min(current.enabledModelIds?.length ?? 0, total),
|
|
45383
|
+
totalModelCount: total
|
|
45384
|
+
};
|
|
45385
|
+
}
|
|
45386
|
+
},
|
|
45387
|
+
{
|
|
45388
|
+
id: "workbuddy",
|
|
45389
|
+
providerId: PROVIDER_ID$1,
|
|
45390
|
+
canToggle: true,
|
|
45391
|
+
read: async () => {
|
|
45392
|
+
const current = workBuddyPreferences.status();
|
|
45393
|
+
const accounts = await workBuddyAccountPool.listAccounts().catch(() => []);
|
|
45394
|
+
const total = catalogTotal(getCachedCatalog$1().length);
|
|
45395
|
+
return {
|
|
45396
|
+
enabled: current.enabled !== false,
|
|
45397
|
+
accountCount: accounts.length,
|
|
45398
|
+
authenticated: routable(accounts),
|
|
45399
|
+
enabledModelCount: total === null ? null : Math.min(current.enabledModelIds?.length ?? 0, total),
|
|
45400
|
+
totalModelCount: total
|
|
45401
|
+
};
|
|
45402
|
+
}
|
|
45403
|
+
},
|
|
45404
|
+
{
|
|
45405
|
+
id: "minimax-code",
|
|
45406
|
+
providerId: PROVIDER_ID$2,
|
|
45407
|
+
canToggle: true,
|
|
45408
|
+
read: async () => {
|
|
45409
|
+
const current = minimaxCodePreferences.status();
|
|
45410
|
+
const accounts = await minimaxCodeAccountPool.listAccounts().catch(() => []);
|
|
45411
|
+
const total = catalogTotal(catalogSize());
|
|
45412
|
+
return {
|
|
45413
|
+
enabled: current.enabled !== false,
|
|
45414
|
+
accountCount: accounts.length,
|
|
45415
|
+
authenticated: routable(accounts),
|
|
45416
|
+
enabledModelCount: total === null ? null : Math.min(current.enabledModelIds?.length ?? 0, total),
|
|
45417
|
+
totalModelCount: total
|
|
45418
|
+
};
|
|
45419
|
+
}
|
|
45420
|
+
},
|
|
45421
|
+
{
|
|
45422
|
+
id: "claude",
|
|
45423
|
+
providerId: PROVIDER_ID,
|
|
45424
|
+
canToggle: true,
|
|
45425
|
+
read: async () => {
|
|
45426
|
+
const current = claudePreferences.status();
|
|
45427
|
+
const accounts = await claudeAccountPool.listAccounts().catch(() => []);
|
|
45428
|
+
const total = catalogTotal(getCachedCatalog().length);
|
|
45429
|
+
return {
|
|
45430
|
+
enabled: current.enabled !== false,
|
|
45431
|
+
accountCount: accounts.length,
|
|
45432
|
+
authenticated: routable(accounts),
|
|
45433
|
+
enabledModelCount: total === null ? null : Math.min(current.enabledModelIds?.length ?? 0, total),
|
|
45434
|
+
totalModelCount: total
|
|
45435
|
+
};
|
|
45436
|
+
}
|
|
45437
|
+
},
|
|
45438
|
+
{
|
|
45439
|
+
id: "ollama",
|
|
45440
|
+
providerId: PROVIDER_ID$4,
|
|
45441
|
+
canToggle: false,
|
|
45442
|
+
read: async () => {
|
|
45443
|
+
const accounts = await ollamaAccountPool.listAccounts().catch(() => []);
|
|
45444
|
+
const current = ollamaModelSettings.status();
|
|
45445
|
+
const total = catalogTotal(current.catalogModels.length);
|
|
45446
|
+
const enabled = current.enabledModelIds.length === 0 ? total : current.enabledModelIds.length;
|
|
45447
|
+
return {
|
|
45448
|
+
enabled: true,
|
|
45449
|
+
accountCount: accounts.length,
|
|
45450
|
+
authenticated: routable(accounts),
|
|
45451
|
+
enabledModelCount: total === null ? null : Math.min(enabled ?? 0, total),
|
|
45452
|
+
totalModelCount: total
|
|
45453
|
+
};
|
|
45454
|
+
}
|
|
45455
|
+
}
|
|
45456
|
+
]);
|
|
44590
45457
|
const disposeAdapter = ctx.llm.registerAdapter([PROVIDER_ID$7], adapter);
|
|
44591
45458
|
const disposeImageTool = ctx.tools.register(createCodexImageTool(oauth, ctx.attachments, { fetchFn: proxyFetch }));
|
|
44592
45459
|
const disposeVideoTool = ctx.tools.register(createKimiVideoTool(ctx, { fetchFn: proxyFetch }));
|
|
@@ -44613,48 +45480,28 @@ function apply(ctx, pluginConfig = {}) {
|
|
|
44613
45480
|
disposeVideoTool();
|
|
44614
45481
|
disposeAdapter();
|
|
44615
45482
|
disposeRoutes();
|
|
45483
|
+
disposeHubOverview();
|
|
44616
45484
|
disposeAntigravityRoutes();
|
|
44617
|
-
|
|
44618
|
-
antigravityRegistration?.();
|
|
44619
|
-
antigravityRegistration = void 0;
|
|
45485
|
+
antigravityClaim.dispose();
|
|
44620
45486
|
disposeOllamaRoutes();
|
|
44621
|
-
|
|
44622
|
-
ollamaRegistration = void 0;
|
|
45487
|
+
ollamaClaim.dispose();
|
|
44623
45488
|
disposeCommandCodeRoutes();
|
|
44624
|
-
|
|
44625
|
-
commandCodeRegistration?.();
|
|
44626
|
-
commandCodeRegistration = void 0;
|
|
45489
|
+
commandCodeClaim.dispose();
|
|
44627
45490
|
disposeKimiCodeRoutes();
|
|
44628
|
-
|
|
44629
|
-
kimiCodeRegistration?.();
|
|
44630
|
-
kimiCodeRegistration = void 0;
|
|
45491
|
+
kimiCodeClaim.dispose();
|
|
44631
45492
|
disposeMinimaxCodeRoutes();
|
|
44632
|
-
|
|
44633
|
-
minimaxCodeRegistration?.();
|
|
44634
|
-
minimaxCodeRegistration = void 0;
|
|
45493
|
+
minimaxCodeClaim.dispose();
|
|
44635
45494
|
clearInterval(minimaxCodeCheckinTimer);
|
|
44636
45495
|
clearInterval(checkinTimer);
|
|
44637
45496
|
disposeWorkBuddyRoutes();
|
|
44638
|
-
|
|
44639
|
-
workBuddyRegistration?.();
|
|
44640
|
-
workBuddyRegistration = void 0;
|
|
45497
|
+
workBuddyClaim.dispose();
|
|
44641
45498
|
disposeClaudeRoutes();
|
|
44642
|
-
|
|
44643
|
-
claudeRegistration?.();
|
|
44644
|
-
claudeRegistration = void 0;
|
|
45499
|
+
claudeClaim.dispose();
|
|
44645
45500
|
oauth.dispose();
|
|
44646
45501
|
proxyManager.dispose();
|
|
44647
45502
|
};
|
|
44648
45503
|
}, "dsh-chatgpt-subscription: adapter, routes, and lifecycle");
|
|
44649
45504
|
}
|
|
44650
|
-
/** Cordis event handles are either a disposer function or a disposable object. */
|
|
44651
|
-
function releaseHandle(handle) {
|
|
44652
|
-
if (typeof handle === "function") {
|
|
44653
|
-
handle();
|
|
44654
|
-
return;
|
|
44655
|
-
}
|
|
44656
|
-
handle?.dispose?.();
|
|
44657
|
-
}
|
|
44658
45505
|
function localWebServerBaseUrl(host, port) {
|
|
44659
45506
|
return `http://${host === "0.0.0.0" ? "127.0.0.1" : host}:${port}`;
|
|
44660
45507
|
}
|