dsh-codearts 0.2.1 → 0.4.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 +16 -0
- package/lib/client/index.js +308 -34
- package/lib/index.d.mts +143 -17
- package/lib/index.mjs +472 -36
- package/lib/{usage-ClRZWUS4.mjs → usage-3W88T_H1.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 { C as codeartsAccountsPath, b as isBenefitModel, n as codeartsUsagePath, r as discoverModels, t as CodeArtsUsageTracker, u as fetchCallerIdentity, v as FALLBACK_CODEARTS_MODELS, x as CodeArtsAccountStore } from "./usage-3W88T_H1.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,20 @@ 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;
|
|
70
|
+
claimButton: string;
|
|
71
|
+
claiming: string;
|
|
72
|
+
claimSuccess: string;
|
|
73
|
+
claimFailed: string;
|
|
58
74
|
[key: string]: string;
|
|
59
75
|
}
|
|
60
76
|
//#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
|
-
"
|
|
22
|
-
"name": "DZPfya_name",
|
|
23
|
-
"manual": "DZPfya_manual",
|
|
24
|
-
"manualSummary": "DZPfya_manualSummary",
|
|
25
|
-
"statusLine": "DZPfya_statusLine",
|
|
21
|
+
"choices": "DZPfya_choices",
|
|
26
22
|
"actions": "DZPfya_actions",
|
|
27
|
-
"
|
|
23
|
+
"choiceRow": "DZPfya_choiceRow",
|
|
24
|
+
"header": "DZPfya_header",
|
|
25
|
+
"manualSummary": "DZPfya_manualSummary",
|
|
28
26
|
"field": "DZPfya_field",
|
|
29
|
-
"
|
|
30
|
-
"
|
|
27
|
+
"meta": "DZPfya_meta",
|
|
28
|
+
"link": "DZPfya_link",
|
|
31
29
|
"area": "DZPfya_area",
|
|
32
|
-
"
|
|
30
|
+
"headActions": "DZPfya_headActions",
|
|
33
31
|
"hint": "DZPfya_hint",
|
|
32
|
+
"statusLine": "DZPfya_statusLine",
|
|
33
|
+
"check": "DZPfya_check",
|
|
34
|
+
"manual": "DZPfya_manual",
|
|
34
35
|
"desc": "DZPfya_desc",
|
|
35
|
-
"meta": "DZPfya_meta",
|
|
36
|
-
"choiceRow": "DZPfya_choiceRow",
|
|
37
|
-
"choices": "DZPfya_choices",
|
|
38
|
-
"sectionHead": "DZPfya_sectionHead",
|
|
39
36
|
"fieldLabel": "DZPfya_fieldLabel",
|
|
37
|
+
"body": "DZPfya_body",
|
|
38
|
+
"section": "DZPfya_section",
|
|
40
39
|
"card": "DZPfya_card",
|
|
41
|
-
"
|
|
42
|
-
"
|
|
40
|
+
"name": "DZPfya_name",
|
|
41
|
+
"sectionHead": "DZPfya_sectionHead",
|
|
42
|
+
"sectionLabel": "DZPfya_sectionLabel",
|
|
43
|
+
"count": "DZPfya_count",
|
|
43
44
|
"headText": "DZPfya_headText",
|
|
44
|
-
"
|
|
45
|
-
"
|
|
45
|
+
"error": "DZPfya_error",
|
|
46
|
+
"danger": "DZPfya_danger"
|
|
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,133 @@ 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, onClaimed }) {
|
|
94
|
+
const [claimState, setClaimState] = (0, react.useState)(() => {
|
|
95
|
+
try {
|
|
96
|
+
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
97
|
+
if (typeof localStorage !== "undefined" && localStorage.getItem("codearts-claim-date") === today) return "success";
|
|
98
|
+
} catch {}
|
|
99
|
+
return "idle";
|
|
100
|
+
});
|
|
101
|
+
const [claimMessage, setClaimMessage] = (0, react.useState)("");
|
|
102
|
+
if (credits === void 0 && error === void 0) return null;
|
|
103
|
+
const handleClaim = async () => {
|
|
104
|
+
setClaimState("loading");
|
|
105
|
+
try {
|
|
106
|
+
const res = await fetch("/api/codearts/claim", {
|
|
107
|
+
method: "POST",
|
|
108
|
+
headers: { Accept: "application/json" },
|
|
109
|
+
credentials: "same-origin"
|
|
110
|
+
});
|
|
111
|
+
const data = await res.json().catch(() => void 0);
|
|
112
|
+
if (res.ok && data?.ok === true) {
|
|
113
|
+
setClaimState("success");
|
|
114
|
+
try {
|
|
115
|
+
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
116
|
+
if (typeof localStorage !== "undefined") localStorage.setItem("codearts-claim-date", today);
|
|
117
|
+
} catch {}
|
|
118
|
+
onClaimed?.();
|
|
119
|
+
} else {
|
|
120
|
+
setClaimState("error");
|
|
121
|
+
setClaimMessage(data?.message ?? `HTTP ${res.status}`);
|
|
122
|
+
}
|
|
123
|
+
} catch (err) {
|
|
124
|
+
setClaimState("error");
|
|
125
|
+
setClaimMessage(err instanceof Error ? err.message : String(err));
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
const c = credits?.credits;
|
|
129
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
130
|
+
className: CodeArtsPluginCard_module_css_default.section,
|
|
131
|
+
children: [
|
|
132
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
133
|
+
className: CodeArtsPluginCard_module_css_default.sectionHead,
|
|
134
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
135
|
+
className: CodeArtsPluginCard_module_css_default.sectionLabel,
|
|
136
|
+
children: t("creditsTitle")
|
|
137
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
138
|
+
className: CodeArtsPluginCard_module_css_default.headActions,
|
|
139
|
+
children: [c !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
140
|
+
className: CodeArtsPluginCard_module_css_default.count,
|
|
141
|
+
children: t("creditsRemaining", {
|
|
142
|
+
remain: formatCredits(c.total.remain),
|
|
143
|
+
total: formatCredits(c.total.total)
|
|
144
|
+
})
|
|
145
|
+
}), onClaimed !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
146
|
+
variant: "outline",
|
|
147
|
+
size: "sm",
|
|
148
|
+
disabled: claimState === "loading" || claimState === "success",
|
|
149
|
+
onClick: () => void handleClaim(),
|
|
150
|
+
children: claimState === "loading" ? t("claiming") : claimState === "success" ? t("claimSuccess") : t("claimButton")
|
|
151
|
+
})]
|
|
152
|
+
})]
|
|
153
|
+
}),
|
|
154
|
+
error !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
155
|
+
className: CodeArtsPluginCard_module_css_default.hint,
|
|
156
|
+
children: t("creditsUnavailable", { message: error })
|
|
157
|
+
}),
|
|
158
|
+
claimState === "error" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
159
|
+
className: CodeArtsPluginCard_module_css_default.hint,
|
|
160
|
+
children: t("claimFailed", { message: claimMessage })
|
|
161
|
+
}),
|
|
162
|
+
c !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
163
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
164
|
+
className: CodeArtsPluginCard_module_css_default.choiceRow,
|
|
165
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
166
|
+
className: CodeArtsPluginCard_module_css_default.name,
|
|
167
|
+
children: c.planName
|
|
168
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
169
|
+
className: CodeArtsPluginCard_module_css_default.meta,
|
|
170
|
+
children: t("creditsUsed", { used: formatCredits(c.total.used) })
|
|
171
|
+
})]
|
|
172
|
+
}),
|
|
173
|
+
c.periodEnd !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
174
|
+
className: CodeArtsPluginCard_module_css_default.choiceRow,
|
|
175
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
176
|
+
className: CodeArtsPluginCard_module_css_default.name,
|
|
177
|
+
children: t("creditsReset", { date: c.periodEnd })
|
|
178
|
+
}), c.total.expiring > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
179
|
+
className: CodeArtsPluginCard_module_css_default.meta,
|
|
180
|
+
children: t("creditsExpiring", {
|
|
181
|
+
expiring: formatCredits(c.total.expiring),
|
|
182
|
+
date: c.periodEnd
|
|
183
|
+
})
|
|
184
|
+
})]
|
|
185
|
+
}),
|
|
186
|
+
credits?.tokens !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
187
|
+
className: CodeArtsPluginCard_module_css_default.choiceRow,
|
|
188
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
189
|
+
className: CodeArtsPluginCard_module_css_default.name,
|
|
190
|
+
children: t("creditsTokensToday", {
|
|
191
|
+
used: formatCredits(credits.tokens.dailyUsed),
|
|
192
|
+
limit: formatCredits(credits.tokens.dailyLimit)
|
|
193
|
+
})
|
|
194
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
195
|
+
className: CodeArtsPluginCard_module_css_default.meta,
|
|
196
|
+
children: t("creditsTokensBalance", { balance: formatCredits(credits.tokens.balance) })
|
|
197
|
+
})]
|
|
198
|
+
})
|
|
199
|
+
] })
|
|
200
|
+
]
|
|
201
|
+
});
|
|
202
|
+
}
|
|
74
203
|
/**
|
|
75
204
|
* 用量区块。
|
|
76
205
|
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
* 才释放,这也正是「打断后重新提问要等」的原因。
|
|
206
|
+
* 只展示**本机经插件发出**的请求(不等于账号总额度 —— 账号额度见上方积分区块);
|
|
207
|
+
* 会话槽位是真事实 —— 每账号 3 个并发会话、被占时要等约 52 秒才释放,这也正是
|
|
208
|
+
* 「打断后重新提问要等」的原因。
|
|
81
209
|
*/
|
|
82
210
|
function UsageSection({ usage, t }) {
|
|
83
211
|
const total = usage.today.requests;
|
|
@@ -198,6 +326,8 @@ function CodeArtsPluginCard({ t }) {
|
|
|
198
326
|
const [savingModels, setSavingModels] = (0, react.useState)(false);
|
|
199
327
|
const [savedModels, setSavedModels] = (0, react.useState)(false);
|
|
200
328
|
const [modelError, setModelError] = (0, react.useState)(null);
|
|
329
|
+
/** 账号身份是否展开:默认遮蔽(false = 显示 *******)。 */
|
|
330
|
+
const [accountsRevealed, setAccountsRevealed] = (0, react.useState)(false);
|
|
201
331
|
async function refresh() {
|
|
202
332
|
try {
|
|
203
333
|
const data = await (await fetch("/api/codearts/status", { headers: { Accept: "application/json" } })).json();
|
|
@@ -357,6 +487,8 @@ function CodeArtsPluginCard({ t }) {
|
|
|
357
487
|
const expired = status?.status === "expired";
|
|
358
488
|
const accounts = status?.accounts ?? [];
|
|
359
489
|
const accountName = (account) => account.label?.trim() || account.userName?.trim() || account.id;
|
|
490
|
+
/** 遮蔽态下账号身份一律换成占位符:原值连 DOM 都不进。 */
|
|
491
|
+
const reveal = (value) => accountsRevealed ? value : ACCOUNT_MASK;
|
|
360
492
|
/**
|
|
361
493
|
* 每个账号的「获取时间 + 过期状态」。同一账号重复登录可能留下多条记录(上游不给
|
|
362
494
|
* 稳定身份时的妥协),把时间摆出来用户才能一眼认出哪条是旧的、放心删。
|
|
@@ -373,7 +505,7 @@ function CodeArtsPluginCard({ t }) {
|
|
|
373
505
|
const statusText = signedIn ? t("statusSignedIn") : expired ? t("statusExpired") : t("statusSignedOut");
|
|
374
506
|
const storedTime = formatStored(status?.storedAt);
|
|
375
507
|
const storedLabel = status?.label?.trim() ?? "";
|
|
376
|
-
const meta = !signedIn || storedTime === "" ? "" : storedLabel === "" ? t("storedMetaNoLabel", { time: storedTime }) : t("storedMeta", {
|
|
508
|
+
const meta = !signedIn || storedTime === "" ? "" : storedLabel === "" || !accountsRevealed ? t("storedMetaNoLabel", { time: storedTime }) : t("storedMeta", {
|
|
377
509
|
label: storedLabel,
|
|
378
510
|
time: storedTime
|
|
379
511
|
});
|
|
@@ -419,9 +551,18 @@ function CodeArtsPluginCard({ t }) {
|
|
|
419
551
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
420
552
|
className: CodeArtsPluginCard_module_css_default.sectionLabel,
|
|
421
553
|
children: t("accountsTitle")
|
|
422
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.
|
|
423
|
-
className: CodeArtsPluginCard_module_css_default.
|
|
424
|
-
children:
|
|
554
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
555
|
+
className: CodeArtsPluginCard_module_css_default.headActions,
|
|
556
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
557
|
+
className: CodeArtsPluginCard_module_css_default.count,
|
|
558
|
+
children: accounts.length
|
|
559
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
560
|
+
variant: "outline",
|
|
561
|
+
size: "sm",
|
|
562
|
+
"aria-pressed": accountsRevealed,
|
|
563
|
+
onClick: () => setAccountsRevealed((revealed) => !revealed),
|
|
564
|
+
children: accountsRevealed ? t("accountsHide") : t("accountsShow")
|
|
565
|
+
})]
|
|
425
566
|
})]
|
|
426
567
|
}),
|
|
427
568
|
accounts.length > 1 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
@@ -435,11 +576,11 @@ function CodeArtsPluginCard({ t }) {
|
|
|
435
576
|
children: [
|
|
436
577
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
437
578
|
className: CodeArtsPluginCard_module_css_default.name,
|
|
438
|
-
children: accountName(account)
|
|
579
|
+
children: reveal(accountName(account))
|
|
439
580
|
}),
|
|
440
|
-
|
|
581
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
441
582
|
className: CodeArtsPluginCard_module_css_default.meta,
|
|
442
|
-
children: meta
|
|
583
|
+
children: reveal(meta)
|
|
443
584
|
}),
|
|
444
585
|
account.stale && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tag, { children: t("accountNeedsSignIn") }),
|
|
445
586
|
!account.signable && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tag, { children: t("accountNoKey") }),
|
|
@@ -636,6 +777,12 @@ function CodeArtsPluginCard({ t }) {
|
|
|
636
777
|
className: CodeArtsPluginCard_module_css_default.hint,
|
|
637
778
|
children: t("modelsLoading")
|
|
638
779
|
}),
|
|
780
|
+
signedIn && (status?.credits !== void 0 || status?.creditsError !== void 0) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CreditsSection, {
|
|
781
|
+
credits: status?.credits,
|
|
782
|
+
error: status?.creditsError,
|
|
783
|
+
t,
|
|
784
|
+
onClaimed: () => void refresh()
|
|
785
|
+
}),
|
|
639
786
|
status?.usage !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(UsageSection, {
|
|
640
787
|
usage: status.usage,
|
|
641
788
|
t
|
|
@@ -645,6 +792,94 @@ function CodeArtsPluginCard({ t }) {
|
|
|
645
792
|
});
|
|
646
793
|
}
|
|
647
794
|
//#endregion
|
|
795
|
+
//#region src/client/CodeArtsCreditDock.tsx
|
|
796
|
+
/**
|
|
797
|
+
* 对话底部的积分条。
|
|
798
|
+
*
|
|
799
|
+
* 用户最初的诉求就是「对话底部要显示积分」—— 这一条挂在
|
|
800
|
+
* `conversation.composer.dock` 槽位上(与宿主 session-stats strip 同位)。
|
|
801
|
+
* 只在当前 provider 是 codearts 时才拉取并显示一行「积分 N」,别的 provider 下
|
|
802
|
+
* 完全不渲染,不抢别人的行。
|
|
803
|
+
*
|
|
804
|
+
* 积分数据走插件自己的 `/api/codearts/status`(带 TTL 缓存,见 src/credits.ts),
|
|
805
|
+
* 不会因为这条 dock 让上游多挨一次请求。
|
|
806
|
+
*/
|
|
807
|
+
/** 与 src/adapter.ts 的 CODEARTS_PROVIDER 对齐 —— client 不能 import host 模块。 */
|
|
808
|
+
const CODEARTS_PROVIDER = "codearts";
|
|
809
|
+
const STATUS_PATH = "/api/codearts/status";
|
|
810
|
+
/** 轮询间隔:与缓存 TTL(60s)对齐,再短也只是反复命中缓存。 */
|
|
811
|
+
const REFRESH_INTERVAL_MS = 6e4;
|
|
812
|
+
function readSelection(useProjection) {
|
|
813
|
+
if (useProjection === void 0) return void 0;
|
|
814
|
+
try {
|
|
815
|
+
return useProjection("modelSelection");
|
|
816
|
+
} catch {
|
|
817
|
+
return;
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
function isCodeArts(selection) {
|
|
821
|
+
return (selection?.next ?? selection?.lastUsed)?.provider === CODEARTS_PROVIDER;
|
|
822
|
+
}
|
|
823
|
+
function CodeArtsCreditDock({ useProjection, t }) {
|
|
824
|
+
const active = isCodeArts(readSelection(useProjection));
|
|
825
|
+
const [remain, setRemain] = (0, react.useState)(null);
|
|
826
|
+
const [total, setTotal] = (0, react.useState)(0);
|
|
827
|
+
const mounted = (0, react.useRef)(true);
|
|
828
|
+
(0, react.useEffect)(() => {
|
|
829
|
+
mounted.current = true;
|
|
830
|
+
return () => {
|
|
831
|
+
mounted.current = false;
|
|
832
|
+
};
|
|
833
|
+
}, []);
|
|
834
|
+
(0, react.useEffect)(() => {
|
|
835
|
+
if (!active) {
|
|
836
|
+
setRemain(null);
|
|
837
|
+
return;
|
|
838
|
+
}
|
|
839
|
+
let timer;
|
|
840
|
+
const refresh = async () => {
|
|
841
|
+
try {
|
|
842
|
+
const res = await fetch(STATUS_PATH, {
|
|
843
|
+
headers: { Accept: "application/json" },
|
|
844
|
+
credentials: "same-origin"
|
|
845
|
+
});
|
|
846
|
+
if (!res.ok) return;
|
|
847
|
+
const data = await res.json().catch(() => void 0);
|
|
848
|
+
if (data === void 0 || data.credits === void 0) return;
|
|
849
|
+
if (mounted.current) {
|
|
850
|
+
setRemain(Math.round(data.credits.credits.total.remain));
|
|
851
|
+
setTotal(Math.round(data.credits.credits.total.total));
|
|
852
|
+
}
|
|
853
|
+
} catch {}
|
|
854
|
+
};
|
|
855
|
+
refresh();
|
|
856
|
+
timer = window.setInterval(refresh, REFRESH_INTERVAL_MS);
|
|
857
|
+
return () => {
|
|
858
|
+
if (timer !== void 0) window.clearInterval(timer);
|
|
859
|
+
};
|
|
860
|
+
}, [active]);
|
|
861
|
+
if (!active || remain === null) return null;
|
|
862
|
+
const text = t("creditsDock", { remain: new Intl.NumberFormat().format(remain) });
|
|
863
|
+
const title = t("creditsDockTitle", {
|
|
864
|
+
remain,
|
|
865
|
+
total
|
|
866
|
+
});
|
|
867
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
868
|
+
style: {
|
|
869
|
+
display: "inline-flex",
|
|
870
|
+
alignItems: "center",
|
|
871
|
+
gap: 6,
|
|
872
|
+
color: "var(--dsw-alias-label-tertiary)",
|
|
873
|
+
fontSize: "var(--dsh-content-font-size-secondary, 13px)",
|
|
874
|
+
lineHeight: "18px",
|
|
875
|
+
fontVariantNumeric: "tabular-nums",
|
|
876
|
+
whiteSpace: "nowrap"
|
|
877
|
+
},
|
|
878
|
+
title,
|
|
879
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: text })
|
|
880
|
+
});
|
|
881
|
+
}
|
|
882
|
+
//#endregion
|
|
648
883
|
//#region src/client/locales.ts
|
|
649
884
|
const zh = {
|
|
650
885
|
tabLabel: "CodeArts",
|
|
@@ -665,6 +900,8 @@ const zh = {
|
|
|
665
900
|
saveToken: "保存 token",
|
|
666
901
|
expiredHint: "凭证已过期,请重新登录以继续使用;已勾选的模型设置会保留。",
|
|
667
902
|
accountsTitle: "账号",
|
|
903
|
+
accountsShow: "显示账号",
|
|
904
|
+
accountsHide: "隐藏账号",
|
|
668
905
|
accountRemove: "删除",
|
|
669
906
|
addAccount: "添加账号",
|
|
670
907
|
accountsRotateHint: "已存多个账号:请求会自动轮转,某个账号忙时改用下一个,不用干等。",
|
|
@@ -699,8 +936,22 @@ const zh = {
|
|
|
699
936
|
usageStateCapped: "撞上限,优先避开",
|
|
700
937
|
usageStateCooling: "冷却中",
|
|
701
938
|
usageStateDisabled: "已停用",
|
|
702
|
-
usageNoQuota: "
|
|
703
|
-
usageEmpty: "还没有记录:发一条消息就会开始累计。"
|
|
939
|
+
usageNoQuota: "这里是本机经插件发出的请求统计(不等于账号总额度);官方用量明细见",
|
|
940
|
+
usageEmpty: "还没有记录:发一条消息就会开始累计。",
|
|
941
|
+
creditsTitle: "积分",
|
|
942
|
+
creditsRemaining: "剩余 {remain} / {total}",
|
|
943
|
+
creditsUsed: "已用 {used}",
|
|
944
|
+
creditsExpiring: "其中 {expiring} 将在 {date} 重置时作废",
|
|
945
|
+
creditsReset: "额度重置 {date}",
|
|
946
|
+
creditsTokensToday: "今日 token {used} / {limit}",
|
|
947
|
+
creditsTokensBalance: "余额 {balance}",
|
|
948
|
+
creditsUnavailable: "积分不可用:{message}",
|
|
949
|
+
creditsDock: "积分 {remain}",
|
|
950
|
+
creditsDockTitle: "CodeArts 剩余积分 {remain} / {total}",
|
|
951
|
+
claimButton: "领取积分",
|
|
952
|
+
claiming: "领取中…",
|
|
953
|
+
claimSuccess: "已领取",
|
|
954
|
+
claimFailed: "领取失败:{message}"
|
|
704
955
|
};
|
|
705
956
|
const en = {
|
|
706
957
|
tabLabel: "CodeArts",
|
|
@@ -721,6 +972,8 @@ const en = {
|
|
|
721
972
|
saveToken: "Save token",
|
|
722
973
|
expiredHint: "Your credential has expired. Sign in again to continue; your model selection is kept.",
|
|
723
974
|
accountsTitle: "Accounts",
|
|
975
|
+
accountsShow: "Show accounts",
|
|
976
|
+
accountsHide: "Hide accounts",
|
|
724
977
|
accountRemove: "Remove",
|
|
725
978
|
addAccount: "Add account",
|
|
726
979
|
accountsRotateHint: "Multiple accounts stored: requests rotate automatically, so a busy account hands over to the next one instead of making you wait.",
|
|
@@ -755,8 +1008,22 @@ const en = {
|
|
|
755
1008
|
usageStateCapped: "Cap hit, avoiding",
|
|
756
1009
|
usageStateCooling: "Cooling down",
|
|
757
1010
|
usageStateDisabled: "Disabled",
|
|
758
|
-
usageNoQuota: "
|
|
759
|
-
usageEmpty: "Nothing recorded yet: send a message to start counting."
|
|
1011
|
+
usageNoQuota: "Counts the requests this machine sent through the plugin (not the account balance). Official usage:",
|
|
1012
|
+
usageEmpty: "Nothing recorded yet: send a message to start counting.",
|
|
1013
|
+
creditsTitle: "Credits",
|
|
1014
|
+
creditsRemaining: "{remain} of {total} left",
|
|
1015
|
+
creditsUsed: "{used} used",
|
|
1016
|
+
creditsExpiring: "{expiring} of them expire at the next reset on {date}",
|
|
1017
|
+
creditsReset: "Quota resets {date}",
|
|
1018
|
+
creditsTokensToday: "Today {used} / {limit} tokens",
|
|
1019
|
+
creditsTokensBalance: "{balance} left",
|
|
1020
|
+
creditsUnavailable: "Credits unavailable: {message}",
|
|
1021
|
+
creditsDock: "Credits {remain}",
|
|
1022
|
+
creditsDockTitle: "CodeArts credits left {remain} / {total}",
|
|
1023
|
+
claimButton: "Claim credits",
|
|
1024
|
+
claiming: "Claiming…",
|
|
1025
|
+
claimSuccess: "Claimed",
|
|
1026
|
+
claimFailed: "Claim failed: {message}"
|
|
760
1027
|
};
|
|
761
1028
|
//#endregion
|
|
762
1029
|
//#region src/client/index.tsx
|
|
@@ -775,6 +1042,13 @@ function apply(ctx) {
|
|
|
775
1042
|
key: "dsh-codearts",
|
|
776
1043
|
locale: namespace
|
|
777
1044
|
}, () => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CodeArtsPluginCard, { t })));
|
|
1045
|
+
ctx.slots.inject("conversation.composer.dock", () => ctx.slots.register({
|
|
1046
|
+
name: "conversation.composer.dock",
|
|
1047
|
+
id: "codearts-credits",
|
|
1048
|
+
order: 20,
|
|
1049
|
+
locale: namespace,
|
|
1050
|
+
inject: () => ({ t })
|
|
1051
|
+
}, CodeArtsCreditDock));
|
|
778
1052
|
} catch (error) {
|
|
779
1053
|
console.error("[dsh-codearts] client card failed to load (host provider unaffected):", error);
|
|
780
1054
|
}
|