dsh-workbuddy-xdpool 1.7.2 → 1.7.4

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
@@ -23,6 +23,16 @@ window.__ModuleLoader__.load({
23
23
  const POOL_STATUS_PATH = "/plugins/dsh-workbuddy-xdpool/status";
24
24
  /** Plugin-owned local account rescan endpoint (re-read desktop snapshots). */
25
25
  const POOL_RESCAN_PATH = "/plugins/dsh-workbuddy-xdpool/accounts/rescan";
26
+ /**
27
+ * Re-fetch the upstream model catalog for both regions.
28
+ *
29
+ * Separate from {@link POOL_RESCAN_PATH} because they answer different
30
+ * questions, and conflating them misled users: "detect accounts again" only
31
+ * re-read the desktop snapshots, so it could NOT recover a model list that had
32
+ * fallen back to the static table after a failed startup fetch. The only way
33
+ * out was restarting DSH.
34
+ */
35
+ const POOL_CATALOG_REFRESH_PATH = "/plugins/dsh-workbuddy-xdpool/models/refresh";
26
36
  /** Plugin-owned cooldown reset endpoint (clear all 429 cooldowns). */
27
37
  const POOL_RESET_COOLDOWN_PATH = "/plugins/dsh-workbuddy-xdpool/cooldowns/reset";
28
38
  /** Plugin-owned daily check-in action endpoint (claim today's reward). */
@@ -276,6 +286,9 @@ window.__ModuleLoader__.load({
276
286
  .dsm-workbuddy-xdpool-model-budget input{margin:0;accent-color:var(--dsw-alias-brand-primary,#5686fe)}
277
287
  .dsm-workbuddy-xdpool-models-heading{display:flex;flex-direction:column;gap:2px;min-width:0}
278
288
  .dsm-workbuddy-xdpool-models-actions{display:flex;align-items:center;gap:8px;flex:none}
289
+ /* "Built-in list (offline)" chip: a warning tint, since the user is looking at
290
+ a SHORTER roster than the gateway offers and may wonder where models went. */
291
+ .dsm-workbuddy-xdpool-catalog-offline{flex:none;padding:2px 9px;border-radius:999px;font-size:11px;line-height:17px;font-weight:600;background:var(--dsw-alias-state-warning-subtle,rgba(217,119,6,.15));color:var(--dsw-alias-state-warning-primary,#d97706);white-space:nowrap}
279
292
 
280
293
 
281
294
  /* Automation: run-now button and the per-job progress line. */
@@ -585,6 +598,8 @@ window.__ModuleLoader__.load({
585
598
  const [error, setError] = (0, react.useState)(void 0);
586
599
  const [busy, setBusy] = (0, react.useState)(false);
587
600
  const [cooldownBusy, setCooldownBusy] = (0, react.useState)(false);
601
+ /** Model-catalog refresh in flight (separate from the account rescan). */
602
+ const [catalogBusy, setCatalogBusy] = (0, react.useState)(false);
588
603
  const [automationBusy, setAutomationBusy] = (0, react.useState)(false);
589
604
  /** The automation job currently running from the card, if any. */
590
605
  const [automationRun, setAutomationRun] = (0, react.useState)(void 0);
@@ -679,6 +694,35 @@ window.__ModuleLoader__.load({
679
694
  if (mounted.current) setBusy(false);
680
695
  }
681
696
  };
697
+ /**
698
+ * Re-fetch the upstream model catalog for both regions.
699
+ *
700
+ * Its own action, and its own BUTTON, because the account rescan beside it
701
+ * could not do this job: when the startup fetch failed, the picker held the
702
+ * shorter built-in list and "detect accounts again" left it untouched, so the
703
+ * only recovery was restarting DSH. Users reasonably assumed the button
704
+ * covered both.
705
+ */
706
+ const refreshCatalog = async () => {
707
+ setCatalogBusy(true);
708
+ setFlash(void 0);
709
+ try {
710
+ const response = await fetch(POOL_CATALOG_REFRESH_PATH, {
711
+ method: "POST",
712
+ headers: { accept: "application/json" },
713
+ credentials: "same-origin"
714
+ });
715
+ const body = await response.json();
716
+ if (!response.ok) throw new Error(body.error ?? `HTTP ${response.status}`);
717
+ await refresh(activeRegion);
718
+ const here = body.regions?.[activeRegion];
719
+ if (mounted.current) setFlash(here?.source === "live" ? t?.("row.catalogRefreshed", { count: here.models ?? 0 }) ?? "" : t?.("row.catalogRefreshOffline") ?? "");
720
+ } catch (cause) {
721
+ if (mounted.current) setError(cause instanceof Error ? cause.message : String(cause));
722
+ } finally {
723
+ if (mounted.current) setCatalogBusy(false);
724
+ }
725
+ };
682
726
  const resetCooldowns = async () => {
683
727
  setCooldownBusy(true);
684
728
  setFlash(void 0);
@@ -1430,21 +1474,39 @@ window.__ModuleLoader__.load({
1430
1474
  })]
1431
1475
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1432
1476
  className: "dsm-workbuddy-xdpool-models-actions",
1433
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1434
- type: "button",
1435
- className: "dsm-btn dsm-btn-outline",
1436
- disabled: !modelsDirty || savingModels,
1437
- onClick: discardModels,
1438
- children: t?.("row.modelsDiscard") ?? "Discard"
1439
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1440
- type: "button",
1441
- className: "dsm-btn dsm-btn-primary",
1442
- disabled: !modelsDirty || savingModels || enabledCount === 0,
1443
- onClick: () => {
1444
- saveModels();
1445
- },
1446
- children: savingModels ? t?.("row.modelsSaving") ?? "Saving…" : t?.("row.modelsSave") ?? "Save"
1447
- })]
1477
+ children: [
1478
+ status?.catalogSource !== "fallback" ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1479
+ className: "dsm-workbuddy-xdpool-catalog-offline",
1480
+ title: status.catalogError ?? void 0,
1481
+ children: t?.("row.catalogOffline") ?? "built-in list (offline)"
1482
+ }),
1483
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1484
+ type: "button",
1485
+ className: "dsm-btn dsm-btn-outline",
1486
+ disabled: catalogBusy,
1487
+ onClick: () => {
1488
+ refreshCatalog();
1489
+ },
1490
+ title: t?.("row.catalogRefreshHint") ?? "Fetch the model list again from WorkBuddy",
1491
+ children: catalogBusy ? t?.("row.catalogRefreshing") ?? "Fetching…" : t?.("row.catalogRefresh") ?? "Refresh models"
1492
+ }),
1493
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1494
+ type: "button",
1495
+ className: "dsm-btn dsm-btn-outline",
1496
+ disabled: !modelsDirty || savingModels,
1497
+ onClick: discardModels,
1498
+ children: t?.("row.modelsDiscard") ?? "Discard"
1499
+ }),
1500
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1501
+ type: "button",
1502
+ className: "dsm-btn dsm-btn-primary",
1503
+ disabled: !modelsDirty || savingModels || enabledCount === 0,
1504
+ onClick: () => {
1505
+ saveModels();
1506
+ },
1507
+ children: savingModels ? t?.("row.modelsSaving") ?? "Saving…" : t?.("row.modelsSave") ?? "Save"
1508
+ })
1509
+ ]
1448
1510
  })]
1449
1511
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1450
1512
  className: "dsm-workbuddy-xdpool-model-list",
@@ -2023,6 +2085,12 @@ window.__ModuleLoader__.load({
2023
2085
  "row.modelsSaved": "Model selection saved",
2024
2086
  "row.modelsSaveError": "Could not save: {message}",
2025
2087
  "row.modelsEmpty": "No model enabled — enable at least one before saving.",
2088
+ "row.catalogOffline": "built-in list (offline)",
2089
+ "row.catalogRefresh": "Refresh models",
2090
+ "row.catalogRefreshing": "Fetching…",
2091
+ "row.catalogRefreshHint": "Fetch the model list again from WorkBuddy",
2092
+ "row.catalogRefreshed": "Model list updated ({count} models)",
2093
+ "row.catalogRefreshOffline": "Still offline — kept the built-in list",
2026
2094
  "row.free": "free",
2027
2095
  "row.limitedFree": "limited free",
2028
2096
  "row.nightDiscount": "night",
@@ -2162,6 +2230,12 @@ window.__ModuleLoader__.load({
2162
2230
  "row.modelsSaved": "模型选择已保存",
2163
2231
  "row.modelsSaveError": "保存失败:{message}",
2164
2232
  "row.modelsEmpty": "至少要启用一个模型才能保存。",
2233
+ "row.catalogOffline": "内置列表(离线)",
2234
+ "row.catalogRefresh": "重新获取模型",
2235
+ "row.catalogRefreshing": "获取中…",
2236
+ "row.catalogRefreshHint": "重新从 WorkBuddy 拉取模型列表",
2237
+ "row.catalogRefreshed": "模型列表已更新({count} 个模型)",
2238
+ "row.catalogRefreshOffline": "仍然离线,继续使用内置列表",
2165
2239
  "row.free": "免费",
2166
2240
  "row.limitedFree": "限量免费",
2167
2241
  "row.nightDiscount": "夜间",