dsh-codearts 1.2.8 → 1.2.10

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 CHANGED
@@ -3,6 +3,29 @@
3
3
  本文件记录本插件的重要改动。格式参考 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/),
4
4
  版本号遵循 [语义化版本](https://semver.org/lang/zh-CN/)。
5
5
 
6
+ ## [1.2.10] - 2026-11-06
7
+
8
+ ### 新增
9
+
10
+ - **每个账号都能「重新登录」,凭证写回原条目**:以前账号过期时卡片上只有「删除」,
11
+ 要先删掉再加回来,账号的展示顺序和备注全丢。现在账号行多了「重新登录」按钮
12
+ (过期的账号显示为主色按钮),走一遍浏览器 OAuth 就把新凭证写回同一条,id、顺序、
13
+ 备注都保留。手工粘贴 token 的账号同样适用。
14
+ - 点了 A 账号的重登却登成了 B 账号时,B 会作为新账号添加,A 原样不动,并提示
15
+ 「你登录的是另一个账号,已作为新账号添加;原账号保持不变」——不会把 A 的凭证
16
+ 悄悄换成别人的。
17
+
18
+ ## [1.2.9] - 2026-11-06
19
+
20
+ ### 变更
21
+
22
+ - **热力图的悬停提示统一成明细卡**:日历格子和逐小时格子原来只有浏览器原生
23
+ `title`(一个灰底小文字框),下面再挂一行同内容的小字;现在和「按账号 / 按模型」
24
+ 的用量条共用同一张悬停卡 —— 标题、分隔线、输入 / 输出 / 思考 / 缓存 / 请求 /
25
+ 命中率,数字精确到个位。卡片贴着指针画(格子只有 36px 宽,锚在格子上会横穿整张
26
+ 卡片),靠近视口右/下边界时自动翻到另一侧。底部那行改成固定的操作提示,不再复述
27
+ 明细。
28
+
6
29
  ## [1.2.8] - 2026-11-05
7
30
 
8
31
  ### 变更
package/lib/bin.mjs CHANGED
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
- import { R as isBenefitModel, V as CodeArtsAccountStore, W as codeartsAccountsPath, d as fetchCallerIdentity, n as codeartsUsagePath, r as discoverModels, t as CodeArtsUsageTracker } from "./usage-B2LNsUuR.mjs";
2
+ import { R as isBenefitModel, V as CodeArtsAccountStore, W as codeartsAccountsPath, d as fetchCallerIdentity, n as codeartsUsagePath, r as discoverModels, t as CodeArtsUsageTracker } from "./usage-CjPd0Gok.mjs";
3
3
  import { existsSync, statSync } from "node:fs";
4
4
  //#region src/version.ts
5
- const CODEARTS_VERSION = "1.2.8";
5
+ const CODEARTS_VERSION = "1.2.10";
6
6
  //#endregion
7
7
  //#region src/bin.ts
8
8
  /**
@@ -32,6 +32,12 @@ interface CodeArtsSettingsKey {
32
32
  expiredHint: string;
33
33
  accountsTitle: string;
34
34
  accountRemove: string;
35
+ /** 重新登录这个账号:新凭证写回原条目,不会多出一条。 */
36
+ accountRelogin: string;
37
+ /** 该账号正在浏览器里授权。 */
38
+ reloginPending: string;
39
+ /** 「重新登录」却登了另一个账号:已作为新账号添加,原账号未动。 */
40
+ reloginOtherAccount: string;
35
41
  addAccount: string;
36
42
  pasteTokenAdd: string;
37
43
  accountsRotateHint: string;
@@ -62,7 +62,7 @@ function subscribeSidebarPanelWanted(listener) {
62
62
  }
63
63
  //#endregion
64
64
  //#region \0dsh-css:/home/runner/work/dsh-codearts/dsh-codearts/src/client/CodeArtsPluginCard.module.css.mjs
65
- const css$1 = ".xoziZG_card{border:.5px solid var(--dsw-alias-settings-card-stroke);border-radius:var(--dsw-radius-lg);background:var(--dsw-alias-settings-card-fill);max-width:720px}.xoziZG_header{align-items:flex-start;gap:12px;padding:14px 16px;display:flex}.xoziZG_headText{flex-direction:column;flex:1;gap:6px;min-width:0;display:flex}.xoziZG_name{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:22px}.xoziZG_desc{color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:20px}.xoziZG_statusLine{color:var(--dsw-alias-label-primary);align-items:center;gap:6px;font-size:14px;font-weight:500;line-height:22px;display:inline-flex}.xoziZG_meta{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;font-size:12px;line-height:18px}.xoziZG_body{border-top:.5px solid var(--dsw-alias-border-l2);margin:0 16px;padding:4px 0 16px}.xoziZG_tabs{margin-top:12px}.xoziZG_tabPanel{padding-top:2px}.xoziZG_accountToolbar{gap:8px;margin-top:12px;display:flex}.xoziZG_accountToolbar>*{flex:1}.xoziZG_manualForm{border:.5px solid var(--dsw-alias-border-l3);border-radius:var(--dsw-radius-md);margin-top:12px;padding:12px}.xoziZG_accountCard{flex-direction:column;gap:10px;margin-top:12px;display:flex}.xoziZG_accountEntry{border:.5px solid var(--dsw-alias-border-l2);border-radius:var(--dsw-radius-md);background:var(--dsw-alias-bg-layer-2)}.xoziZG_accountRow{align-items:center;gap:10px;padding:12px;display:flex}.xoziZG_claimAllRow{border-top:.5px solid var(--dsw-alias-border-l2);justify-content:flex-end;padding:10px 12px 0;display:flex}.xoziZG_avatar{background:var(--dsw-alias-bg-layer-3);width:32px;height:32px;color:var(--dsw-alias-label-primary);border-radius:50%;flex:none;justify-content:center;align-items:center;font-size:14px;font-weight:600;display:inline-flex}.xoziZG_accountInfo{flex-direction:column;flex:1;gap:2px;min-width:0;display:flex}.xoziZG_accountNameRow{align-items:center;gap:6px;min-width:0;display:flex}.xoziZG_accountName{color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;font-size:14px;font-weight:600;line-height:20px;overflow:hidden}.xoziZG_accountRowActions{flex:none;gap:6px;display:flex}.xoziZG_accountHint{color:var(--dsw-alias-label-tertiary);margin:0;padding:0 12px 12px;font-size:12px;line-height:18px}.xoziZG_creditBlock{border-top:.5px solid var(--dsw-alias-border-l2);padding:12px}.xoziZG_balanceRow{flex-wrap:wrap;align-items:baseline;gap:6px;display:flex}.xoziZG_balance{color:var(--dsw-alias-label-primary);letter-spacing:-.02em;font-variant-numeric:tabular-nums;font-size:28px;font-weight:600;line-height:34px}.xoziZG_balanceUnit{color:var(--dsw-alias-label-secondary);font-size:12px}.xoziZG_balanceMeta{color:var(--dsw-alias-label-tertiary);margin-left:2px;font-size:12px}.xoziZG_updated{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;margin-left:auto;font-size:12px}.xoziZG_creditRows{flex-direction:column;gap:4px;margin-top:8px;display:flex}.xoziZG_creditRow{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;justify-content:space-between;align-items:baseline;gap:12px;font-size:12px;line-height:18px;display:flex}.xoziZG_usageBar{background:var(--dsw-alias-border-l2);border-radius:2px;height:4px;margin-top:4px;display:block;overflow:hidden}.xoziZG_usageFill{background:var(--dsw-alias-brand-primary);border-radius:2px;height:100%;transition:width .2s;display:block}.xoziZG_expiryRow{margin-top:2px}.xoziZG_expiryLabel{color:var(--dsw-alias-state-warn-label)}.xoziZG_bar{background:var(--dsw-alias-bg-layer-3);border-radius:2px;height:4px;margin-top:6px;display:block;overflow:hidden}.xoziZG_barFill{background:var(--dsw-alias-state-warn-primary);border-radius:2px;height:100%;display:block}.xoziZG_creditLink{margin-top:8px;display:inline-block}.xoziZG_creditFooter{border-top:.5px solid var(--dsw-alias-border-l2);justify-content:space-between;align-items:center;gap:8px;margin-top:12px;padding-top:10px;display:flex}.xoziZG_creditHint{color:var(--dsw-alias-label-tertiary);margin:8px 0 0;font-size:12px;line-height:18px}.xoziZG_section{margin-top:16px}.xoziZG_sectionHead{justify-content:space-between;align-items:baseline;gap:12px;display:flex}.xoziZG_sectionLabel{color:var(--dsw-alias-label-tertiary);font-size:11px;font-weight:500}.xoziZG_count{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;flex:none;font-size:12px}.xoziZG_hint{color:var(--dsw-alias-label-secondary);margin:8px 0 0;font-size:13px;line-height:20px}.xoziZG_error{color:var(--dsw-alias-state-error-primary);margin:10px 0 0;font-size:13px;line-height:20px}.xoziZG_actions{flex-wrap:wrap;align-items:center;gap:8px;margin-top:12px;display:flex}.xoziZG_danger{color:var(--dsw-alias-state-error-primary)}.xoziZG_link{appearance:none;color:var(--dsw-alias-brand-text);font:inherit;text-align:left;word-break:break-all;cursor:pointer;background:0 0;border:none;padding:0;font-size:12px}.xoziZG_link:hover{text-decoration:underline}.xoziZG_choices{flex-direction:column;gap:2px;margin-top:8px;display:flex}.xoziZG_choiceRow{border-radius:var(--dsw-radius-sm);align-items:center;gap:8px;margin:0 -6px;padding:5px 6px;display:flex}.xoziZG_choiceRow:hover{background:var(--dsw-alias-interactive-bg-hover)}.xoziZG_statGrid{grid-template-columns:repeat(3,minmax(0,1fr));gap:8px;margin:10px 0 14px;display:grid}.xoziZG_statCard{border:.5px solid var(--dsw-alias-border-l3);border-radius:var(--dsw-radius-md);flex-direction:column;gap:1px;padding:8px 10px;display:flex}.xoziZG_statLabel{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:16px}.xoziZG_statValue{color:var(--dsw-alias-label-primary);font-variant-numeric:tabular-nums;font-size:15px;line-height:20px}.xoziZG_statSub{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;font-size:11px;line-height:16px}.xoziZG_modelChart{flex-direction:column;gap:2px;margin-top:8px;display:flex}.xoziZG_modelRow{font-variant-numeric:tabular-nums;border-radius:6px;grid-template-columns:minmax(0,1.2fr) minmax(48px,1fr) 56px 52px 64px;align-items:center;gap:8px;padding:4px 0;display:grid;position:relative}.xoziZG_modelRow:hover{background:var(--dsw-alias-interactive-bg-hover)}.xoziZG_usageTip{z-index:5;border:.5px solid var(--dsw-alias-border-l3);border-radius:var(--dsw-radius-md);background:var(--dsw-alias-bg-layer-3);min-width:180px;max-width:260px;color:var(--dsw-alias-label-secondary);text-align:left;font-variant-numeric:tabular-nums;pointer-events:none;padding:8px 10px;font-size:12px;line-height:1.9;position:absolute;bottom:calc(100% + 6px);right:0;box-shadow:0 10px 28px #00000073}.xoziZG_usageTipName{max-width:240px;color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.xoziZG_usageTipSep{background:var(--dsw-alias-border-l2);height:1px;margin:4px 0}.xoziZG_usageTipRow{justify-content:space-between;gap:24px;display:flex}.xoziZG_usageTipRow span:last-child{color:var(--dsw-alias-label-primary);font-weight:600}.xoziZG_modelName{color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;font-size:12px;line-height:18px;overflow:hidden}.xoziZG_modelTrack{background:var(--dsw-alias-border-l2);border-radius:4px;height:8px;display:block;overflow:hidden}.xoziZG_modelFill{background:var(--dsw-alias-brand-primary);border-radius:4px;height:100%;transition:width .16s;display:block}.xoziZG_modelTokens,.xoziZG_modelShare,.xoziZG_modelRequests{color:var(--dsw-alias-label-secondary);text-align:right;white-space:nowrap;font-size:11px;line-height:16px}.xoziZG_modelRequests{color:var(--dsw-alias-label-tertiary)}.xoziZG_heatGrid{grid-template-columns:repeat(7,minmax(0,1fr));gap:4px;margin:8px 0 2px;display:grid}.xoziZG_heatWeekday{color:var(--dsw-alias-label-tertiary);text-align:center;font-size:10px;line-height:14px}.xoziZG_heatCell{background:color-mix(in srgb, var(--dsw-alias-label-primary) 6%, transparent);height:36px;color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;border:0;border-radius:8px;outline:0;justify-content:center;align-items:center;font-size:12px;transition:background .12s ease-out;display:flex}.xoziZG_heatCell[data-tone=empty]{color:var(--dsw-alias-label-tertiary)}.xoziZG_heatCell[data-tone=pad]{background:0 0}.xoziZG_heatCell[data-tone=out]{color:var(--dsw-alias-label-tertiary);opacity:.45;background:0 0}.xoziZG_heatCell[data-tone=lv1]{color:#0f1115;background:#ddf4e7}.xoziZG_heatCell[data-tone=lv2]{color:#0f1115;background:#b3e8cc}.xoziZG_heatCell[data-tone=lv3]{color:#0f1115;background:#7dd8ac}.xoziZG_heatCell[data-tone=lv4]{color:#fff;background:#40c584}.xoziZG_heatCell[data-tone=lv5]{color:#fff;background:#16a34a}.xoziZG_heatCell[data-today=true]{font-weight:700;box-shadow:inset 0 -2px}.xoziZG_heatHours{grid-template-columns:repeat(24,minmax(0,1fr));gap:3px;margin:8px 0 0;display:grid}.xoziZG_heatHourCell{background:color-mix(in srgb, var(--dsw-alias-label-primary) 6%, transparent);border-radius:4px;height:26px;transition:background .12s ease-out}.xoziZG_heatHourCell[data-tone=lv1]{background:#ddf4e7}.xoziZG_heatHourCell[data-tone=lv2]{background:#b3e8cc}.xoziZG_heatHourCell[data-tone=lv3]{background:#7dd8ac}.xoziZG_heatHourCell[data-tone=lv4]{background:#40c584}.xoziZG_heatHourCell[data-tone=lv5]{background:#16a34a}.xoziZG_heatAxis{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;grid-template-columns:repeat(24,minmax(0,1fr));gap:3px;font-size:10px;line-height:14px;display:grid}.xoziZG_heatAxisSlot{text-align:center;white-space:nowrap;overflow:hidden}.xoziZG_heatLegend{color:var(--dsw-alias-label-tertiary);justify-content:flex-start;align-items:center;gap:3px;margin:0 0 6px;font-size:10px;display:flex}.xoziZG_heatLegendChip{border-radius:3px;width:10px;height:10px}.xoziZG_heatLegendChip[data-tone=lv1]{background:#ddf4e7}.xoziZG_heatLegendChip[data-tone=lv2]{background:#b3e8cc}.xoziZG_heatLegendChip[data-tone=lv3]{background:#7dd8ac}.xoziZG_heatLegendChip[data-tone=lv4]{background:#40c584}.xoziZG_heatLegendChip[data-tone=lv5]{background:#16a34a}.xoziZG_trendTip{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;margin:2px 0 0;font-size:11px;line-height:16px}.xoziZG_check{flex:1;min-width:0}.xoziZG_check>span{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.xoziZG_manual{border:.5px solid var(--dsw-alias-border-l3);border-radius:var(--dsw-radius-md);margin-top:12px;padding:0 12px}.xoziZG_manual[open]{padding-bottom:12px}.xoziZG_manualSummary{color:var(--dsw-alias-label-secondary);cursor:pointer;align-items:center;gap:6px;padding:9px 0;font-size:13px;list-style:none;display:flex}.xoziZG_manualSummary::-webkit-details-marker{display:none}.xoziZG_field{flex-direction:column;gap:5px;margin-top:10px;display:flex}.xoziZG_fieldLabel{color:var(--dsw-alias-label-tertiary);font-size:12px}.xoziZG_area{box-sizing:border-box;resize:vertical;border:.5px solid var(--dsw-alias-border-l4);border-radius:var(--dsw-radius-md);background:var(--dsw-alias-bg-layer-1);width:100%;color:var(--dsw-alias-label-primary);padding:6px 8px;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:13px;line-height:20px}.xoziZG_area::placeholder{color:var(--dsw-alias-label-dimmed)}.xoziZG_area:focus{border-color:var(--dsw-alias-state-business-primary);outline:none}.xoziZG_skeleton{flex-direction:column;gap:10px;padding:4px 0;display:flex}.xoziZG_skeletonRow{border-radius:var(--dsw-radius-sm,4px);background:var(--dsw-alias-border-l2);height:12px;animation:1.4s ease-in-out infinite xoziZG_skeletonBreath}.xoziZG_skeletonRow:nth-child(2){width:72%}.xoziZG_skeletonRow:nth-child(3){width:46%}@keyframes xoziZG_skeletonBreath{0%,to{opacity:.45}50%{opacity:.9}}@media (prefers-reduced-motion:reduce){.xoziZG_skeletonRow{animation:none}}";
65
+ const css$1 = ".xoziZG_card{border:.5px solid var(--dsw-alias-settings-card-stroke);border-radius:var(--dsw-radius-lg);background:var(--dsw-alias-settings-card-fill);max-width:720px}.xoziZG_header{align-items:flex-start;gap:12px;padding:14px 16px;display:flex}.xoziZG_headText{flex-direction:column;flex:1;gap:6px;min-width:0;display:flex}.xoziZG_name{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:22px}.xoziZG_desc{color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:20px}.xoziZG_statusLine{color:var(--dsw-alias-label-primary);align-items:center;gap:6px;font-size:14px;font-weight:500;line-height:22px;display:inline-flex}.xoziZG_meta{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;font-size:12px;line-height:18px}.xoziZG_body{border-top:.5px solid var(--dsw-alias-border-l2);margin:0 16px;padding:4px 0 16px}.xoziZG_tabs{margin-top:12px}.xoziZG_tabPanel{padding-top:2px}.xoziZG_accountToolbar{gap:8px;margin-top:12px;display:flex}.xoziZG_accountToolbar>*{flex:1}.xoziZG_manualForm{border:.5px solid var(--dsw-alias-border-l3);border-radius:var(--dsw-radius-md);margin-top:12px;padding:12px}.xoziZG_accountCard{flex-direction:column;gap:10px;margin-top:12px;display:flex}.xoziZG_accountEntry{border:.5px solid var(--dsw-alias-border-l2);border-radius:var(--dsw-radius-md);background:var(--dsw-alias-bg-layer-2)}.xoziZG_accountRow{align-items:center;gap:10px;padding:12px;display:flex}.xoziZG_claimAllRow{border-top:.5px solid var(--dsw-alias-border-l2);justify-content:flex-end;padding:10px 12px 0;display:flex}.xoziZG_avatar{background:var(--dsw-alias-bg-layer-3);width:32px;height:32px;color:var(--dsw-alias-label-primary);border-radius:50%;flex:none;justify-content:center;align-items:center;font-size:14px;font-weight:600;display:inline-flex}.xoziZG_accountInfo{flex-direction:column;flex:1;gap:2px;min-width:0;display:flex}.xoziZG_accountNameRow{align-items:center;gap:6px;min-width:0;display:flex}.xoziZG_accountName{color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;font-size:14px;font-weight:600;line-height:20px;overflow:hidden}.xoziZG_accountRowActions{flex-wrap:wrap;flex:none;justify-content:flex-end;gap:6px;display:flex}.xoziZG_accountHint{color:var(--dsw-alias-label-tertiary);margin:0;padding:0 12px 12px;font-size:12px;line-height:18px}.xoziZG_creditBlock{border-top:.5px solid var(--dsw-alias-border-l2);padding:12px}.xoziZG_balanceRow{flex-wrap:wrap;align-items:baseline;gap:6px;display:flex}.xoziZG_balance{color:var(--dsw-alias-label-primary);letter-spacing:-.02em;font-variant-numeric:tabular-nums;font-size:28px;font-weight:600;line-height:34px}.xoziZG_balanceUnit{color:var(--dsw-alias-label-secondary);font-size:12px}.xoziZG_balanceMeta{color:var(--dsw-alias-label-tertiary);margin-left:2px;font-size:12px}.xoziZG_updated{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;margin-left:auto;font-size:12px}.xoziZG_creditRows{flex-direction:column;gap:4px;margin-top:8px;display:flex}.xoziZG_creditRow{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;justify-content:space-between;align-items:baseline;gap:12px;font-size:12px;line-height:18px;display:flex}.xoziZG_usageBar{background:var(--dsw-alias-border-l2);border-radius:2px;height:4px;margin-top:4px;display:block;overflow:hidden}.xoziZG_usageFill{background:var(--dsw-alias-brand-primary);border-radius:2px;height:100%;transition:width .2s;display:block}.xoziZG_expiryRow{margin-top:2px}.xoziZG_expiryLabel{color:var(--dsw-alias-state-warn-label)}.xoziZG_bar{background:var(--dsw-alias-bg-layer-3);border-radius:2px;height:4px;margin-top:6px;display:block;overflow:hidden}.xoziZG_barFill{background:var(--dsw-alias-state-warn-primary);border-radius:2px;height:100%;display:block}.xoziZG_creditLink{margin-top:8px;display:inline-block}.xoziZG_creditFooter{border-top:.5px solid var(--dsw-alias-border-l2);justify-content:space-between;align-items:center;gap:8px;margin-top:12px;padding-top:10px;display:flex}.xoziZG_creditHint{color:var(--dsw-alias-label-tertiary);margin:8px 0 0;font-size:12px;line-height:18px}.xoziZG_section{margin-top:16px}.xoziZG_sectionHead{justify-content:space-between;align-items:baseline;gap:12px;display:flex}.xoziZG_sectionLabel{color:var(--dsw-alias-label-tertiary);font-size:11px;font-weight:500}.xoziZG_count{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;flex:none;font-size:12px}.xoziZG_hint{color:var(--dsw-alias-label-secondary);margin:8px 0 0;font-size:13px;line-height:20px}.xoziZG_error{color:var(--dsw-alias-state-error-primary);margin:10px 0 0;font-size:13px;line-height:20px}.xoziZG_actions{flex-wrap:wrap;align-items:center;gap:8px;margin-top:12px;display:flex}.xoziZG_danger{color:var(--dsw-alias-state-error-primary)}.xoziZG_link{appearance:none;color:var(--dsw-alias-brand-text);font:inherit;text-align:left;word-break:break-all;cursor:pointer;background:0 0;border:none;padding:0;font-size:12px}.xoziZG_link:hover{text-decoration:underline}.xoziZG_choices{flex-direction:column;gap:2px;margin-top:8px;display:flex}.xoziZG_choiceRow{border-radius:var(--dsw-radius-sm);align-items:center;gap:8px;margin:0 -6px;padding:5px 6px;display:flex}.xoziZG_choiceRow:hover{background:var(--dsw-alias-interactive-bg-hover)}.xoziZG_statGrid{grid-template-columns:repeat(3,minmax(0,1fr));gap:8px;margin:10px 0 14px;display:grid}.xoziZG_statCard{border:.5px solid var(--dsw-alias-border-l3);border-radius:var(--dsw-radius-md);flex-direction:column;gap:1px;padding:8px 10px;display:flex}.xoziZG_statLabel{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:16px}.xoziZG_statValue{color:var(--dsw-alias-label-primary);font-variant-numeric:tabular-nums;font-size:15px;line-height:20px}.xoziZG_statSub{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;font-size:11px;line-height:16px}.xoziZG_modelChart{flex-direction:column;gap:2px;margin-top:8px;display:flex}.xoziZG_modelRow{font-variant-numeric:tabular-nums;border-radius:6px;grid-template-columns:minmax(0,1.2fr) minmax(48px,1fr) 56px 52px 64px;align-items:center;gap:8px;padding:4px 0;display:grid;position:relative}.xoziZG_modelRow:hover{background:var(--dsw-alias-interactive-bg-hover)}.xoziZG_usageTip{z-index:5;border:.5px solid var(--dsw-alias-border-l3);border-radius:var(--dsw-radius-md);background:var(--dsw-alias-bg-layer-3);min-width:180px;max-width:260px;color:var(--dsw-alias-label-secondary);text-align:left;font-variant-numeric:tabular-nums;pointer-events:none;padding:8px 10px;font-size:12px;line-height:1.9;position:absolute;bottom:calc(100% + 6px);right:0;box-shadow:0 10px 28px #00000073}.xoziZG_usageTip[data-float=true]{z-index:40;position:fixed;bottom:auto;right:auto}.xoziZG_usageTipName{max-width:240px;color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.xoziZG_usageTipSep{background:var(--dsw-alias-border-l2);height:1px;margin:4px 0}.xoziZG_usageTipRow{justify-content:space-between;gap:24px;display:flex}.xoziZG_usageTipRow span:last-child{color:var(--dsw-alias-label-primary);font-weight:600}.xoziZG_modelName{color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;font-size:12px;line-height:18px;overflow:hidden}.xoziZG_modelTrack{background:var(--dsw-alias-border-l2);border-radius:4px;height:8px;display:block;overflow:hidden}.xoziZG_modelFill{background:var(--dsw-alias-brand-primary);border-radius:4px;height:100%;transition:width .16s;display:block}.xoziZG_modelTokens,.xoziZG_modelShare,.xoziZG_modelRequests{color:var(--dsw-alias-label-secondary);text-align:right;white-space:nowrap;font-size:11px;line-height:16px}.xoziZG_modelRequests{color:var(--dsw-alias-label-tertiary)}.xoziZG_heatGrid{grid-template-columns:repeat(7,minmax(0,1fr));gap:4px;margin:8px 0 2px;display:grid}.xoziZG_heatWeekday{color:var(--dsw-alias-label-tertiary);text-align:center;font-size:10px;line-height:14px}.xoziZG_heatCell{background:color-mix(in srgb, var(--dsw-alias-label-primary) 6%, transparent);height:36px;color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;border:0;border-radius:8px;outline:0;justify-content:center;align-items:center;font-size:12px;transition:background .12s ease-out;display:flex}.xoziZG_heatCell[data-tone=empty]{color:var(--dsw-alias-label-tertiary)}.xoziZG_heatCell[data-tone=pad]{background:0 0}.xoziZG_heatCell[data-tone=out]{color:var(--dsw-alias-label-tertiary);opacity:.45;background:0 0}.xoziZG_heatCell[data-tone=lv1]{color:#0f1115;background:#ddf4e7}.xoziZG_heatCell[data-tone=lv2]{color:#0f1115;background:#b3e8cc}.xoziZG_heatCell[data-tone=lv3]{color:#0f1115;background:#7dd8ac}.xoziZG_heatCell[data-tone=lv4]{color:#fff;background:#40c584}.xoziZG_heatCell[data-tone=lv5]{color:#fff;background:#16a34a}.xoziZG_heatCell[data-today=true]{font-weight:700;box-shadow:inset 0 -2px}.xoziZG_heatHours{grid-template-columns:repeat(24,minmax(0,1fr));gap:3px;margin:8px 0 0;display:grid}.xoziZG_heatHourCell{background:color-mix(in srgb, var(--dsw-alias-label-primary) 6%, transparent);border-radius:4px;height:26px;transition:background .12s ease-out}.xoziZG_heatHourCell[data-tone=lv1]{background:#ddf4e7}.xoziZG_heatHourCell[data-tone=lv2]{background:#b3e8cc}.xoziZG_heatHourCell[data-tone=lv3]{background:#7dd8ac}.xoziZG_heatHourCell[data-tone=lv4]{background:#40c584}.xoziZG_heatHourCell[data-tone=lv5]{background:#16a34a}.xoziZG_heatAxis{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;grid-template-columns:repeat(24,minmax(0,1fr));gap:3px;font-size:10px;line-height:14px;display:grid}.xoziZG_heatAxisSlot{text-align:center;white-space:nowrap;overflow:hidden}.xoziZG_heatLegend{color:var(--dsw-alias-label-tertiary);justify-content:flex-start;align-items:center;gap:3px;margin:0 0 6px;font-size:10px;display:flex}.xoziZG_heatLegendChip{border-radius:3px;width:10px;height:10px}.xoziZG_heatLegendChip[data-tone=lv1]{background:#ddf4e7}.xoziZG_heatLegendChip[data-tone=lv2]{background:#b3e8cc}.xoziZG_heatLegendChip[data-tone=lv3]{background:#7dd8ac}.xoziZG_heatLegendChip[data-tone=lv4]{background:#40c584}.xoziZG_heatLegendChip[data-tone=lv5]{background:#16a34a}.xoziZG_trendTip{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;margin:2px 0 0;font-size:11px;line-height:16px}.xoziZG_check{flex:1;min-width:0}.xoziZG_check>span{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.xoziZG_manual{border:.5px solid var(--dsw-alias-border-l3);border-radius:var(--dsw-radius-md);margin-top:12px;padding:0 12px}.xoziZG_manual[open]{padding-bottom:12px}.xoziZG_manualSummary{color:var(--dsw-alias-label-secondary);cursor:pointer;align-items:center;gap:6px;padding:9px 0;font-size:13px;list-style:none;display:flex}.xoziZG_manualSummary::-webkit-details-marker{display:none}.xoziZG_field{flex-direction:column;gap:5px;margin-top:10px;display:flex}.xoziZG_fieldLabel{color:var(--dsw-alias-label-tertiary);font-size:12px}.xoziZG_area{box-sizing:border-box;resize:vertical;border:.5px solid var(--dsw-alias-border-l4);border-radius:var(--dsw-radius-md);background:var(--dsw-alias-bg-layer-1);width:100%;color:var(--dsw-alias-label-primary);padding:6px 8px;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:13px;line-height:20px}.xoziZG_area::placeholder{color:var(--dsw-alias-label-dimmed)}.xoziZG_area:focus{border-color:var(--dsw-alias-state-business-primary);outline:none}.xoziZG_skeleton{flex-direction:column;gap:10px;padding:4px 0;display:flex}.xoziZG_skeletonRow{border-radius:var(--dsw-radius-sm,4px);background:var(--dsw-alias-border-l2);height:12px;animation:1.4s ease-in-out infinite xoziZG_skeletonBreath}.xoziZG_skeletonRow:nth-child(2){width:72%}.xoziZG_skeletonRow:nth-child(3){width:46%}@keyframes xoziZG_skeletonBreath{0%,to{opacity:.45}50%{opacity:.9}}@media (prefers-reduced-motion:reduce){.xoziZG_skeletonRow{animation:none}}";
66
66
  const tagId$1 = "dsh-codearts/CodeArtsPluginCard.module.css";
67
67
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
68
68
  const tag = document.createElement("style");
@@ -72,92 +72,92 @@ if (typeof document !== "undefined" && document.querySelector("style[data-plugin
72
72
  document.head.appendChild(tag);
73
73
  }
74
74
  var CodeArtsPluginCard_module_css_default = {
75
- "heatWeekday": "xoziZG_heatWeekday",
76
- "headText": "xoziZG_headText",
77
- "sectionLabel": "xoziZG_sectionLabel",
78
- "avatar": "xoziZG_avatar",
79
- "usageFill": "xoziZG_usageFill",
80
- "creditLink": "xoziZG_creditLink",
81
- "modelRequests": "xoziZG_modelRequests",
82
- "hint": "xoziZG_hint",
83
- "usageTipSep": "xoziZG_usageTipSep",
84
- "usageTipRow": "xoziZG_usageTipRow",
85
- "expiryLabel": "xoziZG_expiryLabel",
86
- "area": "xoziZG_area",
87
- "balanceUnit": "xoziZG_balanceUnit",
88
- "sectionHead": "xoziZG_sectionHead",
89
- "danger": "xoziZG_danger",
90
- "modelFill": "xoziZG_modelFill",
91
- "creditRow": "xoziZG_creditRow",
92
- "choices": "xoziZG_choices",
93
- "modelRow": "xoziZG_modelRow",
94
- "creditHint": "xoziZG_creditHint",
95
- "desc": "xoziZG_desc",
96
- "header": "xoziZG_header",
97
75
  "accountHint": "xoziZG_accountHint",
98
- "heatCell": "xoziZG_heatCell",
99
76
  "heatLegendChip": "xoziZG_heatLegendChip",
100
- "check": "xoziZG_check",
101
- "fieldLabel": "xoziZG_fieldLabel",
102
- "statusLine": "xoziZG_statusLine",
103
- "skeletonRow": "xoziZG_skeletonRow",
104
- "tabPanel": "xoziZG_tabPanel",
105
- "accountInfo": "xoziZG_accountInfo",
106
- "usageBar": "xoziZG_usageBar",
107
- "heatHourCell": "xoziZG_heatHourCell",
108
- "creditFooter": "xoziZG_creditFooter",
109
- "statValue": "xoziZG_statValue",
110
77
  "balance": "xoziZG_balance",
111
- "tabs": "xoziZG_tabs",
112
- "count": "xoziZG_count",
113
- "usageTip": "xoziZG_usageTip",
114
78
  "claimAllRow": "xoziZG_claimAllRow",
115
- "creditRows": "xoziZG_creditRows",
116
- "link": "xoziZG_link",
117
- "accountNameRow": "xoziZG_accountNameRow",
118
- "accountName": "xoziZG_accountName",
119
- "modelShare": "xoziZG_modelShare",
120
- "choiceRow": "xoziZG_choiceRow",
121
- "manual": "xoziZG_manual",
122
- "modelTokens": "xoziZG_modelTokens",
123
- "skeleton": "xoziZG_skeleton",
124
- "statSub": "xoziZG_statSub",
79
+ "balanceUnit": "xoziZG_balanceUnit",
80
+ "heatAxisSlot": "xoziZG_heatAxisSlot",
81
+ "creditBlock": "xoziZG_creditBlock",
82
+ "statusLine": "xoziZG_statusLine",
83
+ "modelChart": "xoziZG_modelChart",
84
+ "sectionHead": "xoziZG_sectionHead",
85
+ "usageBar": "xoziZG_usageBar",
86
+ "accountCard": "xoziZG_accountCard",
125
87
  "usageTipName": "xoziZG_usageTipName",
88
+ "choiceRow": "xoziZG_choiceRow",
89
+ "fieldLabel": "xoziZG_fieldLabel",
90
+ "modelRow": "xoziZG_modelRow",
91
+ "expiryRow": "xoziZG_expiryRow",
92
+ "headText": "xoziZG_headText",
93
+ "modelTrack": "xoziZG_modelTrack",
94
+ "heatHourCell": "xoziZG_heatHourCell",
95
+ "header": "xoziZG_header",
96
+ "accountToolbar": "xoziZG_accountToolbar",
97
+ "statGrid": "xoziZG_statGrid",
98
+ "skeletonBreath": "xoziZG_skeletonBreath",
99
+ "balanceRow": "xoziZG_balanceRow",
100
+ "modelFill": "xoziZG_modelFill",
126
101
  "heatAxis": "xoziZG_heatAxis",
127
- "name": "xoziZG_name",
128
- "card": "xoziZG_card",
102
+ "accountRow": "xoziZG_accountRow",
103
+ "heatGrid": "xoziZG_heatGrid",
104
+ "field": "xoziZG_field",
105
+ "link": "xoziZG_link",
106
+ "heatHours": "xoziZG_heatHours",
107
+ "tabPanel": "xoziZG_tabPanel",
108
+ "choices": "xoziZG_choices",
109
+ "desc": "xoziZG_desc",
110
+ "creditHint": "xoziZG_creditHint",
111
+ "creditFooter": "xoziZG_creditFooter",
112
+ "accountInfo": "xoziZG_accountInfo",
129
113
  "manualForm": "xoziZG_manualForm",
130
- "accountCard": "xoziZG_accountCard",
131
- "statGrid": "xoziZG_statGrid",
132
- "modelTrack": "xoziZG_modelTrack",
133
- "accountRowActions": "xoziZG_accountRowActions",
114
+ "card": "xoziZG_card",
134
115
  "actions": "xoziZG_actions",
116
+ "usageFill": "xoziZG_usageFill",
117
+ "usageTipRow": "xoziZG_usageTipRow",
118
+ "modelTokens": "xoziZG_modelTokens",
135
119
  "trendTip": "xoziZG_trendTip",
136
- "field": "xoziZG_field",
137
- "creditBlock": "xoziZG_creditBlock",
138
- "error": "xoziZG_error",
139
- "statCard": "xoziZG_statCard",
140
- "heatLegend": "xoziZG_heatLegend",
141
- "statLabel": "xoziZG_statLabel",
142
- "barFill": "xoziZG_barFill",
120
+ "section": "xoziZG_section",
121
+ "tabs": "xoziZG_tabs",
143
122
  "meta": "xoziZG_meta",
144
- "modelChart": "xoziZG_modelChart",
145
- "balanceRow": "xoziZG_balanceRow",
146
123
  "bar": "xoziZG_bar",
147
- "section": "xoziZG_section",
148
- "heatGrid": "xoziZG_heatGrid",
149
- "heatAxisSlot": "xoziZG_heatAxisSlot",
150
- "heatHours": "xoziZG_heatHours",
124
+ "barFill": "xoziZG_barFill",
125
+ "modelRequests": "xoziZG_modelRequests",
126
+ "skeleton": "xoziZG_skeleton",
127
+ "modelName": "xoziZG_modelName",
128
+ "updated": "xoziZG_updated",
151
129
  "manualSummary": "xoziZG_manualSummary",
152
- "body": "xoziZG_body",
130
+ "area": "xoziZG_area",
131
+ "statCard": "xoziZG_statCard",
132
+ "heatWeekday": "xoziZG_heatWeekday",
133
+ "creditRow": "xoziZG_creditRow",
134
+ "check": "xoziZG_check",
135
+ "accountNameRow": "xoziZG_accountNameRow",
136
+ "skeletonRow": "xoziZG_skeletonRow",
153
137
  "balanceMeta": "xoziZG_balanceMeta",
154
- "expiryRow": "xoziZG_expiryRow",
155
- "skeletonBreath": "xoziZG_skeletonBreath",
138
+ "statSub": "xoziZG_statSub",
139
+ "count": "xoziZG_count",
140
+ "name": "xoziZG_name",
141
+ "accountRowActions": "xoziZG_accountRowActions",
142
+ "danger": "xoziZG_danger",
143
+ "statLabel": "xoziZG_statLabel",
144
+ "usageTipSep": "xoziZG_usageTipSep",
145
+ "modelShare": "xoziZG_modelShare",
146
+ "heatCell": "xoziZG_heatCell",
147
+ "heatLegend": "xoziZG_heatLegend",
148
+ "manual": "xoziZG_manual",
149
+ "avatar": "xoziZG_avatar",
150
+ "error": "xoziZG_error",
151
+ "body": "xoziZG_body",
152
+ "creditLink": "xoziZG_creditLink",
153
+ "accountName": "xoziZG_accountName",
154
+ "statValue": "xoziZG_statValue",
155
+ "expiryLabel": "xoziZG_expiryLabel",
156
+ "hint": "xoziZG_hint",
157
+ "usageTip": "xoziZG_usageTip",
156
158
  "accountEntry": "xoziZG_accountEntry",
157
- "accountRow": "xoziZG_accountRow",
158
- "accountToolbar": "xoziZG_accountToolbar",
159
- "updated": "xoziZG_updated",
160
- "modelName": "xoziZG_modelName"
159
+ "sectionLabel": "xoziZG_sectionLabel",
160
+ "creditRows": "xoziZG_creditRows"
161
161
  };
162
162
  //#endregion
163
163
  //#region src/client/CodeArtsPluginCard.tsx
@@ -444,6 +444,62 @@ function hitPercentOf(totals) {
444
444
  return Math.min(100, Math.round(cached / totals.promptTokens * 100));
445
445
  }
446
446
  /**
447
+ * 悬停明细卡的正文:标题(账号 / 模型 / 日期 / 钟点)+ 输入 / 输出 / 思考 / 缓存 /
448
+ * 请求 / 命中率。用量条和热力图格子共用这一份,改文案或加字段只需动这里。
449
+ */
450
+ function UsageTipBody({ label, totals, t }) {
451
+ const cached = totals.cachedTokens;
452
+ const pct = hitPercentOf(totals);
453
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
454
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
455
+ className: CodeArtsPluginCard_module_css_default.usageTipName,
456
+ children: label
457
+ }),
458
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: CodeArtsPluginCard_module_css_default.usageTipSep }),
459
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
460
+ className: CodeArtsPluginCard_module_css_default.usageTipRow,
461
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("usageTipInput") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: exactCount(totals.promptTokens) })]
462
+ }),
463
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
464
+ className: CodeArtsPluginCard_module_css_default.usageTipRow,
465
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("usageTipOutput") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: exactCount(totals.completionTokens) })]
466
+ }),
467
+ (totals.reasoningTokens ?? 0) > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
468
+ className: CodeArtsPluginCard_module_css_default.usageTipRow,
469
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("usageTipReasoning") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: exactCount(totals.reasoningTokens ?? 0) })]
470
+ }),
471
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
472
+ className: CodeArtsPluginCard_module_css_default.usageTipRow,
473
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("usageTipCached") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: cached === void 0 ? t("usageTipNoCache") : exactCount(cached) })]
474
+ }),
475
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: CodeArtsPluginCard_module_css_default.usageTipSep }),
476
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
477
+ className: CodeArtsPluginCard_module_css_default.usageTipRow,
478
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("usageTipRequests") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("usageRequestCount", { n: formatCount(totals.requests) }) })]
479
+ }),
480
+ pct !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
481
+ className: CodeArtsPluginCard_module_css_default.usageTipRow,
482
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("usageTipHit") }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [pct, "%"] })]
483
+ })
484
+ ] });
485
+ }
486
+ /**
487
+ * 悬停卡贴着指针画:热力图格子只有 36px 宽,卡片锚在格子上会横穿整张卡片,
488
+ * 所以和 agent-acta 一样用 fixed + 指针坐标,靠近右下边界时翻到另一侧。
489
+ */
490
+ function tipPointStyle(point) {
491
+ const width = 230;
492
+ const height = 190;
493
+ const viewWidth = typeof window === "undefined" ? 0 : window.innerWidth;
494
+ const viewHeight = typeof window === "undefined" ? 0 : window.innerHeight;
495
+ const left = viewWidth > 0 && point.x + 16 + width > viewWidth ? point.x - 16 - width : point.x + 16;
496
+ const top = viewHeight > 0 && point.y + 16 + height > viewHeight ? point.y - 16 - height : point.y + 16;
497
+ return {
498
+ left: Math.max(8, left),
499
+ top: Math.max(8, top)
500
+ };
501
+ }
502
+ /**
447
503
  * 横向条形列表:名称 / 条 / token / 占比 / 请求数。
448
504
  *
449
505
  * 条长按「占组内总量的比例」画(不是按最大值归一化),所以几条加起来就是全部。
@@ -463,8 +519,6 @@ function UsageBars({ rows, t }) {
463
519
  const value = valueOf(row);
464
520
  const share = sum > 0 ? value / sum * 100 : 0;
465
521
  const totals = row.totals;
466
- const cached = totals.cachedTokens;
467
- const pct = hitPercentOf(totals);
468
522
  const detail = [t("usageRequests", { n: formatCount(totals.requests) }), t("usageTokens", {
469
523
  prompt: formatTokens$1(totals.promptTokens),
470
524
  completion: formatTokens$1(totals.completionTokens)
@@ -498,41 +552,14 @@ function UsageBars({ rows, t }) {
498
552
  className: CodeArtsPluginCard_module_css_default.modelRequests,
499
553
  children: t("usageRequestCount", { n: formatCount(totals.requests) })
500
554
  }),
501
- hovered === row.id && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
555
+ hovered === row.id && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
502
556
  className: CodeArtsPluginCard_module_css_default.usageTip,
503
557
  role: "tooltip",
504
- children: [
505
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
506
- className: CodeArtsPluginCard_module_css_default.usageTipName,
507
- children: row.label
508
- }),
509
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: CodeArtsPluginCard_module_css_default.usageTipSep }),
510
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
511
- className: CodeArtsPluginCard_module_css_default.usageTipRow,
512
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("usageTipInput") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: exactCount(totals.promptTokens) })]
513
- }),
514
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
515
- className: CodeArtsPluginCard_module_css_default.usageTipRow,
516
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("usageTipOutput") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: exactCount(totals.completionTokens) })]
517
- }),
518
- (totals.reasoningTokens ?? 0) > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
519
- className: CodeArtsPluginCard_module_css_default.usageTipRow,
520
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("usageTipReasoning") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: exactCount(totals.reasoningTokens ?? 0) })]
521
- }),
522
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
523
- className: CodeArtsPluginCard_module_css_default.usageTipRow,
524
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("usageTipCached") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: cached === void 0 ? t("usageTipNoCache") : exactCount(cached) })]
525
- }),
526
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: CodeArtsPluginCard_module_css_default.usageTipSep }),
527
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
528
- className: CodeArtsPluginCard_module_css_default.usageTipRow,
529
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("usageTipRequests") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("usageRequestCount", { n: formatCount(totals.requests) }) })]
530
- }),
531
- pct !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
532
- className: CodeArtsPluginCard_module_css_default.usageTipRow,
533
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("usageTipHit") }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [pct, "%"] })]
534
- })
535
- ]
558
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(UsageTipBody, {
559
+ label: row.label,
560
+ totals,
561
+ t
562
+ })
536
563
  })
537
564
  ]
538
565
  }, row.id);
@@ -562,6 +589,8 @@ function weekdayOf(date) {
562
589
  */
563
590
  function UsageHeat({ days, t }) {
564
591
  const [hovered, setHovered] = (0, react.useState)(null);
592
+ /** 指针离开格子就清掉,卡片跟着指针停在那一次进入的位置。 */
593
+ const [point, setPoint] = (0, react.useState)(null);
565
594
  const last = days.at(-1);
566
595
  const month = last?.date.slice(0, 7) ?? "";
567
596
  const inMonth = days.filter((day) => day.date.startsWith(month));
@@ -614,9 +643,12 @@ function UsageHeat({ days, t }) {
614
643
  className: CodeArtsPluginCard_module_css_default.heatCell,
615
644
  "data-tone": tone,
616
645
  "data-today": entry.date === last?.date ? "true" : void 0,
617
- title: entry.totals === void 0 ? void 0 : `${entry.date} · ${trendDetail(entry.totals, t)}`,
618
- onMouseEnter: entry.totals === void 0 ? void 0 : () => {
646
+ onMouseEnter: entry.totals === void 0 ? void 0 : (event) => {
619
647
  setHovered(entry.date);
648
+ setPoint({
649
+ x: event.clientX,
650
+ y: event.clientY
651
+ });
620
652
  },
621
653
  onMouseLeave: entry.totals === void 0 ? void 0 : () => {
622
654
  setHovered(null);
@@ -626,9 +658,20 @@ function UsageHeat({ days, t }) {
626
658
  })
627
659
  ]
628
660
  }),
661
+ shown?.totals !== void 0 && point !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
662
+ className: CodeArtsPluginCard_module_css_default.usageTip,
663
+ "data-float": "true",
664
+ role: "tooltip",
665
+ style: tipPointStyle(point),
666
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(UsageTipBody, {
667
+ label: shown.date,
668
+ totals: shown.totals,
669
+ t
670
+ })
671
+ }),
629
672
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
630
673
  className: CodeArtsPluginCard_module_css_default.trendTip,
631
- children: shown?.totals === void 0 ? t("usageTrendHint") : `${shown.date} · ${trendDetail(shown.totals, t)}`
674
+ children: t("usageTrendHint")
632
675
  })
633
676
  ] });
634
677
  }
@@ -639,6 +682,7 @@ function UsageHeat({ days, t }) {
639
682
  */
640
683
  function UsageHours({ hours, t }) {
641
684
  const [hovered, setHovered] = (0, react.useState)(null);
685
+ const [point, setPoint] = (0, react.useState)(null);
642
686
  const max = hours.reduce((peak, hour) => Math.max(peak, hour.totals.totalTokens), 0);
643
687
  const shown = hovered === null ? void 0 : hours.find((entry) => entry.hour === hovered);
644
688
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
@@ -647,9 +691,12 @@ function UsageHours({ hours, t }) {
647
691
  children: hours.map((entry) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
648
692
  className: CodeArtsPluginCard_module_css_default.heatHourCell,
649
693
  "data-tone": toneOf(entry.totals.totalTokens, max),
650
- title: `${String(entry.hour)}:00 · ${trendDetail(entry.totals, t)}`,
651
- onMouseEnter: () => {
694
+ onMouseEnter: (event) => {
652
695
  setHovered(entry.hour);
696
+ setPoint({
697
+ x: event.clientX,
698
+ y: event.clientY
699
+ });
653
700
  },
654
701
  onMouseLeave: () => {
655
702
  setHovered(null);
@@ -663,22 +710,23 @@ function UsageHours({ hours, t }) {
663
710
  children: entry.hour % 6 === 0 ? entry.hour : ""
664
711
  }, entry.hour))
665
712
  }),
713
+ shown !== void 0 && point !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
714
+ className: CodeArtsPluginCard_module_css_default.usageTip,
715
+ "data-float": "true",
716
+ role: "tooltip",
717
+ style: tipPointStyle(point),
718
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(UsageTipBody, {
719
+ label: `${String(shown.hour).padStart(2, "0")}:00`,
720
+ totals: shown.totals,
721
+ t
722
+ })
723
+ }),
666
724
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
667
725
  className: CodeArtsPluginCard_module_css_default.trendTip,
668
- children: shown === void 0 ? t("usageTrendHint") : `${String(shown.hour).padStart(2, "0")}:00 · ${trendDetail(shown.totals, t)}`
726
+ children: t("usageTrendHint")
669
727
  })
670
728
  ] });
671
729
  }
672
- /** 一格趋势的明细文案:输入 / 缓存 / 命中率 / 请求数(输出与思考在明细卡里看)。 */
673
- function trendDetail(totals, t) {
674
- const pct = hitPercentOf(totals);
675
- return [
676
- t("usageStatIn", { n: formatTokens$1(totals.promptTokens) }),
677
- `${t("usageTipCached")} ${formatTokens$1(totals.cachedTokens ?? 0)}`,
678
- `${t("usageTipHit")} ${pct === void 0 ? "—" : `${pct}%`}`,
679
- t("usageRequestCount", { n: formatCount(totals.requests) })
680
- ].join(" · ");
681
- }
682
730
  /**
683
731
  * 用量区块。
684
732
  *
@@ -839,6 +887,8 @@ function CodeArtsPluginCard({ t }) {
839
887
  const [msg, setMsg] = (0, react.useState)(null);
840
888
  const [loginUrl, setLoginUrl] = (0, react.useState)(null);
841
889
  const [loginPending, setLoginPending] = (0, react.useState)(false);
890
+ /** 正在进行的是哪个账号的「重新登录」(无则 null)。用来只让那一行的按钮变「登录中」。 */
891
+ const [reloginId, setReloginId] = (0, react.useState)(null);
842
892
  const [selection, setSelection] = (0, react.useState)(null);
843
893
  const [draft, setDraft] = (0, react.useState)([]);
844
894
  const [savingModels, setSavingModels] = (0, react.useState)(false);
@@ -1163,16 +1213,29 @@ function CodeArtsPluginCard({ t }) {
1163
1213
  setRefreshing(false);
1164
1214
  }
1165
1215
  }
1166
- async function startOAuthLogin() {
1216
+ /**
1217
+ * 开始一次浏览器登录。
1218
+ *
1219
+ * 不带 `targetId` 是「添加账号」;带 `targetId` 是「重新登录这个账号」——
1220
+ * 服务端会把新凭证写回原条目(保留顺序与备注),而不是又长出一条。
1221
+ */
1222
+ async function startOAuthLogin(targetId) {
1167
1223
  setBusy(true);
1168
1224
  setMsg(null);
1169
1225
  setLoginPending(true);
1226
+ if (targetId !== void 0) setReloginId(targetId);
1227
+ const finish = () => {
1228
+ setLoginUrl(null);
1229
+ setLoginPending(false);
1230
+ setReloginId(null);
1231
+ };
1170
1232
  try {
1171
- const res = await fetch("/api/codearts/login", { method: "POST" });
1233
+ const query = targetId === void 0 ? "" : `?account=${encodeURIComponent(targetId)}`;
1234
+ const res = await fetch(`/api/codearts/login${query}`, { method: "POST" });
1172
1235
  const data = await res.json().catch(() => ({}));
1173
1236
  if (!res.ok || typeof data.url !== "string") {
1174
1237
  setMsg(data.error ?? `HTTP ${res.status}`);
1175
- setLoginPending(false);
1238
+ finish();
1176
1239
  return;
1177
1240
  }
1178
1241
  setLoginUrl(data.url);
@@ -1180,20 +1243,18 @@ function CodeArtsPluginCard({ t }) {
1180
1243
  const poll = async () => {
1181
1244
  const st = await (await fetch(`/api/codearts/login/status?url=${encodeURIComponent(data.url)}`, { headers: { Accept: "application/json" } })).json().catch(() => ({ status: "pending" }));
1182
1245
  if (st.status === "done") {
1183
- setLoginUrl(null);
1184
- setLoginPending(false);
1246
+ finish();
1247
+ if (st.conflict === true) setMsg(t("reloginOtherAccount"));
1185
1248
  await refresh();
1186
1249
  return;
1187
1250
  }
1188
1251
  if (st.status === "error") {
1189
- setLoginUrl(null);
1190
- setLoginPending(false);
1252
+ finish();
1191
1253
  setMsg(t("loginFailed"));
1192
1254
  return;
1193
1255
  }
1194
1256
  if (st.status === "idle") {
1195
- setLoginUrl(null);
1196
- setLoginPending(false);
1257
+ finish();
1197
1258
  await refresh();
1198
1259
  return;
1199
1260
  }
@@ -1202,7 +1263,7 @@ function CodeArtsPluginCard({ t }) {
1202
1263
  poll();
1203
1264
  } catch (err) {
1204
1265
  setMsg(err instanceof Error ? err.message : String(err));
1205
- setLoginPending(false);
1266
+ finish();
1206
1267
  } finally {
1207
1268
  setBusy(false);
1208
1269
  }
@@ -1452,16 +1513,22 @@ function CodeArtsPluginCard({ t }) {
1452
1513
  children: accountLine
1453
1514
  })]
1454
1515
  }),
1455
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1516
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1456
1517
  className: CodeArtsPluginCard_module_css_default.accountRowActions,
1457
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1518
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1519
+ variant: account.stale ? "primary" : "outline",
1520
+ size: "sm",
1521
+ disabled: busy || loginPending,
1522
+ onClick: () => void startOAuthLogin(account.id),
1523
+ children: reloginId === account.id && loginPending ? t("reloginPending") : t("accountRelogin")
1524
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1458
1525
  variant: "outline",
1459
1526
  size: "sm",
1460
1527
  className: CodeArtsPluginCard_module_css_default.danger,
1461
- disabled: busy,
1528
+ disabled: busy || loginPending,
1462
1529
  onClick: () => void removeAccount(account.id),
1463
1530
  children: t("accountRemove")
1464
- })
1531
+ })]
1465
1532
  })
1466
1533
  ]
1467
1534
  }), credit !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CreditBlock, {
@@ -2363,14 +2430,14 @@ if (typeof document !== "undefined" && document.querySelector("style[data-plugin
2363
2430
  document.head.appendChild(tag);
2364
2431
  }
2365
2432
  var CodeArtsPanel_module_css_default = {
2366
- "icon": "Z66cgG_icon",
2367
- "back": "Z66cgG_back",
2368
- "backCaret": "Z66cgG_backCaret",
2433
+ "head": "Z66cgG_head",
2434
+ "body": "Z66cgG_body",
2369
2435
  "title": "Z66cgG_title",
2370
2436
  "desc": "Z66cgG_desc",
2437
+ "back": "Z66cgG_back",
2438
+ "icon": "Z66cgG_icon",
2371
2439
  "page": "Z66cgG_page",
2372
- "body": "Z66cgG_body",
2373
- "head": "Z66cgG_head"
2440
+ "backCaret": "Z66cgG_backCaret"
2374
2441
  };
2375
2442
  //#endregion
2376
2443
  //#region src/client/CodeArtsPanel.tsx
@@ -2471,6 +2538,9 @@ const zh = {
2471
2538
  expiredHint: "凭证已过期,请重新登录以继续使用;已勾选的模型设置会保留。",
2472
2539
  accountsTitle: "账号",
2473
2540
  accountRemove: "删除",
2541
+ accountRelogin: "重新登录",
2542
+ reloginPending: "登录中…",
2543
+ reloginOtherAccount: "你登录的是另一个账号,已作为新账号添加;原账号保持不变。",
2474
2544
  addAccount: "添加账号",
2475
2545
  pasteTokenAdd: "粘贴 Token 添加",
2476
2546
  accountsRotateHint: "已存多个账号:请求会自动轮转,某个账号忙时改用下一个,不用干等。",
@@ -2621,6 +2691,9 @@ const en = {
2621
2691
  expiredHint: "Your credential has expired. Sign in again to continue; your model selection is kept.",
2622
2692
  accountsTitle: "Accounts",
2623
2693
  accountRemove: "Remove",
2694
+ accountRelogin: "Sign in again",
2695
+ reloginPending: "Signing in…",
2696
+ reloginOtherAccount: "That was a different account, so it was added as a new one; the original stayed unchanged.",
2624
2697
  addAccount: "Add account",
2625
2698
  pasteTokenAdd: "Paste a token",
2626
2699
  accountsRotateHint: "Multiple accounts stored: requests rotate automatically, so a busy account hands over to the next one instead of making you wait.",
package/lib/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { A as upstreamErrorMessage, B as modelUnavailableReason, C as isWelfareClaimedStatus, D as prepareChatBody, E as pickDailyWelfareCampaign, F as filterEnabledModels, G as codeartsAuthPath, H as CodeArtsCredentialStore, I as forgetModelUnavailable, K as startLogin, L as isBenefitBlocked, M as FALLBACK_CODEARTS_MODELS, N as clearBenefitBlocked, O as rateLimitFrame, P as creditRatioLabel, R as isBenefitModel, S as isTpmLimit, T as modelUnavailableReasonText, U as MANUAL_ACCOUNT_ID, V as CodeArtsAccountStore, W as codeartsAccountsPath, _ as isIamTokenError, a as SNAP_HOST, b as isParamInvalidFrame, c as claimDailyWelfare, d as fetchCallerIdentity, f as fetchModels, g as isConcurrencyCap, h as firstFrameError, i as refreshCatalog, j as CodeArtsCatalog, k as signedGet, l as clearQueueStatus, m as fetchWelfareCampaigns, n as codeartsUsagePath, o as canonicalModel, p as fetchQueueStatus, r as discoverModels, s as chatStream, t as CodeArtsUsageTracker, u as degradeTokenCeiling, v as isModelNotAccessible, w as maxTokensCeilingFor, x as isQueueableRate, y as isNotMultimodal, z as markModelUnavailable } from "./usage-B2LNsUuR.mjs";
1
+ import { A as upstreamErrorMessage, B as modelUnavailableReason, C as isWelfareClaimedStatus, D as prepareChatBody, E as pickDailyWelfareCampaign, F as filterEnabledModels, G as codeartsAuthPath, H as CodeArtsCredentialStore, I as forgetModelUnavailable, K as credentialFromOAuth, L as isBenefitBlocked, M as FALLBACK_CODEARTS_MODELS, N as clearBenefitBlocked, O as rateLimitFrame, P as creditRatioLabel, R as isBenefitModel, S as isTpmLimit, T as modelUnavailableReasonText, U as MANUAL_ACCOUNT_ID, V as CodeArtsAccountStore, W as codeartsAccountsPath, _ as isIamTokenError, a as SNAP_HOST, b as isParamInvalidFrame, c as claimDailyWelfare, d as fetchCallerIdentity, f as fetchModels, g as isConcurrencyCap, h as firstFrameError, i as refreshCatalog, j as CodeArtsCatalog, k as signedGet, l as clearQueueStatus, m as fetchWelfareCampaigns, n as codeartsUsagePath, o as canonicalModel, p as fetchQueueStatus, q as startLogin, r as discoverModels, s as chatStream, t as CodeArtsUsageTracker, u as degradeTokenCeiling, v as isModelNotAccessible, w as maxTokensCeilingFor, x as isQueueableRate, y as isNotMultimodal, z as markModelUnavailable } from "./usage-CjPd0Gok.mjs";
2
2
  import { i as lazyApi, r as createProvider } from "./models-CgKCibpk.mjs";
3
3
  import z from "@deepseek-ai/schemastery";
4
4
  import { randomBytes, timingSafeEqual } from "node:crypto";
@@ -1609,6 +1609,58 @@ async function probeIdentity(token) {
1609
1609
  clearTimeout(timer);
1610
1610
  }
1611
1611
  }
1612
+ /**
1613
+ * 落一次 OAuth 登录的凭证。
1614
+ *
1615
+ * 不带 `targetId` 是「添加账号」:同一账号更新,别的账号新增。
1616
+ *
1617
+ * 带 `targetId` 是「重新登录这个账号」:凭证写回原条目(保留 id、展示顺序和
1618
+ * 备注),而不是又长出一条 —— 以前卡片上只有「删除」,用户遇到凭证过期只能
1619
+ * 先把账号删掉再加回来,顺序和备注都丢。
1620
+ *
1621
+ * 上游只在 `fetchCallerIdentity` 成功时才给稳定 `userId`,拿不到身份就判断不了
1622
+ * 「是不是同一个人」。此时按用户意图替换(他点的就是这个账号的重登),并沿用
1623
+ * 旧条目的身份字段;只有两边 `userId` 都非空且不同,才判为登了另一个账号,
1624
+ * 退回「新增」,原账号原样不动。
1625
+ */
1626
+ async function settleLogin(deps, token, targetId) {
1627
+ const identity = await probeIdentity(token);
1628
+ const target = targetId === void 0 ? void 0 : await deps.store.credential(targetId);
1629
+ if (targetId !== void 0 && target !== void 0) {
1630
+ const known = typeof target.userId === "string" && target.userId !== "";
1631
+ if (!(identity !== null && known && target.userId !== identity.userId)) {
1632
+ const cred = credentialFromOAuth(token, target.label);
1633
+ cred.userId = cred.userId || target.userId;
1634
+ cred.userName = cred.userName || target.userName;
1635
+ cred.domainId = cred.domainId || target.domainId;
1636
+ const id = await deps.store.upsert(cred, targetId);
1637
+ deps.reviveAccount?.(id);
1638
+ if (identity !== null && identity.userId !== "") {
1639
+ if (identity.userId !== id) await deps.store.adoptIdentity(id, identity);
1640
+ deps.reviveAccount?.(identity.userId);
1641
+ return {
1642
+ id: identity.userId,
1643
+ replaced: true,
1644
+ conflict: false
1645
+ };
1646
+ }
1647
+ return {
1648
+ id,
1649
+ replaced: true,
1650
+ conflict: false
1651
+ };
1652
+ }
1653
+ }
1654
+ const id = await deps.store.upsertFromOAuth(token, void 0, identity ?? void 0);
1655
+ if (identity !== null && id !== identity.userId) await deps.store.adoptIdentity(id, identity);
1656
+ deps.reviveAccount?.(id);
1657
+ if (identity !== null && identity.userId !== id) deps.reviveAccount?.(identity.userId);
1658
+ return {
1659
+ id: identity?.userId ?? id,
1660
+ replaced: false,
1661
+ conflict: target !== void 0
1662
+ };
1663
+ }
1612
1664
  /** 账号还能用吗(没被标 stale、也没过期)。 */
1613
1665
  function accountUsable(summary) {
1614
1666
  if (summary.stale) return false;
@@ -2169,6 +2221,8 @@ function registerCodeArtsStatusRoute(ctx, deps) {
2169
2221
  const activeLogins = /* @__PURE__ */ new Map();
2170
2222
  /** 已结束登录的终态,供迟到的轮询读取。被读一次即删。 */
2171
2223
  const recentLogins = /* @__PURE__ */ new Map();
2224
+ /** 本次登录是「重新登录」时,授权 URL → 目标账号 id。终态落库后即删。 */
2225
+ const reloginTargets = /* @__PURE__ */ new Map();
2172
2226
  const disposeStatus = ctx.webServer.register({
2173
2227
  kind: "exact",
2174
2228
  path: CODEARTS_STATUS_PATH,
@@ -2192,7 +2246,7 @@ function registerCodeArtsStatusRoute(ctx, deps) {
2192
2246
  const disposeLoginStart = ctx.webServer.register({
2193
2247
  kind: "exact",
2194
2248
  path: CODEARTS_LOGIN_PATH,
2195
- handler: loginStartHandler(deps, activeLogins, recentLogins)
2249
+ handler: loginStartHandler(deps, activeLogins, recentLogins, reloginTargets)
2196
2250
  });
2197
2251
  const disposeLoginStatus = ctx.webServer.register({
2198
2252
  kind: "exact",
@@ -2250,6 +2304,7 @@ function registerCodeArtsStatusRoute(ctx, deps) {
2250
2304
  disposeDebug();
2251
2305
  for (const s of activeLogins.values()) s.close();
2252
2306
  activeLogins.clear();
2307
+ reloginTargets.clear();
2253
2308
  };
2254
2309
  }, "dsh-codearts: Web status route");
2255
2310
  }
@@ -2267,8 +2322,12 @@ function recordLoginOutcome(recent, url, outcome) {
2267
2322
  }
2268
2323
  recent.set(url, outcome);
2269
2324
  }
2270
- /** POST /api/codearts/login — 启动本地 OAuth 回调,返回授权 URL。 */
2271
- function loginStartHandler(deps, active, recent) {
2325
+ /**
2326
+ * POST /api/codearts/login — 启动本地 OAuth 回调,返回授权 URL。
2327
+ *
2328
+ * `?account=<id>` 表示「重新登录这个账号」(见 settleLogin);省略就是添加账号。
2329
+ */
2330
+ function loginStartHandler(deps, active, recent, targets) {
2272
2331
  return async (req, res) => {
2273
2332
  if (req.method !== "POST") {
2274
2333
  json(res, 405, { error: "method not allowed" });
@@ -2278,28 +2337,33 @@ function loginStartHandler(deps, active, recent) {
2278
2337
  json(res, 403, { error: "request-not-trusted" });
2279
2338
  return;
2280
2339
  }
2340
+ const targetId = (new URL(req.url ?? "", "http://localhost").searchParams.get("account") ?? "").trim();
2281
2341
  try {
2282
2342
  const session = await startLogin();
2283
2343
  active.set(session.url, session);
2344
+ if (targetId !== "") targets.set(session.url, targetId);
2284
2345
  session.promise.then(async (token) => {
2285
2346
  active.delete(session.url);
2347
+ const reloginId = targets.get(session.url);
2348
+ targets.delete(session.url);
2286
2349
  try {
2287
- const identity = await probeIdentity(token);
2288
- const id = await deps.store.upsertFromOAuth(token, void 0, identity ?? void 0);
2289
- if (identity !== null && id !== identity.userId) await deps.store.adoptIdentity(id, identity);
2290
- deps.reviveAccount?.(id);
2291
- if (identity !== null && identity.userId !== id) deps.reviveAccount?.(identity.userId);
2292
- recordLoginOutcome(recent, session.url, "done");
2350
+ const result = await settleLogin(deps, token, reloginId);
2351
+ recordLoginOutcome(recent, session.url, {
2352
+ status: "done",
2353
+ ...result
2354
+ });
2293
2355
  } catch {
2294
- recordLoginOutcome(recent, session.url, "error");
2356
+ recordLoginOutcome(recent, session.url, { status: "error" });
2295
2357
  }
2296
2358
  }, () => {
2297
2359
  active.delete(session.url);
2298
- recordLoginOutcome(recent, session.url, "error");
2360
+ targets.delete(session.url);
2361
+ recordLoginOutcome(recent, session.url, { status: "error" });
2299
2362
  });
2300
2363
  const timer = setTimeout(() => {
2301
2364
  session.close();
2302
- if (active.delete(session.url)) recordLoginOutcome(recent, session.url, "error");
2365
+ targets.delete(session.url);
2366
+ if (active.delete(session.url)) recordLoginOutcome(recent, session.url, { status: "error" });
2303
2367
  }, 3e5);
2304
2368
  session.promise.finally(() => clearTimeout(timer)).catch(() => {});
2305
2369
  json(res, 200, {
@@ -2330,7 +2394,7 @@ function loginPollHandler(_deps, active, recent) {
2330
2394
  const outcome = recent.get(key);
2331
2395
  if (outcome !== void 0) {
2332
2396
  recent.delete(key);
2333
- json(res, 200, { status: outcome });
2397
+ json(res, 200, { ...outcome });
2334
2398
  return;
2335
2399
  }
2336
2400
  json(res, 200, { status: "idle" });
@@ -3052,4 +3052,4 @@ function sumOf(store) {
3052
3052
  return out;
3053
3053
  }
3054
3054
  //#endregion
3055
- export { upstreamErrorMessage as A, modelUnavailableReason as B, isWelfareClaimedStatus as C, prepareChatBody as D, pickDailyWelfareCampaign as E, filterEnabledModels as F, codeartsAuthPath as G, CodeArtsCredentialStore as H, forgetModelUnavailable as I, startLogin as K, isBenefitBlocked as L, FALLBACK_CODEARTS_MODELS as M, clearBenefitBlocked as N, rateLimitFrame as O, creditRatioLabel as P, isBenefitModel as R, isTpmLimit as S, modelUnavailableReasonText as T, MANUAL_ACCOUNT_ID as U, CodeArtsAccountStore as V, codeartsAccountsPath as W, isIamTokenError as _, SNAP_HOST as a, isParamInvalidFrame as b, claimDailyWelfare as c, fetchCallerIdentity as d, fetchModels as f, isConcurrencyCap as g, firstFrameError as h, refreshCatalog as i, CodeArtsCatalog as j, signedGet as k, clearQueueStatus as l, fetchWelfareCampaigns as m, codeartsUsagePath as n, canonicalModel as o, fetchQueueStatus as p, discoverModels as r, chatStream as s, CodeArtsUsageTracker as t, degradeTokenCeiling as u, isModelNotAccessible as v, maxTokensCeilingFor as w, isQueueableRate as x, isNotMultimodal as y, markModelUnavailable as z };
3055
+ export { upstreamErrorMessage as A, modelUnavailableReason as B, isWelfareClaimedStatus as C, prepareChatBody as D, pickDailyWelfareCampaign as E, filterEnabledModels as F, codeartsAuthPath as G, CodeArtsCredentialStore as H, forgetModelUnavailable as I, credentialFromOAuth as K, isBenefitBlocked as L, FALLBACK_CODEARTS_MODELS as M, clearBenefitBlocked as N, rateLimitFrame as O, creditRatioLabel as P, isBenefitModel as R, isTpmLimit as S, modelUnavailableReasonText as T, MANUAL_ACCOUNT_ID as U, CodeArtsAccountStore as V, codeartsAccountsPath as W, isIamTokenError as _, SNAP_HOST as a, isParamInvalidFrame as b, claimDailyWelfare as c, fetchCallerIdentity as d, fetchModels as f, isConcurrencyCap as g, firstFrameError as h, refreshCatalog as i, CodeArtsCatalog as j, signedGet as k, clearQueueStatus as l, fetchWelfareCampaigns as m, codeartsUsagePath as n, canonicalModel as o, fetchQueueStatus as p, startLogin as q, discoverModels as r, chatStream as s, CodeArtsUsageTracker as t, degradeTokenCeiling as u, isModelNotAccessible as v, maxTokensCeilingFor as w, isQueueableRate as x, isNotMultimodal as y, markModelUnavailable as z };
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "dsh-codearts",
3
3
  "displayName": "DSH CodeArts Connect",
4
4
  "description": "把华为云 CodeArts 接入 DeepSeek Harness —— 内置 OAuth2 登录(PKCE + DPoP),登录后即可在 DSH 对话窗口使用 CodeArts 的模型。",
5
- "version": "1.2.8",
5
+ "version": "1.2.10",
6
6
  "packageManager": "pnpm@11.24.0",
7
7
  "author": "elegant01",
8
8
  "keywords": [