dsh-connect-workbuddy 1.4.0 → 2.0.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 +32 -0
- package/README.en.md +14 -10
- package/README.md +14 -10
- package/lib/bin.d.ts +3 -1
- package/lib/bin.js +103 -69
- package/lib/client.js +185 -64
- package/lib/{host-heartbeat-DQQwiUtm.js → host-heartbeat-sqjxgXkW.js} +988 -910
- package/lib/index.d.ts +133 -28
- package/lib/index.js +197 -97
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -29,6 +29,17 @@ window.__ModuleLoader__.load({
|
|
|
29
29
|
const WORKBUDDY_ACCOUNTS_REFRESH_PATH = "/plugins/dsh-connect-workbuddy/accounts/refresh";
|
|
30
30
|
/** Plugin-owned daily check-in action endpoint. */
|
|
31
31
|
const WORKBUDDY_CHECKIN_PATH = "/plugins/dsh-connect-workbuddy/checkin";
|
|
32
|
+
/** Query parameter naming the region a card request addresses. */
|
|
33
|
+
const WORKBUDDY_REGION_PARAM = "region";
|
|
34
|
+
/** Every region, in card tab order. */
|
|
35
|
+
const WORKBUDDY_REGIONS = ["cn", "global"];
|
|
36
|
+
/**
|
|
37
|
+
* Address one region's status route. The two regions are separate provider
|
|
38
|
+
* stacks; every card request carries the region whose tab the user is on.
|
|
39
|
+
*/
|
|
40
|
+
function withWorkBuddyRegion(path, region) {
|
|
41
|
+
return `${path}?${WORKBUDDY_REGION_PARAM}=${region}`;
|
|
42
|
+
}
|
|
32
43
|
/**
|
|
33
44
|
* Project one card row into its persisted `lastCatalog` shape: the native
|
|
34
45
|
* context window becomes the stored `contextWindow`, and the card-only
|
|
@@ -70,7 +81,8 @@ window.__ModuleLoader__.load({
|
|
|
70
81
|
* dingminhua/dsh-subagent-default-model(MIT)的 SETTINGS_CSS。
|
|
71
82
|
* 沿用目的是让两个插件共享同一套外部表现语言。
|
|
72
83
|
* 改动:类名由 `dsm-trae-*` 改为 `dsm-workbuddy-*`;
|
|
73
|
-
* 移除 trae 特有的 1M
|
|
84
|
+
* 移除 trae 特有的 1M 变体样式,新增按套餐聚合的积分行样式;
|
|
85
|
+
* 双 provider 化后新增国内版/国际版 tab 栏样式。
|
|
74
86
|
*
|
|
75
87
|
* @module dsh-connect-workbuddy/client/styles
|
|
76
88
|
*/
|
|
@@ -95,6 +107,12 @@ window.__ModuleLoader__.load({
|
|
|
95
107
|
.dsm-btn-primary{background:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-layer-3)}
|
|
96
108
|
.dsm-btn-primary:hover:not(:disabled){opacity:.9}
|
|
97
109
|
.dsm-workbuddy-usage{display:flex;flex-direction:column;gap:16px;margin:0;padding:16px 0 4px}
|
|
110
|
+
.dsm-workbuddy-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)}
|
|
111
|
+
.dsm-workbuddy-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}
|
|
112
|
+
.dsm-workbuddy-tab:hover:not(:disabled):not(.dsm-workbuddy-tab-active){color:var(--dsw-alias-label-primary,#e6e6e6)}
|
|
113
|
+
.dsm-workbuddy-tab:focus-visible{outline:2px solid var(--dsw-alias-brand-primary,#5686fe);outline-offset:1px}
|
|
114
|
+
.dsm-workbuddy-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)}
|
|
115
|
+
.dsm-workbuddy-tab-dot{display:inline-block;width:7px;height:7px;border-radius:50%;margin-right:6px;vertical-align:baseline}
|
|
98
116
|
.dsm-workbuddy-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)}
|
|
99
117
|
.dsm-workbuddy-usage-account-copy{display:flex;flex-direction:column;gap:3px;min-width:0}
|
|
100
118
|
.dsm-workbuddy-usage-expiry{padding-left:19px;color:var(--dsw-alias-label-tertiary,#9aa0a8);font-size:12px;line-height:18px}
|
|
@@ -177,12 +195,15 @@ window.__ModuleLoader__.load({
|
|
|
177
195
|
* 60 秒轮询与 AbortController 清理、以及
|
|
178
196
|
* `IconChevronDownOutline14` 的使用,均来自该项目的 TraeUsageCard。
|
|
179
197
|
* 折叠卡片外壳与 `settings.plugin.item` 槽位形态来自
|
|
180
|
-
*
|
|
198
|
+
* dingminhua/dsh-subagent-default-model(MIT)。
|
|
181
199
|
* 改动:
|
|
182
200
|
* 1. 积分区改为「合计 + 按套餐名聚合的进度条」,因为实测单个账号下
|
|
183
201
|
* 同名套餐可达 19 个,逐条渲染会淹没卡片(原项目按上游条目直出);
|
|
184
202
|
* 2. 模型行补上 WorkBuddy 上游给出的积分倍率、多模态与推理档位;
|
|
185
|
-
* 3. 移除与 WorkBuddy 上游无关的 1M
|
|
203
|
+
* 3. 移除与 WorkBuddy 上游无关的 1M 变体勾选;
|
|
204
|
+
* 4. 双 provider 化后卡片顶部为「国内版 / 国际版」tab 栏 —— 每个 tab
|
|
205
|
+
* 是一个独立供应商(workbuddy / workbuddy-global),账号、积分、
|
|
206
|
+
* 模型目录与草稿完全按区域隔离,切 tab 不丢另一侧未保存的草稿。
|
|
186
207
|
*
|
|
187
208
|
* @module dsh-connect-workbuddy/client/WorkBuddyCard
|
|
188
209
|
*/
|
|
@@ -234,20 +255,33 @@ window.__ModuleLoader__.load({
|
|
|
234
255
|
function dotStyle(status) {
|
|
235
256
|
return { background: status === "signed-in" ? "var(--dsw-alias-state-success-primary, #22a06b)" : status === "error" ? "var(--dsw-alias-state-error-primary, #d92d20)" : "var(--dsw-alias-label-dimmed, #9aa0a6)" };
|
|
236
257
|
}
|
|
258
|
+
/** Read the per-region account selections out of the settings snapshot. */
|
|
259
|
+
function configuredAccountsOf(configured) {
|
|
260
|
+
const accounts = configured?.accounts;
|
|
261
|
+
return typeof accounts === "object" && accounts !== null ? accounts : {};
|
|
262
|
+
}
|
|
237
263
|
/** Render WorkBuddy sign-in state, credits, and model selection as one card. */
|
|
238
264
|
function WorkBuddyCard({ t, settingsScope }) {
|
|
239
265
|
if (t === void 0) throw new Error("WorkBuddy plugin card requires its translation function");
|
|
240
266
|
const [open, setOpen] = (0, react.useState)(false);
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
267
|
+
/** The region whose tab is on screen; each tab is its own provider stack. */
|
|
268
|
+
const [activeRegion, setActiveRegion] = (0, react.useState)("cn");
|
|
269
|
+
/** Last-known usage per region, so tab dots survive tab switches. */
|
|
270
|
+
const [statusByRegion, setStatusByRegion] = (0, react.useState)({
|
|
271
|
+
cn: {
|
|
272
|
+
status: "signed-out",
|
|
273
|
+
accounts: []
|
|
274
|
+
},
|
|
275
|
+
global: {
|
|
276
|
+
status: "signed-out",
|
|
277
|
+
accounts: []
|
|
278
|
+
}
|
|
244
279
|
});
|
|
245
280
|
const [busy, setBusy] = (0, react.useState)(false);
|
|
246
281
|
const [settingsRevision, setSettingsRevision] = (0, react.useState)(0);
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
const [
|
|
250
|
-
const [draftContextBudgets, setDraftContextBudgets] = (0, react.useState)(void 0);
|
|
282
|
+
/** Per-region unsaved model edits; a draft on one tab is never dropped by
|
|
283
|
+
* switching to the other tab, only by that tab's discard/save. */
|
|
284
|
+
const [drafts, setDrafts] = (0, react.useState)({});
|
|
251
285
|
const [saving, setSaving] = (0, react.useState)(false);
|
|
252
286
|
/** Save failure surfaced next to the buttons; cleared by the next attempt. */
|
|
253
287
|
const [saveError, setSaveError] = (0, react.useState)(void 0);
|
|
@@ -264,38 +298,53 @@ window.__ModuleLoader__.load({
|
|
|
264
298
|
(0, react.useEffect)(() => settingsScope?.subscribe(() => {
|
|
265
299
|
setSettingsRevision((value) => value + 1);
|
|
266
300
|
}), [settingsScope]);
|
|
267
|
-
const refreshUsage = (0, react.useCallback)(async (signal) => {
|
|
301
|
+
const refreshUsage = (0, react.useCallback)(async (region, signal) => {
|
|
268
302
|
try {
|
|
269
|
-
const response = await fetch(WORKBUDDY_USAGE_PATH, {
|
|
303
|
+
const response = await fetch(withWorkBuddyRegion(WORKBUDDY_USAGE_PATH, region), {
|
|
270
304
|
headers: { accept: "application/json" },
|
|
271
305
|
credentials: "same-origin",
|
|
272
306
|
...signal === void 0 ? {} : { signal }
|
|
273
307
|
});
|
|
274
308
|
const value = await response.json().catch(() => void 0);
|
|
275
309
|
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
|
276
|
-
|
|
277
|
-
|
|
310
|
+
const usage = value;
|
|
311
|
+
if (mounted.current && signal?.aborted !== true) setStatusByRegion((prev) => ({
|
|
312
|
+
...prev,
|
|
313
|
+
[region]: usage
|
|
314
|
+
}));
|
|
315
|
+
return usage;
|
|
278
316
|
} catch (error) {
|
|
279
|
-
if (mounted.current && signal?.aborted !== true)
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
317
|
+
if (mounted.current && signal?.aborted !== true) setStatusByRegion((prev) => ({
|
|
318
|
+
...prev,
|
|
319
|
+
[region]: {
|
|
320
|
+
status: "error",
|
|
321
|
+
message: error instanceof Error ? error.message : t("row.requestFailed")
|
|
322
|
+
}
|
|
323
|
+
}));
|
|
283
324
|
return;
|
|
284
325
|
}
|
|
285
326
|
}, [t]);
|
|
286
327
|
(0, react.useEffect)(() => {
|
|
287
328
|
if (!open) return;
|
|
288
329
|
const controller = new AbortController();
|
|
289
|
-
refreshUsage(controller.signal);
|
|
330
|
+
refreshUsage(activeRegion, controller.signal);
|
|
290
331
|
return () => {
|
|
291
332
|
controller.abort();
|
|
292
333
|
};
|
|
293
|
-
}, [
|
|
334
|
+
}, [
|
|
335
|
+
open,
|
|
336
|
+
activeRegion,
|
|
337
|
+
refreshUsage
|
|
338
|
+
]);
|
|
339
|
+
const status = statusByRegion[activeRegion] ?? {
|
|
340
|
+
status: "signed-out",
|
|
341
|
+
accounts: []
|
|
342
|
+
};
|
|
294
343
|
(0, react.useEffect)(() => {
|
|
295
344
|
if (!open || status.status !== "signed-in") return;
|
|
296
345
|
const controller = new AbortController();
|
|
297
346
|
const timer = window.setInterval(() => {
|
|
298
|
-
refreshUsage(controller.signal);
|
|
347
|
+
refreshUsage(activeRegion, controller.signal);
|
|
299
348
|
}, POLL_INTERVAL_MS);
|
|
300
349
|
return () => {
|
|
301
350
|
window.clearInterval(timer);
|
|
@@ -303,13 +352,14 @@ window.__ModuleLoader__.load({
|
|
|
303
352
|
};
|
|
304
353
|
}, [
|
|
305
354
|
open,
|
|
355
|
+
activeRegion,
|
|
306
356
|
refreshUsage,
|
|
307
357
|
status.status
|
|
308
358
|
]);
|
|
309
359
|
const rescanAccounts = async () => {
|
|
310
360
|
setBusy(true);
|
|
311
361
|
try {
|
|
312
|
-
const response = await fetch(WORKBUDDY_ACCOUNTS_REFRESH_PATH, {
|
|
362
|
+
const response = await fetch(withWorkBuddyRegion(WORKBUDDY_ACCOUNTS_REFRESH_PATH, activeRegion), {
|
|
313
363
|
method: "POST",
|
|
314
364
|
headers: { accept: "application/json" },
|
|
315
365
|
credentials: "same-origin"
|
|
@@ -317,10 +367,13 @@ window.__ModuleLoader__.load({
|
|
|
317
367
|
const body = await response.json();
|
|
318
368
|
if (!response.ok || !Array.isArray(body.accounts)) throw new Error(`HTTP ${response.status}`);
|
|
319
369
|
const selected = body.accounts.find((account) => account.selected)?.id;
|
|
320
|
-
const
|
|
321
|
-
const configuredId =
|
|
322
|
-
if (selected !== void 0 && selected !== configuredId && settingsScope?.getSnapshot().writable === true) await settingsScope.set("
|
|
323
|
-
|
|
370
|
+
const configuredAccounts = configuredAccountsOf(settingsScope?.getSnapshot().value);
|
|
371
|
+
const configuredId = configuredAccounts[activeRegion];
|
|
372
|
+
if (selected !== void 0 && selected !== configuredId && settingsScope?.getSnapshot().writable === true) await settingsScope.set("accounts", {
|
|
373
|
+
...configuredAccounts,
|
|
374
|
+
[activeRegion]: selected
|
|
375
|
+
});
|
|
376
|
+
await refreshUsage(activeRegion);
|
|
324
377
|
} finally {
|
|
325
378
|
if (mounted.current) setBusy(false);
|
|
326
379
|
}
|
|
@@ -329,8 +382,12 @@ window.__ModuleLoader__.load({
|
|
|
329
382
|
if (settingsScope === void 0) return;
|
|
330
383
|
setSwitchingAccount(true);
|
|
331
384
|
try {
|
|
332
|
-
|
|
333
|
-
await
|
|
385
|
+
const configuredAccounts = configuredAccountsOf(settingsScope.getSnapshot().value);
|
|
386
|
+
await settingsScope.set("accounts", {
|
|
387
|
+
...configuredAccounts,
|
|
388
|
+
[activeRegion]: accountId
|
|
389
|
+
});
|
|
390
|
+
await refreshUsage(activeRegion);
|
|
334
391
|
} finally {
|
|
335
392
|
if (mounted.current) setSwitchingAccount(false);
|
|
336
393
|
}
|
|
@@ -339,14 +396,14 @@ window.__ModuleLoader__.load({
|
|
|
339
396
|
setCheckingIn(true);
|
|
340
397
|
setCheckinActionError(void 0);
|
|
341
398
|
try {
|
|
342
|
-
const response = await fetch(WORKBUDDY_CHECKIN_PATH, {
|
|
399
|
+
const response = await fetch(withWorkBuddyRegion(WORKBUDDY_CHECKIN_PATH, activeRegion), {
|
|
343
400
|
method: "POST",
|
|
344
401
|
headers: { accept: "application/json" },
|
|
345
402
|
credentials: "same-origin"
|
|
346
403
|
});
|
|
347
404
|
const body = await response.json().catch(() => void 0);
|
|
348
405
|
if (!response.ok) throw new Error(body?.error ?? `HTTP ${response.status}`);
|
|
349
|
-
await refreshUsage();
|
|
406
|
+
await refreshUsage(activeRegion);
|
|
350
407
|
} catch (error) {
|
|
351
408
|
if (mounted.current) setCheckinActionError(error instanceof Error ? error.message : t("row.requestFailed"));
|
|
352
409
|
} finally {
|
|
@@ -356,7 +413,7 @@ window.__ModuleLoader__.load({
|
|
|
356
413
|
const refreshModels = async () => {
|
|
357
414
|
setBusy(true);
|
|
358
415
|
try {
|
|
359
|
-
const response = await fetch(WORKBUDDY_MODELS_REFRESH_PATH, {
|
|
416
|
+
const response = await fetch(withWorkBuddyRegion(WORKBUDDY_MODELS_REFRESH_PATH, activeRegion), {
|
|
360
417
|
method: "POST",
|
|
361
418
|
headers: { accept: "application/json" },
|
|
362
419
|
credentials: "same-origin"
|
|
@@ -372,54 +429,86 @@ window.__ModuleLoader__.load({
|
|
|
372
429
|
const budget = activeContextBudgets[id];
|
|
373
430
|
if (typeof budget === "number") stillBudgets[id] = budget;
|
|
374
431
|
}
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
432
|
+
setDrafts((prev) => ({
|
|
433
|
+
...prev,
|
|
434
|
+
[activeRegion]: {
|
|
435
|
+
models: fresh,
|
|
436
|
+
enabledIds: new Set(stillEnabled),
|
|
437
|
+
imageIds: new Set(stillImages),
|
|
438
|
+
contextBudgets: stillBudgets
|
|
439
|
+
}
|
|
440
|
+
}));
|
|
379
441
|
} catch (error) {
|
|
380
|
-
if (mounted.current)
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
442
|
+
if (mounted.current) setStatusByRegion((prev) => ({
|
|
443
|
+
...prev,
|
|
444
|
+
[activeRegion]: {
|
|
445
|
+
status: "error",
|
|
446
|
+
message: error instanceof Error ? error.message : t("row.requestFailed")
|
|
447
|
+
}
|
|
448
|
+
}));
|
|
384
449
|
} finally {
|
|
385
450
|
if (mounted.current) setBusy(false);
|
|
386
451
|
}
|
|
387
452
|
};
|
|
388
|
-
const
|
|
453
|
+
const draft = drafts[activeRegion];
|
|
454
|
+
const visibleModels = draft?.models ?? (status.status === "signed-in" ? status.models : []);
|
|
389
455
|
const savedEnabledIds = status.status === "signed-in" ? new Set(status.enabledModelIds) : /* @__PURE__ */ new Set();
|
|
390
|
-
const activeEnabledIds =
|
|
456
|
+
const activeEnabledIds = draft?.enabledIds ?? savedEnabledIds;
|
|
391
457
|
const savedImageIds = status.status === "signed-in" ? new Set(status.imageModelIds) : /* @__PURE__ */ new Set();
|
|
392
|
-
const activeImageIds =
|
|
458
|
+
const activeImageIds = draft?.imageIds ?? savedImageIds;
|
|
393
459
|
const configured = settingsScope?.getSnapshot().value;
|
|
394
460
|
const configuredRegion = status.status === "signed-in" ? configured?.regions?.[status.region] : void 0;
|
|
395
461
|
const legacyContextBudgets = status.status === "signed-in" && status.region === "cn" ? configured?.contextBudgets : void 0;
|
|
396
462
|
const savedContextBudgetsSource = configuredRegion?.contextBudgets ?? legacyContextBudgets;
|
|
397
|
-
const
|
|
398
|
-
const
|
|
463
|
+
const savedContextBudgets = typeof savedContextBudgetsSource === "object" && savedContextBudgetsSource !== null ? savedContextBudgetsSource : {};
|
|
464
|
+
const activeContextBudgets = draft?.contextBudgets ?? savedContextBudgets;
|
|
465
|
+
const dirty = draft !== void 0;
|
|
466
|
+
const editDraft = (edit) => {
|
|
467
|
+
setDrafts((prev) => ({
|
|
468
|
+
...prev,
|
|
469
|
+
[activeRegion]: edit(prev[activeRegion] ?? {
|
|
470
|
+
models: [...visibleModels],
|
|
471
|
+
enabledIds: new Set(activeEnabledIds),
|
|
472
|
+
imageIds: new Set(activeImageIds),
|
|
473
|
+
contextBudgets: { ...activeContextBudgets }
|
|
474
|
+
})
|
|
475
|
+
}));
|
|
476
|
+
};
|
|
399
477
|
const toggleModel = (modelId) => {
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
478
|
+
editDraft((current) => {
|
|
479
|
+
const next = new Set(current.enabledIds);
|
|
480
|
+
if (!next.delete(modelId)) next.add(modelId);
|
|
481
|
+
return {
|
|
482
|
+
...current,
|
|
483
|
+
enabledIds: next
|
|
484
|
+
};
|
|
485
|
+
});
|
|
404
486
|
};
|
|
405
487
|
const toggleImage = (modelId) => {
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
488
|
+
editDraft((current) => {
|
|
489
|
+
const next = new Set(current.imageIds);
|
|
490
|
+
if (!next.delete(modelId)) next.add(modelId);
|
|
491
|
+
return {
|
|
492
|
+
...current,
|
|
493
|
+
imageIds: next
|
|
494
|
+
};
|
|
495
|
+
});
|
|
410
496
|
};
|
|
411
497
|
const setContextBudget = (modelId, budget) => {
|
|
412
|
-
|
|
413
|
-
...
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
498
|
+
editDraft((current) => ({
|
|
499
|
+
...current,
|
|
500
|
+
contextBudgets: {
|
|
501
|
+
...current.contextBudgets,
|
|
502
|
+
[modelId]: budget
|
|
503
|
+
}
|
|
504
|
+
}));
|
|
417
505
|
};
|
|
418
506
|
const discardModels = () => {
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
507
|
+
setDrafts((prev) => {
|
|
508
|
+
const next = { ...prev };
|
|
509
|
+
delete next[activeRegion];
|
|
510
|
+
return next;
|
|
511
|
+
});
|
|
423
512
|
};
|
|
424
513
|
const saveModels = async () => {
|
|
425
514
|
if (settingsScope === void 0) return;
|
|
@@ -438,7 +527,7 @@ window.__ModuleLoader__.load({
|
|
|
438
527
|
}
|
|
439
528
|
});
|
|
440
529
|
discardModels();
|
|
441
|
-
await refreshUsage();
|
|
530
|
+
await refreshUsage(activeRegion);
|
|
442
531
|
} catch (error) {
|
|
443
532
|
if (mounted.current) setSaveError(error instanceof Error ? error.message : t("row.requestFailed"));
|
|
444
533
|
} finally {
|
|
@@ -485,6 +574,32 @@ window.__ModuleLoader__.load({
|
|
|
485
574
|
children: open ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
486
575
|
className: "dsm-workbuddy-usage",
|
|
487
576
|
children: [
|
|
577
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
578
|
+
className: "dsm-workbuddy-tabs",
|
|
579
|
+
role: "tablist",
|
|
580
|
+
"aria-label": title,
|
|
581
|
+
children: WORKBUDDY_REGIONS.map((region) => {
|
|
582
|
+
const regionStatus = statusByRegion[region];
|
|
583
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
584
|
+
type: "button",
|
|
585
|
+
role: "tab",
|
|
586
|
+
"aria-selected": region === activeRegion,
|
|
587
|
+
className: `dsm-workbuddy-tab${region === activeRegion ? " dsm-workbuddy-tab-active" : ""}`,
|
|
588
|
+
onClick: () => {
|
|
589
|
+
setActiveRegion(region);
|
|
590
|
+
},
|
|
591
|
+
children: [regionStatus === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
592
|
+
"aria-hidden": "true",
|
|
593
|
+
className: "dsm-workbuddy-tab-dot",
|
|
594
|
+
style: dotStyle(regionStatus.status)
|
|
595
|
+
}), region === "cn" ? t("row.tabCn") : t("row.tabGlobal")]
|
|
596
|
+
}, region);
|
|
597
|
+
})
|
|
598
|
+
}),
|
|
599
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
600
|
+
className: "dsm-workbuddy-models-summary",
|
|
601
|
+
children: t("row.tabHint")
|
|
602
|
+
}),
|
|
488
603
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
489
604
|
className: "dsm-workbuddy-usage-account",
|
|
490
605
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -787,9 +902,12 @@ window.__ModuleLoader__.load({
|
|
|
787
902
|
*/
|
|
788
903
|
const en = {
|
|
789
904
|
"row.title": "WorkBuddy credits & models (dsh-connect-workbuddy)",
|
|
790
|
-
"row.desc": "Use
|
|
905
|
+
"row.desc": "Use WorkBuddy 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.",
|
|
791
906
|
"row.expand": "Expand",
|
|
792
907
|
"row.collapse": "Collapse",
|
|
908
|
+
"row.tabCn": "Domestic",
|
|
909
|
+
"row.tabGlobal": "Global",
|
|
910
|
+
"row.tabHint": "Each tab is a separate provider (workbuddy / workbuddy-global) with its own account, credits, and models. Both sides are live at once: different sessions can pick from either side, and changes on one tab never touch the other.",
|
|
793
911
|
"row.signedOut": "Not signed in",
|
|
794
912
|
"row.signedOutHint": "Sign in once in the WorkBuddy desktop app; this plugin follows that sign-in automatically.",
|
|
795
913
|
"row.signedIn": "Signed in: {accountName}",
|
|
@@ -832,9 +950,12 @@ window.__ModuleLoader__.load({
|
|
|
832
950
|
};
|
|
833
951
|
const zh = {
|
|
834
952
|
"row.title": "接入使用 WorkBuddy 积分与模型(dsh-connect-workbuddy)",
|
|
835
|
-
"row.desc": "在 DSH
|
|
953
|
+
"row.desc": "在 DSH 中使用 WorkBuddy 模型并随时查看剩余积分;国内版与国际版是两个独立供应商,各有自己的账号,可同时使用。",
|
|
836
954
|
"row.expand": "展开",
|
|
837
955
|
"row.collapse": "收起",
|
|
956
|
+
"row.tabCn": "国内版",
|
|
957
|
+
"row.tabGlobal": "国际版",
|
|
958
|
+
"row.tabHint": "每个 tab 是一个独立供应商(workbuddy / workbuddy-global),各有自己的账号、积分与模型。两边同时生效:不同会话可各选一边,一侧的改动不影响另一侧。",
|
|
838
959
|
"row.signedOut": "未登录",
|
|
839
960
|
"row.signedOutHint": "在 WorkBuddy 桌面 App 里登录一次即可,插件会自动跟随当前登录的账号。",
|
|
840
961
|
"row.signedIn": "已登录:{accountName}",
|