dsh-codearts 1.2.4 → 1.2.6
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 +72 -0
- package/README.en.md +9 -0
- package/README.md +2 -0
- package/lib/bin.mjs +2 -2
- package/lib/client/index.d.cts +40 -0
- package/lib/client/index.js +534 -90
- package/lib/index.d.mts +37 -1
- package/lib/index.mjs +21 -8
- package/lib/{usage-DGIuT79_.mjs → usage-4B0o-CQN.mjs} +57 -3
- package/package.json +1 -1
package/lib/client/index.js
CHANGED
|
@@ -22,90 +22,138 @@ function stripModelSuffixes(name) {
|
|
|
22
22
|
return base.replace(/\s*[((]\s*(?:(?:免费|福利)(?:\s+x\d+(?:\.\d+)?)?|x\d+(?:\.\d+)?)\s*[))]\s*$/, "").trim();
|
|
23
23
|
}
|
|
24
24
|
//#endregion
|
|
25
|
+
//#region src/client/panel-switch.ts
|
|
26
|
+
/**
|
|
27
|
+
* 「要不要在 DSH 侧边栏占一格」这个偏好,浏览器侧的单一真相。
|
|
28
|
+
*
|
|
29
|
+
* 为什么不靠组件返回 null 来隐藏:宿主是按**槽位里的注册条目**(entry metadata)
|
|
30
|
+
* 画侧边栏导航行的 —— 只要注册还在,那一行就在;渲染函数 return null 只会留下一个
|
|
31
|
+
* 「空白但可点」的按钮。所以开关必须落到「注册 / 不注册」上,这里只存那个意图,
|
|
32
|
+
* 真正的注册动作由 index.tsx 的 sync 控制器按它做。
|
|
33
|
+
*
|
|
34
|
+
* 默认 **false**:读不到配置时必须当作关闭。侧边栏那一格是所有插件共用的全局座位,
|
|
35
|
+
* 猜错的代价比「少一个入口」大得多(用户还能从「设置 → 插件」进同一张卡片)。
|
|
36
|
+
*/
|
|
37
|
+
let wanted = false;
|
|
38
|
+
/** 当前是否要显示侧边栏入口。 */
|
|
39
|
+
function sidebarPanelWanted() {
|
|
40
|
+
return wanted;
|
|
41
|
+
}
|
|
42
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
43
|
+
/**
|
|
44
|
+
* 改开关。值没变就直接返回 —— 调用方会在每次刷新状态时调用它,
|
|
45
|
+
* 无变化的重注册会让侧边栏闪一下。
|
|
46
|
+
*/
|
|
47
|
+
function setSidebarPanelWanted(next) {
|
|
48
|
+
if (wanted === next) return;
|
|
49
|
+
wanted = next;
|
|
50
|
+
for (const listener of [...listeners]) try {
|
|
51
|
+
listener();
|
|
52
|
+
} catch (error) {
|
|
53
|
+
console.error("[dsh-codearts] sidebar panel listener failed:", error);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/** 订阅开关变化,返回取消订阅函数。 */
|
|
57
|
+
function subscribeSidebarPanelWanted(listener) {
|
|
58
|
+
listeners.add(listener);
|
|
59
|
+
return () => {
|
|
60
|
+
listeners.delete(listener);
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
//#endregion
|
|
25
64
|
//#region \0dsh-css:/home/runner/work/dsh-codearts/dsh-codearts/src/client/CodeArtsPluginCard.module.css.mjs
|
|
26
|
-
const css = ".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_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}";
|
|
27
|
-
const tagId = "dsh-codearts/CodeArtsPluginCard.module.css";
|
|
28
|
-
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
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_trendBars{align-items:flex-end;gap:3px;height:44px;margin:8px 0 2px;display:flex}.xoziZG_trendSlot{flex-direction:column;flex:1;justify-content:flex-end;min-width:0;height:100%;display:flex}.xoziZG_trendBar{background:var(--dsw-alias-brand-primary);border-radius:2px 2px 0 0;min-height:2px;transition:height .16s,background .16s}.xoziZG_trendBar[data-tone=mid]{background:var(--dsw-alias-state-warn-label)}.xoziZG_trendBar[data-tone=low]{background:var(--dsw-alias-state-error-primary,var(--dsw-alias-state-warn-label))}.xoziZG_trendBar[data-tone=empty]{background:var(--dsw-alias-border-l2)}.xoziZG_trendAxis{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;gap:3px;font-size:10px;line-height:14px;display:flex}.xoziZG_trendAxisSlot{text-align:center;white-space:nowrap;flex:1;min-width:0;overflow:hidden}.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
|
+
const tagId$1 = "dsh-codearts/CodeArtsPluginCard.module.css";
|
|
67
|
+
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
|
|
29
68
|
const tag = document.createElement("style");
|
|
30
69
|
tag.dataset.plugin = "dsh-codearts";
|
|
31
|
-
tag.dataset.pluginCss = tagId;
|
|
32
|
-
tag.textContent = css;
|
|
70
|
+
tag.dataset.pluginCss = tagId$1;
|
|
71
|
+
tag.textContent = css$1;
|
|
33
72
|
document.head.appendChild(tag);
|
|
34
73
|
}
|
|
35
74
|
var CodeArtsPluginCard_module_css_default = {
|
|
36
|
-
"
|
|
37
|
-
"
|
|
38
|
-
"
|
|
39
|
-
"
|
|
75
|
+
"header": "xoziZG_header",
|
|
76
|
+
"modelChart": "xoziZG_modelChart",
|
|
77
|
+
"trendBar": "xoziZG_trendBar",
|
|
78
|
+
"creditHint": "xoziZG_creditHint",
|
|
79
|
+
"creditLink": "xoziZG_creditLink",
|
|
80
|
+
"tabs": "xoziZG_tabs",
|
|
81
|
+
"accountCard": "xoziZG_accountCard",
|
|
82
|
+
"usageTipSep": "xoziZG_usageTipSep",
|
|
40
83
|
"expiryLabel": "xoziZG_expiryLabel",
|
|
41
|
-
"
|
|
42
|
-
"
|
|
84
|
+
"creditRow": "xoziZG_creditRow",
|
|
85
|
+
"skeletonRow": "xoziZG_skeletonRow",
|
|
86
|
+
"updated": "xoziZG_updated",
|
|
87
|
+
"manual": "xoziZG_manual",
|
|
88
|
+
"desc": "xoziZG_desc",
|
|
89
|
+
"usageFill": "xoziZG_usageFill",
|
|
90
|
+
"trendTip": "xoziZG_trendTip",
|
|
91
|
+
"balanceRow": "xoziZG_balanceRow",
|
|
92
|
+
"modelShare": "xoziZG_modelShare",
|
|
93
|
+
"accountNameRow": "xoziZG_accountNameRow",
|
|
94
|
+
"usageTip": "xoziZG_usageTip",
|
|
43
95
|
"accountToolbar": "xoziZG_accountToolbar",
|
|
44
|
-
"
|
|
45
|
-
"
|
|
96
|
+
"balance": "xoziZG_balance",
|
|
97
|
+
"actions": "xoziZG_actions",
|
|
98
|
+
"choices": "xoziZG_choices",
|
|
46
99
|
"meta": "xoziZG_meta",
|
|
47
|
-
"
|
|
100
|
+
"section": "xoziZG_section",
|
|
101
|
+
"modelRow": "xoziZG_modelRow",
|
|
48
102
|
"expiryRow": "xoziZG_expiryRow",
|
|
49
|
-
"
|
|
50
|
-
"
|
|
103
|
+
"claimAllRow": "xoziZG_claimAllRow",
|
|
104
|
+
"sectionHead": "xoziZG_sectionHead",
|
|
105
|
+
"modelTokens": "xoziZG_modelTokens",
|
|
106
|
+
"trendBars": "xoziZG_trendBars",
|
|
107
|
+
"skeleton": "xoziZG_skeleton",
|
|
108
|
+
"skeletonBreath": "xoziZG_skeletonBreath",
|
|
109
|
+
"statGrid": "xoziZG_statGrid",
|
|
51
110
|
"hint": "xoziZG_hint",
|
|
52
|
-
"
|
|
53
|
-
"
|
|
54
|
-
"
|
|
111
|
+
"accountRowActions": "xoziZG_accountRowActions",
|
|
112
|
+
"choiceRow": "xoziZG_choiceRow",
|
|
113
|
+
"error": "xoziZG_error",
|
|
114
|
+
"headText": "xoziZG_headText",
|
|
55
115
|
"card": "xoziZG_card",
|
|
56
|
-
"
|
|
57
|
-
"
|
|
58
|
-
"creditBlock": "xoziZG_creditBlock",
|
|
59
|
-
"header": "xoziZG_header",
|
|
116
|
+
"accountEntry": "xoziZG_accountEntry",
|
|
117
|
+
"statValue": "xoziZG_statValue",
|
|
60
118
|
"statSub": "xoziZG_statSub",
|
|
61
|
-
"
|
|
119
|
+
"body": "xoziZG_body",
|
|
120
|
+
"accountHint": "xoziZG_accountHint",
|
|
121
|
+
"usageTipName": "xoziZG_usageTipName",
|
|
122
|
+
"trendSlot": "xoziZG_trendSlot",
|
|
62
123
|
"modelRequests": "xoziZG_modelRequests",
|
|
63
|
-
"usageBar": "xoziZG_usageBar",
|
|
64
|
-
"bar": "xoziZG_bar",
|
|
65
|
-
"creditRow": "xoziZG_creditRow",
|
|
66
|
-
"sectionLabel": "xoziZG_sectionLabel",
|
|
67
|
-
"accountEntry": "xoziZG_accountEntry",
|
|
68
|
-
"modelTrack": "xoziZG_modelTrack",
|
|
69
|
-
"link": "xoziZG_link",
|
|
70
|
-
"updated": "xoziZG_updated",
|
|
71
|
-
"desc": "xoziZG_desc",
|
|
72
124
|
"avatar": "xoziZG_avatar",
|
|
73
|
-
"
|
|
74
|
-
"
|
|
75
|
-
"fieldLabel": "xoziZG_fieldLabel",
|
|
76
|
-
"modelName": "xoziZG_modelName",
|
|
125
|
+
"barFill": "xoziZG_barFill",
|
|
126
|
+
"sectionLabel": "xoziZG_sectionLabel",
|
|
77
127
|
"danger": "xoziZG_danger",
|
|
78
|
-
"statValue": "xoziZG_statValue",
|
|
79
|
-
"area": "xoziZG_area",
|
|
80
|
-
"claimAllRow": "xoziZG_claimAllRow",
|
|
81
|
-
"tabs": "xoziZG_tabs",
|
|
82
|
-
"usageTipSep": "xoziZG_usageTipSep",
|
|
83
|
-
"name": "xoziZG_name",
|
|
84
|
-
"headText": "xoziZG_headText",
|
|
85
|
-
"accountRowActions": "xoziZG_accountRowActions",
|
|
86
|
-
"sectionHead": "xoziZG_sectionHead",
|
|
87
|
-
"modelRow": "xoziZG_modelRow",
|
|
88
|
-
"modelFill": "xoziZG_modelFill",
|
|
89
|
-
"accountHint": "xoziZG_accountHint",
|
|
90
|
-
"modelChart": "xoziZG_modelChart",
|
|
91
|
-
"error": "xoziZG_error",
|
|
92
|
-
"body": "xoziZG_body",
|
|
93
|
-
"manualSummary": "xoziZG_manualSummary",
|
|
94
|
-
"balanceMeta": "xoziZG_balanceMeta",
|
|
95
|
-
"statGrid": "xoziZG_statGrid",
|
|
96
|
-
"choiceRow": "xoziZG_choiceRow",
|
|
97
|
-
"modelShare": "xoziZG_modelShare",
|
|
98
|
-
"accountName": "xoziZG_accountName",
|
|
99
|
-
"modelTokens": "xoziZG_modelTokens",
|
|
100
|
-
"creditLink": "xoziZG_creditLink",
|
|
101
|
-
"creditFooter": "xoziZG_creditFooter",
|
|
102
|
-
"manual": "xoziZG_manual",
|
|
103
128
|
"statusLine": "xoziZG_statusLine",
|
|
104
129
|
"creditRows": "xoziZG_creditRows",
|
|
130
|
+
"accountInfo": "xoziZG_accountInfo",
|
|
131
|
+
"trendAxisSlot": "xoziZG_trendAxisSlot",
|
|
132
|
+
"check": "xoziZG_check",
|
|
133
|
+
"field": "xoziZG_field",
|
|
134
|
+
"creditFooter": "xoziZG_creditFooter",
|
|
135
|
+
"balanceMeta": "xoziZG_balanceMeta",
|
|
136
|
+
"trendAxis": "xoziZG_trendAxis",
|
|
137
|
+
"manualSummary": "xoziZG_manualSummary",
|
|
138
|
+
"balanceUnit": "xoziZG_balanceUnit",
|
|
139
|
+
"manualForm": "xoziZG_manualForm",
|
|
140
|
+
"accountRow": "xoziZG_accountRow",
|
|
141
|
+
"creditBlock": "xoziZG_creditBlock",
|
|
142
|
+
"name": "xoziZG_name",
|
|
143
|
+
"modelName": "xoziZG_modelName",
|
|
144
|
+
"tabPanel": "xoziZG_tabPanel",
|
|
145
|
+
"bar": "xoziZG_bar",
|
|
146
|
+
"statLabel": "xoziZG_statLabel",
|
|
105
147
|
"statCard": "xoziZG_statCard",
|
|
106
|
-
"
|
|
148
|
+
"usageBar": "xoziZG_usageBar",
|
|
149
|
+
"link": "xoziZG_link",
|
|
150
|
+
"fieldLabel": "xoziZG_fieldLabel",
|
|
151
|
+
"accountName": "xoziZG_accountName",
|
|
107
152
|
"usageTipRow": "xoziZG_usageTipRow",
|
|
108
|
-
"
|
|
153
|
+
"count": "xoziZG_count",
|
|
154
|
+
"modelTrack": "xoziZG_modelTrack",
|
|
155
|
+
"modelFill": "xoziZG_modelFill",
|
|
156
|
+
"area": "xoziZG_area"
|
|
109
157
|
};
|
|
110
158
|
//#endregion
|
|
111
159
|
//#region src/client/CodeArtsPluginCard.tsx
|
|
@@ -155,11 +203,21 @@ function claimMessagesOf(data, accountIds, t) {
|
|
|
155
203
|
for (const id of accountIds) out[id] = claimText(data, t);
|
|
156
204
|
return out;
|
|
157
205
|
}
|
|
158
|
-
/**
|
|
206
|
+
/**
|
|
207
|
+
* 开关的兜底值:后端没这条路由(老版本)时按「都显示」渲染,与原有行为一致。
|
|
208
|
+
* 侧边栏那一格相反 —— 缺省关闭。
|
|
209
|
+
*/
|
|
159
210
|
const DOCK_DEFAULT = {
|
|
160
211
|
credits: true,
|
|
161
|
-
queue: true
|
|
212
|
+
queue: true,
|
|
213
|
+
sidebar: false
|
|
162
214
|
};
|
|
215
|
+
/**
|
|
216
|
+
* 上一次读到的状态。`/api/codearts/status` 会顺带去上游拉积分(有 TTL 缓存),
|
|
217
|
+
* 冷的时候要等近一秒;模块级留一份快照,再进这一页就能立刻按旧值画出来,
|
|
218
|
+
* 后台再刷新 —— 比每次都先闪骨架舒服,也不会把「还没读到」误判成未登录。
|
|
219
|
+
*/
|
|
220
|
+
let lastStatusSnapshot = null;
|
|
163
221
|
/** 一个 Tab 面板;未选中的用 hidden 留在 DOM 里,草稿和滚动位置都别丢。 */
|
|
164
222
|
function TabPanel({ id, labelledBy, active, children }) {
|
|
165
223
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
@@ -478,6 +536,63 @@ function UsageBars({ rows, t }) {
|
|
|
478
536
|
});
|
|
479
537
|
}
|
|
480
538
|
/**
|
|
539
|
+
* 趋势柱:近 7 天按天、今天按小时。
|
|
540
|
+
*
|
|
541
|
+
* 两张图共用一套柱子,但编码不同,因为要看的问题不同:
|
|
542
|
+
* - `hit`:柱高就是命中率,颜色分档 —— 命中率一掉就能看见,这是诊断「系统提示词
|
|
543
|
+
* 前缀变了 / 上下文突然变长」最直接的信号;
|
|
544
|
+
* - `volume`:柱高按组内最大值归一化 —— 只用来看「什么时候在跑」,绝对值看悬停。
|
|
545
|
+
*
|
|
546
|
+
* 悬停柱子时下面那行换成该格明细,移开回到提示语。轴标签只画整数倍格,24 格全画会挤成一片。
|
|
547
|
+
*/
|
|
548
|
+
function UsageTrend({ points, mode, axisEvery, hint, t }) {
|
|
549
|
+
const [hovered, setHovered] = (0, react.useState)(null);
|
|
550
|
+
const max = points.reduce((peak, point) => Math.max(peak, point.totals.totalTokens), 0);
|
|
551
|
+
const shown = hovered === null ? void 0 : points[hovered];
|
|
552
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
553
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
554
|
+
className: CodeArtsPluginCard_module_css_default.trendBars,
|
|
555
|
+
children: points.map((point, index) => {
|
|
556
|
+
const pct = hitPercentOf(point.totals);
|
|
557
|
+
const share = mode === "hit" ? pct === void 0 ? 0 : Math.max(pct, 2) : max === 0 ? 0 : point.totals.totalTokens / max * 100;
|
|
558
|
+
const tone = mode === "hit" ? pct === void 0 ? "empty" : pct >= 80 ? "ok" : pct >= 50 ? "mid" : "low" : point.totals.totalTokens === 0 ? "empty" : "ok";
|
|
559
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
560
|
+
className: CodeArtsPluginCard_module_css_default.trendSlot,
|
|
561
|
+
title: `${point.label} · ${trendDetail(point.totals, t)}`,
|
|
562
|
+
onMouseEnter: () => setHovered(index),
|
|
563
|
+
onMouseLeave: () => setHovered(null),
|
|
564
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
565
|
+
className: CodeArtsPluginCard_module_css_default.trendBar,
|
|
566
|
+
"data-tone": tone,
|
|
567
|
+
style: { height: `${share}%` }
|
|
568
|
+
})
|
|
569
|
+
}, point.key);
|
|
570
|
+
})
|
|
571
|
+
}),
|
|
572
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
573
|
+
className: CodeArtsPluginCard_module_css_default.trendAxis,
|
|
574
|
+
children: points.map((point, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
575
|
+
className: CodeArtsPluginCard_module_css_default.trendAxisSlot,
|
|
576
|
+
children: index % axisEvery === 0 ? point.label : ""
|
|
577
|
+
}, point.key))
|
|
578
|
+
}),
|
|
579
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
580
|
+
className: CodeArtsPluginCard_module_css_default.trendTip,
|
|
581
|
+
children: shown === void 0 ? hint : `${shown.label} · ${trendDetail(shown.totals, t)}`
|
|
582
|
+
})
|
|
583
|
+
] });
|
|
584
|
+
}
|
|
585
|
+
/** 一格趋势的明细文案:输入 / 缓存 / 命中率 / 请求数(输出与思考在明细卡里看)。 */
|
|
586
|
+
function trendDetail(totals, t) {
|
|
587
|
+
const pct = hitPercentOf(totals);
|
|
588
|
+
return [
|
|
589
|
+
t("usageStatIn", { n: formatTokens$1(totals.promptTokens) }),
|
|
590
|
+
`${t("usageTipCached")} ${formatTokens$1(totals.cachedTokens ?? 0)}`,
|
|
591
|
+
`${t("usageTipHit")} ${pct === void 0 ? "—" : `${pct}%`}`,
|
|
592
|
+
t("usageRequestCount", { n: formatCount(totals.requests) })
|
|
593
|
+
].join(" · ");
|
|
594
|
+
}
|
|
595
|
+
/**
|
|
481
596
|
* 用量区块。
|
|
482
597
|
*
|
|
483
598
|
* 只展示**本机经插件发出**的请求(不等于账号总额度 —— 账号额度见上方积分区块);
|
|
@@ -567,6 +682,37 @@ function UsageSection({ usage, accounts, t }) {
|
|
|
567
682
|
})
|
|
568
683
|
]
|
|
569
684
|
}),
|
|
685
|
+
(usage.recentDays ?? []).length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
686
|
+
className: CodeArtsPluginCard_module_css_default.hint,
|
|
687
|
+
children: t("usageTrendWeek")
|
|
688
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(UsageTrend, {
|
|
689
|
+
mode: "hit",
|
|
690
|
+
axisEvery: 1,
|
|
691
|
+
hint: t("usageTrendHint"),
|
|
692
|
+
points: (usage.recentDays ?? []).map((day) => ({
|
|
693
|
+
key: day.date,
|
|
694
|
+
label: day.date.slice(5),
|
|
695
|
+
totals: day.totals
|
|
696
|
+
})),
|
|
697
|
+
t
|
|
698
|
+
})] }),
|
|
699
|
+
(usage.todayByHour ?? []).length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
700
|
+
className: CodeArtsPluginCard_module_css_default.hint,
|
|
701
|
+
children: t("usageTrendHour")
|
|
702
|
+
}), (usage.todayByHour ?? []).some((entry) => entry.totals.requests > 0) ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(UsageTrend, {
|
|
703
|
+
mode: "volume",
|
|
704
|
+
axisEvery: 6,
|
|
705
|
+
hint: t("usageTrendHint"),
|
|
706
|
+
points: (usage.todayByHour ?? []).map((entry) => ({
|
|
707
|
+
key: String(entry.hour),
|
|
708
|
+
label: String(entry.hour),
|
|
709
|
+
totals: entry.totals
|
|
710
|
+
})),
|
|
711
|
+
t
|
|
712
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
713
|
+
className: CodeArtsPluginCard_module_css_default.trendTip,
|
|
714
|
+
children: t("usageTrendHourEmpty")
|
|
715
|
+
})] }),
|
|
570
716
|
accounts.length > 1 && accountRows.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
571
717
|
className: CodeArtsPluginCard_module_css_default.hint,
|
|
572
718
|
children: t("usageByAccount")
|
|
@@ -613,7 +759,7 @@ function UsageSection({ usage, accounts, t }) {
|
|
|
613
759
|
});
|
|
614
760
|
}
|
|
615
761
|
function CodeArtsPluginCard({ t }) {
|
|
616
|
-
const [status, setStatus] = (0, react.useState)(
|
|
762
|
+
const [status, setStatus] = (0, react.useState)(lastStatusSnapshot);
|
|
617
763
|
const [token, setToken] = (0, react.useState)("");
|
|
618
764
|
const [label, setLabel] = (0, react.useState)("");
|
|
619
765
|
const [busy, setBusy] = (0, react.useState)(false);
|
|
@@ -645,19 +791,33 @@ function CodeArtsPluginCard({ t }) {
|
|
|
645
791
|
const [dockWritable, setDockWritable] = (0, react.useState)(false);
|
|
646
792
|
const [dockSaving, setDockSaving] = (0, react.useState)(false);
|
|
647
793
|
const [dockError, setDockError] = (0, react.useState)(null);
|
|
794
|
+
/**
|
|
795
|
+
* 首次读取状态的三态。为什么要单独记:`status === null` 只说明「还没读到」,
|
|
796
|
+
* 直接按它画就会先闪一下「未登录」,等数据回来再翻成「已登录」—— 看起来像
|
|
797
|
+
* 掉线又自己好了。只有服务端明确回 signed-out 才允许画登录框。
|
|
798
|
+
*/
|
|
799
|
+
const [statusPhase, setStatusPhase] = (0, react.useState)(lastStatusSnapshot === null ? "loading" : "ready");
|
|
800
|
+
const [loadError, setLoadError] = (0, react.useState)(null);
|
|
648
801
|
async function refreshDock() {
|
|
649
802
|
try {
|
|
650
803
|
const res = await fetch("/api/codearts/dock", { headers: { Accept: "application/json" } });
|
|
651
804
|
if (!res.ok) return;
|
|
652
805
|
const data = await res.json();
|
|
653
|
-
if (data.dock !== void 0)
|
|
806
|
+
if (data.dock !== void 0) {
|
|
807
|
+
const next = {
|
|
808
|
+
...DOCK_DEFAULT,
|
|
809
|
+
...data.dock
|
|
810
|
+
};
|
|
811
|
+
setDock(next);
|
|
812
|
+
setSidebarPanelWanted(next.sidebar);
|
|
813
|
+
}
|
|
654
814
|
setDockWritable(data.writable === true);
|
|
655
815
|
} catch {}
|
|
656
816
|
}
|
|
657
817
|
/**
|
|
658
818
|
* 改一个开关:先按新值渲染,写失败再退回去。
|
|
659
819
|
*
|
|
660
|
-
* 这里不像模型勾选那样攒草稿再点保存 ——
|
|
820
|
+
* 这里不像模型勾选那样攒草稿再点保存 —— 只有几个布尔,攒草稿反而让用户猜
|
|
661
821
|
* 「我刚才那一下到底生效没有」。
|
|
662
822
|
*/
|
|
663
823
|
async function toggleDock(key, on) {
|
|
@@ -668,6 +828,7 @@ function CodeArtsPluginCard({ t }) {
|
|
|
668
828
|
});
|
|
669
829
|
setDockSaving(true);
|
|
670
830
|
setDockError(null);
|
|
831
|
+
if (key === "sidebar") setSidebarPanelWanted(on);
|
|
671
832
|
try {
|
|
672
833
|
const res = await fetch("/api/codearts/dock", {
|
|
673
834
|
method: "POST",
|
|
@@ -682,9 +843,17 @@ function CodeArtsPluginCard({ t }) {
|
|
|
682
843
|
throw new Error(typeof data.error === "string" ? data.error : `HTTP ${res.status}`);
|
|
683
844
|
}
|
|
684
845
|
const data = await res.json();
|
|
685
|
-
if (data.dock !== void 0)
|
|
846
|
+
if (data.dock !== void 0) {
|
|
847
|
+
const next = {
|
|
848
|
+
...DOCK_DEFAULT,
|
|
849
|
+
...data.dock
|
|
850
|
+
};
|
|
851
|
+
setDock(next);
|
|
852
|
+
setSidebarPanelWanted(next.sidebar);
|
|
853
|
+
}
|
|
686
854
|
} catch (error) {
|
|
687
855
|
setDock(previous);
|
|
856
|
+
if (key === "sidebar") setSidebarPanelWanted(previous.sidebar);
|
|
688
857
|
setDockError(error instanceof Error ? error.message : String(error));
|
|
689
858
|
} finally {
|
|
690
859
|
setDockSaving(false);
|
|
@@ -732,14 +901,16 @@ function CodeArtsPluginCard({ t }) {
|
|
|
732
901
|
}
|
|
733
902
|
async function refresh() {
|
|
734
903
|
try {
|
|
735
|
-
const
|
|
904
|
+
const res = await fetch("/api/codearts/status", { headers: { Accept: "application/json" } });
|
|
905
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
906
|
+
const data = await res.json();
|
|
907
|
+
lastStatusSnapshot = data;
|
|
736
908
|
setStatus(data);
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
});
|
|
909
|
+
setLoadError(null);
|
|
910
|
+
setStatusPhase("ready");
|
|
911
|
+
} catch (error) {
|
|
912
|
+
setLoadError(error instanceof Error ? error.message : String(error));
|
|
913
|
+
setStatusPhase((phase) => phase === "ready" ? "ready" : "failed");
|
|
743
914
|
}
|
|
744
915
|
}
|
|
745
916
|
async function refreshSelection() {
|
|
@@ -965,6 +1136,10 @@ function CodeArtsPluginCard({ t }) {
|
|
|
965
1136
|
}
|
|
966
1137
|
const signedIn = status?.status === "signed-in";
|
|
967
1138
|
const expired = status?.status === "expired";
|
|
1139
|
+
/** 首次数据还没回来:标题栏说「加载中」,正文放骨架,别画登录框。 */
|
|
1140
|
+
const loading = statusPhase === "loading";
|
|
1141
|
+
/** 连状态都读不到(服务没起 / 路由 404):给错误和重试,不要假装没登录。 */
|
|
1142
|
+
const failed = statusPhase === "failed" && status === null;
|
|
968
1143
|
const accounts = status?.accounts ?? [];
|
|
969
1144
|
const accountName = (account) => account.label?.trim() || account.userName?.trim() || account.id;
|
|
970
1145
|
/**
|
|
@@ -979,8 +1154,10 @@ function CodeArtsPluginCard({ t }) {
|
|
|
979
1154
|
if (Number.isFinite(exp)) parts.push(exp <= Date.now() ? t("accountExpired", { time: formatStored(exp) }) : t("accountExpires", { time: formatStored(exp) }));
|
|
980
1155
|
return parts.join(" · ");
|
|
981
1156
|
};
|
|
982
|
-
const dotState = signedIn ? "done" : expired ? "warning" : "idle";
|
|
983
|
-
const statusText = signedIn ? t("statusSignedIn") : expired ? t("statusExpired") : t("statusSignedOut");
|
|
1157
|
+
const dotState = !loading && signedIn ? "done" : !loading && expired ? "warning" : "idle";
|
|
1158
|
+
const statusText = loading ? t("statusLoading") : failed ? t("statusUnavailable") : signedIn ? t("statusSignedIn") : expired ? t("statusExpired") : t("statusSignedOut");
|
|
1159
|
+
/** 读不到状态时别在下面写「去登录」—— 用户可能已经登录了,只是接口没起来。 */
|
|
1160
|
+
const descText = loading ? t("descLoading") : failed ? null : signedIn ? t("descSignedIn") : t("descSignedOut");
|
|
984
1161
|
const storedTime = formatStored(status?.storedAt);
|
|
985
1162
|
const storedLabel = status?.label?.trim() ?? "";
|
|
986
1163
|
const meta = !signedIn || storedTime === "" ? "" : storedLabel === "" ? t("storedMetaNoLabel", { time: storedTime }) : t("storedMeta", {
|
|
@@ -1058,15 +1235,15 @@ function CodeArtsPluginCard({ t }) {
|
|
|
1058
1235
|
className: CodeArtsPluginCard_module_css_default.meta,
|
|
1059
1236
|
children: meta
|
|
1060
1237
|
}),
|
|
1061
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1238
|
+
descText !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1062
1239
|
className: CodeArtsPluginCard_module_css_default.desc,
|
|
1063
|
-
children:
|
|
1240
|
+
children: descText
|
|
1064
1241
|
})
|
|
1065
1242
|
]
|
|
1066
1243
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
1067
1244
|
variant: "outline",
|
|
1068
1245
|
size: "sm",
|
|
1069
|
-
disabled: busy,
|
|
1246
|
+
disabled: busy || loading,
|
|
1070
1247
|
onClick: () => void refresh(),
|
|
1071
1248
|
children: t("refresh")
|
|
1072
1249
|
})]
|
|
@@ -1077,7 +1254,31 @@ function CodeArtsPluginCard({ t }) {
|
|
|
1077
1254
|
className: CodeArtsPluginCard_module_css_default.error,
|
|
1078
1255
|
children: status.piAiError
|
|
1079
1256
|
}),
|
|
1080
|
-
|
|
1257
|
+
failed ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1258
|
+
className: CodeArtsPluginCard_module_css_default.section,
|
|
1259
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1260
|
+
className: CodeArtsPluginCard_module_css_default.error,
|
|
1261
|
+
children: t("loadFailed", { message: loadError ?? "" })
|
|
1262
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1263
|
+
className: CodeArtsPluginCard_module_css_default.actions,
|
|
1264
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
1265
|
+
variant: "outline",
|
|
1266
|
+
size: "sm",
|
|
1267
|
+
disabled: busy,
|
|
1268
|
+
onClick: () => void refresh(),
|
|
1269
|
+
children: t("retry")
|
|
1270
|
+
})
|
|
1271
|
+
})]
|
|
1272
|
+
}) : loading ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1273
|
+
className: CodeArtsPluginCard_module_css_default.skeleton,
|
|
1274
|
+
"aria-busy": "true",
|
|
1275
|
+
"aria-label": t("statusLoading"),
|
|
1276
|
+
children: [
|
|
1277
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: CodeArtsPluginCard_module_css_default.skeletonRow }),
|
|
1278
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: CodeArtsPluginCard_module_css_default.skeletonRow }),
|
|
1279
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: CodeArtsPluginCard_module_css_default.skeletonRow })
|
|
1280
|
+
]
|
|
1281
|
+
}) : signedIn ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
1081
1282
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.SegmentedTabs, {
|
|
1082
1283
|
className: CodeArtsPluginCard_module_css_default.tabs,
|
|
1083
1284
|
items: tabs,
|
|
@@ -1361,11 +1562,11 @@ function CodeArtsPluginCard({ t }) {
|
|
|
1361
1562
|
t
|
|
1362
1563
|
})
|
|
1363
1564
|
}),
|
|
1364
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
1565
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(TabPanel, {
|
|
1365
1566
|
id: panelId("display"),
|
|
1366
1567
|
labelledBy: tabId("display"),
|
|
1367
1568
|
active: activeTab === "display",
|
|
1368
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1569
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1369
1570
|
className: CodeArtsPluginCard_module_css_default.section,
|
|
1370
1571
|
children: [
|
|
1371
1572
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
@@ -1410,7 +1611,35 @@ function CodeArtsPluginCard({ t }) {
|
|
|
1410
1611
|
children: t("displayFailed", { message: dockError })
|
|
1411
1612
|
})
|
|
1412
1613
|
]
|
|
1413
|
-
})
|
|
1614
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1615
|
+
className: CodeArtsPluginCard_module_css_default.section,
|
|
1616
|
+
children: [
|
|
1617
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1618
|
+
className: CodeArtsPluginCard_module_css_default.sectionHead,
|
|
1619
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1620
|
+
className: CodeArtsPluginCard_module_css_default.sectionLabel,
|
|
1621
|
+
children: t("displaySidebarTitle")
|
|
1622
|
+
})
|
|
1623
|
+
}),
|
|
1624
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1625
|
+
className: CodeArtsPluginCard_module_css_default.hint,
|
|
1626
|
+
children: t("displaySidebarHint")
|
|
1627
|
+
}),
|
|
1628
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1629
|
+
className: CodeArtsPluginCard_module_css_default.choices,
|
|
1630
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1631
|
+
className: CodeArtsPluginCard_module_css_default.choiceRow,
|
|
1632
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Checkbox, {
|
|
1633
|
+
className: CodeArtsPluginCard_module_css_default.check,
|
|
1634
|
+
checked: dock.sidebar,
|
|
1635
|
+
disabled: !dockWritable || dockSaving,
|
|
1636
|
+
onChange: (on) => void toggleDock("sidebar", on),
|
|
1637
|
+
label: t("displaySidebarToggle")
|
|
1638
|
+
})
|
|
1639
|
+
})
|
|
1640
|
+
})
|
|
1641
|
+
]
|
|
1642
|
+
})]
|
|
1414
1643
|
})
|
|
1415
1644
|
] }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1416
1645
|
className: CodeArtsPluginCard_module_css_default.section,
|
|
@@ -1704,7 +1933,8 @@ function CodeArtsCreditDock({ useProjection, t, zone = "dock" }) {
|
|
|
1704
1933
|
const [modelInfo, setModelInfo] = (0, react.useState)({});
|
|
1705
1934
|
const [flags, setFlags] = (0, react.useState)({
|
|
1706
1935
|
credits: true,
|
|
1707
|
-
queue: true
|
|
1936
|
+
queue: true,
|
|
1937
|
+
sidebar: false
|
|
1708
1938
|
});
|
|
1709
1939
|
const [queued, setQueued] = (0, react.useState)(null);
|
|
1710
1940
|
const [anchor, setAnchor] = (0, react.useState)(null);
|
|
@@ -1740,7 +1970,8 @@ function CodeArtsCreditDock({ useProjection, t, zone = "dock" }) {
|
|
|
1740
1970
|
if (data === void 0 || !mounted.current) return;
|
|
1741
1971
|
setFlags(data.dock ?? {
|
|
1742
1972
|
credits: true,
|
|
1743
|
-
queue: true
|
|
1973
|
+
queue: true,
|
|
1974
|
+
sidebar: false
|
|
1744
1975
|
});
|
|
1745
1976
|
setRows(rowsOf(data));
|
|
1746
1977
|
setModelInfo(Object.fromEntries((data.models ?? []).map((model) => [model.id, {
|
|
@@ -2048,6 +2279,95 @@ function CodeArtsCreditDock({ useProjection, t, zone = "dock" }) {
|
|
|
2048
2279
|
});
|
|
2049
2280
|
}
|
|
2050
2281
|
//#endregion
|
|
2282
|
+
//#region \0dsh-css:/home/runner/work/dsh-codearts/dsh-codearts/src/client/CodeArtsPanel.module.css.mjs
|
|
2283
|
+
const css = ".Z66cgG_page{box-sizing:border-box;height:100%;min-height:0;padding:calc(28px + var(--dsh-frame-top-clearance,0px)) clamp(24px, 4vw, 48px) 48px;color:var(--dsw-alias-label-primary);flex-direction:column;display:flex;overflow:auto}.Z66cgG_head{flex-direction:column;gap:6px;width:100%;max-width:860px;margin:0 auto;display:flex}.Z66cgG_back{appearance:none;font:inherit;cursor:pointer;border:1px solid var(--dsw-alias-border-l2);border-radius:var(--dsw-radius-md);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-secondary);align-self:flex-start;align-items:center;gap:6px;margin-bottom:10px;padding:5px 12px;font-size:13px;line-height:20px;display:inline-flex}.Z66cgG_back:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.Z66cgG_backCaret{border-bottom:1.6px solid;border-left:1.6px solid;width:7px;height:7px;display:inline-block;transform:rotate(45deg)}.Z66cgG_title{margin:0;font-size:20px;font-weight:600;line-height:1.4}.Z66cgG_desc{color:var(--dsw-alias-label-tertiary);margin:0;font-size:13px;line-height:1.5}.Z66cgG_body{width:100%;max-width:860px;margin:20px auto 0}.Z66cgG_icon{flex:none;display:block}";
|
|
2284
|
+
const tagId = "dsh-codearts/CodeArtsPanel.module.css";
|
|
2285
|
+
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
2286
|
+
const tag = document.createElement("style");
|
|
2287
|
+
tag.dataset.plugin = "dsh-codearts";
|
|
2288
|
+
tag.dataset.pluginCss = tagId;
|
|
2289
|
+
tag.textContent = css;
|
|
2290
|
+
document.head.appendChild(tag);
|
|
2291
|
+
}
|
|
2292
|
+
var CodeArtsPanel_module_css_default = {
|
|
2293
|
+
"title": "Z66cgG_title",
|
|
2294
|
+
"icon": "Z66cgG_icon",
|
|
2295
|
+
"back": "Z66cgG_back",
|
|
2296
|
+
"page": "Z66cgG_page",
|
|
2297
|
+
"backCaret": "Z66cgG_backCaret",
|
|
2298
|
+
"body": "Z66cgG_body",
|
|
2299
|
+
"head": "Z66cgG_head",
|
|
2300
|
+
"desc": "Z66cgG_desc"
|
|
2301
|
+
};
|
|
2302
|
+
//#endregion
|
|
2303
|
+
//#region src/client/CodeArtsPanel.tsx
|
|
2304
|
+
/** 侧边栏按钮里的图标。宿主按 { size, active } 渲染,我们用 currentColor 跟随主题。 */
|
|
2305
|
+
function CodeArtsPanelIcon({ size }) {
|
|
2306
|
+
const px = typeof size === "number" && size > 0 ? size : 16;
|
|
2307
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
|
|
2308
|
+
className: CodeArtsPanel_module_css_default.icon,
|
|
2309
|
+
width: px,
|
|
2310
|
+
height: px,
|
|
2311
|
+
viewBox: "0 0 16 16",
|
|
2312
|
+
fill: "none",
|
|
2313
|
+
"aria-hidden": "true",
|
|
2314
|
+
focusable: "false",
|
|
2315
|
+
children: [
|
|
2316
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
|
|
2317
|
+
d: "M5.1 3.9 1.9 8l3.2 4.1",
|
|
2318
|
+
stroke: "currentColor",
|
|
2319
|
+
strokeWidth: "1",
|
|
2320
|
+
strokeLinecap: "round",
|
|
2321
|
+
strokeLinejoin: "round"
|
|
2322
|
+
}),
|
|
2323
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
|
|
2324
|
+
d: "M10.9 3.9 14.1 8l-3.2 4.1",
|
|
2325
|
+
stroke: "currentColor",
|
|
2326
|
+
strokeWidth: "1",
|
|
2327
|
+
strokeLinecap: "round",
|
|
2328
|
+
strokeLinejoin: "round"
|
|
2329
|
+
}),
|
|
2330
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
|
|
2331
|
+
d: "M9 3.2 7 12.8",
|
|
2332
|
+
stroke: "currentColor",
|
|
2333
|
+
strokeWidth: "1",
|
|
2334
|
+
strokeLinecap: "round"
|
|
2335
|
+
})
|
|
2336
|
+
]
|
|
2337
|
+
});
|
|
2338
|
+
}
|
|
2339
|
+
/** 侧边栏入口页:一个返回按钮 + 标题,正文直接复用设置里那张卡片。 */
|
|
2340
|
+
function CodeArtsPanelPage({ t, backToConversation }) {
|
|
2341
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2342
|
+
className: CodeArtsPanel_module_css_default.page,
|
|
2343
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2344
|
+
className: CodeArtsPanel_module_css_default.head,
|
|
2345
|
+
children: [
|
|
2346
|
+
backToConversation !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
2347
|
+
type: "button",
|
|
2348
|
+
className: CodeArtsPanel_module_css_default.back,
|
|
2349
|
+
onClick: backToConversation,
|
|
2350
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2351
|
+
className: CodeArtsPanel_module_css_default.backCaret,
|
|
2352
|
+
"aria-hidden": "true"
|
|
2353
|
+
}), t("panelBack")]
|
|
2354
|
+
}),
|
|
2355
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h1", {
|
|
2356
|
+
className: CodeArtsPanel_module_css_default.title,
|
|
2357
|
+
children: t("cardTitle")
|
|
2358
|
+
}),
|
|
2359
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2360
|
+
className: CodeArtsPanel_module_css_default.desc,
|
|
2361
|
+
children: t("panelDesc")
|
|
2362
|
+
})
|
|
2363
|
+
]
|
|
2364
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2365
|
+
className: CodeArtsPanel_module_css_default.body,
|
|
2366
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CodeArtsPluginCard, { t })
|
|
2367
|
+
})]
|
|
2368
|
+
});
|
|
2369
|
+
}
|
|
2370
|
+
//#endregion
|
|
2051
2371
|
//#region src/client/locales.ts
|
|
2052
2372
|
const zh = {
|
|
2053
2373
|
tabLabel: "CodeArts",
|
|
@@ -2061,6 +2381,11 @@ const zh = {
|
|
|
2061
2381
|
statusExpired: "凭证已过期",
|
|
2062
2382
|
descSignedIn: "凭证已就绪,勾选的模型会出现在模型选择器里。",
|
|
2063
2383
|
descSignedOut: "用华为云账号登录,或手动粘贴一个 CodeArts cloud_dragon_token。",
|
|
2384
|
+
statusLoading: "加载中…",
|
|
2385
|
+
statusUnavailable: "状态读取失败",
|
|
2386
|
+
descLoading: "正在读取账号、模型与用量…",
|
|
2387
|
+
loadFailed: "读不到插件状态({message})",
|
|
2388
|
+
retry: "重试",
|
|
2064
2389
|
storedMeta: "{label} · 存于 {time}",
|
|
2065
2390
|
storedMetaNoLabel: "存于 {time}",
|
|
2066
2391
|
refresh: "刷新",
|
|
@@ -2125,6 +2450,10 @@ const zh = {
|
|
|
2125
2450
|
usageStatHit: "缓存命中",
|
|
2126
2451
|
usageStatRequests: "今日请求",
|
|
2127
2452
|
usageRequests: "{n} 次请求",
|
|
2453
|
+
usageTrendWeek: "近 7 天 · 缓存命中率",
|
|
2454
|
+
usageTrendHour: "今天 · 逐小时 token",
|
|
2455
|
+
usageTrendHint: "悬停柱子看那一格明细",
|
|
2456
|
+
usageTrendHourEmpty: "今天还没有逐小时数据(启用前的小时不回填)",
|
|
2128
2457
|
usageByAccount: "今日按账号",
|
|
2129
2458
|
usageRequestCount: "{n} 条",
|
|
2130
2459
|
usageTokens: "输入 {prompt} · 输出 {completion}",
|
|
@@ -2170,6 +2499,9 @@ const zh = {
|
|
|
2170
2499
|
displayQueueToggle: "显示上游排队位置",
|
|
2171
2500
|
displayNotWritable: "这个宿主没给插件开配置存储,开关只能看不能改。",
|
|
2172
2501
|
displayFailed: "保存失败:{message}",
|
|
2502
|
+
displaySidebarTitle: "侧边栏图标",
|
|
2503
|
+
displaySidebarHint: "勾上以后,DSH 左侧那一列图标里会多一个 CodeArts,点它直接在中间列打开当前这一页,不必每次都绕进设置。默认不勾:这列图标是全宿主共用的,每个插件都来占一格很快就挤满了。改完立刻生效,没有保存步骤。",
|
|
2504
|
+
displaySidebarToggle: "在侧边栏图标列显示 CodeArts",
|
|
2173
2505
|
queueDock: "排队第 {position} 位",
|
|
2174
2506
|
queueDockTitle: "上游排队:{model} · 第 {position} 位 / 共 {length} 条",
|
|
2175
2507
|
claimButton: "签到领积分",
|
|
@@ -2180,7 +2512,9 @@ const zh = {
|
|
|
2180
2512
|
claimDone: "已领取 {amount} 积分",
|
|
2181
2513
|
claimAlready: "今日已领,明天再来",
|
|
2182
2514
|
claimUnavailable: "这个账号当前没有可领的签到活动",
|
|
2183
|
-
claimFailed: "领取失败:{message}"
|
|
2515
|
+
claimFailed: "领取失败:{message}",
|
|
2516
|
+
panelBack: "返回对话",
|
|
2517
|
+
panelDesc: "账号、模型开关与用量都在这一页里管,和设置 → 插件里那张卡片是同一份状态。"
|
|
2184
2518
|
};
|
|
2185
2519
|
const en = {
|
|
2186
2520
|
tabLabel: "CodeArts",
|
|
@@ -2194,6 +2528,11 @@ const en = {
|
|
|
2194
2528
|
statusExpired: "Credential expired",
|
|
2195
2529
|
descSignedIn: "Credential is ready. Checked models show up in the model picker.",
|
|
2196
2530
|
descSignedOut: "Sign in with your Huawei Cloud account, or paste a CodeArts cloud_dragon_token.",
|
|
2531
|
+
statusLoading: "Loading…",
|
|
2532
|
+
statusUnavailable: "Status unavailable",
|
|
2533
|
+
descLoading: "Reading accounts, models and usage…",
|
|
2534
|
+
loadFailed: "Could not read plugin status ({message})",
|
|
2535
|
+
retry: "Retry",
|
|
2197
2536
|
storedMeta: "{label} · stored {time}",
|
|
2198
2537
|
storedMetaNoLabel: "stored {time}",
|
|
2199
2538
|
refresh: "Refresh",
|
|
@@ -2258,6 +2597,10 @@ const en = {
|
|
|
2258
2597
|
usageStatHit: "Cache hit",
|
|
2259
2598
|
usageStatRequests: "Today requests",
|
|
2260
2599
|
usageRequests: "{n} request(s)",
|
|
2600
|
+
usageTrendWeek: "Last 7 days · cache hit rate",
|
|
2601
|
+
usageTrendHour: "Today · tokens by hour",
|
|
2602
|
+
usageTrendHint: "Hover a bar for that slot",
|
|
2603
|
+
usageTrendHourEmpty: "No hourly data yet today (hours before this feature are not backfilled)",
|
|
2261
2604
|
usageByAccount: "Today by account",
|
|
2262
2605
|
usageRequestCount: "{n} reqs",
|
|
2263
2606
|
usageTokens: "in {prompt} · out {completion}",
|
|
@@ -2303,6 +2646,9 @@ const en = {
|
|
|
2303
2646
|
displayQueueToggle: "Show the upstream queue position",
|
|
2304
2647
|
displayNotWritable: "This host gives the plugin nowhere to persist settings, so the switches are read-only.",
|
|
2305
2648
|
displayFailed: "Failed to save: {message}",
|
|
2649
|
+
displaySidebarTitle: "Sidebar icon",
|
|
2650
|
+
displaySidebarHint: "Once checked, a CodeArts icon joins the icon column on the left of DSH and opens this very page in the middle column, so you do not have to go through Settings each time. Off by default: that column is shared by the whole host, and it fills up quickly if every plugin claims a slot. Takes effect immediately — there is nothing to save.",
|
|
2651
|
+
displaySidebarToggle: "Show CodeArts in the sidebar icon column",
|
|
2306
2652
|
queueDock: "Queued #{position}",
|
|
2307
2653
|
queueDockTitle: "Upstream queue: {model} · position {position} of {length}",
|
|
2308
2654
|
claimButton: "Claim daily credits",
|
|
@@ -2313,13 +2659,32 @@ const en = {
|
|
|
2313
2659
|
claimDone: "Claimed {amount} credits",
|
|
2314
2660
|
claimAlready: "Already claimed today — come back tomorrow",
|
|
2315
2661
|
claimUnavailable: "No check-in campaign available for this account",
|
|
2316
|
-
claimFailed: "Claim failed: {message}"
|
|
2662
|
+
claimFailed: "Claim failed: {message}",
|
|
2663
|
+
panelBack: "Back to chat",
|
|
2664
|
+
panelDesc: "Manage accounts, model switches and usage here — same state as the card under Settings → Plugins."
|
|
2317
2665
|
};
|
|
2318
2666
|
//#endregion
|
|
2319
2667
|
//#region src/client/index.tsx
|
|
2320
2668
|
const name = "dsh-codearts-client";
|
|
2321
2669
|
const inject = ["slots", "locale"];
|
|
2670
|
+
/**
|
|
2671
|
+
* 侧边栏按钮的 id,同时也是中间列面板的 key —— 宿主靠这两个同名值把
|
|
2672
|
+
* 「点了哪一行」和「中间列画哪一页」配对。
|
|
2673
|
+
*/
|
|
2674
|
+
const PANEL_ID = "dsh-codearts";
|
|
2322
2675
|
function apply(ctx) {
|
|
2676
|
+
/**
|
|
2677
|
+
* 回对话页。软取 layout 服务:`ctx.get` 在服务没提供时返回 undefined 而不会抛,
|
|
2678
|
+
* 所以老宿主/非桌面端只是没有返回按钮,不影响整块 client 加载。
|
|
2679
|
+
* 故意不写进 `inject` —— 依赖缺失会让 apply 整个不跑。
|
|
2680
|
+
*/
|
|
2681
|
+
const backToConversation = () => {
|
|
2682
|
+
try {
|
|
2683
|
+
ctx.get("layout")?.selectPanel?.(null);
|
|
2684
|
+
} catch (error) {
|
|
2685
|
+
console.error("[dsh-codearts] failed to switch back to conversation:", error);
|
|
2686
|
+
}
|
|
2687
|
+
};
|
|
2323
2688
|
try {
|
|
2324
2689
|
const namespace = "settings.codearts";
|
|
2325
2690
|
ctx.effect(() => ctx.locale.register(namespace, {
|
|
@@ -2352,6 +2717,85 @@ function apply(ctx) {
|
|
|
2352
2717
|
zone: "dock"
|
|
2353
2718
|
})
|
|
2354
2719
|
}, CodeArtsCreditDock));
|
|
2720
|
+
/** 每次 claim 拿到的 inject disposer;拆的时候逐个调用(连带注销里面的注册)。 */
|
|
2721
|
+
const panelClaims = [];
|
|
2722
|
+
const dropPanelSlots = () => {
|
|
2723
|
+
for (const dispose of panelClaims.splice(0)) try {
|
|
2724
|
+
dispose();
|
|
2725
|
+
} catch (error) {
|
|
2726
|
+
console.error("[dsh-codearts] failed to release sidebar panel:", error);
|
|
2727
|
+
}
|
|
2728
|
+
};
|
|
2729
|
+
const syncPanelRegistration = () => {
|
|
2730
|
+
dropPanelSlots();
|
|
2731
|
+
if (!sidebarPanelWanted()) return;
|
|
2732
|
+
try {
|
|
2733
|
+
panelClaims.push(ctx.slots.inject("sidebar.panellist", () => {
|
|
2734
|
+
try {
|
|
2735
|
+
return ctx.slots.register({
|
|
2736
|
+
name: "sidebar.panellist",
|
|
2737
|
+
id: PANEL_ID,
|
|
2738
|
+
order: 50,
|
|
2739
|
+
label: () => t("tabLabel"),
|
|
2740
|
+
locale: namespace
|
|
2741
|
+
}, CodeArtsPanelIcon);
|
|
2742
|
+
} catch (error) {
|
|
2743
|
+
console.error("[dsh-codearts] sidebar panel entry unavailable:", error);
|
|
2744
|
+
return () => {};
|
|
2745
|
+
}
|
|
2746
|
+
}));
|
|
2747
|
+
} catch (error) {
|
|
2748
|
+
console.error("[dsh-codearts] sidebar panel slot unavailable:", error);
|
|
2749
|
+
}
|
|
2750
|
+
try {
|
|
2751
|
+
panelClaims.push(ctx.slots.inject("main", () => {
|
|
2752
|
+
try {
|
|
2753
|
+
return ctx.slots.register({
|
|
2754
|
+
name: "main",
|
|
2755
|
+
key: PANEL_ID,
|
|
2756
|
+
locale: namespace,
|
|
2757
|
+
inject: () => ({
|
|
2758
|
+
t,
|
|
2759
|
+
backToConversation
|
|
2760
|
+
})
|
|
2761
|
+
}, CodeArtsPanelPage);
|
|
2762
|
+
} catch (error) {
|
|
2763
|
+
console.error("[dsh-codearts] main panel page unavailable:", error);
|
|
2764
|
+
return () => {};
|
|
2765
|
+
}
|
|
2766
|
+
}));
|
|
2767
|
+
} catch (error) {
|
|
2768
|
+
console.error("[dsh-codearts] main panel slot unavailable:", error);
|
|
2769
|
+
}
|
|
2770
|
+
};
|
|
2771
|
+
/**
|
|
2772
|
+
* 开关关掉时如果用户正站在那一页上,先回对话 —— 否则中间列会留在
|
|
2773
|
+
* 一个已经没了的 key 上。软取 layout:没有这个服务就跳过。
|
|
2774
|
+
*/
|
|
2775
|
+
const leavePanelIfActive = () => {
|
|
2776
|
+
try {
|
|
2777
|
+
const layout = ctx.get("layout");
|
|
2778
|
+
if (layout?.panelInfo?.getSnapshot?.()?.activePanelId === PANEL_ID) layout.selectPanel?.(null);
|
|
2779
|
+
} catch {}
|
|
2780
|
+
};
|
|
2781
|
+
ctx.effect(() => {
|
|
2782
|
+
const off = subscribeSidebarPanelWanted(() => {
|
|
2783
|
+
if (!sidebarPanelWanted()) leavePanelIfActive();
|
|
2784
|
+
syncPanelRegistration();
|
|
2785
|
+
});
|
|
2786
|
+
syncPanelRegistration();
|
|
2787
|
+
return () => {
|
|
2788
|
+
off();
|
|
2789
|
+
dropPanelSlots();
|
|
2790
|
+
};
|
|
2791
|
+
}, "dsh-codearts: sidebar panel opt-in");
|
|
2792
|
+
(async () => {
|
|
2793
|
+
try {
|
|
2794
|
+
const res = await fetch("/api/codearts/dock", { headers: { Accept: "application/json" } });
|
|
2795
|
+
if (!res.ok) return;
|
|
2796
|
+
setSidebarPanelWanted((await res.json()).dock?.sidebar === true);
|
|
2797
|
+
} catch {}
|
|
2798
|
+
})();
|
|
2355
2799
|
} catch (error) {
|
|
2356
2800
|
console.error("[dsh-codearts] client card failed to load (host provider unaffected):", error);
|
|
2357
2801
|
}
|