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/client.js CHANGED
@@ -8,17 +8,36 @@ window.__ModuleLoader__.load({
8
8
  let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
9
9
  let react_jsx_runtime = require("react/jsx-runtime");
10
10
  //#region src/status-paths.ts
11
- /**
12
- * Node-free constants and types shared by the Host and browser halves.
13
- * Mirrors the `dsh-workbuddy-connect` status-route pattern so the plugin card
14
- * stays consistent with that project's external presentation.
15
- */
16
11
  /** Plugin-owned usage endpoint consumed by its browser half. */
17
12
  const TRAE_USAGE_PATH = "/plugins/dsh-connect-trae/usage";
18
13
  /** Plugin-owned live model refresh endpoint. */
19
14
  const TRAE_MODELS_REFRESH_PATH = "/plugins/dsh-connect-trae/models/refresh";
20
15
  /** Plugin-owned local account rescan endpoint. */
21
16
  const TRAE_ACCOUNTS_REFRESH_PATH = "/plugins/dsh-connect-trae/accounts/refresh";
17
+ /** Query parameter naming the region a card request addresses. */
18
+ const TRAE_REGION_PARAM = "region";
19
+ /** Every region, in card tab order. */
20
+ const TRAE_REGIONS = ["cn", "ai"];
21
+ /**
22
+ * Address one region's status route. The two regions are separate provider
23
+ * stacks; every card request carries the region whose tab the user is on.
24
+ */
25
+ function withTraeRegion(path, region) {
26
+ return `${path}?${TRAE_REGION_PARAM}=${region}`;
27
+ }
28
+ /**
29
+ * Build the next `regions` settings value for the card's save. The write
30
+ * targets ONLY the signed-in account's region slot; every other region's slot
31
+ * is carried over untouched, so switching accounts never clobbers the other
32
+ * region's picks. Tolerates any stored shape (absent, non-object) by starting
33
+ * from an empty document.
34
+ */
35
+ function nextRegionSlots(regions, region, slot) {
36
+ return {
37
+ ...typeof regions === "object" && regions !== null && !Array.isArray(regions) ? regions : {},
38
+ [region]: slot
39
+ };
40
+ }
22
41
  //#endregion
23
42
  //#region src/client/icon.ts
24
43
  /**
@@ -57,6 +76,13 @@ window.__ModuleLoader__.load({
57
76
  .dsm-btn-primary{background:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-layer-3)}
58
77
  .dsm-btn-primary:hover:not(:disabled){opacity:.9}
59
78
  .dsm-trae-usage{display:flex;flex-direction:column;gap:16px;margin:0;padding:16px 0 4px}
79
+ .dsm-trae-tabs{display:flex;gap:6px;padding:4px;border:1px solid var(--dsw-alias-border-l2,#3a3d45);border-radius:10px;background:var(--dsw-alias-bg-layer-3,#2a2c33)}
80
+ .dsm-trae-tab{appearance:none;font:inherit;cursor:pointer;flex:1;border:0;border-radius:7px;padding:7px 10px;color:var(--dsw-alias-label-tertiary,#999);font-size:13px;font-weight:500;line-height:18px;background:transparent;transition:color .15s,background .15s;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
81
+ .dsm-trae-tab:hover:not(:disabled):not(.dsm-trae-tab-active){color:var(--dsw-alias-label-primary,#e6e6e6)}
82
+ .dsm-trae-tab:focus-visible{outline:2px solid var(--dsw-alias-brand-primary,#5686fe);outline-offset:1px}
83
+ .dsm-trae-tab-active{color:var(--dsw-alias-label-primary,#e6e6e6);background:var(--dsw-alias-bg-layer-2,#232529);box-shadow:inset 0 0 0 1px var(--dsw-alias-border-l2,#3a3d45)}
84
+ .dsm-trae-tab-dot{display:inline-block;width:7px;height:7px;border-radius:50%;margin-right:6px;vertical-align:baseline}
85
+ .dsm-trae-tab-hint{margin:0;color:var(--dsw-alias-label-tertiary,#999);font-size:12px;line-height:18px}
60
86
  .dsm-trae-usage-account{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:12px 14px;border:1px solid var(--dsw-alias-border-l2,#3a3d45);border-radius:14px;background:var(--dsw-alias-bg-layer-2,#24262c)}
61
87
  .dsm-trae-usage-account-copy{display:flex;flex-direction:column;gap:3px;min-width:0}
62
88
  .dsm-trae-usage-expiry{padding-left:19px;color:var(--dsw-alias-label-tertiary,#9aa0a8);font-size:12px;line-height:18px}
@@ -133,6 +159,11 @@ window.__ModuleLoader__.load({
133
159
  */
134
160
  const POLL_INTERVAL_MS = 6e4;
135
161
  const TRAE_GITHUB_URL = "https://github.com/dingminhua/dsh-connect-trae";
162
+ /** Read the per-region account selections out of the settings snapshot. */
163
+ function configuredAccountsOf(configured) {
164
+ const accounts = configured?.accounts;
165
+ return typeof accounts === "object" && accounts !== null ? accounts : {};
166
+ }
136
167
  /** Inject the shared card CSS once. */
137
168
  if (typeof document !== "undefined") {
138
169
  const cssId = "dsh-connect-trae/client.css";
@@ -172,16 +203,24 @@ window.__ModuleLoader__.load({
172
203
  function TraeUsageCard({ t, settingsScope }) {
173
204
  if (t === void 0) throw new Error("Trae usage card requires its translation function");
174
205
  const [open, setOpen] = (0, react.useState)(false);
175
- const [status, setStatus] = (0, react.useState)({
176
- status: "signed-out",
177
- accounts: []
206
+ /** The region whose tab is on screen; each tab is its own provider stack. */
207
+ const [activeRegion, setActiveRegion] = (0, react.useState)("cn");
208
+ /** Last-known usage per region, so tab dots survive tab switches. */
209
+ const [statusByRegion, setStatusByRegion] = (0, react.useState)({
210
+ cn: {
211
+ status: "signed-out",
212
+ accounts: []
213
+ },
214
+ ai: {
215
+ status: "signed-out",
216
+ accounts: []
217
+ }
178
218
  });
179
219
  const [busy, setBusy] = (0, react.useState)(false);
180
220
  const [settingsRevision, setSettingsRevision] = (0, react.useState)(0);
181
- const [draftModels, setDraftModels] = (0, react.useState)(void 0);
182
- const [draftEnabledIds, setDraftEnabledIds] = (0, react.useState)(void 0);
183
- const [draftImageIds, setDraftImageIds] = (0, react.useState)(void 0);
184
- const [draftContextBudgets, setDraftContextBudgets] = (0, react.useState)(void 0);
221
+ /** Per-region unsaved model edits; a draft on one tab is never dropped by
222
+ * switching to the other tab, only by that tab's discard/save. */
223
+ const [drafts, setDrafts] = (0, react.useState)({});
185
224
  const [saving, setSaving] = (0, react.useState)(false);
186
225
  const [switchingAccount, setSwitchingAccount] = (0, react.useState)(false);
187
226
  const mounted = (0, react.useRef)(true);
@@ -194,38 +233,53 @@ window.__ModuleLoader__.load({
194
233
  (0, react.useEffect)(() => settingsScope?.subscribe(() => {
195
234
  setSettingsRevision((value) => value + 1);
196
235
  }), [settingsScope]);
197
- const refreshUsage = (0, react.useCallback)(async (signal) => {
236
+ const refreshUsage = (0, react.useCallback)(async (region, signal) => {
198
237
  try {
199
- const response = await fetch(TRAE_USAGE_PATH, {
238
+ const response = await fetch(withTraeRegion(TRAE_USAGE_PATH, region), {
200
239
  headers: { accept: "application/json" },
201
240
  credentials: "same-origin",
202
241
  ...signal === void 0 ? {} : { signal }
203
242
  });
204
243
  const value = await response.json().catch(() => void 0);
205
244
  if (!response.ok) throw new Error(`HTTP ${response.status}`);
206
- if (mounted.current && signal?.aborted !== true) setStatus(value);
207
- return value;
245
+ const usage = value;
246
+ if (mounted.current && signal?.aborted !== true) setStatusByRegion((prev) => ({
247
+ ...prev,
248
+ [region]: usage
249
+ }));
250
+ return usage;
208
251
  } catch (error) {
209
- if (mounted.current && signal?.aborted !== true) setStatus({
210
- status: "error",
211
- message: error instanceof Error ? error.message : t("row.requestFailed")
212
- });
252
+ if (mounted.current && signal?.aborted !== true) setStatusByRegion((prev) => ({
253
+ ...prev,
254
+ [region]: {
255
+ status: "error",
256
+ message: error instanceof Error ? error.message : t("row.requestFailed")
257
+ }
258
+ }));
213
259
  return;
214
260
  }
215
261
  }, [t]);
216
262
  (0, react.useEffect)(() => {
217
263
  if (!open) return;
218
264
  const controller = new AbortController();
219
- refreshUsage(controller.signal);
265
+ refreshUsage(activeRegion, controller.signal);
220
266
  return () => {
221
267
  controller.abort();
222
268
  };
223
- }, [open, refreshUsage]);
269
+ }, [
270
+ open,
271
+ activeRegion,
272
+ refreshUsage
273
+ ]);
274
+ const status = statusByRegion[activeRegion] ?? {
275
+ status: "signed-out",
276
+ accounts: []
277
+ };
224
278
  (0, react.useEffect)(() => {
225
279
  if (!open || status.status !== "signed-in") return;
226
280
  const controller = new AbortController();
227
281
  const timer = window.setInterval(() => {
228
- refreshUsage(controller.signal);
282
+ refreshUsage(activeRegion, controller.signal);
229
283
  }, POLL_INTERVAL_MS);
230
284
  return () => {
231
285
  window.clearInterval(timer);
@@ -233,13 +287,14 @@ window.__ModuleLoader__.load({
233
287
  };
234
288
  }, [
235
289
  open,
290
+ activeRegion,
236
291
  refreshUsage,
237
292
  status.status
238
293
  ]);
239
294
  const rescanAccounts = async () => {
240
295
  setBusy(true);
241
296
  try {
242
- const response = await fetch(TRAE_ACCOUNTS_REFRESH_PATH, {
297
+ const response = await fetch(withTraeRegion(TRAE_ACCOUNTS_REFRESH_PATH, activeRegion), {
243
298
  method: "POST",
244
299
  headers: { accept: "application/json" },
245
300
  credentials: "same-origin"
@@ -247,10 +302,12 @@ window.__ModuleLoader__.load({
247
302
  const body = await response.json();
248
303
  if (!response.ok || !Array.isArray(body.accounts)) throw new Error(`HTTP ${response.status}`);
249
304
  const selected = body.accounts.find((account) => account.selected)?.id;
250
- const configured = settingsScope?.getSnapshot().value;
251
- const configuredId = typeof configured === "object" && configured !== null && typeof configured.accountId === "string" ? configured.accountId : void 0;
252
- if (selected !== void 0 && selected !== configuredId && settingsScope?.getSnapshot().writable === true) await settingsScope.set("accountId", selected);
253
- await refreshUsage();
305
+ const configured = configuredAccountsOf(settingsScope?.getSnapshot().value);
306
+ if (selected !== void 0 && selected !== configured[activeRegion] && settingsScope?.getSnapshot().writable === true) await settingsScope.set("accounts", {
307
+ ...configured,
308
+ [activeRegion]: selected
309
+ });
310
+ await refreshUsage(activeRegion);
254
311
  } finally {
255
312
  if (mounted.current) setBusy(false);
256
313
  }
@@ -259,8 +316,12 @@ window.__ModuleLoader__.load({
259
316
  if (settingsScope === void 0) return;
260
317
  setSwitchingAccount(true);
261
318
  try {
262
- await settingsScope.set("accountId", accountId);
263
- await refreshUsage();
319
+ const configured = configuredAccountsOf(settingsScope.getSnapshot().value);
320
+ await settingsScope.set("accounts", {
321
+ ...configured,
322
+ [activeRegion]: accountId
323
+ });
324
+ await refreshUsage(activeRegion);
264
325
  } finally {
265
326
  if (mounted.current) setSwitchingAccount(false);
266
327
  }
@@ -268,7 +329,7 @@ window.__ModuleLoader__.load({
268
329
  const refreshModels = async () => {
269
330
  setBusy(true);
270
331
  try {
271
- const response = await fetch(TRAE_MODELS_REFRESH_PATH, {
332
+ const response = await fetch(withTraeRegion(TRAE_MODELS_REFRESH_PATH, activeRegion), {
272
333
  method: "POST",
273
334
  headers: { accept: "application/json" },
274
335
  credentials: "same-origin"
@@ -284,69 +345,114 @@ window.__ModuleLoader__.load({
284
345
  const budget = activeContextBudgets[id];
285
346
  if (typeof budget === "number") stillBudgets[id] = budget;
286
347
  }
287
- setDraftModels(fresh.map((model) => ({
288
- ...model,
289
- input: ["text"]
290
- })));
291
- setDraftEnabledIds(new Set(stillEnabled));
292
- setDraftImageIds(new Set(stillImages));
293
- setDraftContextBudgets(stillBudgets);
348
+ setDrafts((prev) => ({
349
+ ...prev,
350
+ [activeRegion]: {
351
+ models: fresh.map((model) => ({
352
+ ...model,
353
+ input: ["text"]
354
+ })),
355
+ enabledIds: new Set(stillEnabled),
356
+ imageIds: new Set(stillImages),
357
+ contextBudgets: stillBudgets
358
+ }
359
+ }));
294
360
  } catch (error) {
295
- if (mounted.current) setStatus({
296
- status: "error",
297
- message: error instanceof Error ? error.message : t("row.requestFailed")
298
- });
361
+ if (mounted.current) setStatusByRegion((prev) => ({
362
+ ...prev,
363
+ [activeRegion]: {
364
+ status: "error",
365
+ message: error instanceof Error ? error.message : t("row.requestFailed")
366
+ }
367
+ }));
299
368
  } finally {
300
369
  if (mounted.current) setBusy(false);
301
370
  }
302
371
  };
303
372
  const settingsValue = settingsScope?.getSnapshot().value;
304
- const savedContextBudgets = typeof settingsValue === "object" && settingsValue !== null && typeof settingsValue.contextBudgets === "object" && settingsValue.contextBudgets !== null ? settingsValue.contextBudgets : {};
305
- const savedImageIds = new Set(typeof settingsValue === "object" && settingsValue !== null && Array.isArray(settingsValue.imageModelIds) ? settingsValue.imageModelIds.filter((id) => typeof id === "string") : []);
306
- const visibleModels = draftModels ?? (status.status === "signed-in" ? status.models : []);
373
+ const region = activeRegion;
374
+ const configuredRegions = typeof settingsValue === "object" && settingsValue !== null && typeof settingsValue.regions === "object" && settingsValue.regions !== null ? settingsValue.regions : {};
375
+ const regionSlot = configuredRegions[region];
376
+ const legacySlot = region === "cn" && regionSlot === void 0;
377
+ const slotContextBudgets = typeof regionSlot?.contextBudgets === "object" && regionSlot.contextBudgets !== null ? regionSlot.contextBudgets : void 0;
378
+ const legacyContextBudgets = legacySlot && typeof settingsValue === "object" && settingsValue !== null && typeof settingsValue.contextBudgets === "object" && settingsValue.contextBudgets !== null ? settingsValue.contextBudgets : void 0;
379
+ const savedContextBudgets = slotContextBudgets ?? legacyContextBudgets ?? {};
380
+ const slotImageIds = Array.isArray(regionSlot?.imageModelIds) ? regionSlot.imageModelIds.filter((id) => typeof id === "string") : void 0;
381
+ const legacyImageIds = legacySlot && typeof settingsValue === "object" && settingsValue !== null && Array.isArray(settingsValue.imageModelIds) ? settingsValue.imageModelIds.filter((id) => typeof id === "string") : [];
382
+ const savedImageIds = new Set(slotImageIds ?? legacyImageIds);
383
+ const draft = drafts[activeRegion];
384
+ const visibleModels = draft?.models ?? (status.status === "signed-in" ? status.models : []);
307
385
  const savedEnabledIds = status.status === "signed-in" ? new Set(status.enabledModelIds) : /* @__PURE__ */ new Set();
308
- const activeEnabledIds = draftEnabledIds ?? savedEnabledIds;
309
- const activeImageIds = draftImageIds ?? savedImageIds;
310
- const activeContextBudgets = draftContextBudgets ?? savedContextBudgets;
311
- const dirty = draftModels !== void 0 || draftEnabledIds !== void 0 || draftImageIds !== void 0 || draftContextBudgets !== void 0;
386
+ const activeEnabledIds = draft?.enabledIds ?? savedEnabledIds;
387
+ const activeImageIds = draft?.imageIds ?? savedImageIds;
388
+ const activeContextBudgets = draft?.contextBudgets ?? savedContextBudgets;
389
+ const dirty = draft !== void 0;
390
+ /** Apply an edit to the ACTIVE tab's draft, seeding it from the current view. */
391
+ const editDraft = (edit) => {
392
+ setDrafts((prev) => ({
393
+ ...prev,
394
+ [activeRegion]: edit(prev[activeRegion] ?? {
395
+ models: [...visibleModels],
396
+ enabledIds: new Set(activeEnabledIds),
397
+ imageIds: new Set(activeImageIds),
398
+ contextBudgets: { ...activeContextBudgets }
399
+ })
400
+ }));
401
+ };
312
402
  const toggleModel = (modelId) => {
313
- const next = new Set(activeEnabledIds);
314
- if (!next.delete(modelId)) next.add(modelId);
315
- setDraftEnabledIds(next);
316
- setDraftModels([...visibleModels]);
403
+ editDraft((current) => {
404
+ const next = new Set(current.enabledIds);
405
+ if (!next.delete(modelId)) next.add(modelId);
406
+ return {
407
+ ...current,
408
+ enabledIds: next
409
+ };
410
+ });
317
411
  };
318
412
  const toggleImage = (modelId) => {
319
- const next = new Set(activeImageIds);
320
- if (!next.delete(modelId)) next.add(modelId);
321
- setDraftImageIds(next);
322
- setDraftModels([...visibleModels]);
413
+ editDraft((current) => {
414
+ const next = new Set(current.imageIds);
415
+ if (!next.delete(modelId)) next.add(modelId);
416
+ return {
417
+ ...current,
418
+ imageIds: next
419
+ };
420
+ });
323
421
  };
324
422
  const setContextBudget = (modelId, budget) => {
325
- const next = { ...activeContextBudgets };
326
- if (budget === void 0) delete next[modelId];
327
- else next[modelId] = budget;
328
- setDraftContextBudgets(next);
329
- setDraftModels([...visibleModels]);
423
+ editDraft((current) => {
424
+ const next = { ...current.contextBudgets };
425
+ if (budget === void 0) delete next[modelId];
426
+ else next[modelId] = budget;
427
+ return {
428
+ ...current,
429
+ contextBudgets: next
430
+ };
431
+ });
330
432
  };
331
433
  const discardModels = () => {
332
- setDraftModels(void 0);
333
- setDraftEnabledIds(void 0);
334
- setDraftImageIds(void 0);
335
- setDraftContextBudgets(void 0);
434
+ setDrafts((prev) => {
435
+ const next = { ...prev };
436
+ delete next[activeRegion];
437
+ return next;
438
+ });
336
439
  };
337
440
  const saveModels = async () => {
338
441
  if (settingsScope === void 0) return;
339
442
  setSaving(true);
340
443
  try {
341
- await settingsScope.set("lastCatalog", visibleModels.map((model) => ({
342
- ...model,
343
- input: ["text"]
344
- })));
345
- await settingsScope.set("enabledModelIds", [...activeEnabledIds]);
346
- await settingsScope.set("imageModelIds", [...activeImageIds].filter((id) => activeEnabledIds.has(id)));
347
- await settingsScope.set("contextBudgets", activeContextBudgets);
444
+ if (status.status !== "signed-in") return;
445
+ await settingsScope.set("regions", nextRegionSlots(configuredRegions, activeRegion, {
446
+ lastCatalog: visibleModels.map((model) => ({
447
+ ...model,
448
+ input: ["text"]
449
+ })),
450
+ enabledModelIds: [...activeEnabledIds],
451
+ imageModelIds: [...activeImageIds].filter((id) => activeEnabledIds.has(id)),
452
+ contextBudgets: activeContextBudgets
453
+ }));
348
454
  discardModels();
349
- await refreshUsage();
455
+ await refreshUsage(activeRegion);
350
456
  } finally {
351
457
  if (mounted.current) setSaving(false);
352
458
  }
@@ -391,6 +497,32 @@ window.__ModuleLoader__.load({
391
497
  children: open ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
392
498
  className: "dsm-trae-usage",
393
499
  children: [
500
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
501
+ className: "dsm-trae-tabs",
502
+ role: "tablist",
503
+ "aria-label": title,
504
+ children: TRAE_REGIONS.map((item) => {
505
+ const regionStatus = statusByRegion[item];
506
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
507
+ type: "button",
508
+ role: "tab",
509
+ "aria-selected": item === activeRegion,
510
+ className: `dsm-trae-tab${item === activeRegion ? " dsm-trae-tab-active" : ""}`,
511
+ onClick: () => {
512
+ setActiveRegion(item);
513
+ },
514
+ children: [regionStatus === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
515
+ "aria-hidden": "true",
516
+ className: "dsm-trae-tab-dot",
517
+ style: dotStyle(regionStatus.status)
518
+ }), item === "cn" ? t("row.tabCn") : t("row.tabAi")]
519
+ }, item);
520
+ })
521
+ }),
522
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
523
+ className: "dsm-trae-tab-hint",
524
+ children: t("row.tabHint")
525
+ }),
394
526
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
395
527
  className: "dsm-trae-usage-account",
396
528
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
@@ -434,6 +566,8 @@ window.__ModuleLoader__.load({
434
566
  children: [
435
567
  account.accountName,
436
568
  " · ",
569
+ account.region === "ai" ? t("row.regionAi") : t("row.regionCn"),
570
+ " · ",
437
571
  account.edition
438
572
  ]
439
573
  }, account.id))
@@ -441,6 +575,44 @@ window.__ModuleLoader__.load({
441
575
  })
442
576
  }) : null,
443
577
  status.status === "signed-in" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
578
+ status.payStatus === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
579
+ className: "dsm-trae-usage-list",
580
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
581
+ className: "dsm-trae-usage-stats dsm-trae-usage-stats-two",
582
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
583
+ className: "dsm-trae-usage-stat dsm-trae-usage-stat-general",
584
+ children: [
585
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
586
+ className: "dsm-trae-usage-stat-head",
587
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
588
+ className: "dsm-trae-usage-stat-label",
589
+ children: t("row.subscriptionLabel")
590
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
591
+ className: `dsm-trae-usage-stat-badge ${status.payStatus.hasPackage ? "dsm-trae-usage-stat-badge-on" : "dsm-trae-usage-stat-badge-off"}`,
592
+ children: t(status.payStatus.hasPackage ? "row.subscribed" : "row.noPackage")
593
+ })]
594
+ }),
595
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
596
+ className: "dsm-trae-usage-stat-value dsm-trae-usage-stat-value-general",
597
+ children: status.payStatus.inTrial && status.payStatus.trialEndTimeMs > 0 ? t("row.trialUntil", { date: formatDateTime(status.payStatus.trialEndTimeMs) }) : t(status.payStatus.hasPackage ? "row.subscribed" : "row.noPackage")
598
+ }),
599
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
600
+ className: "dsm-trae-usage-stat-hint",
601
+ children: status.payStatus.enableSoloLite || status.payStatus.enableSoloCoder || status.payStatus.enableSoloBuilder || status.payStatus.enableSoloWeb ? [
602
+ status.payStatus.enableSoloLite ? "SOLO Lite" : "",
603
+ status.payStatus.enableSoloCoder ? "SOLO Coder" : "",
604
+ status.payStatus.enableSoloBuilder ? "SOLO Builder" : "",
605
+ status.payStatus.enableSoloWeb ? "SOLO Web" : ""
606
+ ].filter(Boolean).join(" · ") : status.payStatus.isDollarUsageBilling ? "dollar usage billing" : ""
607
+ })
608
+ ]
609
+ })
610
+ })
611
+ }),
612
+ status.payStatusError === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
613
+ className: "dsm-trae-usage-error",
614
+ children: t("row.payStatusError", { message: status.payStatusError })
615
+ }),
444
616
  status.credits === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
445
617
  className: "dsm-trae-usage-list",
446
618
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
@@ -672,9 +844,12 @@ window.__ModuleLoader__.load({
672
844
  */
673
845
  const en = {
674
846
  "row.title": "Trae credits & models (dsh-connect-trae)",
675
- "row.desc": "Use the models in the Trae desktop app directly in DSH, and see your remaining credits at a glance.",
847
+ "row.desc": "Use Trae models in DSH and see your remaining credits; the domestic and international sides are two independent providers, each with its own account — use both at the same time.",
676
848
  "row.expand": "Expand",
677
849
  "row.collapse": "Collapse",
850
+ "row.tabCn": "Domestic",
851
+ "row.tabAi": "Global",
852
+ "row.tabHint": "Each tab is a separate provider (trae / trae-global) with its own account, usage, and models. Both sides are live at once: different sessions can pick from either side, and changes on one tab never touch the other.",
678
853
  "row.signedOut": "Not signed in",
679
854
  "row.signedOutHint": "Sign in once in the Trae desktop app; this plugin follows that sign-in automatically.",
680
855
  "row.searchedTitle": "Paths checked",
@@ -698,6 +873,13 @@ window.__ModuleLoader__.load({
698
873
  "row.creditsConsumedLabel": "Consumed",
699
874
  "row.creditsTotalLabel": "Total",
700
875
  "row.creditsError": "Usage unavailable: {message}",
876
+ "row.regionCn": "CN",
877
+ "row.regionAi": "International",
878
+ "row.subscriptionLabel": "Subscription",
879
+ "row.subscribed": "Active package",
880
+ "row.noPackage": "No active package",
881
+ "row.trialUntil": "Trial until {date}",
882
+ "row.payStatusError": "Subscription status unavailable: {message}",
701
883
  "row.refresh": "Refresh",
702
884
  "row.refreshTokens": "Refresh accounts & tokens",
703
885
  "row.refreshCredits": "Refresh usage",
@@ -727,9 +909,12 @@ window.__ModuleLoader__.load({
727
909
  };
728
910
  const zh = {
729
911
  "row.title": "接入使用Trae积分与模型(dsh-connect-trae)",
730
- "row.desc": "在 DSH 中直接使用 Trae 桌面 App 包含的模型,并随时查看剩余积分。",
912
+ "row.desc": "在 DSH 中使用 Trae 模型并随时查看剩余积分;国内版与国际版是两个独立供应商,各有自己的账号,可同时使用。",
731
913
  "row.expand": "展开",
732
914
  "row.collapse": "收起",
915
+ "row.tabCn": "国内版",
916
+ "row.tabAi": "国际版",
917
+ "row.tabHint": "每个 tab 是一个独立供应商(trae / trae-global),各有自己的账号、用量与模型。两边同时生效:不同会话可各选一边,一侧的改动不影响另一侧。",
733
918
  "row.signedOut": "未登录",
734
919
  "row.signedOutHint": "在 Trae 桌面 App 里登录一次即可,插件会自动跟随当前登录的账号。",
735
920
  "row.searchedTitle": "已检查的路径",
@@ -753,6 +938,13 @@ window.__ModuleLoader__.load({
753
938
  "row.creditsConsumedLabel": "消耗",
754
939
  "row.creditsTotalLabel": "合计",
755
940
  "row.creditsError": "用量查询失败:{message}",
941
+ "row.regionCn": "国内版",
942
+ "row.regionAi": "国际版",
943
+ "row.subscriptionLabel": "订阅状态",
944
+ "row.subscribed": "已有有效套餐",
945
+ "row.noPackage": "暂无有效套餐",
946
+ "row.trialUntil": "试用至 {date}",
947
+ "row.payStatusError": "订阅状态查询失败:{message}",
756
948
  "row.refresh": "刷新",
757
949
  "row.refreshTokens": "刷新账号与 Token",
758
950
  "row.refreshCredits": "刷新用量",