dsh-connect-trae 1.4.2 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.d.ts CHANGED
@@ -33,6 +33,62 @@ interface TraeDiscoveredModel {
33
33
  /** Parse only capabilities explicitly advertised by Trae's remote model API. */
34
34
  declare function parseTraeRemoteModel(value: unknown): TraeDiscoveredModel | undefined;
35
35
  //#endregion
36
+ //#region src/paths.d.ts
37
+ type TraeEdition = 'cn' | 'sg' | 'solo' | 'solo-sg';
38
+ /**
39
+ * Where a local sign-in was persisted. `desktop` candidates hold an Electron
40
+ * `globalStorage/storage.json` whose auth value is encrypted; `cli` candidates
41
+ * hold a bare JWT written by the Trae CLI, which needs no decryption.
42
+ */
43
+ type TraeCredentialSource = 'desktop' | 'cli';
44
+ interface TraeStorageCandidate {
45
+ edition: TraeEdition;
46
+ path: string;
47
+ source: TraeCredentialSource;
48
+ }
49
+ declare function traeStorageCandidates(platform?: NodeJS.Platform, home?: string, env?: NodeJS.ProcessEnv): TraeStorageCandidate[];
50
+ //#endregion
51
+ //#region src/region.d.ts
52
+ /** Storage/routing bucket: the CN service or the international (ai) service. */
53
+ type TraeRegion = 'cn' | 'ai';
54
+ /** One region's upstream gateway bases. */
55
+ interface TraeRegionGateways {
56
+ /** Chat + agent API base (the `llm_utils_chat` / raw-chat family). */
57
+ readonly chat: string;
58
+ /** SOLO remote model directory base (`/api/remote/v1`). */
59
+ readonly remote: string;
60
+ /** Pay/status API base; the credential's own host is preferred when known. */
61
+ readonly pay: string;
62
+ }
63
+ /**
64
+ * Verified gateway bases per region (docs/INTL_SG_EVIDENCE.md §2).
65
+ * The AI gateway is shared by both international installs (Trae desktop and
66
+ * TRAE SOLO); its mchost shards (`api16/api22-normal-alisg.mchost.guru`)
67
+ * answer the same bytes but stay internal — `coresg-normal.trae.ai` is the
68
+ * single stable entry point.
69
+ */
70
+ declare const REGION_GATEWAYS: Readonly<Record<TraeRegion, TraeRegionGateways>>;
71
+ /** Region for an edition label: the international installs belong to `ai`. */
72
+ declare function regionOfEdition(edition: TraeEdition): TraeRegion;
73
+ /**
74
+ * Region from the credential's `userRegion` claim. The desktop storage spells
75
+ * it as an object (`{"region":"CN","_aiRegion":"CN"}`); the app logs also
76
+ * spell the bare value lowercase (`"sg"`). Both are accepted, case-blind.
77
+ */
78
+ declare function regionOfUserRegion(value: unknown): TraeRegion | undefined;
79
+ /** Region from a credential host (`.trae.ai` → ai, `.trae.cn`/`.trae.com.cn` → cn). */
80
+ declare function regionOfHost(host: string | undefined): TraeRegion | undefined;
81
+ /**
82
+ * Region of a credential: the `userRegion` claim wins, the host suffix is the
83
+ * fallback, and the edition label is the last resort. Every level is derived
84
+ * from data the credential itself carries, so no user configuration is needed.
85
+ */
86
+ declare function regionOfCredential(credential: {
87
+ edition: TraeEdition;
88
+ host?: string;
89
+ userRegion?: string;
90
+ }): TraeRegion;
91
+ //#endregion
36
92
  //#region src/catalog.d.ts
37
93
  type TraeInputModality = 'text' | 'image';
38
94
  /**
@@ -56,6 +112,21 @@ interface TraeModelInfo {
56
112
  }
57
113
  /** Bootstrap catalog: identity only where current Trae metadata has not been fetched yet. */
58
114
  declare const FALLBACK_TRAE_MODELS: readonly TraeModelInfo[];
115
+ /**
116
+ * Bootstrap catalog for the international (ai) region, captured from the
117
+ * live `coresg-normal.trae.ai/api/remote/v1/models` directory on 2026-09-15
118
+ * (docs/INTL_SG_EVIDENCE.md §3). The two rosters barely overlap (the CN list
119
+ * has no Gemini/GPT/MiniMax entries), so an international account must never
120
+ * be seeded with the CN list. Like the CN fallback it is replaced by the live
121
+ * refresh; image input stays the user's explicit opt-in (`imageModelIds`).
122
+ */
123
+ declare const FALLBACK_TRAE_MODELS_AI: readonly TraeModelInfo[];
124
+ /**
125
+ * Static fallback directory for a region. Each region keeps its own model
126
+ * slot in settings; the fallback must match the region so an account never
127
+ * shows the other region's roster.
128
+ */
129
+ declare function fallbackModelsFor(region: TraeRegion): readonly TraeModelInfo[];
59
130
  /** Exact DSH modalities for one catalog entry; absent metadata is text-only. */
60
131
  declare function traeInputModalities(model: Pick<TraeModelInfo, 'input'>): TraeInputModality[];
61
132
  /**
@@ -127,6 +198,12 @@ declare function sanitizeCatalog(catalog: readonly TraeModelInfo[]): TraeModelIn
127
198
  declare function deriveCatalog(catalog: readonly TraeModelInfo[], enabled: ReadonlySet<string>, budgets?: Readonly<Record<string, TraeContextBudget | undefined>>): TraeModelInfo[];
128
199
  declare class TraeCatalog {
129
200
  private models;
201
+ /**
202
+ * @param region Seeds the static fallback for this region; each region's
203
+ * provider must never serve the other region's roster before its first live
204
+ * refresh lands.
205
+ */
206
+ constructor(region?: TraeRegion);
130
207
  current(): readonly TraeModelInfo[];
131
208
  set(models: readonly TraeModelInfo[]): void;
132
209
  }
@@ -172,11 +249,28 @@ interface TraeShimOptions {
172
249
  declare function createTraeShim(options: TraeShimOptions): TraeShim;
173
250
  //#endregion
174
251
  //#region src/adapter.d.ts
252
+ /** Provider route this bundle owns for the domestic (CN) gateway. */
175
253
  declare const TRAE_PROVIDER = "trae";
254
+ /**
255
+ * Provider route this bundle owns for the international (trae.ai) gateway.
256
+ * Named `-global` to match the plugin family's convention (`workbuddy-global`);
257
+ * the internal region bucket stays `ai`, which is the gateway/protocol name.
258
+ */
259
+ declare const TRAE_AI_PROVIDER = "trae-global";
260
+ /** The provider id each region registers as. */
261
+ declare const TRAE_PROVIDERS: Readonly<Record<TraeRegion, string>>;
262
+ /** Human-readable provider names, shown in the DSH model picker. */
263
+ declare const TRAE_PROVIDER_DISPLAY_NAMES: Readonly<Record<TraeRegion, string>>;
264
+ /** Region a provider route id belongs to. */
265
+ declare function regionOfTraeProvider(provider: string): TraeRegion | undefined;
176
266
  declare const TRAE_STREAM_IDLE_TIMEOUT_MS = 300000;
177
267
  interface TraeAdapterOptions {
178
268
  shim: TraeShim;
179
269
  catalog: TraeCatalog;
270
+ /** Provider route id this instance serves; defaults to the CN route. */
271
+ provider?: string;
272
+ /** pi-ai provider name and profile display name; defaults to the CN name. */
273
+ displayName?: string;
180
274
  resolveAttachments?: () => AttachmentStore | undefined;
181
275
  }
182
276
  interface TraeAdapter {
@@ -185,21 +279,6 @@ interface TraeAdapter {
185
279
  }
186
280
  declare function createTraeAdapter(options: TraeAdapterOptions): TraeAdapter;
187
281
  //#endregion
188
- //#region src/paths.d.ts
189
- type TraeEdition = 'cn' | 'sg' | 'solo' | 'solo-sg';
190
- /**
191
- * Where a local sign-in was persisted. `desktop` candidates hold an Electron
192
- * `globalStorage/storage.json` whose auth value is encrypted; `cli` candidates
193
- * hold a bare JWT written by the Trae CLI, which needs no decryption.
194
- */
195
- type TraeCredentialSource = 'desktop' | 'cli';
196
- interface TraeStorageCandidate {
197
- edition: TraeEdition;
198
- path: string;
199
- source: TraeCredentialSource;
200
- }
201
- declare function traeStorageCandidates(platform?: NodeJS.Platform, home?: string, env?: NodeJS.ProcessEnv): TraeStorageCandidate[];
202
- //#endregion
203
282
  //#region src/auth.d.ts
204
283
  interface TraeCredential {
205
284
  accessToken: string;
@@ -207,6 +286,12 @@ interface TraeCredential {
207
286
  userId: string;
208
287
  accountName?: string;
209
288
  host: string;
289
+ /**
290
+ * Region claim from the decrypted storage document (`userRegion.region`,
291
+ * 'CN' | 'SG', possibly lowercase). Drives the routing bucket together with
292
+ * `host`; see `regionOfCredential`.
293
+ */
294
+ userRegion?: string;
210
295
  expiresAtMs: number;
211
296
  refreshExpiresAtMs?: number;
212
297
  edition: TraeEdition;
@@ -224,6 +309,14 @@ interface TraeCredentialStoreOptions {
224
309
  edition?: TraeEdition | 'auto';
225
310
  accountId?: string;
226
311
  ownPath?: string;
312
+ /**
313
+ * Region this store serves. When set, only credentials whose own claim maps
314
+ * to this region are discovered, selected, or refreshed — the two regions'
315
+ * stores run side by side without seeing each other's accounts.
316
+ */
317
+ region?: TraeRegion;
318
+ /** Legacy single-copy path read as a migration source; injectable for tests. */
319
+ legacyOwnPath?: string;
227
320
  refresh: (credential: TraeCredential) => Promise<TraeRefreshOutcome>;
228
321
  refreshMarginMs?: number;
229
322
  }
@@ -231,6 +324,8 @@ interface TraeAccountChoice {
231
324
  id: string;
232
325
  accountName: string;
233
326
  edition: TraeEdition;
327
+ /** Routing bucket of this account (`cn` | `ai`), derived from its credential. */
328
+ region: TraeRegion;
234
329
  source: 'desktop' | 'dsh' | 'cli';
235
330
  tokenExpiresAtMs: number;
236
331
  selected: boolean;
@@ -246,17 +341,50 @@ interface TraeCandidateFailure {
246
341
  reason: 'missing' | 'unreadable' | 'invalid';
247
342
  message?: string;
248
343
  }
249
- declare function traeOwnAuthPath(): string;
344
+ /**
345
+ * Plugin-owned copy path for one region. Each region's store refreshes into
346
+ * its own file so two simultaneously signed-in regions never overwrite each
347
+ * other's refreshed token.
348
+ */
349
+ declare function traeOwnAuthPath(region: TraeRegion): string;
350
+ /**
351
+ * Pre-dual-provider single-copy path. Still read as a migration source (a
352
+ * legacy credential serves the region it belongs to until that region's own
353
+ * first refresh writes the per-region file), and removed by `logout`.
354
+ */
355
+ declare function legacyTraeOwnAuthPath(): string;
250
356
  declare function normalizeTraeCredential(raw: unknown, edition: TraeEdition, source: TraeCredential['source']): TraeCredential | undefined;
251
357
  declare class TraeCredentialStore {
252
358
  private storagePathOverride;
253
359
  private edition;
254
360
  private accountId;
255
- private readonly ownPath;
361
+ private readonly region;
362
+ private readonly ownPathExplicit;
363
+ private readonly legacyOwnPath;
364
+ private readonly legacyOwnPathExplicit;
256
365
  private readonly refresh;
257
366
  private readonly refreshMarginMs;
258
367
  private inflight;
259
368
  constructor(options: TraeCredentialStoreOptions);
369
+ /** Whether a credential's own claim belongs to this store's region. */
370
+ private matchesRegion;
371
+ /**
372
+ * The path this store refreshes into: the per-region file for a
373
+ * region-scoped store, the legacy single file otherwise, or an explicitly
374
+ * injected path in tests.
375
+ */
376
+ ownAuthPath(): string;
377
+ /**
378
+ * Every plugin-owned copy to read, most preferred first. A region-scoped
379
+ * store reads the legacy single copy as its migration source (readAll's
380
+ * region filter drops it when it carries the other region's credential); an
381
+ * unscoped store reads everything so diagnostics see both regions.
382
+ *
383
+ * With an explicitly injected own path the legacy source is read ONLY when
384
+ * it was injected too — a test that pins one file must not accidentally see
385
+ * the real machine's legacy copy.
386
+ */
387
+ private ownCandidates;
260
388
  setSource(storagePath: string | undefined, edition?: TraeEdition | 'auto', accountId?: string): void;
261
389
  selectAccount(accountId: string | undefined): void;
262
390
  candidates(): TraeStorageCandidate[];
@@ -277,7 +405,20 @@ declare class TraeCredentialStore {
277
405
  source?: TraeCredential['source'];
278
406
  }>;
279
407
  desktopFilePresent(): Promise<boolean>;
408
+ /**
409
+ * Remove every plugin-owned copy this store could read (per-region file,
410
+ * legacy single file, and their lock siblings); the desktop storage files
411
+ * are untouched. A region store's logout therefore also clears the legacy
412
+ * migration source — deliberate: `logout` is the user's "forget what the
413
+ * plugin stored" action, not a per-account toggle.
414
+ */
280
415
  logout(): Promise<void>;
416
+ /**
417
+ * Every local credential of this store's region, deduplicated by account id.
418
+ * A region-scoped store sees only its own region's credentials: the other
419
+ * region's accounts are invisible to selection, refresh, and status alike,
420
+ * which is what keeps the two regions' providers from cross-billing.
421
+ */
281
422
  private readAll;
282
423
  /**
283
424
  * Which paths were tried and why each one failed. Read-only and token-free:
@@ -292,7 +433,11 @@ declare class TraeCredentialStore {
292
433
  /** Parse one candidate file's text into a credential, or throw. */
293
434
  private credentialFrom;
294
435
  private readDesktopAll;
295
- private readOwn;
436
+ /**
437
+ * Every readable plugin-owned copy, in candidate order; absent or corrupt
438
+ * files are skipped rather than propagated.
439
+ */
440
+ private readOwns;
296
441
  private refreshNow;
297
442
  }
298
443
  //#endregion
@@ -332,6 +477,37 @@ declare function readTraeIdentity(candidate: TraeStorageCandidate, options?: Tra
332
477
  * a candidate that exists but fails to parse still surfaces its own error.
333
478
  */
334
479
  declare function pickTraeStorageIdentity(candidates: readonly TraeStorageCandidate[], options?: TraeIdentityReadOptions): Promise<TraeIdentity>;
480
+ /**
481
+ * Deterministic identity for a machine that only has the Trae CLI (`traecli`).
482
+ *
483
+ * A CLI-only machine has no desktop `storage.json`, so the desktop identity
484
+ * reader has nothing to read — yet the request headers still need stable
485
+ * machine/device ids. Everything here comes from identifiers the CLI itself
486
+ * persists (never a per-request random value):
487
+ *
488
+ * - `argv.json`'s `crash-reporter-id` — a stable per-install UUID the CLI
489
+ * writes on first run; used directly as the device id.
490
+ * - `builtin/ide_version.json`'s `version` — the CLI build, sent as
491
+ * `x-app-version` (the desktop reader gets this from `product.json`).
492
+ * - a SHA-256 over the device id, host name and user name for `machineId`,
493
+ * matching the 64-char hex shape the official clients send.
494
+ *
495
+ * When `crash-reporter-id` is absent the device id falls back to the same
496
+ * hash (still deterministic). A machine with no CLI home at all keeps failing
497
+ * loudly — a fabricated identity is worse than a visible "not signed in".
498
+ */
499
+ declare function readTraeCliIdentity(edition: TraeEdition, options?: TraeIdentityReadOptions): Promise<TraeIdentity>;
500
+ /**
501
+ * Resolve the request identity for one region: the desktop storage identity
502
+ * when any desktop install exists, otherwise the CLI home's deterministic
503
+ * identity (see {@link readTraeCliIdentity}).
504
+ *
505
+ * This is the seam the WSL2 / CLI-only case needs: `traecli` writes its token
506
+ * to `~/.trae-cn/trae-jwt-token` and no `storage.json` exists anywhere, so
507
+ * desktop-only resolution used to fail every directory refresh and chat
508
+ * request even though the account itself was found.
509
+ */
510
+ declare function resolveTraeIdentity(candidates: readonly TraeStorageCandidate[], edition: TraeEdition, options?: TraeIdentityReadOptions): Promise<TraeIdentity>;
335
511
  /** Headers derived from actual persisted identity, never a new random identity per request. */
336
512
  declare function identityHeaders(identity: TraeIdentity): Record<string, string>;
337
513
  //#endregion
@@ -456,11 +632,19 @@ type TraeHeaderProfile = 'agent-task' | 'model-detail' | 'raw-chat' | 'native-cu
456
632
  declare const TRAE_VERSION_CODE_FALLBACK = "20260716";
457
633
  /** Keep a purely numeric build version; fall back when it cannot bind. */
458
634
  declare function normalizeTraeVersionCode(buildVersion: string | undefined): string;
459
- declare function buildTraeCnHeaders(credential: TraeCredential, identity: TraeIdentity, options?: {
635
+ /**
636
+ * Headers shared by every Trae edition. The same shape is accepted by both
637
+ * gateways (verified read-only on the international gateway 2026-09-15,
638
+ * docs/INTL_SG_EVIDENCE.md §2.3: identical `x-app-id`, identity headers, and
639
+ * `Cloud-IDE-JWT` auth), so there is no per-edition branch any more.
640
+ */
641
+ declare function buildTraeHeaders(credential: TraeCredential, identity: TraeIdentity, options?: {
460
642
  appId?: string;
461
643
  requestId?: string;
462
644
  profile?: TraeHeaderProfile;
463
645
  }): Record<string, string>;
646
+ /** Backwards-compatible alias; the headers are no longer CN-specific. */
647
+ declare const buildTraeCnHeaders: typeof buildTraeHeaders;
464
648
  declare function traeEndpoint(baseUrl: string, path: string): string;
465
649
  //#endregion
466
650
  //#region src/raw-chat.d.ts
@@ -749,8 +933,18 @@ declare class TraeGatedUpstreamClient implements TraeUpstreamClient {
749
933
  }
750
934
  //#endregion
751
935
  //#region src/refresh.d.ts
752
- /** Refresh only editions whose client contract is currently evidenced. */
753
- declare function refreshTraeCredential(credential: TraeCredential, signal?: AbortSignal): Promise<TraeRefreshOutcome>;
936
+ /** Stable device identity for the DeviceInfo body, sourced from the app's own storage. */
937
+ interface TraeRefreshDevice {
938
+ deviceId: string;
939
+ machineId: string;
940
+ }
941
+ /**
942
+ * Exchange a refresh token for a fresh access token, following the calling
943
+ * edition's verified contract. `device` is only used by editions whose
944
+ * official client sends a DeviceInfo body; when it cannot be resolved the
945
+ * field is omitted rather than sent empty.
946
+ */
947
+ declare function refreshTraeCredential(credential: TraeCredential, signal?: AbortSignal, device?: TraeRefreshDevice): Promise<TraeRefreshOutcome>;
754
948
  //#endregion
755
949
  //#region src/sse.d.ts
756
950
  interface SseEvent {
@@ -874,11 +1068,13 @@ declare class TraeDelegatingUpstreamClient implements TraeUpstreamClient {
874
1068
  /**
875
1069
  * Read-only Trae usage/credits client.
876
1070
  *
877
- * Sources the verified `api.trae.cn` pay/ug endpoints (see
878
- * `docs/USAGE_API_RESEARCH.md`). All queries are read-only and do not consume
879
- * Trae credits. The per-session consumption detail table is deliberately not
880
- * included: the endpoint returns no rows for the current account, so we only
881
- * expose what is actually retrievable.
1071
+ * CN sources the verified `api.trae.cn` pay/ug endpoints (see
1072
+ * `docs/USAGE_API_RESEARCH.md`); the international (ai) region is
1073
+ * subscription-based and reads `ide_user_pay_status` on its own gateway
1074
+ * (verified 2026-09-15, docs/INTL_SG_EVIDENCE.md §4). All queries are
1075
+ * read-only and do not consume Trae credits. The per-session consumption
1076
+ * detail table is deliberately not included: the endpoint returns no rows
1077
+ * for the current account, so we only expose what is actually retrievable.
882
1078
  */
883
1079
  declare const TRAE_PAY_BASE = "https://api.trae.cn";
884
1080
  interface TraeUsageOptions {
@@ -887,6 +1083,28 @@ interface TraeUsageOptions {
887
1083
  baseUrl?: string;
888
1084
  timeoutMs?: number;
889
1085
  }
1086
+ /**
1087
+ * Subscription/pay status of an international (ai) account, parsed from the
1088
+ * `ide_user_pay_status` answer. The international region has no Work-credit
1089
+ * packs, so this — not `snapshot` — is its usage surface.
1090
+ */
1091
+ interface TraePayStatus {
1092
+ isDollarUsageBilling: boolean;
1093
+ hasPackage: boolean;
1094
+ isPayFreshman: boolean;
1095
+ inTrial: boolean;
1096
+ trialEndTimeMs: number;
1097
+ enableSoloLite: boolean;
1098
+ enableSoloBuilder: boolean;
1099
+ enableSoloCoder: boolean;
1100
+ enableSoloWeb: boolean;
1101
+ /** The fission (referral) program window and cap, when exposed. */
1102
+ fission?: {
1103
+ startTimeMs: number;
1104
+ expireTimeMs: number;
1105
+ maxUsage: number;
1106
+ };
1107
+ }
890
1108
  interface TraeUsageSummary {
891
1109
  totalAmount: number;
892
1110
  consumedAmount: number;
@@ -940,8 +1158,29 @@ declare class TraeUsageClient {
940
1158
  private readonly baseUrl;
941
1159
  private readonly timeoutMs;
942
1160
  constructor(options: TraeUsageOptions);
1161
+ /** Region of the current credential; `cn` when unresolvable. */
1162
+ private currentRegion;
1163
+ /**
1164
+ * Pay base for the current credential's region. An explicit baseUrl (tests,
1165
+ * diagnostics) pins the endpoint; otherwise CN uses `api.trae.cn` and the
1166
+ * international region its own verified pay gateway.
1167
+ */
1168
+ private payBase;
943
1169
  private authedHeaders;
944
1170
  private post;
1171
+ /**
1172
+ * Subscription/pay status of an international (ai) account. The CN region
1173
+ * never calls this (its contract is unverified there); the ai region uses
1174
+ * this instead of the Work-credit `snapshot`.
1175
+ */
1176
+ payStatus(signal?: AbortSignal): Promise<TraePayStatus>;
1177
+ /**
1178
+ * The Work-credit endpoints are CN-only. The international region is
1179
+ * subscription-based and must read {@link payStatus} instead; guarding here
1180
+ * keeps the card's degraded `creditsError` message diagnosable rather than
1181
+ * letting an ai credential hit an unverified path on its pay gateway.
1182
+ */
1183
+ private requireCnRegion;
945
1184
  /** Total entitlements / credits and per-pack breakdown. */
946
1185
  snapshot(signal?: AbortSignal): Promise<TraeUsageSnapshot>;
947
1186
  /** Daily check-in status. */
@@ -953,13 +1192,23 @@ declare class TraeUsageClient {
953
1192
  }
954
1193
  //#endregion
955
1194
  //#region src/status-paths.d.ts
956
- /**
957
- * Node-free constants and types shared by the Host and browser halves.
958
- * Mirrors the `dsh-workbuddy-connect` status-route pattern so the plugin card
959
- * stays consistent with that project's external presentation.
960
- */
961
1195
  /** Plugin-owned usage endpoint consumed by its browser half. */
962
1196
  declare const TRAE_USAGE_PATH = "/plugins/dsh-connect-trae/usage";
1197
+ /** Query parameter naming the region a card request addresses. */
1198
+ declare const TRAE_REGION_PARAM = "region";
1199
+ /** Every region, in card tab order. */
1200
+ declare const TRAE_REGIONS: readonly TraeRegion[];
1201
+ /**
1202
+ * Address one region's status route. The two regions are separate provider
1203
+ * stacks; every card request carries the region whose tab the user is on.
1204
+ */
1205
+ declare function withTraeRegion(path: string, region: TraeRegion): string;
1206
+ /**
1207
+ * Read the region parameter off a status-route URL. Absent means the domestic
1208
+ * tab (`cn`); a present-but-unknown value returns undefined so the route can
1209
+ * answer 400 instead of guessing.
1210
+ */
1211
+ declare function regionOfTraeStatusUrl(url: string): TraeRegion | undefined;
963
1212
  /** One credit pack and its remaining credit. */
964
1213
  interface TraeWebCreditAccount {
965
1214
  displayDesc: string;
@@ -1006,6 +1255,8 @@ interface TraeWebAccount {
1006
1255
  id: string;
1007
1256
  accountName: string;
1008
1257
  edition: 'cn' | 'sg' | 'solo' | 'solo-sg';
1258
+ /** Routing bucket of this account, derived from its credential. */
1259
+ region: TraeRegion;
1009
1260
  source: 'desktop' | 'dsh' | 'cli';
1010
1261
  tokenExpiresAtMs: number;
1011
1262
  selected: boolean;
@@ -1018,6 +1269,23 @@ interface TraeWebSearchPath {
1018
1269
  reason: 'missing' | 'unreadable' | 'invalid';
1019
1270
  message?: string;
1020
1271
  }
1272
+ /** Subscription status of an international (ai) account, rendered instead of the CN credit packs. */
1273
+ interface TraeWebPayStatus {
1274
+ isDollarUsageBilling: boolean;
1275
+ hasPackage: boolean;
1276
+ isPayFreshman: boolean;
1277
+ inTrial: boolean;
1278
+ trialEndTimeMs: number;
1279
+ enableSoloLite: boolean;
1280
+ enableSoloBuilder: boolean;
1281
+ enableSoloCoder: boolean;
1282
+ enableSoloWeb: boolean;
1283
+ fission?: {
1284
+ startTimeMs: number;
1285
+ expireTimeMs: number;
1286
+ maxUsage: number;
1287
+ };
1288
+ }
1021
1289
  /** The JSON document the plugin card renders. */
1022
1290
  type TraeWebUsage = {
1023
1291
  status: 'signed-out';
@@ -1029,6 +1297,8 @@ type TraeWebUsage = {
1029
1297
  accountId: string;
1030
1298
  accountName: string;
1031
1299
  tokenExpiresAtMs: number;
1300
+ /** Which per-region model directory and selection this account owns. */
1301
+ region: TraeRegion;
1032
1302
  accounts: readonly TraeWebAccount[];
1033
1303
  models: readonly TraeWebModel[];
1034
1304
  enabledModelIds: readonly string[];
@@ -1039,29 +1309,43 @@ type TraeWebUsage = {
1039
1309
  };
1040
1310
  credits?: TraeWebCredits;
1041
1311
  creditsError?: string;
1312
+ /** Subscription status of an international account (region ai only). */
1313
+ payStatus?: TraeWebPayStatus;
1314
+ payStatusError?: string;
1042
1315
  } | {
1043
1316
  status: 'error';
1044
1317
  message: string;
1045
1318
  };
1046
1319
  //#endregion
1047
1320
  //#region src/web-status.d.ts
1048
- /** Constructor dependencies. */
1321
+ /**
1322
+ * Constructor dependencies. Everything region-specific is addressed by the
1323
+ * region the request names: the two regions are separate provider stacks, so
1324
+ * the card must be served the directory, selection, and credits of the tab the
1325
+ * user is on.
1326
+ */
1049
1327
  interface TraeUsageRouteOptions {
1050
- store: TraeCredentialStore;
1051
- client: TraeUsageClient;
1052
- /** The last-refreshed Trae raw directory (one entry per upstream model) for card display. */
1053
- displayModels(): readonly TraeModelInfo[];
1054
- /** The user's model selection stored as model id (= Trae name). */
1055
- enabledModelIds(): readonly string[];
1056
- discoverModels?(signal?: AbortSignal): Promise<readonly TraeModelInfo[]>;
1057
- rawDiagnostic?(): TraeRawDiagnostic;
1328
+ /** The region-scoped credential store backing each region's requests. */
1329
+ store(region: TraeRegion): TraeCredentialStore;
1330
+ /** The region-scoped usage client (CN work credits / international pay status). */
1331
+ client(region: TraeRegion): TraeUsageClient;
1332
+ /** The requested region's last-refreshed raw directory (one entry per upstream model). */
1333
+ displayModels(region: TraeRegion): readonly TraeModelInfo[];
1334
+ /** The user's model selection in the requested region, stored as model id (= Trae name). */
1335
+ enabledModelIds(region: TraeRegion): readonly string[];
1336
+ /** Re-read one region's live directory from the upstream. */
1337
+ discoverModels?(region: TraeRegion, signal?: AbortSignal): Promise<readonly TraeModelInfo[]>;
1338
+ /** Raw-Chat capability state of the requested region. */
1339
+ rawDiagnostic?(region: TraeRegion): TraeRawDiagnostic;
1058
1340
  }
1059
1341
  /**
1060
- * Assemble the card's usage document. Sign-in state is read-only; credit is a
1061
- * live billing answer whose failure degrades to `creditsError` rather than
1062
- * failing the whole document.
1342
+ * Assemble one region's card document. `region` is the tab the card is on; the
1343
+ * region-scoped store already answers with only that region's accounts, so the
1344
+ * document's model slots and account list are that region's by construction.
1345
+ * Sign-in state is read-only; credit is a live billing answer whose failure
1346
+ * degrades to `creditsError` rather than failing the whole document.
1063
1347
  */
1064
- declare function traeWebUsage(deps: TraeUsageRouteOptions): Promise<TraeWebUsage>;
1348
+ declare function traeWebUsage(deps: TraeUsageRouteOptions, region: TraeRegion): Promise<TraeWebUsage>;
1065
1349
  /** Mount the GET usage route on an optional webServer context. */
1066
1350
  declare function registerTraeUsageRoute(ctx: Context, deps: TraeUsageRouteOptions): void;
1067
1351
  //#endregion
@@ -1077,23 +1361,64 @@ declare const inject: string[];
1077
1361
  * so no branding is needed for either host generation.
1078
1362
  */
1079
1363
  declare const TRAE_SETTINGS_NS = "trae";
1364
+ /** One region's saved model state: its own directory and the user's selection within it. */
1365
+ interface TraeRegionState {
1366
+ /** The last-refreshed raw directory for this region; what the card displays. */
1367
+ lastCatalog?: TraeModelInfo[];
1368
+ /** The user's selection in this region, as model ids (= Trae name). */
1369
+ enabledModelIds?: string[];
1370
+ /** Models the user explicitly enabled for image input in this region. */
1371
+ imageModelIds?: string[];
1372
+ /** Local DSH context budget per model in this region. */
1373
+ contextBudgets?: Record<string, number>;
1374
+ }
1080
1375
  interface Config {
1081
1376
  authFile?: string;
1082
1377
  edition?: 'auto' | 'cn' | 'sg' | 'solo' | 'solo-sg';
1083
- /** Stable local account selector; tokens remain outside settings. */
1378
+ /**
1379
+ * @deprecated Legacy single-slot account selector from before the dual
1380
+ * provider split. It is attributed to whichever region the account actually
1381
+ * belongs to (resolved once at startup from the local account scan); new
1382
+ * writes go to {@link Config.accounts}.
1383
+ */
1084
1384
  accountId?: string;
1085
- /** The last-refreshed Trae raw directory; what the plugin card displays. */
1385
+ /**
1386
+ * Per-region account selections, keyed `cn` | `ai`. Each region's tab writes
1387
+ * its own slot; tokens remain outside settings.
1388
+ */
1389
+ accounts?: Partial<Record<TraeRegion, string>>;
1390
+ /**
1391
+ * Per-region model state, keyed `cn` | `ai`. The CN and international apps
1392
+ * expose different rosters, so each keeps its own directory and selection
1393
+ * and switching accounts never drops the other region's picks.
1394
+ */
1395
+ regions?: Partial<Record<TraeRegion, TraeRegionState>>;
1396
+ /**
1397
+ * @deprecated Legacy single-slot fields from before the region split. They
1398
+ * predate international support and are read as the CN region's state when
1399
+ * `regions.cn` is absent; new writes go to `regions`.
1400
+ */
1086
1401
  lastCatalog?: TraeModelInfo[];
1087
- /** The user's ordinary-model selection, as model id (= Trae name). */
1402
+ /** @deprecated See {@link Config.lastCatalog}. */
1088
1403
  enabledModelIds?: string[];
1089
- /** Local DSH context budget per model; a value may only select an advertised window. */
1404
+ /** @deprecated See {@link Config.lastCatalog}. */
1090
1405
  contextBudgets?: Record<string, number>;
1091
- /** Models the user explicitly enabled for image input; text is always enabled. */
1406
+ /** @deprecated See {@link Config.lastCatalog}. */
1092
1407
  imageModelIds?: string[];
1093
- /** Legacy generated runtime catalog; kept for backwards compatibility. */
1408
+ /** @deprecated Legacy generated runtime catalog; kept for backwards compatibility. */
1094
1409
  models?: TraeModelInfo[];
1095
1410
  }
1411
+ /**
1412
+ * One region's saved state. A config written before the region split has only
1413
+ * the flat fields: those were always captured from the CN endpoint (the
1414
+ * plugin had no international support), so they are read as the CN state and
1415
+ * only when no explicit CN slot exists. The ai region never inherits them —
1416
+ * that inheritance is exactly the bug where a stale CN directory would be
1417
+ * intersected with the international catalog and silently drop the user's
1418
+ * picks (the same failure workbuddy fixed with its region split).
1419
+ */
1420
+ declare function regionStateOf(config: Config, region: TraeRegion): TraeRegionState;
1096
1421
  declare const Config: z<Config>;
1097
1422
  declare function apply(ctx: Context, config: Config): void;
1098
1423
  //#endregion
1099
- export { Config, FALLBACK_TRAE_MODELS, type RawChatDelta, type RawChatMessage, type RawChatTool, SseDecoder, type SseEvent, TRAE_CN_AGENT_TASK_PATH, TRAE_CN_TITLE_PATH, TRAE_MODEL_DETAIL_FUNCTIONS, TRAE_MODEL_DETAIL_PATH, TRAE_PAY_BASE, TRAE_PROVIDER, TRAE_RAW_CHAT_V1_PATH, TRAE_RAW_CHAT_V2_PATH, TRAE_REASONING_EFFORTS, TRAE_SETTINGS_NS, TRAE_SOLO_CHAT_PATH, TRAE_SOLO_FUNCTION, TRAE_SOLO_MODELS_PATH, TRAE_SOLO_REMOTE_BASE, TRAE_STREAM_IDLE_TIMEOUT_MS, TRAE_USAGE_PATH, TRAE_VERSION_CODE_FALLBACK, type TraeActivityRule, type TraeCachedModelConfig, TraeCatalog, type TraeChatResult, type TraeCheckinStatus, type TraeContextBudget, type TraeCredential, TraeCredentialStore, TraeDelegatingUpstreamClient, type TraeDiscoveredModel, type TraeDiscoveredReasoning, type TraeEdition, TraeFallbackUpstreamClient, type TraeFallbackUpstreamOptions, type TraeFusionRawChatEnvelope, TraeGatedUpstreamClient, type TraeGatedUpstreamOptions, type TraeIdentity, type TraeInputModality, type TraeModelDetailRequest, type TraeModelInfo, type TraeObservedModelConfig, TraeRawCapabilityController, type TraeRawCapabilityControllerOptions, type TraeRawCapabilitySnapshot, TraeRawCapabilityState, type TraeRawChatBehaviorConfig, type TraeRawChatCapability, type TraeRawChatClientOptions, type TraeRawChatConfig, type TraeRawChatFailureReason, type TraeRawChatRuntimeConfig, TraeRawChatUpstreamClient, type TraeRawDiagnostic, type TraeRawDiagnosticState, type TraeRawGateway, type TraeRawGatewayOptions, type TraeRawResolverResult, type TraeReasoningCapability, type TraeReasoningEffort, type TraeShim, TraeSoloBridge, type TraeSoloClientOptions, TraeSoloRemoteCatalogClient, type TraeSoloRemoteCatalogOptions, TraeSoloUpstreamClient, type TraeStorageCandidate, type TraeStreamEvent, type TraeUpstreamClient, TraeUsageClient, type TraeUsageOptions, type TraeUsagePack, type TraeUsageRouteOptions, type TraeUsageSnapshot, type TraeUsageSummary, type TraeUsageView, type TraeWebActivity, type TraeWebCheckin, type TraeWebCredits, type TraeWebUsage, type TraeWireModel, UnconfiguredTraeUpstreamClient, apply, applyContextBudgets, applyImageSelection, applyReasoningEffort, bridgeTraeSoloStream, buildTraeAgentTaskBody, buildTraeCnHeaders, buildTraeFusionRawChatEnvelope, buildTraeModelDetailRequest, buildTraeRawChatDraft, buildTraeRawChatRuntimeConfig, classifyTraeRawChatFailure, createTraeAdapter, createTraeRawGateway, createTraeShim, decodeRawChatChunk, decodeTraeEvent, decryptTraeStorageValue, deriveCatalog, discoveredCatalog, hashTraeRawChatArg, identityHeaders, inject, mergeTraeModelSources, name, normalizeTraeCredential, normalizeTraeVersionCode, parseObservedModelConfig, parseReasoningCapability, parseTraeAuthValue, parseTraeCachedModel, parseTraeModelExtraConfigLogLine, parseTraeRawChatBehaviorConfig, parseTraeRemoteModel, parseTraeStorageDocument, pickTraeStorageIdentity, prepareSoloBody, probeTraeRawChatCapability, rawCapabilityDiagnostic, rawCapabilityFingerprint, readTraeCachedModel, readTraeIdentity, refreshTraeCredential, registerTraeUsageRoute, resolveTraeRawRuntime, sanitizeCatalog, traeEndpoint, traeInputModalities, traeModelDisplayName, traeOwnAuthPath, traeRawChatExtraInfo, traeStorageCandidates, traeWebUsage };
1424
+ export { Config, FALLBACK_TRAE_MODELS, FALLBACK_TRAE_MODELS_AI, REGION_GATEWAYS, type RawChatDelta, type RawChatMessage, type RawChatTool, SseDecoder, type SseEvent, TRAE_AI_PROVIDER, TRAE_CN_AGENT_TASK_PATH, TRAE_CN_TITLE_PATH, TRAE_MODEL_DETAIL_FUNCTIONS, TRAE_MODEL_DETAIL_PATH, TRAE_PAY_BASE, TRAE_PROVIDER, TRAE_PROVIDERS, TRAE_PROVIDER_DISPLAY_NAMES, TRAE_RAW_CHAT_V1_PATH, TRAE_RAW_CHAT_V2_PATH, TRAE_REASONING_EFFORTS, TRAE_REGIONS, TRAE_REGION_PARAM, TRAE_SETTINGS_NS, TRAE_SOLO_CHAT_PATH, TRAE_SOLO_FUNCTION, TRAE_SOLO_MODELS_PATH, TRAE_SOLO_REMOTE_BASE, TRAE_STREAM_IDLE_TIMEOUT_MS, TRAE_USAGE_PATH, TRAE_VERSION_CODE_FALLBACK, type TraeActivityRule, type TraeAdapter, type TraeCachedModelConfig, TraeCatalog, type TraeChatResult, type TraeCheckinStatus, type TraeContextBudget, type TraeCredential, TraeCredentialStore, TraeDelegatingUpstreamClient, type TraeDiscoveredModel, type TraeDiscoveredReasoning, type TraeEdition, TraeFallbackUpstreamClient, type TraeFallbackUpstreamOptions, type TraeFusionRawChatEnvelope, TraeGatedUpstreamClient, type TraeGatedUpstreamOptions, type TraeIdentity, type TraeInputModality, type TraeModelDetailRequest, type TraeModelInfo, type TraeObservedModelConfig, TraeRawCapabilityController, type TraeRawCapabilityControllerOptions, type TraeRawCapabilitySnapshot, TraeRawCapabilityState, type TraeRawChatBehaviorConfig, type TraeRawChatCapability, type TraeRawChatClientOptions, type TraeRawChatConfig, type TraeRawChatFailureReason, type TraeRawChatRuntimeConfig, TraeRawChatUpstreamClient, type TraeRawDiagnostic, type TraeRawDiagnosticState, type TraeRawGateway, type TraeRawGatewayOptions, type TraeRawResolverResult, type TraeReasoningCapability, type TraeReasoningEffort, type TraeRefreshDevice, type TraeRegion, type TraeRegionGateways, TraeRegionState, type TraeShim, TraeSoloBridge, type TraeSoloClientOptions, TraeSoloRemoteCatalogClient, type TraeSoloRemoteCatalogOptions, TraeSoloUpstreamClient, type TraeStorageCandidate, type TraeStreamEvent, type TraeUpstreamClient, TraeUsageClient, type TraeUsageOptions, type TraeUsagePack, type TraeUsageRouteOptions, type TraeUsageSnapshot, type TraeUsageSummary, type TraeUsageView, type TraeWebActivity, type TraeWebCheckin, type TraeWebCredits, type TraeWebUsage, type TraeWireModel, UnconfiguredTraeUpstreamClient, apply, applyContextBudgets, applyImageSelection, applyReasoningEffort, bridgeTraeSoloStream, buildTraeAgentTaskBody, buildTraeCnHeaders, buildTraeFusionRawChatEnvelope, buildTraeModelDetailRequest, buildTraeRawChatDraft, buildTraeRawChatRuntimeConfig, classifyTraeRawChatFailure, createTraeAdapter, createTraeRawGateway, createTraeShim, decodeRawChatChunk, decodeTraeEvent, decryptTraeStorageValue, deriveCatalog, discoveredCatalog, fallbackModelsFor, hashTraeRawChatArg, identityHeaders, inject, legacyTraeOwnAuthPath, mergeTraeModelSources, name, normalizeTraeCredential, normalizeTraeVersionCode, parseObservedModelConfig, parseReasoningCapability, parseTraeAuthValue, parseTraeCachedModel, parseTraeModelExtraConfigLogLine, parseTraeRawChatBehaviorConfig, parseTraeRemoteModel, parseTraeStorageDocument, pickTraeStorageIdentity, prepareSoloBody, probeTraeRawChatCapability, rawCapabilityDiagnostic, rawCapabilityFingerprint, readTraeCachedModel, readTraeCliIdentity, readTraeIdentity, refreshTraeCredential, regionOfCredential, regionOfEdition, regionOfHost, regionOfTraeProvider, regionOfTraeStatusUrl, regionOfUserRegion, regionStateOf, registerTraeUsageRoute, resolveTraeIdentity, resolveTraeRawRuntime, sanitizeCatalog, traeEndpoint, traeInputModalities, traeModelDisplayName, traeOwnAuthPath, traeRawChatExtraInfo, traeStorageCandidates, traeWebUsage, withTraeRegion };