dsh-deepseek-balance-widget 2.3.7 → 2.3.8

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
@@ -110,6 +110,7 @@ window.__ModuleLoader__.load({
110
110
  pasteCookieHint: "请粘贴 Cookie 或 cURL,AI 会自动提取",
111
111
  copied: "已复制",
112
112
  copyFailed: "复制失败",
113
+ copyError: "复制错误信息",
113
114
  refresh: "刷新",
114
115
  peakPeriod: "繁忙时段",
115
116
  offPeakPeriod: "空闲时段"
@@ -195,6 +196,7 @@ window.__ModuleLoader__.load({
195
196
  pasteCookieHint: "Paste a Cookie or cURL; the AI will extract it",
196
197
  copied: "Copied",
197
198
  copyFailed: "Copy failed",
199
+ copyError: "Copy error",
198
200
  refresh: "Refresh",
199
201
  peakPeriod: "Peak",
200
202
  offPeakPeriod: "Off-peak"
@@ -420,7 +422,12 @@ window.__ModuleLoader__.load({
420
422
  ".dshBalanceWizardLink:hover{color:#79b8ff}",
421
423
  ".dshBalanceCookiePreview{font-size:11px;color:#7b8494;background:rgba(255,255,255,.05);border-radius:6px;padding:6px 8px;word-break:break-all}",
422
424
  ".dshBalanceCookiePreview code{color:#e6e9ef;font-size:10px}",
423
- ".dshBalanceCookiePreview[data-found=false]{display:none}"
425
+ ".dshBalanceCookiePreview[data-found=false]{display:none}",
426
+ ".dshBalanceUpdateErr{margin-top:10px;border:1px solid rgba(248,81,73,.25);border-radius:8px;background:rgba(248,81,73,.08);padding:8px 10px}",
427
+ ".dshBalanceUpdateErrHead{display:flex;justify-content:space-between;align-items:center;font-size:12px;font-weight:600;color:#f85149;margin-bottom:6px}",
428
+ ".dshBalanceUpdateErrClose{appearance:none;background:transparent;border:0;color:#9aa4b2;font-size:18px;line-height:1;cursor:pointer;padding:0 2px}",
429
+ ".dshBalanceUpdateErrClose:hover{color:#f85149}",
430
+ ".dshBalanceUpdateErrBody{max-height:120px;overflow:auto;background:#0f1216;border:1px solid rgba(255,255,255,.08);border-radius:6px;padding:6px 8px;margin:0 0 8px;font-family:ui-monospace,Menlo,Consolas,monospace;font-size:10px;line-height:1.4;color:#c9d1d9;white-space:pre-wrap;word-break:break-all}"
424
431
  ].join("");
425
432
  const tag = document.createElement("style");
426
433
  tag.dataset.plugin = "dsh-deepseek-balance-widget";
@@ -565,6 +572,8 @@ window.__ModuleLoader__.load({
565
572
  } else {
566
573
  btn.textContent = t("updateFailed");
567
574
  btn.title = String(result.error || t("updateFailed")) + (result.output ? "\n" + result.output.slice(-200) : "");
575
+ updateErrorDetail = { error: result.error || t("updateFailed"), output: result.output || "" };
576
+ renderPopover();
568
577
  setTimeout(() => { btn.textContent = originalText; btn.disabled = false; btn.title = ""; }, 3000);
569
578
  }
570
579
  }
@@ -835,6 +844,24 @@ window.__ModuleLoader__.load({
835
844
  if (updateBtn !== null) {
836
845
  updateBtn.addEventListener("click", () => handleUpdateClick(updateBtn));
837
846
  }
847
+ const updateErrClose = popRef.querySelector("[data-update-err-close]");
848
+ if (updateErrClose !== null) {
849
+ updateErrClose.addEventListener("click", () => { updateErrorDetail = null; renderPopover(); });
850
+ }
851
+ const updateErrCopy = popRef.querySelector("[data-update-err-copy]");
852
+ if (updateErrCopy !== null) {
853
+ updateErrCopy.addEventListener("click", () => {
854
+ if (!updateErrorDetail) return;
855
+ const text = String(updateErrorDetail.error || "") + "\n" + String(updateErrorDetail.output || "");
856
+ navigator.clipboard?.writeText(text).then(() => {
857
+ updateErrCopy.textContent = t("copied");
858
+ setTimeout(() => updateErrCopy.textContent = t("copyError"), 1500);
859
+ }).catch(() => {
860
+ updateErrCopy.textContent = t("copyFailed");
861
+ setTimeout(() => updateErrCopy.textContent = t("copyError"), 1500);
862
+ });
863
+ });
864
+ }
838
865
  const addBtn = popRef.querySelector("[data-add]");
839
866
  if (addBtn !== null) addBtn.addEventListener("click", () => { addFormState = { kind: "mimo", label: "", key: "", cookie: "" }; showAddForm = true; renderPopover(); });
840
867
  const cancelBtn = popRef.querySelector("[data-cancel]");
@@ -1221,11 +1248,28 @@ window.__ModuleLoader__.load({
1221
1248
  }
1222
1249
  const updated = lastUpdated ? lastUpdated.toLocaleTimeString() : "—";
1223
1250
  const versionHtml = versionHtmlOf(lastVersion);
1251
+ const errorPanel = updateErrorDetail ? updateErrorHtml(updateErrorDetail) : "";
1224
1252
  return header + syncHint + body +
1225
1253
  '<div class="dshBalanceFoot">' + versionHtml +
1226
1254
  '<span style="display:flex;align-items:center;gap:8px">' +
1227
1255
  '<button class="dshBalanceBtn" type="button" data-refresh>' + t("refresh") + "</button>" +
1228
- '<span>' + t("updatedAt") + updated + "</span></span></div>";
1256
+ '<span>' + t("updatedAt") + updated + "</span></span></div>" + errorPanel;
1257
+ }
1258
+
1259
+ /** Render the update-failure detail panel shown below the footer. */
1260
+ function updateErrorHtml(detail) {
1261
+ const summary = String(detail.error || t("updateFailed"));
1262
+ const text = (detail.output || "").trim();
1263
+ const snippet = text.slice(-500) || summary;
1264
+ const escaped = snippet.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
1265
+ return '<div class="dshBalanceUpdateErr">' +
1266
+ '<div class="dshBalanceUpdateErrHead">' +
1267
+ '<span>' + t("updateFailed") + "</span>" +
1268
+ '<button class="dshBalanceUpdateErrClose" type="button" data-update-err-close aria-label="close">×</button>' +
1269
+ "</div>" +
1270
+ '<pre class="dshBalanceUpdateErrBody" title="' + t("updateFailed") + '">' + escaped + "</pre>" +
1271
+ '<button class="dshBalanceBtn" type="button" data-update-err-copy>' + t("copyError") + "</button>" +
1272
+ "</div>";
1229
1273
  }
1230
1274
 
1231
1275
  /** Build the npm version snippet shown in the footer (always a clickable button). */
@@ -1452,6 +1496,8 @@ window.__ModuleLoader__.load({
1452
1496
  let timer = null;
1453
1497
  let versionTimer = null;
1454
1498
  let updateSuccessUntil = 0;
1499
+ /** When the last update attempt failed, hold {error, output} so the user can inspect it. */
1500
+ let updateErrorDetail = null;
1455
1501
 
1456
1502
  /** One refresh cycle: fetch balance + usage + providers, update entry and popover. */
1457
1503
  async function refresh(manual) {
package/lib/index.js CHANGED
@@ -601,12 +601,22 @@ function cleanEnv() {
601
601
  const env = { ...process.env };
602
602
  const no = env.NODE_OPTIONS || "";
603
603
  if (/genie-safe-delete/i.test(no)) {
604
+ // Strip the WorkBuddy safe-delete shim entirely. The shim monkey-patches
605
+ // fs.unlink/rm to route through a trash channel which is disabled inside
606
+ // the desktop sandbox, causing pnpm/npm to fail-closed whenever they delete
607
+ // temporary files during an install. Removing the --require prevents the
608
+ // child Node process from loading it at all.
604
609
  env.NODE_OPTIONS = no
605
610
  .replace(/\s*--require="[^"]*genie-safe-delete[^"]*"/gi, "")
606
611
  .replace(/\s*--require=[^\s"]*genie-safe-delete[^\s"]*/gi, "")
607
612
  .trim();
608
613
  if (!env.NODE_OPTIONS) delete env.NODE_OPTIONS;
609
614
  }
615
+ // Also delete any remaining WorkBuddy/shim variables that can re-enable
616
+ // safe-delete behavior in spawned package managers.
617
+ delete env.WORKBUDDY_SAFE_DELETE;
618
+ delete env.GENIE_SAFE_DELETE;
619
+ delete env.SAFE_DELETE_ENABLED;
610
620
  env.NPM_CONFIG_FUND = "false";
611
621
  env.NPM_CONFIG_AUDIT = "false";
612
622
  return env;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-deepseek-balance-widget",
3
- "version": "2.3.7",
3
+ "version": "2.3.8",
4
4
  "type": "module",
5
5
  "description": "Multi-provider AI balance widget for the dsh web sidebar: a live, auto-refreshing balance pill plus a detail popover listing DeepSeek and any added providers (MiMo etc.). Keys are stored per-machine in ~/.dsh/ai-balances.json and resolved from the local credential seam, never hardcoded.",
6
6
  "keywords": [