dsh-codearts 0.3.0 → 0.4.1
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/DEV.md +29 -0
- package/lib/bin.mjs +2 -2
- package/lib/client/index.d.cts +2 -0
- package/lib/client/index.js +59 -26
- package/lib/index.mjs +62 -2
- package/lib/{usage-Cn1Bzmxj.mjs → usage-D6EeUWiQ.mjs} +13 -8
- package/package.json +1 -1
package/DEV.md
CHANGED
|
@@ -40,6 +40,35 @@ pnpm run hmr:off # 关掉,回到 base 默认(只监听 profile 配置
|
|
|
40
40
|
|
|
41
41
|
改完这个 patch 通常不用重启:profile 的 patch 文件本身也在 HMR 的监听范围内(profile 里 `patchReload: live`),条目会重新加载。若发现没生效,重启一次 DSH 即可,之后就一直有效。
|
|
42
42
|
|
|
43
|
+
> ⚠️ **开了模块监听就别用插件管理器/npm 升级本插件。** 宿主为热重载监视着
|
|
44
|
+
> `node_modules/dsh-codearts`,目录被占用后 pnpm 替换版本时会失败:
|
|
45
|
+
>
|
|
46
|
+
> ```
|
|
47
|
+
> [ERR_PNPM_EPERM] [importPackage ...\node_modules\dsh-codearts]
|
|
48
|
+
> EPERM: operation not permitted, rename
|
|
49
|
+
> '...\dsh-codearts_tmp_20976_1' -> '...\dsh-codearts'
|
|
50
|
+
> ```
|
|
51
|
+
>
|
|
52
|
+
> 更麻烦的是失败后**插件管理器会回滚**:把 `dsh-codearts` 从 profile 的
|
|
53
|
+
> `dependencies` 和 `bundles` 里一起删掉,表现为「插件列表里它没了」。升级前的正确顺序是
|
|
54
|
+
> `pnpm run hmr:off` → 升级 → (要接着开发再)`pnpm run hmr:on`。
|
|
55
|
+
>
|
|
56
|
+
> 这条只影响**跑过 `hmr:on` 的开发机**:该覆盖行写在 profile 的
|
|
57
|
+
> `cordis.patch.yml` 里,插件包自带的 patch 只有 `insert: llm-codearts`,
|
|
58
|
+
> 普通用户从 dshmarket 直接升级不会碰到。DSH base 的 desktop bundle 里默认是
|
|
59
|
+
> **不监视模块**的(原文,`app.asar` 内 base 的 patch):
|
|
60
|
+
>
|
|
61
|
+
> ```yaml
|
|
62
|
+
> # Profile configuration reloads by default; module roots are opt-in.
|
|
63
|
+
> - id: hmr
|
|
64
|
+
> name: '@deepseek-ai/dsh-hmr'
|
|
65
|
+
> disabled: !!js "!ctx.get('profileContext')"
|
|
66
|
+
> config:
|
|
67
|
+
> root: []
|
|
68
|
+
> ```
|
|
69
|
+
>
|
|
70
|
+
> 即 `root` 默认空表 —— 没人去开它,就没有句柄占用 `node_modules/dsh-codearts`。
|
|
71
|
+
|
|
43
72
|
## 日常循环
|
|
44
73
|
|
|
45
74
|
```sh
|
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-D6EeUWiQ.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.4.1";
|
|
6
6
|
//#endregion
|
|
7
7
|
//#region src/bin.ts
|
|
8
8
|
/**
|
package/lib/client/index.d.cts
CHANGED
package/lib/client/index.js
CHANGED
|
@@ -18,32 +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
|
+
"manual": "DZPfya_manual",
|
|
22
|
+
"area": "DZPfya_area",
|
|
23
|
+
"error": "DZPfya_error",
|
|
24
|
+
"choiceRow": "DZPfya_choiceRow",
|
|
21
25
|
"fieldLabel": "DZPfya_fieldLabel",
|
|
22
|
-
"
|
|
26
|
+
"desc": "DZPfya_desc",
|
|
23
27
|
"card": "DZPfya_card",
|
|
24
|
-
"
|
|
28
|
+
"field": "DZPfya_field",
|
|
25
29
|
"header": "DZPfya_header",
|
|
26
30
|
"link": "DZPfya_link",
|
|
27
|
-
"
|
|
28
|
-
"headText": "DZPfya_headText",
|
|
29
|
-
"name": "DZPfya_name",
|
|
30
|
-
"meta": "DZPfya_meta",
|
|
31
|
+
"manualSummary": "DZPfya_manualSummary",
|
|
31
32
|
"section": "DZPfya_section",
|
|
32
33
|
"sectionLabel": "DZPfya_sectionLabel",
|
|
33
|
-
"
|
|
34
|
-
"choices": "DZPfya_choices",
|
|
35
|
-
"desc": "DZPfya_desc",
|
|
36
|
-
"sectionHead": "DZPfya_sectionHead",
|
|
37
|
-
"choiceRow": "DZPfya_choiceRow",
|
|
38
|
-
"check": "DZPfya_check",
|
|
39
|
-
"manual": "DZPfya_manual",
|
|
40
|
-
"manualSummary": "DZPfya_manualSummary",
|
|
34
|
+
"headText": "DZPfya_headText",
|
|
41
35
|
"statusLine": "DZPfya_statusLine",
|
|
42
|
-
"
|
|
43
|
-
"actions": "DZPfya_actions",
|
|
44
|
-
"area": "DZPfya_area",
|
|
36
|
+
"meta": "DZPfya_meta",
|
|
45
37
|
"headActions": "DZPfya_headActions",
|
|
46
|
-
"
|
|
38
|
+
"body": "DZPfya_body",
|
|
39
|
+
"sectionHead": "DZPfya_sectionHead",
|
|
40
|
+
"name": "DZPfya_name",
|
|
41
|
+
"actions": "DZPfya_actions",
|
|
42
|
+
"danger": "DZPfya_danger",
|
|
43
|
+
"count": "DZPfya_count",
|
|
44
|
+
"hint": "DZPfya_hint",
|
|
45
|
+
"choices": "DZPfya_choices",
|
|
46
|
+
"check": "DZPfya_check"
|
|
47
47
|
};
|
|
48
48
|
//#endregion
|
|
49
49
|
//#region src/client/CodeArtsPluginCard.tsx
|
|
@@ -84,6 +84,23 @@ function formatCredits(value) {
|
|
|
84
84
|
return Number.isFinite(value) ? new Intl.NumberFormat().format(Math.round(value)) : "0";
|
|
85
85
|
}
|
|
86
86
|
/**
|
|
87
|
+
* 签到领积分的入口页。
|
|
88
|
+
*
|
|
89
|
+
* 官方 CodeArts Agent 客户端里,用户菜单的「活动福利(签到领 1000 积分)」点击后
|
|
90
|
+
* **不发任何接口请求**,只是用系统浏览器打开这个页面(SnapChat 的 isActivity 分支 →
|
|
91
|
+
* `jumpToBrowser(INIT_CONFIG.personalUsageSettings, isOutSideOpen: true)`,URL 来自
|
|
92
|
+
* `vscode-codebot/product.json`)。也就是说积分的签到动作只在那一页上完成,AK/SK
|
|
93
|
+
* 网关那套(benefit/claim、statistics/plugin)里没有任何发积分的接口 —— 详见
|
|
94
|
+
* src/upstream.ts 的 claimBenefit:它开通的是「限时福利免费模型」渠道,不是积分。
|
|
95
|
+
*/
|
|
96
|
+
const CODEARTS_SIGN_IN_URL = "https://codearts.huaweicloud.com/portal/settings/personal-usage";
|
|
97
|
+
/** 打开签到页;带 locale 参数,与官方客户端的拼法一致。 */
|
|
98
|
+
function openSignInPage() {
|
|
99
|
+
if (typeof window === "undefined") return;
|
|
100
|
+
const locale = (typeof navigator === "undefined" ? "" : navigator.language ?? "").toLowerCase().startsWith("en") ? "en-us" : "zh-cn";
|
|
101
|
+
window.open(`${CODEARTS_SIGN_IN_URL}?locale=${locale}`, "_blank", "noopener");
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
87
104
|
* 积分区块。
|
|
88
105
|
*
|
|
89
106
|
* 2026-10 从官方 CodeArts Agent 客户端挖出积分接口并实测通过(见 src/credits.ts),
|
|
@@ -101,18 +118,30 @@ function CreditsSection({ credits, error, t }) {
|
|
|
101
118
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
102
119
|
className: CodeArtsPluginCard_module_css_default.sectionLabel,
|
|
103
120
|
children: t("creditsTitle")
|
|
104
|
-
}),
|
|
105
|
-
className: CodeArtsPluginCard_module_css_default.
|
|
106
|
-
children:
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
121
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
122
|
+
className: CodeArtsPluginCard_module_css_default.headActions,
|
|
123
|
+
children: [c !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
124
|
+
className: CodeArtsPluginCard_module_css_default.count,
|
|
125
|
+
children: t("creditsRemaining", {
|
|
126
|
+
remain: formatCredits(c.total.remain),
|
|
127
|
+
total: formatCredits(c.total.total)
|
|
128
|
+
})
|
|
129
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
130
|
+
variant: "outline",
|
|
131
|
+
size: "sm",
|
|
132
|
+
onClick: () => openSignInPage(),
|
|
133
|
+
children: t("signInButton")
|
|
134
|
+
})]
|
|
110
135
|
})]
|
|
111
136
|
}),
|
|
112
137
|
error !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
113
138
|
className: CodeArtsPluginCard_module_css_default.hint,
|
|
114
139
|
children: t("creditsUnavailable", { message: error })
|
|
115
140
|
}),
|
|
141
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
142
|
+
className: CodeArtsPluginCard_module_css_default.hint,
|
|
143
|
+
children: t("signInHint")
|
|
144
|
+
}),
|
|
116
145
|
c !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
117
146
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
118
147
|
className: CodeArtsPluginCard_module_css_default.choiceRow,
|
|
@@ -900,7 +929,9 @@ const zh = {
|
|
|
900
929
|
creditsTokensBalance: "余额 {balance}",
|
|
901
930
|
creditsUnavailable: "积分不可用:{message}",
|
|
902
931
|
creditsDock: "积分 {remain}",
|
|
903
|
-
creditsDockTitle: "CodeArts 剩余积分 {remain} / {total}"
|
|
932
|
+
creditsDockTitle: "CodeArts 剩余积分 {remain} / {total}",
|
|
933
|
+
signInButton: "去签到领积分",
|
|
934
|
+
signInHint: "积分由 CodeArts 官网活动页发放,签到要在官网页面完成(和官方客户端同一入口)。"
|
|
904
935
|
};
|
|
905
936
|
const en = {
|
|
906
937
|
tabLabel: "CodeArts",
|
|
@@ -968,7 +999,9 @@ const en = {
|
|
|
968
999
|
creditsTokensBalance: "{balance} left",
|
|
969
1000
|
creditsUnavailable: "Credits unavailable: {message}",
|
|
970
1001
|
creditsDock: "Credits {remain}",
|
|
971
|
-
creditsDockTitle: "CodeArts credits left {remain} / {total}"
|
|
1002
|
+
creditsDockTitle: "CodeArts credits left {remain} / {total}",
|
|
1003
|
+
signInButton: "Check in for credits",
|
|
1004
|
+
signInHint: "Credits are issued on the CodeArts portal; check-in happens on that page (same entry as the official client)."
|
|
972
1005
|
};
|
|
973
1006
|
//#endregion
|
|
974
1007
|
//#region src/client/index.tsx
|
package/lib/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { C as
|
|
1
|
+
import { C as codeartsAccountsPath, S as CodeArtsCredentialStore, T as startLogin, _ as CodeArtsCatalog, a as SNAP_HOST, b as isBenefitModel, c as claimBenefit, d as fetchModels, f as isConcurrencyCap, g as signedGet, h as prepareChatBody, i as refreshCatalog, l as degradeTokenCeiling, m as maxTokensCeilingFor, n as codeartsUsagePath, o as canonicalModel, p as isParamInvalidFrame, r as discoverModels, s as chatStream, t as CodeArtsUsageTracker, u as fetchCallerIdentity, v as FALLBACK_CODEARTS_MODELS, w as codeartsAuthPath, x as CodeArtsAccountStore, y as filterEnabledModels } from "./usage-D6EeUWiQ.mjs";
|
|
2
2
|
import z from "@deepseek-ai/schemastery";
|
|
3
3
|
import { randomBytes, timingSafeEqual } from "node:crypto";
|
|
4
4
|
import { createServer } from "node:http";
|
|
@@ -999,6 +999,8 @@ const CODEARTS_LOGIN_PATH = "/api/codearts/login";
|
|
|
999
999
|
const CODEARTS_LOGIN_STATUS_PATH = "/api/codearts/login/status";
|
|
1000
1000
|
/** 删除某个账号:DELETE /api/codearts/accounts?id=<accountId> */
|
|
1001
1001
|
const CODEARTS_ACCOUNTS_PATH = "/api/codearts/accounts";
|
|
1002
|
+
/** POST /api/codearts/claim — 开通「限时福利」免费模型渠道(幂等);**不发积分**。 */
|
|
1003
|
+
const CODEARTS_CLAIM_PATH = "/api/codearts/claim";
|
|
1002
1004
|
/**
|
|
1003
1005
|
* 由完整目录 + 已存 enabled 计算 selection。
|
|
1004
1006
|
* - enabled 为空/未存 => 全部勾选(restricted=false)
|
|
@@ -1331,6 +1333,36 @@ function accountsHandler(deps) {
|
|
|
1331
1333
|
}
|
|
1332
1334
|
};
|
|
1333
1335
|
}
|
|
1336
|
+
/** POST /api/codearts/claim — 开通「限时福利」免费模型渠道(幂等);**不发积分**。 */
|
|
1337
|
+
function claimHandler(deps) {
|
|
1338
|
+
return async (req, res) => {
|
|
1339
|
+
if (req.method !== "POST") {
|
|
1340
|
+
json(res, 405, { error: "method not allowed" });
|
|
1341
|
+
return;
|
|
1342
|
+
}
|
|
1343
|
+
if (deps.claim === void 0) {
|
|
1344
|
+
json(res, 404, { error: "claim not available" });
|
|
1345
|
+
return;
|
|
1346
|
+
}
|
|
1347
|
+
if (!loopbackRequest(req)) {
|
|
1348
|
+
json(res, 403, { error: "request-not-trusted" });
|
|
1349
|
+
return;
|
|
1350
|
+
}
|
|
1351
|
+
try {
|
|
1352
|
+
const result = await deps.claim();
|
|
1353
|
+
if (result.ok) json(res, 200, { ok: true });
|
|
1354
|
+
else json(res, 500, {
|
|
1355
|
+
ok: false,
|
|
1356
|
+
message: result.message
|
|
1357
|
+
});
|
|
1358
|
+
} catch (error) {
|
|
1359
|
+
json(res, 500, {
|
|
1360
|
+
ok: false,
|
|
1361
|
+
message: safeMessage(error)
|
|
1362
|
+
});
|
|
1363
|
+
}
|
|
1364
|
+
};
|
|
1365
|
+
}
|
|
1334
1366
|
/** Mount the status / models / token routes. */
|
|
1335
1367
|
function registerCodeArtsStatusRoute(ctx, deps) {
|
|
1336
1368
|
ctx.effect(() => {
|
|
@@ -1372,6 +1404,11 @@ function registerCodeArtsStatusRoute(ctx, deps) {
|
|
|
1372
1404
|
path: CODEARTS_ACCOUNTS_PATH,
|
|
1373
1405
|
handler: accountsHandler(deps)
|
|
1374
1406
|
});
|
|
1407
|
+
const disposeClaim = ctx.webServer.register({
|
|
1408
|
+
kind: "exact",
|
|
1409
|
+
path: CODEARTS_CLAIM_PATH,
|
|
1410
|
+
handler: claimHandler(deps)
|
|
1411
|
+
});
|
|
1375
1412
|
return () => {
|
|
1376
1413
|
disposeStatus();
|
|
1377
1414
|
disposeModels();
|
|
@@ -1380,6 +1417,7 @@ function registerCodeArtsStatusRoute(ctx, deps) {
|
|
|
1380
1417
|
disposeLoginStart();
|
|
1381
1418
|
disposeLoginStatus();
|
|
1382
1419
|
disposeAccounts();
|
|
1420
|
+
disposeClaim();
|
|
1383
1421
|
for (const s of activeLogins.values()) s.close();
|
|
1384
1422
|
activeLogins.clear();
|
|
1385
1423
|
};
|
|
@@ -1607,7 +1645,29 @@ function apply(ctx, rawConfig) {
|
|
|
1607
1645
|
setEnabledModels,
|
|
1608
1646
|
pool: () => pool.list(),
|
|
1609
1647
|
usage: () => usage.snapshot(),
|
|
1610
|
-
credits: (signal) => loadCredits(signal)
|
|
1648
|
+
credits: (signal) => loadCredits(signal),
|
|
1649
|
+
claim: async () => {
|
|
1650
|
+
try {
|
|
1651
|
+
const ids = await store.ids();
|
|
1652
|
+
for (const id of ids) {
|
|
1653
|
+
const stored = await store.credential(id);
|
|
1654
|
+
if (stored === void 0 || stored.stale === true) continue;
|
|
1655
|
+
const resolved = await store.resolve(id);
|
|
1656
|
+
if (resolved === void 0) continue;
|
|
1657
|
+
await claimBenefit(resolved, AbortSignal.timeout(1e4));
|
|
1658
|
+
return { ok: true };
|
|
1659
|
+
}
|
|
1660
|
+
return {
|
|
1661
|
+
ok: false,
|
|
1662
|
+
message: "no usable credential"
|
|
1663
|
+
};
|
|
1664
|
+
} catch (error) {
|
|
1665
|
+
return {
|
|
1666
|
+
ok: false,
|
|
1667
|
+
message: error instanceof Error ? error.message : String(error)
|
|
1668
|
+
};
|
|
1669
|
+
}
|
|
1670
|
+
}
|
|
1611
1671
|
}));
|
|
1612
1672
|
installSettingsSectionCompat(ctx, CODEARTS_SETTINGS_NS, Config, config, {
|
|
1613
1673
|
setSource(source) {
|
|
@@ -1883,9 +1883,14 @@ async function fetchModels(credential, signal) {
|
|
|
1883
1883
|
};
|
|
1884
1884
|
}
|
|
1885
1885
|
/**
|
|
1886
|
-
*
|
|
1887
|
-
*
|
|
1886
|
+
* 开通「限时福利」(免费模型)渠道,幂等:已开通就原样返回。官方客户端打开模型菜单
|
|
1887
|
+
* 即调用(GET),用户点「领取」时也调(POST)——两种方法实测都返回 200/0000。
|
|
1888
|
+
* 不开通时福利模型调用必报 InferHub.4004.200 benefit not found。
|
|
1888
1889
|
* 需要 AK/SK 签名(凭证要带 accessKeyId/secretAccessKey)。
|
|
1890
|
+
*
|
|
1891
|
+
* **它不发积分。** 返回体只是一条渠道开通记录(channel / create_time / update_time,
|
|
1892
|
+
* 幂等所以时间戳是旧的),账号积分由套餐决定(见 credits.ts),领取动作在官网签到页。
|
|
1893
|
+
* 别把它当「领取积分」用 —— 早先卡片这么用,结果就是「点了显示已领取、积分没变」。
|
|
1889
1894
|
*/
|
|
1890
1895
|
async function claimBenefit(credential, abort) {
|
|
1891
1896
|
if (!credential.accessKeyId || !credential.secretAccessKey) return;
|
|
@@ -1908,13 +1913,13 @@ async function claimBenefit(credential, abort) {
|
|
|
1908
1913
|
const resp = await fetch(req, { signal: abort });
|
|
1909
1914
|
const raw = await resp.text().catch(() => "");
|
|
1910
1915
|
if (!resp.ok) throw new Error(`claim benefit failed: ${resp.status} ${raw.slice(0, 200)}`);
|
|
1916
|
+
let json;
|
|
1911
1917
|
try {
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
if (e instanceof SyntaxError) return;
|
|
1916
|
-
throw e;
|
|
1918
|
+
json = JSON.parse(raw);
|
|
1919
|
+
} catch {
|
|
1920
|
+
throw new Error(`claim benefit: unexpected non-JSON response: ${raw.slice(0, 200)}`);
|
|
1917
1921
|
}
|
|
1922
|
+
if (json.error_code !== "0000") throw new Error(`claim benefit rejected: ${json.error_code ?? "(no error_code)"} ${json.error_msg ?? ""}`.trim());
|
|
1918
1923
|
}
|
|
1919
1924
|
//#endregion
|
|
1920
1925
|
//#region src/discovery.ts
|
|
@@ -2220,4 +2225,4 @@ function sumOf(store) {
|
|
|
2220
2225
|
return out;
|
|
2221
2226
|
}
|
|
2222
2227
|
//#endregion
|
|
2223
|
-
export {
|
|
2228
|
+
export { codeartsAccountsPath as C, CodeArtsCredentialStore as S, startLogin as T, CodeArtsCatalog as _, SNAP_HOST as a, isBenefitModel as b, claimBenefit as c, fetchModels as d, isConcurrencyCap as f, signedGet as g, prepareChatBody as h, refreshCatalog as i, degradeTokenCeiling as l, maxTokensCeilingFor as m, codeartsUsagePath as n, canonicalModel as o, isParamInvalidFrame as p, discoverModels as r, chatStream as s, CodeArtsUsageTracker as t, fetchCallerIdentity as u, FALLBACK_CODEARTS_MODELS as v, codeartsAuthPath as w, CodeArtsAccountStore as x, filterEnabledModels as y };
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "dsh-codearts",
|
|
3
3
|
"displayName": "DSH CodeArts Connect",
|
|
4
4
|
"description": "把华为云 CodeArts 接入 DeepSeek Harness —— 内置 OAuth2 登录(PKCE + DPoP),登录后即可在 DSH 对话窗口使用 CodeArts 的模型。",
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "0.4.1",
|
|
6
6
|
"author": "elegant01",
|
|
7
7
|
"keywords": [
|
|
8
8
|
"dsh-plugin",
|