dsh-codearts 0.2.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/bin.mjs +5 -5
- package/lib/client/index.d.cts +12 -0
- package/lib/client/index.js +254 -35
- package/lib/index.d.mts +143 -17
- package/lib/index.mjs +411 -36
- package/lib/{usage-ClRZWUS4.mjs → usage-Cn1Bzmxj.mjs} +104 -18
- package/package.json +1 -1
package/lib/bin.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
2
|
+
import { S as codeartsAccountsPath, _ as FALLBACK_CODEARTS_MODELS, b as CodeArtsAccountStore, l as fetchCallerIdentity, n as codeartsUsagePath, r as discoverModels, t as CodeArtsUsageTracker, y as isBenefitModel } from "./usage-Cn1Bzmxj.mjs";
|
|
3
3
|
import { existsSync, statSync } from "node:fs";
|
|
4
4
|
//#region src/version.ts
|
|
5
|
-
const CODEARTS_VERSION = "0.
|
|
5
|
+
const CODEARTS_VERSION = "0.3.0";
|
|
6
6
|
//#endregion
|
|
7
7
|
//#region src/bin.ts
|
|
8
8
|
/**
|
|
@@ -23,8 +23,8 @@ const CODEARTS_VERSION = "0.2.1";
|
|
|
23
23
|
* benefit and agent-center sources) instead of printing the hand-maintained seed —
|
|
24
24
|
* that is the first thing to run when a model is missing from the picker.
|
|
25
25
|
*
|
|
26
|
-
* `usage` reads the plugin's own ledger of requests this machine sent
|
|
27
|
-
*
|
|
26
|
+
* `usage` reads the plugin's own ledger of requests this machine sent — not an
|
|
27
|
+
* account balance (account credits live in the card / `credits` route).
|
|
28
28
|
*
|
|
29
29
|
* `identity` asks the gateway which account each stored credential belongs to. The
|
|
30
30
|
* login response carries no user id, so credentials used to be keyed by their DPoP
|
|
@@ -204,7 +204,7 @@ async function usage(jsonOutput) {
|
|
|
204
204
|
process.stdout.write("today by account:\n");
|
|
205
205
|
for (const [id, totals] of accounts) process.stdout.write(` - ${id.slice(0, 12)}… ${totals.requests} req in ${totals.promptTokens} / out ${totals.completionTokens}\n`);
|
|
206
206
|
}
|
|
207
|
-
process.stdout.write("note:
|
|
207
|
+
process.stdout.write("note: this counts requests this machine sent through the plugin; account credits are in the card\n");
|
|
208
208
|
return 0;
|
|
209
209
|
}
|
|
210
210
|
/**
|
package/lib/client/index.d.cts
CHANGED
|
@@ -19,6 +19,8 @@ interface CodeArtsSettingsKey {
|
|
|
19
19
|
saveToken: string;
|
|
20
20
|
expiredHint: string;
|
|
21
21
|
accountsTitle: string;
|
|
22
|
+
accountsShow: string;
|
|
23
|
+
accountsHide: string;
|
|
22
24
|
accountRemove: string;
|
|
23
25
|
addAccount: string;
|
|
24
26
|
accountsRotateHint: string;
|
|
@@ -55,6 +57,16 @@ interface CodeArtsSettingsKey {
|
|
|
55
57
|
usageStateDisabled: string;
|
|
56
58
|
usageNoQuota: string;
|
|
57
59
|
usageEmpty: string;
|
|
60
|
+
creditsTitle: string;
|
|
61
|
+
creditsRemaining: string;
|
|
62
|
+
creditsUsed: string;
|
|
63
|
+
creditsExpiring: string;
|
|
64
|
+
creditsReset: string;
|
|
65
|
+
creditsTokensToday: string;
|
|
66
|
+
creditsTokensBalance: string;
|
|
67
|
+
creditsUnavailable: string;
|
|
68
|
+
creditsDock: string;
|
|
69
|
+
creditsDockTitle: string;
|
|
58
70
|
[key: string]: string;
|
|
59
71
|
}
|
|
60
72
|
//#endregion
|
package/lib/client/index.js
CHANGED
|
@@ -8,7 +8,7 @@ let react = require("react");
|
|
|
8
8
|
let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
9
9
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
10
10
|
//#region \0dsh-css:F:\centos\dsh-codearts\src\client\CodeArtsPluginCard.module.css.mjs
|
|
11
|
-
const css = ".DZPfya_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}.DZPfya_header{align-items:flex-start;gap:12px;padding:14px 16px;display:flex}.DZPfya_headText{flex-direction:column;flex:1;gap:6px;min-width:0;display:flex}.DZPfya_name{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:22px}.DZPfya_desc{color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:20px}.DZPfya_statusLine{color:var(--dsw-alias-label-primary);align-items:center;gap:6px;font-size:14px;font-weight:500;line-height:22px;display:inline-flex}.DZPfya_meta{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;font-size:12px;line-height:18px}.DZPfya_body{border-top:.5px solid var(--dsw-alias-border-l2);margin:0 16px;padding:4px 0 16px}.DZPfya_section{margin-top:16px}.DZPfya_sectionHead{justify-content:space-between;align-items:baseline;gap:12px;display:flex}.DZPfya_sectionLabel{color:var(--dsw-alias-label-tertiary);font-size:11px;font-weight:500}.DZPfya_count{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;flex:none;font-size:12px}.DZPfya_hint{color:var(--dsw-alias-label-secondary);margin:8px 0 0;font-size:13px;line-height:20px}.DZPfya_error{color:var(--dsw-alias-state-error-primary);margin:10px 0 0;font-size:13px;line-height:20px}.DZPfya_actions{flex-wrap:wrap;align-items:center;gap:8px;margin-top:12px;display:flex}.DZPfya_danger{color:var(--dsw-alias-state-error-primary)}.DZPfya_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}.DZPfya_link:hover{text-decoration:underline}.DZPfya_choices{flex-direction:column;gap:2px;margin-top:8px;display:flex}.DZPfya_choiceRow{border-radius:var(--dsw-radius-sm);align-items:center;gap:8px;margin:0 -6px;padding:5px 6px;display:flex}.DZPfya_choiceRow:hover{background:var(--dsw-alias-interactive-bg-hover)}.DZPfya_check{flex:1;min-width:0}.DZPfya_check>span{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.DZPfya_manual{border:.5px solid var(--dsw-alias-border-l3);border-radius:var(--dsw-radius-md);margin-top:12px;padding:0 12px}.DZPfya_manual[open]{padding-bottom:12px}.DZPfya_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}.DZPfya_manualSummary::-webkit-details-marker{display:none}.DZPfya_field{flex-direction:column;gap:5px;margin-top:10px;display:flex}.DZPfya_fieldLabel{color:var(--dsw-alias-label-tertiary);font-size:12px}.DZPfya_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}.DZPfya_area::placeholder{color:var(--dsw-alias-label-dimmed)}.DZPfya_area:focus{border-color:var(--dsw-alias-state-business-primary);outline:none}";
|
|
11
|
+
const css = ".DZPfya_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}.DZPfya_header{align-items:flex-start;gap:12px;padding:14px 16px;display:flex}.DZPfya_headText{flex-direction:column;flex:1;gap:6px;min-width:0;display:flex}.DZPfya_name{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:22px}.DZPfya_desc{color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:20px}.DZPfya_statusLine{color:var(--dsw-alias-label-primary);align-items:center;gap:6px;font-size:14px;font-weight:500;line-height:22px;display:inline-flex}.DZPfya_meta{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;font-size:12px;line-height:18px}.DZPfya_body{border-top:.5px solid var(--dsw-alias-border-l2);margin:0 16px;padding:4px 0 16px}.DZPfya_section{margin-top:16px}.DZPfya_sectionHead{justify-content:space-between;align-items:baseline;gap:12px;display:flex}.DZPfya_sectionLabel{color:var(--dsw-alias-label-tertiary);font-size:11px;font-weight:500}.DZPfya_headActions{flex:none;align-items:center;gap:8px;display:flex}.DZPfya_count{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;flex:none;font-size:12px}.DZPfya_hint{color:var(--dsw-alias-label-secondary);margin:8px 0 0;font-size:13px;line-height:20px}.DZPfya_error{color:var(--dsw-alias-state-error-primary);margin:10px 0 0;font-size:13px;line-height:20px}.DZPfya_actions{flex-wrap:wrap;align-items:center;gap:8px;margin-top:12px;display:flex}.DZPfya_danger{color:var(--dsw-alias-state-error-primary)}.DZPfya_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}.DZPfya_link:hover{text-decoration:underline}.DZPfya_choices{flex-direction:column;gap:2px;margin-top:8px;display:flex}.DZPfya_choiceRow{border-radius:var(--dsw-radius-sm);align-items:center;gap:8px;margin:0 -6px;padding:5px 6px;display:flex}.DZPfya_choiceRow:hover{background:var(--dsw-alias-interactive-bg-hover)}.DZPfya_check{flex:1;min-width:0}.DZPfya_check>span{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.DZPfya_manual{border:.5px solid var(--dsw-alias-border-l3);border-radius:var(--dsw-radius-md);margin-top:12px;padding:0 12px}.DZPfya_manual[open]{padding-bottom:12px}.DZPfya_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}.DZPfya_manualSummary::-webkit-details-marker{display:none}.DZPfya_field{flex-direction:column;gap:5px;margin-top:10px;display:flex}.DZPfya_fieldLabel{color:var(--dsw-alias-label-tertiary);font-size:12px}.DZPfya_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}.DZPfya_area::placeholder{color:var(--dsw-alias-label-dimmed)}.DZPfya_area:focus{border-color:var(--dsw-alias-state-business-primary);outline:none}";
|
|
12
12
|
const tagId = "dsh-codearts/CodeArtsPluginCard.module.css";
|
|
13
13
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
14
14
|
const tag = document.createElement("style");
|
|
@@ -18,31 +18,32 @@ if (typeof document !== "undefined" && document.querySelector("style[data-plugin
|
|
|
18
18
|
document.head.appendChild(tag);
|
|
19
19
|
}
|
|
20
20
|
var CodeArtsPluginCard_module_css_default = {
|
|
21
|
+
"fieldLabel": "DZPfya_fieldLabel",
|
|
22
|
+
"danger": "DZPfya_danger",
|
|
23
|
+
"card": "DZPfya_card",
|
|
24
|
+
"hint": "DZPfya_hint",
|
|
25
|
+
"header": "DZPfya_header",
|
|
26
|
+
"link": "DZPfya_link",
|
|
21
27
|
"body": "DZPfya_body",
|
|
28
|
+
"headText": "DZPfya_headText",
|
|
22
29
|
"name": "DZPfya_name",
|
|
30
|
+
"meta": "DZPfya_meta",
|
|
31
|
+
"section": "DZPfya_section",
|
|
32
|
+
"sectionLabel": "DZPfya_sectionLabel",
|
|
33
|
+
"error": "DZPfya_error",
|
|
34
|
+
"choices": "DZPfya_choices",
|
|
35
|
+
"desc": "DZPfya_desc",
|
|
36
|
+
"sectionHead": "DZPfya_sectionHead",
|
|
37
|
+
"choiceRow": "DZPfya_choiceRow",
|
|
38
|
+
"check": "DZPfya_check",
|
|
23
39
|
"manual": "DZPfya_manual",
|
|
24
40
|
"manualSummary": "DZPfya_manualSummary",
|
|
25
41
|
"statusLine": "DZPfya_statusLine",
|
|
26
|
-
"actions": "DZPfya_actions",
|
|
27
|
-
"sectionLabel": "DZPfya_sectionLabel",
|
|
28
42
|
"field": "DZPfya_field",
|
|
29
|
-
"
|
|
30
|
-
"danger": "DZPfya_danger",
|
|
43
|
+
"actions": "DZPfya_actions",
|
|
31
44
|
"area": "DZPfya_area",
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"desc": "DZPfya_desc",
|
|
35
|
-
"meta": "DZPfya_meta",
|
|
36
|
-
"choiceRow": "DZPfya_choiceRow",
|
|
37
|
-
"choices": "DZPfya_choices",
|
|
38
|
-
"sectionHead": "DZPfya_sectionHead",
|
|
39
|
-
"fieldLabel": "DZPfya_fieldLabel",
|
|
40
|
-
"card": "DZPfya_card",
|
|
41
|
-
"link": "DZPfya_link",
|
|
42
|
-
"header": "DZPfya_header",
|
|
43
|
-
"headText": "DZPfya_headText",
|
|
44
|
-
"section": "DZPfya_section",
|
|
45
|
-
"check": "DZPfya_check"
|
|
45
|
+
"headActions": "DZPfya_headActions",
|
|
46
|
+
"count": "DZPfya_count"
|
|
46
47
|
};
|
|
47
48
|
//#endregion
|
|
48
49
|
//#region src/client/CodeArtsPluginCard.tsx
|
|
@@ -59,8 +60,15 @@ const TRAILING_FREE = /\s*[((]\s*免费\s*[))]\s*$/;
|
|
|
59
60
|
function modelName(choice) {
|
|
60
61
|
return choice.free === true ? choice.name.replace(TRAILING_FREE, "") : choice.name;
|
|
61
62
|
}
|
|
62
|
-
/**
|
|
63
|
+
/** 官方用量明细页。 */
|
|
63
64
|
const OFFICIAL_USAGE_URL = "https://codearts.huaweicloud.com/portal/settings/personal-usage";
|
|
65
|
+
/**
|
|
66
|
+
* 账号身份默认遮蔽后的占位符。
|
|
67
|
+
*
|
|
68
|
+
* 卡片经常被截图贴进问题反馈,账号名(label / userName / id)与获取、过期时间
|
|
69
|
+
* 没有出现在截图里的必要,所以默认遮住,点一下才展开。
|
|
70
|
+
*/
|
|
71
|
+
const ACCOUNT_MASK = "*******";
|
|
64
72
|
/** token 数按人类习惯缩写:12345 -> 12.3k。 */
|
|
65
73
|
function formatTokens(value) {
|
|
66
74
|
if (!Number.isFinite(value)) return "0";
|
|
@@ -71,13 +79,87 @@ function formatTokens(value) {
|
|
|
71
79
|
function formatCount(value) {
|
|
72
80
|
return Number.isFinite(value) ? String(Math.round(value)) : "0";
|
|
73
81
|
}
|
|
82
|
+
/** 积分/token 千分位格式化(2000 → "2,000")。 */
|
|
83
|
+
function formatCredits(value) {
|
|
84
|
+
return Number.isFinite(value) ? new Intl.NumberFormat().format(Math.round(value)) : "0";
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* 积分区块。
|
|
88
|
+
*
|
|
89
|
+
* 2026-10 从官方 CodeArts Agent 客户端挖出积分接口并实测通过(见 src/credits.ts),
|
|
90
|
+
* 所以这里能直接显示账号总额度 —— 与下面的「本机用量」互补:一个是账号级、一个是
|
|
91
|
+
* 本机级。拉不到时显示原因(creditsError),不静默吞掉。
|
|
92
|
+
*/
|
|
93
|
+
function CreditsSection({ credits, error, t }) {
|
|
94
|
+
if (credits === void 0 && error === void 0) return null;
|
|
95
|
+
const c = credits?.credits;
|
|
96
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
97
|
+
className: CodeArtsPluginCard_module_css_default.section,
|
|
98
|
+
children: [
|
|
99
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
100
|
+
className: CodeArtsPluginCard_module_css_default.sectionHead,
|
|
101
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
102
|
+
className: CodeArtsPluginCard_module_css_default.sectionLabel,
|
|
103
|
+
children: t("creditsTitle")
|
|
104
|
+
}), c !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
105
|
+
className: CodeArtsPluginCard_module_css_default.count,
|
|
106
|
+
children: t("creditsRemaining", {
|
|
107
|
+
remain: formatCredits(c.total.remain),
|
|
108
|
+
total: formatCredits(c.total.total)
|
|
109
|
+
})
|
|
110
|
+
})]
|
|
111
|
+
}),
|
|
112
|
+
error !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
113
|
+
className: CodeArtsPluginCard_module_css_default.hint,
|
|
114
|
+
children: t("creditsUnavailable", { message: error })
|
|
115
|
+
}),
|
|
116
|
+
c !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
117
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
118
|
+
className: CodeArtsPluginCard_module_css_default.choiceRow,
|
|
119
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
120
|
+
className: CodeArtsPluginCard_module_css_default.name,
|
|
121
|
+
children: c.planName
|
|
122
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
123
|
+
className: CodeArtsPluginCard_module_css_default.meta,
|
|
124
|
+
children: t("creditsUsed", { used: formatCredits(c.total.used) })
|
|
125
|
+
})]
|
|
126
|
+
}),
|
|
127
|
+
c.periodEnd !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
128
|
+
className: CodeArtsPluginCard_module_css_default.choiceRow,
|
|
129
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
130
|
+
className: CodeArtsPluginCard_module_css_default.name,
|
|
131
|
+
children: t("creditsReset", { date: c.periodEnd })
|
|
132
|
+
}), c.total.expiring > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
133
|
+
className: CodeArtsPluginCard_module_css_default.meta,
|
|
134
|
+
children: t("creditsExpiring", {
|
|
135
|
+
expiring: formatCredits(c.total.expiring),
|
|
136
|
+
date: c.periodEnd
|
|
137
|
+
})
|
|
138
|
+
})]
|
|
139
|
+
}),
|
|
140
|
+
credits?.tokens !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
141
|
+
className: CodeArtsPluginCard_module_css_default.choiceRow,
|
|
142
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
143
|
+
className: CodeArtsPluginCard_module_css_default.name,
|
|
144
|
+
children: t("creditsTokensToday", {
|
|
145
|
+
used: formatCredits(credits.tokens.dailyUsed),
|
|
146
|
+
limit: formatCredits(credits.tokens.dailyLimit)
|
|
147
|
+
})
|
|
148
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
149
|
+
className: CodeArtsPluginCard_module_css_default.meta,
|
|
150
|
+
children: t("creditsTokensBalance", { balance: formatCredits(credits.tokens.balance) })
|
|
151
|
+
})]
|
|
152
|
+
})
|
|
153
|
+
] })
|
|
154
|
+
]
|
|
155
|
+
});
|
|
156
|
+
}
|
|
74
157
|
/**
|
|
75
158
|
* 用量区块。
|
|
76
159
|
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
* 才释放,这也正是「打断后重新提问要等」的原因。
|
|
160
|
+
* 只展示**本机经插件发出**的请求(不等于账号总额度 —— 账号额度见上方积分区块);
|
|
161
|
+
* 会话槽位是真事实 —— 每账号 3 个并发会话、被占时要等约 52 秒才释放,这也正是
|
|
162
|
+
* 「打断后重新提问要等」的原因。
|
|
81
163
|
*/
|
|
82
164
|
function UsageSection({ usage, t }) {
|
|
83
165
|
const total = usage.today.requests;
|
|
@@ -198,6 +280,8 @@ function CodeArtsPluginCard({ t }) {
|
|
|
198
280
|
const [savingModels, setSavingModels] = (0, react.useState)(false);
|
|
199
281
|
const [savedModels, setSavedModels] = (0, react.useState)(false);
|
|
200
282
|
const [modelError, setModelError] = (0, react.useState)(null);
|
|
283
|
+
/** 账号身份是否展开:默认遮蔽(false = 显示 *******)。 */
|
|
284
|
+
const [accountsRevealed, setAccountsRevealed] = (0, react.useState)(false);
|
|
201
285
|
async function refresh() {
|
|
202
286
|
try {
|
|
203
287
|
const data = await (await fetch("/api/codearts/status", { headers: { Accept: "application/json" } })).json();
|
|
@@ -357,6 +441,8 @@ function CodeArtsPluginCard({ t }) {
|
|
|
357
441
|
const expired = status?.status === "expired";
|
|
358
442
|
const accounts = status?.accounts ?? [];
|
|
359
443
|
const accountName = (account) => account.label?.trim() || account.userName?.trim() || account.id;
|
|
444
|
+
/** 遮蔽态下账号身份一律换成占位符:原值连 DOM 都不进。 */
|
|
445
|
+
const reveal = (value) => accountsRevealed ? value : ACCOUNT_MASK;
|
|
360
446
|
/**
|
|
361
447
|
* 每个账号的「获取时间 + 过期状态」。同一账号重复登录可能留下多条记录(上游不给
|
|
362
448
|
* 稳定身份时的妥协),把时间摆出来用户才能一眼认出哪条是旧的、放心删。
|
|
@@ -373,7 +459,7 @@ function CodeArtsPluginCard({ t }) {
|
|
|
373
459
|
const statusText = signedIn ? t("statusSignedIn") : expired ? t("statusExpired") : t("statusSignedOut");
|
|
374
460
|
const storedTime = formatStored(status?.storedAt);
|
|
375
461
|
const storedLabel = status?.label?.trim() ?? "";
|
|
376
|
-
const meta = !signedIn || storedTime === "" ? "" : storedLabel === "" ? t("storedMetaNoLabel", { time: storedTime }) : t("storedMeta", {
|
|
462
|
+
const meta = !signedIn || storedTime === "" ? "" : storedLabel === "" || !accountsRevealed ? t("storedMetaNoLabel", { time: storedTime }) : t("storedMeta", {
|
|
377
463
|
label: storedLabel,
|
|
378
464
|
time: storedTime
|
|
379
465
|
});
|
|
@@ -419,9 +505,18 @@ function CodeArtsPluginCard({ t }) {
|
|
|
419
505
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
420
506
|
className: CodeArtsPluginCard_module_css_default.sectionLabel,
|
|
421
507
|
children: t("accountsTitle")
|
|
422
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.
|
|
423
|
-
className: CodeArtsPluginCard_module_css_default.
|
|
424
|
-
children:
|
|
508
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
509
|
+
className: CodeArtsPluginCard_module_css_default.headActions,
|
|
510
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
511
|
+
className: CodeArtsPluginCard_module_css_default.count,
|
|
512
|
+
children: accounts.length
|
|
513
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
514
|
+
variant: "outline",
|
|
515
|
+
size: "sm",
|
|
516
|
+
"aria-pressed": accountsRevealed,
|
|
517
|
+
onClick: () => setAccountsRevealed((revealed) => !revealed),
|
|
518
|
+
children: accountsRevealed ? t("accountsHide") : t("accountsShow")
|
|
519
|
+
})]
|
|
425
520
|
})]
|
|
426
521
|
}),
|
|
427
522
|
accounts.length > 1 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
@@ -435,11 +530,11 @@ function CodeArtsPluginCard({ t }) {
|
|
|
435
530
|
children: [
|
|
436
531
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
437
532
|
className: CodeArtsPluginCard_module_css_default.name,
|
|
438
|
-
children: accountName(account)
|
|
533
|
+
children: reveal(accountName(account))
|
|
439
534
|
}),
|
|
440
|
-
|
|
535
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
441
536
|
className: CodeArtsPluginCard_module_css_default.meta,
|
|
442
|
-
children: meta
|
|
537
|
+
children: reveal(meta)
|
|
443
538
|
}),
|
|
444
539
|
account.stale && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tag, { children: t("accountNeedsSignIn") }),
|
|
445
540
|
!account.signable && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tag, { children: t("accountNoKey") }),
|
|
@@ -636,6 +731,11 @@ function CodeArtsPluginCard({ t }) {
|
|
|
636
731
|
className: CodeArtsPluginCard_module_css_default.hint,
|
|
637
732
|
children: t("modelsLoading")
|
|
638
733
|
}),
|
|
734
|
+
signedIn && (status?.credits !== void 0 || status?.creditsError !== void 0) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CreditsSection, {
|
|
735
|
+
credits: status?.credits,
|
|
736
|
+
error: status?.creditsError,
|
|
737
|
+
t
|
|
738
|
+
}),
|
|
639
739
|
status?.usage !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(UsageSection, {
|
|
640
740
|
usage: status.usage,
|
|
641
741
|
t
|
|
@@ -645,6 +745,94 @@ function CodeArtsPluginCard({ t }) {
|
|
|
645
745
|
});
|
|
646
746
|
}
|
|
647
747
|
//#endregion
|
|
748
|
+
//#region src/client/CodeArtsCreditDock.tsx
|
|
749
|
+
/**
|
|
750
|
+
* 对话底部的积分条。
|
|
751
|
+
*
|
|
752
|
+
* 用户最初的诉求就是「对话底部要显示积分」—— 这一条挂在
|
|
753
|
+
* `conversation.composer.dock` 槽位上(与宿主 session-stats strip 同位)。
|
|
754
|
+
* 只在当前 provider 是 codearts 时才拉取并显示一行「积分 N」,别的 provider 下
|
|
755
|
+
* 完全不渲染,不抢别人的行。
|
|
756
|
+
*
|
|
757
|
+
* 积分数据走插件自己的 `/api/codearts/status`(带 TTL 缓存,见 src/credits.ts),
|
|
758
|
+
* 不会因为这条 dock 让上游多挨一次请求。
|
|
759
|
+
*/
|
|
760
|
+
/** 与 src/adapter.ts 的 CODEARTS_PROVIDER 对齐 —— client 不能 import host 模块。 */
|
|
761
|
+
const CODEARTS_PROVIDER = "codearts";
|
|
762
|
+
const STATUS_PATH = "/api/codearts/status";
|
|
763
|
+
/** 轮询间隔:与缓存 TTL(60s)对齐,再短也只是反复命中缓存。 */
|
|
764
|
+
const REFRESH_INTERVAL_MS = 6e4;
|
|
765
|
+
function readSelection(useProjection) {
|
|
766
|
+
if (useProjection === void 0) return void 0;
|
|
767
|
+
try {
|
|
768
|
+
return useProjection("modelSelection");
|
|
769
|
+
} catch {
|
|
770
|
+
return;
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
function isCodeArts(selection) {
|
|
774
|
+
return (selection?.next ?? selection?.lastUsed)?.provider === CODEARTS_PROVIDER;
|
|
775
|
+
}
|
|
776
|
+
function CodeArtsCreditDock({ useProjection, t }) {
|
|
777
|
+
const active = isCodeArts(readSelection(useProjection));
|
|
778
|
+
const [remain, setRemain] = (0, react.useState)(null);
|
|
779
|
+
const [total, setTotal] = (0, react.useState)(0);
|
|
780
|
+
const mounted = (0, react.useRef)(true);
|
|
781
|
+
(0, react.useEffect)(() => {
|
|
782
|
+
mounted.current = true;
|
|
783
|
+
return () => {
|
|
784
|
+
mounted.current = false;
|
|
785
|
+
};
|
|
786
|
+
}, []);
|
|
787
|
+
(0, react.useEffect)(() => {
|
|
788
|
+
if (!active) {
|
|
789
|
+
setRemain(null);
|
|
790
|
+
return;
|
|
791
|
+
}
|
|
792
|
+
let timer;
|
|
793
|
+
const refresh = async () => {
|
|
794
|
+
try {
|
|
795
|
+
const res = await fetch(STATUS_PATH, {
|
|
796
|
+
headers: { Accept: "application/json" },
|
|
797
|
+
credentials: "same-origin"
|
|
798
|
+
});
|
|
799
|
+
if (!res.ok) return;
|
|
800
|
+
const data = await res.json().catch(() => void 0);
|
|
801
|
+
if (data === void 0 || data.credits === void 0) return;
|
|
802
|
+
if (mounted.current) {
|
|
803
|
+
setRemain(Math.round(data.credits.credits.total.remain));
|
|
804
|
+
setTotal(Math.round(data.credits.credits.total.total));
|
|
805
|
+
}
|
|
806
|
+
} catch {}
|
|
807
|
+
};
|
|
808
|
+
refresh();
|
|
809
|
+
timer = window.setInterval(refresh, REFRESH_INTERVAL_MS);
|
|
810
|
+
return () => {
|
|
811
|
+
if (timer !== void 0) window.clearInterval(timer);
|
|
812
|
+
};
|
|
813
|
+
}, [active]);
|
|
814
|
+
if (!active || remain === null) return null;
|
|
815
|
+
const text = t("creditsDock", { remain: new Intl.NumberFormat().format(remain) });
|
|
816
|
+
const title = t("creditsDockTitle", {
|
|
817
|
+
remain,
|
|
818
|
+
total
|
|
819
|
+
});
|
|
820
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
821
|
+
style: {
|
|
822
|
+
display: "inline-flex",
|
|
823
|
+
alignItems: "center",
|
|
824
|
+
gap: 6,
|
|
825
|
+
color: "var(--dsw-alias-label-tertiary)",
|
|
826
|
+
fontSize: "var(--dsh-content-font-size-secondary, 13px)",
|
|
827
|
+
lineHeight: "18px",
|
|
828
|
+
fontVariantNumeric: "tabular-nums",
|
|
829
|
+
whiteSpace: "nowrap"
|
|
830
|
+
},
|
|
831
|
+
title,
|
|
832
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: text })
|
|
833
|
+
});
|
|
834
|
+
}
|
|
835
|
+
//#endregion
|
|
648
836
|
//#region src/client/locales.ts
|
|
649
837
|
const zh = {
|
|
650
838
|
tabLabel: "CodeArts",
|
|
@@ -665,6 +853,8 @@ const zh = {
|
|
|
665
853
|
saveToken: "保存 token",
|
|
666
854
|
expiredHint: "凭证已过期,请重新登录以继续使用;已勾选的模型设置会保留。",
|
|
667
855
|
accountsTitle: "账号",
|
|
856
|
+
accountsShow: "显示账号",
|
|
857
|
+
accountsHide: "隐藏账号",
|
|
668
858
|
accountRemove: "删除",
|
|
669
859
|
addAccount: "添加账号",
|
|
670
860
|
accountsRotateHint: "已存多个账号:请求会自动轮转,某个账号忙时改用下一个,不用干等。",
|
|
@@ -699,8 +889,18 @@ const zh = {
|
|
|
699
889
|
usageStateCapped: "撞上限,优先避开",
|
|
700
890
|
usageStateCooling: "冷却中",
|
|
701
891
|
usageStateDisabled: "已停用",
|
|
702
|
-
usageNoQuota: "
|
|
703
|
-
usageEmpty: "还没有记录:发一条消息就会开始累计。"
|
|
892
|
+
usageNoQuota: "这里是本机经插件发出的请求统计(不等于账号总额度);官方用量明细见",
|
|
893
|
+
usageEmpty: "还没有记录:发一条消息就会开始累计。",
|
|
894
|
+
creditsTitle: "积分",
|
|
895
|
+
creditsRemaining: "剩余 {remain} / {total}",
|
|
896
|
+
creditsUsed: "已用 {used}",
|
|
897
|
+
creditsExpiring: "其中 {expiring} 将在 {date} 重置时作废",
|
|
898
|
+
creditsReset: "额度重置 {date}",
|
|
899
|
+
creditsTokensToday: "今日 token {used} / {limit}",
|
|
900
|
+
creditsTokensBalance: "余额 {balance}",
|
|
901
|
+
creditsUnavailable: "积分不可用:{message}",
|
|
902
|
+
creditsDock: "积分 {remain}",
|
|
903
|
+
creditsDockTitle: "CodeArts 剩余积分 {remain} / {total}"
|
|
704
904
|
};
|
|
705
905
|
const en = {
|
|
706
906
|
tabLabel: "CodeArts",
|
|
@@ -721,6 +921,8 @@ const en = {
|
|
|
721
921
|
saveToken: "Save token",
|
|
722
922
|
expiredHint: "Your credential has expired. Sign in again to continue; your model selection is kept.",
|
|
723
923
|
accountsTitle: "Accounts",
|
|
924
|
+
accountsShow: "Show accounts",
|
|
925
|
+
accountsHide: "Hide accounts",
|
|
724
926
|
accountRemove: "Remove",
|
|
725
927
|
addAccount: "Add account",
|
|
726
928
|
accountsRotateHint: "Multiple accounts stored: requests rotate automatically, so a busy account hands over to the next one instead of making you wait.",
|
|
@@ -755,8 +957,18 @@ const en = {
|
|
|
755
957
|
usageStateCapped: "Cap hit, avoiding",
|
|
756
958
|
usageStateCooling: "Cooling down",
|
|
757
959
|
usageStateDisabled: "Disabled",
|
|
758
|
-
usageNoQuota: "
|
|
759
|
-
usageEmpty: "Nothing recorded yet: send a message to start counting."
|
|
960
|
+
usageNoQuota: "Counts the requests this machine sent through the plugin (not the account balance). Official usage:",
|
|
961
|
+
usageEmpty: "Nothing recorded yet: send a message to start counting.",
|
|
962
|
+
creditsTitle: "Credits",
|
|
963
|
+
creditsRemaining: "{remain} of {total} left",
|
|
964
|
+
creditsUsed: "{used} used",
|
|
965
|
+
creditsExpiring: "{expiring} of them expire at the next reset on {date}",
|
|
966
|
+
creditsReset: "Quota resets {date}",
|
|
967
|
+
creditsTokensToday: "Today {used} / {limit} tokens",
|
|
968
|
+
creditsTokensBalance: "{balance} left",
|
|
969
|
+
creditsUnavailable: "Credits unavailable: {message}",
|
|
970
|
+
creditsDock: "Credits {remain}",
|
|
971
|
+
creditsDockTitle: "CodeArts credits left {remain} / {total}"
|
|
760
972
|
};
|
|
761
973
|
//#endregion
|
|
762
974
|
//#region src/client/index.tsx
|
|
@@ -775,6 +987,13 @@ function apply(ctx) {
|
|
|
775
987
|
key: "dsh-codearts",
|
|
776
988
|
locale: namespace
|
|
777
989
|
}, () => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CodeArtsPluginCard, { t })));
|
|
990
|
+
ctx.slots.inject("conversation.composer.dock", () => ctx.slots.register({
|
|
991
|
+
name: "conversation.composer.dock",
|
|
992
|
+
id: "codearts-credits",
|
|
993
|
+
order: 20,
|
|
994
|
+
locale: namespace,
|
|
995
|
+
inject: () => ({ t })
|
|
996
|
+
}, CodeArtsCreditDock));
|
|
778
997
|
} catch (error) {
|
|
779
998
|
console.error("[dsh-codearts] client card failed to load (host provider unaffected):", error);
|
|
780
999
|
}
|