dsh-codearts 0.4.0 → 0.4.2
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 +6 -2
- package/lib/client/index.js +74 -59
- package/lib/index.d.mts +14 -0
- package/lib/index.mjs +41 -17
- package/lib/{usage-3W88T_H1.mjs → usage-B4vQb1sP.mjs} +192 -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 { C as
|
|
2
|
+
import { C as isBenefitModel, E as codeartsAccountsPath, n as codeartsUsagePath, r as discoverModels, t as CodeArtsUsageTracker, u as fetchCallerIdentity, w as CodeArtsAccountStore, x as FALLBACK_CODEARTS_MODELS } from "./usage-B4vQb1sP.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.2";
|
|
6
6
|
//#endregion
|
|
7
7
|
//#region src/bin.ts
|
|
8
8
|
/**
|
package/lib/client/index.d.cts
CHANGED
|
@@ -68,8 +68,12 @@ interface CodeArtsSettingsKey {
|
|
|
68
68
|
creditsDock: string;
|
|
69
69
|
creditsDockTitle: string;
|
|
70
70
|
claimButton: string;
|
|
71
|
-
|
|
72
|
-
|
|
71
|
+
claimButtonDone: string;
|
|
72
|
+
claimPending: string;
|
|
73
|
+
claimHint: string;
|
|
74
|
+
claimDone: string;
|
|
75
|
+
claimAlready: string;
|
|
76
|
+
claimUnavailable: string;
|
|
73
77
|
claimFailed: string;
|
|
74
78
|
[key: string]: string;
|
|
75
79
|
}
|
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
|
-
"
|
|
21
|
+
"name": "DZPfya_name",
|
|
22
22
|
"actions": "DZPfya_actions",
|
|
23
23
|
"choiceRow": "DZPfya_choiceRow",
|
|
24
|
-
"header": "DZPfya_header",
|
|
25
24
|
"manualSummary": "DZPfya_manualSummary",
|
|
26
25
|
"field": "DZPfya_field",
|
|
27
26
|
"meta": "DZPfya_meta",
|
|
27
|
+
"headActions": "DZPfya_headActions",
|
|
28
28
|
"link": "DZPfya_link",
|
|
29
|
+
"manual": "DZPfya_manual",
|
|
29
30
|
"area": "DZPfya_area",
|
|
30
|
-
"
|
|
31
|
+
"headText": "DZPfya_headText",
|
|
32
|
+
"sectionHead": "DZPfya_sectionHead",
|
|
33
|
+
"body": "DZPfya_body",
|
|
31
34
|
"hint": "DZPfya_hint",
|
|
32
35
|
"statusLine": "DZPfya_statusLine",
|
|
36
|
+
"choices": "DZPfya_choices",
|
|
33
37
|
"check": "DZPfya_check",
|
|
34
|
-
"manual": "DZPfya_manual",
|
|
35
38
|
"desc": "DZPfya_desc",
|
|
39
|
+
"count": "DZPfya_count",
|
|
40
|
+
"sectionLabel": "DZPfya_sectionLabel",
|
|
36
41
|
"fieldLabel": "DZPfya_fieldLabel",
|
|
37
|
-
"
|
|
38
|
-
"section": "DZPfya_section",
|
|
42
|
+
"header": "DZPfya_header",
|
|
39
43
|
"card": "DZPfya_card",
|
|
40
|
-
"name": "DZPfya_name",
|
|
41
|
-
"sectionHead": "DZPfya_sectionHead",
|
|
42
|
-
"sectionLabel": "DZPfya_sectionLabel",
|
|
43
|
-
"count": "DZPfya_count",
|
|
44
|
-
"headText": "DZPfya_headText",
|
|
45
44
|
"error": "DZPfya_error",
|
|
46
|
-
"danger": "DZPfya_danger"
|
|
45
|
+
"danger": "DZPfya_danger",
|
|
46
|
+
"section": "DZPfya_section"
|
|
47
47
|
};
|
|
48
48
|
//#endregion
|
|
49
49
|
//#region src/client/CodeArtsPluginCard.tsx
|
|
@@ -84,48 +84,28 @@ function formatCredits(value) {
|
|
|
84
84
|
return Number.isFinite(value) ? new Intl.NumberFormat().format(Math.round(value)) : "0";
|
|
85
85
|
}
|
|
86
86
|
/**
|
|
87
|
+
* 领取结果 → 文案。
|
|
88
|
+
*
|
|
89
|
+
* 本地状态(claimed/already/没有这个活动)用界面自己的话;只有 failed 才透出
|
|
90
|
+
* 上游给的 reason —— 那句往往才是排障要的东西(签名失败、404、非 JSON…)。
|
|
91
|
+
*/
|
|
92
|
+
function claimText(data, t) {
|
|
93
|
+
if (data?.claimed === true) return t("claimDone", { amount: formatCredits(data.amount ?? 0) });
|
|
94
|
+
if (data?.state === "already") return t("claimAlready");
|
|
95
|
+
if (data?.state === "unavailable") return t("claimUnavailable");
|
|
96
|
+
return t("claimFailed", { message: typeof data?.message === "string" && data.message !== "" ? data.message : "request failed" });
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
87
99
|
* 积分区块。
|
|
88
100
|
*
|
|
89
101
|
* 2026-10 从官方 CodeArts Agent 客户端挖出积分接口并实测通过(见 src/credits.ts),
|
|
90
102
|
* 所以这里能直接显示账号总额度 —— 与下面的「本机用量」互补:一个是账号级、一个是
|
|
91
103
|
* 本机级。拉不到时显示原因(creditsError),不静默吞掉。
|
|
92
104
|
*/
|
|
93
|
-
function CreditsSection({ credits, error, t,
|
|
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)("");
|
|
105
|
+
function CreditsSection({ credits, error, t, onClaim, claiming, claimResult, justClaimed }) {
|
|
102
106
|
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
107
|
const c = credits?.credits;
|
|
108
|
+
const claimedToday = justClaimed || credits?.welfare?.claimedToday === true;
|
|
129
109
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
130
110
|
className: CodeArtsPluginCard_module_css_default.section,
|
|
131
111
|
children: [
|
|
@@ -142,12 +122,12 @@ function CreditsSection({ credits, error, t, onClaimed }) {
|
|
|
142
122
|
remain: formatCredits(c.total.remain),
|
|
143
123
|
total: formatCredits(c.total.total)
|
|
144
124
|
})
|
|
145
|
-
}),
|
|
125
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
146
126
|
variant: "outline",
|
|
147
127
|
size: "sm",
|
|
148
|
-
disabled:
|
|
149
|
-
onClick:
|
|
150
|
-
children:
|
|
128
|
+
disabled: claiming || claimedToday,
|
|
129
|
+
onClick: onClaim,
|
|
130
|
+
children: claiming ? t("claimPending") : claimedToday ? t("claimButtonDone") : t("claimButton")
|
|
151
131
|
})]
|
|
152
132
|
})]
|
|
153
133
|
}),
|
|
@@ -155,9 +135,9 @@ function CreditsSection({ credits, error, t, onClaimed }) {
|
|
|
155
135
|
className: CodeArtsPluginCard_module_css_default.hint,
|
|
156
136
|
children: t("creditsUnavailable", { message: error })
|
|
157
137
|
}),
|
|
158
|
-
|
|
138
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
159
139
|
className: CodeArtsPluginCard_module_css_default.hint,
|
|
160
|
-
children: t("
|
|
140
|
+
children: claimResult ?? t("claimHint")
|
|
161
141
|
}),
|
|
162
142
|
c !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
163
143
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -328,6 +308,30 @@ function CodeArtsPluginCard({ t }) {
|
|
|
328
308
|
const [modelError, setModelError] = (0, react.useState)(null);
|
|
329
309
|
/** 账号身份是否展开:默认遮蔽(false = 显示 *******)。 */
|
|
330
310
|
const [accountsRevealed, setAccountsRevealed] = (0, react.useState)(false);
|
|
311
|
+
const [claiming, setClaiming] = (0, react.useState)(false);
|
|
312
|
+
const [claimResult, setClaimResult] = (0, react.useState)(null);
|
|
313
|
+
const [justClaimed, setJustClaimed] = (0, react.useState)(false);
|
|
314
|
+
/**
|
|
315
|
+
* 领一次每日签到积分。
|
|
316
|
+
*
|
|
317
|
+
* 除了这一次刚领成,「今天已领」都来自上游的福利活动状态(积分快照里的 welfare),
|
|
318
|
+
* 所以刷新、重开窗口都不会把按钮说错。领完不记日期:去重在上游按天做。
|
|
319
|
+
*/
|
|
320
|
+
async function claim() {
|
|
321
|
+
setClaiming(true);
|
|
322
|
+
try {
|
|
323
|
+
const data = await (await fetch("/api/codearts/claim", { method: "POST" })).json().catch(() => null);
|
|
324
|
+
setClaimResult(claimText(data, t));
|
|
325
|
+
if (data?.claimed === true) {
|
|
326
|
+
setJustClaimed(true);
|
|
327
|
+
await refresh();
|
|
328
|
+
}
|
|
329
|
+
} catch (error) {
|
|
330
|
+
setClaimResult(t("claimFailed", { message: error instanceof Error ? error.message : String(error) }));
|
|
331
|
+
} finally {
|
|
332
|
+
setClaiming(false);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
331
335
|
async function refresh() {
|
|
332
336
|
try {
|
|
333
337
|
const data = await (await fetch("/api/codearts/status", { headers: { Accept: "application/json" } })).json();
|
|
@@ -781,7 +785,10 @@ function CodeArtsPluginCard({ t }) {
|
|
|
781
785
|
credits: status?.credits,
|
|
782
786
|
error: status?.creditsError,
|
|
783
787
|
t,
|
|
784
|
-
|
|
788
|
+
onClaim: () => void claim(),
|
|
789
|
+
claiming,
|
|
790
|
+
claimResult,
|
|
791
|
+
justClaimed
|
|
785
792
|
}),
|
|
786
793
|
status?.usage !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(UsageSection, {
|
|
787
794
|
usage: status.usage,
|
|
@@ -948,9 +955,13 @@ const zh = {
|
|
|
948
955
|
creditsUnavailable: "积分不可用:{message}",
|
|
949
956
|
creditsDock: "积分 {remain}",
|
|
950
957
|
creditsDockTitle: "CodeArts 剩余积分 {remain} / {total}",
|
|
951
|
-
claimButton: "
|
|
952
|
-
|
|
953
|
-
|
|
958
|
+
claimButton: "签到领积分",
|
|
959
|
+
claimButtonDone: "今日已领",
|
|
960
|
+
claimPending: "领取中…",
|
|
961
|
+
claimHint: "每天领一次 1000 积分,走官方福利中心接口(与客户端里那个「每日签到」同一件事)。",
|
|
962
|
+
claimDone: "已领取 {amount} 积分",
|
|
963
|
+
claimAlready: "今日已领,明天再来",
|
|
964
|
+
claimUnavailable: "这个账号当前没有可领的签到活动",
|
|
954
965
|
claimFailed: "领取失败:{message}"
|
|
955
966
|
};
|
|
956
967
|
const en = {
|
|
@@ -1020,9 +1031,13 @@ const en = {
|
|
|
1020
1031
|
creditsUnavailable: "Credits unavailable: {message}",
|
|
1021
1032
|
creditsDock: "Credits {remain}",
|
|
1022
1033
|
creditsDockTitle: "CodeArts credits left {remain} / {total}",
|
|
1023
|
-
claimButton: "Claim credits",
|
|
1024
|
-
|
|
1025
|
-
|
|
1034
|
+
claimButton: "Claim daily credits",
|
|
1035
|
+
claimButtonDone: "Claimed today",
|
|
1036
|
+
claimPending: "Claiming…",
|
|
1037
|
+
claimHint: "Claim 1,000 credits once a day through CodeArts’ welfare centre — the same check-in the official client does.",
|
|
1038
|
+
claimDone: "Claimed {amount} credits",
|
|
1039
|
+
claimAlready: "Already claimed today — come back tomorrow",
|
|
1040
|
+
claimUnavailable: "No check-in campaign available for this account",
|
|
1026
1041
|
claimFailed: "Claim failed: {message}"
|
|
1027
1042
|
};
|
|
1028
1043
|
//#endregion
|
package/lib/index.d.mts
CHANGED
|
@@ -581,10 +581,24 @@ interface CodeArtsTokenQuota {
|
|
|
581
581
|
/** 总额度。 */
|
|
582
582
|
quota: number;
|
|
583
583
|
}
|
|
584
|
+
/** 每日签到活动当前状态(来自福利中心 `/v1/ops/delivery`)。 */
|
|
585
|
+
interface CodeArtsDailyWelfare {
|
|
586
|
+
/** 上游说这条活动现在点得动吗。 */
|
|
587
|
+
claimable: boolean;
|
|
588
|
+
/**
|
|
589
|
+
* 「今天已经领过了」。单独判出来给卡片改按钮文案用 —— 不可领的原因有好几种
|
|
590
|
+
* (已领 / 要先去官网登录 / 账号没资格),只有这一种该把按钮变成「今日已领」。
|
|
591
|
+
*/
|
|
592
|
+
claimedToday: boolean;
|
|
593
|
+
/** 领一次给多少积分。 */
|
|
594
|
+
amount: number;
|
|
595
|
+
}
|
|
584
596
|
interface CodeArtsCreditSnapshot {
|
|
585
597
|
credits: CodeArtsCredits;
|
|
586
598
|
/** 拿不到(接口失败/不支持)时为 undefined,不影响积分本身。 */
|
|
587
599
|
tokens?: CodeArtsTokenQuota;
|
|
600
|
+
/** 没有这个活动(或账号是 token 套餐)时为 undefined。 */
|
|
601
|
+
welfare?: CodeArtsDailyWelfare;
|
|
588
602
|
}
|
|
589
603
|
/** 缓存里的一个结果:成功给值,失败给消息 —— 失败也要能被卡片看见。 */
|
|
590
604
|
type CodeArtsCreditState = {
|
package/lib/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { C as codeartsAccountsPath, S as
|
|
1
|
+
import { C as isBenefitModel, D as codeartsAuthPath, E as codeartsAccountsPath, O as startLogin, S as filterEnabledModels, T as CodeArtsCredentialStore, _ as pickDailyWelfareCampaign, a as SNAP_HOST, b as CodeArtsCatalog, c as claimDailyWelfare, d as fetchModels, f as fetchWelfareCampaigns, g as maxTokensCeilingFor, h as isWelfareClaimedStatus, i as refreshCatalog, l as degradeTokenCeiling, m as isParamInvalidFrame, n as codeartsUsagePath, o as canonicalModel, p as isConcurrencyCap, r as discoverModels, s as chatStream, t as CodeArtsUsageTracker, u as fetchCallerIdentity, v as prepareChatBody, w as CodeArtsAccountStore, x as FALLBACK_CODEARTS_MODELS, y as signedGet } from "./usage-B4vQb1sP.mjs";
|
|
2
2
|
import z from "@deepseek-ai/schemastery";
|
|
3
3
|
import { randomBytes, timingSafeEqual } from "node:crypto";
|
|
4
4
|
import { createServer } from "node:http";
|
|
@@ -273,18 +273,31 @@ function errorOf(action, result) {
|
|
|
273
273
|
* 它失败只让 `tokens` 缺席 —— 别让一个次要接口把主数字一起拖没。
|
|
274
274
|
*/
|
|
275
275
|
async function fetchCredits(credential, signal) {
|
|
276
|
-
const [statistics, balance] = await Promise.all([
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
276
|
+
const [statistics, balance, welfare] = await Promise.all([
|
|
277
|
+
signedGet(`${SNAP_HOST}${EP_STATISTICS_PLUGIN}`, credential, void 0, signal),
|
|
278
|
+
signedGet(`${BENEFIT_GATEWAY_HOST}${EP_TOKEN_BALANCE}`, credential, void 0, signal).catch(() => ({
|
|
279
|
+
ok: false,
|
|
280
|
+
status: 0,
|
|
281
|
+
message: "request failed"
|
|
282
|
+
})),
|
|
283
|
+
fetchWelfareCampaigns(credential, signal).then((campaigns) => {
|
|
284
|
+
const daily = pickDailyWelfareCampaign(campaigns);
|
|
285
|
+
if (daily === void 0) return void 0;
|
|
286
|
+
return {
|
|
287
|
+
claimable: daily.claimable,
|
|
288
|
+
claimedToday: !daily.claimable && isWelfareClaimedStatus(daily.status),
|
|
289
|
+
amount: daily.amount
|
|
290
|
+
};
|
|
291
|
+
}).catch(() => void 0)
|
|
292
|
+
]);
|
|
281
293
|
if (!statistics.ok) throw errorOf("statistics", statistics);
|
|
282
294
|
const credits = parseCreditStatistics(safeJson(statistics.text));
|
|
283
295
|
if (credits === void 0) throw new Error("statistics response carries no credit metrics");
|
|
284
296
|
const tokens = balance.ok ? parseTokenBalance(safeJson(balance.text)) : void 0;
|
|
285
297
|
return {
|
|
286
298
|
credits,
|
|
287
|
-
...tokens === void 0 ? {} : { tokens }
|
|
299
|
+
...tokens === void 0 ? {} : { tokens },
|
|
300
|
+
...welfare === void 0 ? {} : { welfare }
|
|
288
301
|
};
|
|
289
302
|
}
|
|
290
303
|
function safeJson(text) {
|
|
@@ -999,7 +1012,7 @@ const CODEARTS_LOGIN_PATH = "/api/codearts/login";
|
|
|
999
1012
|
const CODEARTS_LOGIN_STATUS_PATH = "/api/codearts/login/status";
|
|
1000
1013
|
/** 删除某个账号:DELETE /api/codearts/accounts?id=<accountId> */
|
|
1001
1014
|
const CODEARTS_ACCOUNTS_PATH = "/api/codearts/accounts";
|
|
1002
|
-
/** POST /api/codearts/claim —
|
|
1015
|
+
/** POST /api/codearts/claim — 领一次福利中心的每日签到积分(幂等由上游按天去重)。 */
|
|
1003
1016
|
const CODEARTS_CLAIM_PATH = "/api/codearts/claim";
|
|
1004
1017
|
/**
|
|
1005
1018
|
* 由完整目录 + 已存 enabled 计算 selection。
|
|
@@ -1333,7 +1346,7 @@ function accountsHandler(deps) {
|
|
|
1333
1346
|
}
|
|
1334
1347
|
};
|
|
1335
1348
|
}
|
|
1336
|
-
/** POST /api/codearts/claim —
|
|
1349
|
+
/** POST /api/codearts/claim — 领一次每日签到积分;未领到也回 200(看 claimed/state)。 */
|
|
1337
1350
|
function claimHandler(deps) {
|
|
1338
1351
|
return async (req, res) => {
|
|
1339
1352
|
if (req.method !== "POST") {
|
|
@@ -1350,14 +1363,13 @@ function claimHandler(deps) {
|
|
|
1350
1363
|
}
|
|
1351
1364
|
try {
|
|
1352
1365
|
const result = await deps.claim();
|
|
1353
|
-
|
|
1354
|
-
else json(res, 500, {
|
|
1355
|
-
ok: false,
|
|
1356
|
-
message: result.message
|
|
1357
|
-
});
|
|
1366
|
+
json(res, result.ok ? 200 : 500, result);
|
|
1358
1367
|
} catch (error) {
|
|
1359
1368
|
json(res, 500, {
|
|
1360
1369
|
ok: false,
|
|
1370
|
+
claimed: false,
|
|
1371
|
+
state: "failed",
|
|
1372
|
+
amount: 0,
|
|
1361
1373
|
message: safeMessage(error)
|
|
1362
1374
|
});
|
|
1363
1375
|
}
|
|
@@ -1654,17 +1666,29 @@ function apply(ctx, rawConfig) {
|
|
|
1654
1666
|
if (stored === void 0 || stored.stale === true) continue;
|
|
1655
1667
|
const resolved = await store.resolve(id);
|
|
1656
1668
|
if (resolved === void 0) continue;
|
|
1657
|
-
await
|
|
1658
|
-
credits.invalidate();
|
|
1659
|
-
return {
|
|
1669
|
+
const outcome = await claimDailyWelfare(resolved, AbortSignal.timeout(2e4));
|
|
1670
|
+
if (outcome.state === "claimed") credits.invalidate();
|
|
1671
|
+
return {
|
|
1672
|
+
ok: outcome.state !== "failed",
|
|
1673
|
+
claimed: outcome.state === "claimed",
|
|
1674
|
+
state: outcome.state,
|
|
1675
|
+
amount: outcome.amount,
|
|
1676
|
+
message: outcome.message
|
|
1677
|
+
};
|
|
1660
1678
|
}
|
|
1661
1679
|
return {
|
|
1662
1680
|
ok: false,
|
|
1681
|
+
claimed: false,
|
|
1682
|
+
state: "failed",
|
|
1683
|
+
amount: 0,
|
|
1663
1684
|
message: "no usable credential"
|
|
1664
1685
|
};
|
|
1665
1686
|
} catch (error) {
|
|
1666
1687
|
return {
|
|
1667
1688
|
ok: false,
|
|
1689
|
+
claimed: false,
|
|
1690
|
+
state: "failed",
|
|
1691
|
+
amount: 0,
|
|
1668
1692
|
message: error instanceof Error ? error.message : String(error)
|
|
1669
1693
|
};
|
|
1670
1694
|
}
|
|
@@ -1168,13 +1168,17 @@ var upstream_exports = /* @__PURE__ */ __exportAll({
|
|
|
1168
1168
|
canonicalModel: () => canonicalModel,
|
|
1169
1169
|
chatStream: () => chatStream,
|
|
1170
1170
|
claimBenefit: () => claimBenefit,
|
|
1171
|
+
claimDailyWelfare: () => claimDailyWelfare,
|
|
1171
1172
|
degradeTokenCeiling: () => degradeTokenCeiling,
|
|
1172
1173
|
estimateTokens: () => estimateTokens,
|
|
1173
1174
|
fetchCallerIdentity: () => fetchCallerIdentity,
|
|
1174
1175
|
fetchModels: () => fetchModels,
|
|
1176
|
+
fetchWelfareCampaigns: () => fetchWelfareCampaigns,
|
|
1175
1177
|
isConcurrencyCap: () => isConcurrencyCap,
|
|
1176
1178
|
isParamInvalidFrame: () => isParamInvalidFrame,
|
|
1179
|
+
isWelfareClaimedStatus: () => isWelfareClaimedStatus,
|
|
1177
1180
|
maxTokensCeilingFor: () => maxTokensCeilingFor,
|
|
1181
|
+
pickDailyWelfareCampaign: () => pickDailyWelfareCampaign,
|
|
1178
1182
|
prepareChatBody: () => prepareChatBody,
|
|
1179
1183
|
signedGet: () => signedGet
|
|
1180
1184
|
});
|
|
@@ -1883,9 +1887,14 @@ async function fetchModels(credential, signal) {
|
|
|
1883
1887
|
};
|
|
1884
1888
|
}
|
|
1885
1889
|
/**
|
|
1886
|
-
*
|
|
1887
|
-
*
|
|
1890
|
+
* 开通「限时福利」(免费模型)渠道,幂等:已开通就原样返回。官方客户端打开模型菜单
|
|
1891
|
+
* 即调用(GET),用户点「领取」时也调(POST)——两种方法实测都返回 200/0000。
|
|
1892
|
+
* 不开通时福利模型调用必报 InferHub.4004.200 benefit not found。
|
|
1888
1893
|
* 需要 AK/SK 签名(凭证要带 accessKeyId/secretAccessKey)。
|
|
1894
|
+
*
|
|
1895
|
+
* **它不发积分。** 返回体只是一条渠道开通记录(channel / create_time / update_time,
|
|
1896
|
+
* 幂等所以时间戳是旧的),账号积分由套餐决定(见 credits.ts),领取动作在官网签到页。
|
|
1897
|
+
* 别把它当「领取积分」用 —— 早先卡片这么用,结果就是「点了显示已领取、积分没变」。
|
|
1889
1898
|
*/
|
|
1890
1899
|
async function claimBenefit(credential, abort) {
|
|
1891
1900
|
if (!credential.accessKeyId || !credential.secretAccessKey) return;
|
|
@@ -1908,13 +1917,188 @@ async function claimBenefit(credential, abort) {
|
|
|
1908
1917
|
const resp = await fetch(req, { signal: abort });
|
|
1909
1918
|
const raw = await resp.text().catch(() => "");
|
|
1910
1919
|
if (!resp.ok) throw new Error(`claim benefit failed: ${resp.status} ${raw.slice(0, 200)}`);
|
|
1920
|
+
let json;
|
|
1921
|
+
try {
|
|
1922
|
+
json = JSON.parse(raw);
|
|
1923
|
+
} catch {
|
|
1924
|
+
throw new Error(`claim benefit: unexpected non-JSON response: ${raw.slice(0, 200)}`);
|
|
1925
|
+
}
|
|
1926
|
+
if (json.error_code !== "0000") throw new Error(`claim benefit rejected: ${json.error_code ?? "(no error_code)"} ${json.error_msg ?? ""}`.trim());
|
|
1927
|
+
}
|
|
1928
|
+
/**
|
|
1929
|
+
* 福利中心(活动积分)接口:26.9.901 起应用内「每日签到领 1000 积分」走这套。
|
|
1930
|
+
*
|
|
1931
|
+
* host 与积分统计是同一个 snap-access 网关,路径前缀 `/v1/ops`,鉴权头对齐官方客户端
|
|
1932
|
+
* 的 `Pz()`(`x-auth-token` + `Agent-Type: PromptCenter`),再补上我们直连必须的
|
|
1933
|
+
* AK/SK 签名。三个实测出来的坑:
|
|
1934
|
+
*
|
|
1935
|
+
* 1. bundle 里 URL 有两套变体,带前缀的 `/PromptCenterService/v1/ops/*` 在这个网关上
|
|
1936
|
+
* 回 **404 APIG.0101(未发布)** —— 只有裸 `/v1/ops/*` 能用;
|
|
1937
|
+
* 2. 只带 `x-auth-token` 会被拒(`APIG.0301 decrypt token fail`);
|
|
1938
|
+
* 3. **业务失败也回 HTTP 200**,成败只看 body 的 `code`(0 才是成功)。
|
|
1939
|
+
* 今天已领时是 `code:40001 尚未到达权益刷新时间,暂时无法领取`。
|
|
1940
|
+
*
|
|
1941
|
+
* 领的是「活动」而不是额度:`/ops/delivery` 给活动清单(含 campaignId / status /
|
|
1942
|
+
* claimable),`/ops/claim` 按 campaignId 领。`idempotentKey` 上游不返回,官方客户端
|
|
1943
|
+
* 自己生成随机串(与 `x-snap-traceid` 同一个生成器),按天去重落在服务端。
|
|
1944
|
+
*/
|
|
1945
|
+
const EP_OPS_DELIVERY = "/v1/ops/delivery";
|
|
1946
|
+
const EP_OPS_CLAIM = "/v1/ops/claim";
|
|
1947
|
+
/** 每日签到活动的 type(实测为 campaignId 1,benefitAmount 1000 CREDIT)。 */
|
|
1948
|
+
const WELFARE_DAILY_TYPE = "USER_LOGIN";
|
|
1949
|
+
/** 上游按钮文案的状态机:这几个都表示「今天已经领过了」。 */
|
|
1950
|
+
const WELFARE_ALREADY_STATES = /* @__PURE__ */ new Set([
|
|
1951
|
+
"CLAIMED",
|
|
1952
|
+
"CONFIRMED",
|
|
1953
|
+
"CONSUMED"
|
|
1954
|
+
]);
|
|
1955
|
+
/** 活动状态是不是「今天已经领过了」(区别于「要先登录」「没资格」这些同样不可领的情况)。 */
|
|
1956
|
+
function isWelfareClaimedStatus(status) {
|
|
1957
|
+
return WELFARE_ALREADY_STATES.has(status);
|
|
1958
|
+
}
|
|
1959
|
+
/**
|
|
1960
|
+
* 「今日已领」的业务码。
|
|
1961
|
+
*
|
|
1962
|
+
* 这个分支不是冗余的:领取成功后的几十秒里 delivery 有可能还回一份**陈旧**的
|
|
1963
|
+
* `claimable:true / ELIGIBLE`(实测 2026-10-16,领完立刻读会看到),于是会真的
|
|
1964
|
+
* POST 第二次 —— 服务端按天去重回这个码,所以按「已领」处理,不能当失败。
|
|
1965
|
+
*/
|
|
1966
|
+
const WELFARE_CODE_NOT_YET = 40001;
|
|
1967
|
+
/** 福利接口的请求:签名 + 官方那套头,返回解析后的 body。 */
|
|
1968
|
+
async function welfareRequest(url, method, credential, body, signal) {
|
|
1969
|
+
const req = new Request(url, {
|
|
1970
|
+
method,
|
|
1971
|
+
headers: {
|
|
1972
|
+
"Content-Type": "application/json",
|
|
1973
|
+
"X-Language": "zh-cn",
|
|
1974
|
+
"x-snap-traceid": hex32(),
|
|
1975
|
+
"x-auth-token": credential.token,
|
|
1976
|
+
"Agent-Type": "PromptCenter",
|
|
1977
|
+
"X-Security-Token": credential.securityToken
|
|
1978
|
+
},
|
|
1979
|
+
...body === void 0 ? {} : { body }
|
|
1980
|
+
});
|
|
1981
|
+
const bodyBuf = Buffer.from(body ?? "");
|
|
1982
|
+
if (credential.accessKeyId !== void 0 && credential.secretAccessKey !== void 0) signRequest(req, bodyBuf, {
|
|
1983
|
+
accessKeyId: credential.accessKeyId,
|
|
1984
|
+
secretAccessKey: credential.secretAccessKey,
|
|
1985
|
+
securityToken: credential.securityToken
|
|
1986
|
+
});
|
|
1987
|
+
let resp;
|
|
1988
|
+
try {
|
|
1989
|
+
resp = await fetch(req, { signal });
|
|
1990
|
+
} catch (error) {
|
|
1991
|
+
return {
|
|
1992
|
+
ok: false,
|
|
1993
|
+
message: error instanceof Error ? error.message : String(error)
|
|
1994
|
+
};
|
|
1995
|
+
}
|
|
1996
|
+
const text = await resp.text().catch(() => "");
|
|
1997
|
+
if (!resp.ok) return {
|
|
1998
|
+
ok: false,
|
|
1999
|
+
message: `HTTP ${resp.status} ${text.slice(0, 200)}`
|
|
2000
|
+
};
|
|
2001
|
+
let parsed;
|
|
1911
2002
|
try {
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
2003
|
+
parsed = JSON.parse(text);
|
|
2004
|
+
} catch {
|
|
2005
|
+
return {
|
|
2006
|
+
ok: false,
|
|
2007
|
+
message: `unexpected non-JSON response: ${text.slice(0, 200)}`
|
|
2008
|
+
};
|
|
1917
2009
|
}
|
|
2010
|
+
const envelope = asRecord(parsed);
|
|
2011
|
+
return {
|
|
2012
|
+
ok: true,
|
|
2013
|
+
code: typeof envelope.code === "number" ? envelope.code : -1,
|
|
2014
|
+
message: firstString(envelope.message),
|
|
2015
|
+
data: envelope.data
|
|
2016
|
+
};
|
|
2017
|
+
}
|
|
2018
|
+
/** 活动清单(`GET /v1/ops/delivery?channel=IDE`)。 */
|
|
2019
|
+
async function fetchWelfareCampaigns(credential, signal) {
|
|
2020
|
+
const resp = await welfareRequest(`${SNAP_HOST}${EP_OPS_DELIVERY}?channel=IDE`, "GET", credential, void 0, signal);
|
|
2021
|
+
if (!resp.ok) throw new Error(`welfare delivery: ${resp.message}`);
|
|
2022
|
+
return asArray(asRecord(resp.data).items).flatMap((item) => {
|
|
2023
|
+
const raw = asRecord(item);
|
|
2024
|
+
const campaignId = typeof raw.campaignId === "number" ? raw.campaignId : NaN;
|
|
2025
|
+
if (Number.isFinite(campaignId) === false) return [];
|
|
2026
|
+
return [{
|
|
2027
|
+
campaignId,
|
|
2028
|
+
title: firstString(raw.title),
|
|
2029
|
+
type: firstString(raw.type),
|
|
2030
|
+
amount: typeof raw.benefitAmount === "number" ? raw.benefitAmount : 0,
|
|
2031
|
+
unit: firstString(raw.benefitUnit),
|
|
2032
|
+
claimable: raw.claimable === true,
|
|
2033
|
+
status: firstString(raw.status)
|
|
2034
|
+
}];
|
|
2035
|
+
});
|
|
2036
|
+
}
|
|
2037
|
+
/**
|
|
2038
|
+
* 从活动清单里挑「每日签到」那条。
|
|
2039
|
+
*
|
|
2040
|
+
* 同一个 type 理论上可能有多条(上游换活动的时候),优先挑当前可领的那条。
|
|
2041
|
+
*/
|
|
2042
|
+
function pickDailyWelfareCampaign(campaigns) {
|
|
2043
|
+
const daily = campaigns.filter((c) => c.type === WELFARE_DAILY_TYPE && c.unit === "CREDIT");
|
|
2044
|
+
return daily.find((c) => c.claimable) ?? daily[0];
|
|
2045
|
+
}
|
|
2046
|
+
/**
|
|
2047
|
+
* 领一次每日签到积分。
|
|
2048
|
+
*
|
|
2049
|
+
* 不抛异常:这是卡片上一个按钮的后续,失败要变成能显示的文案而不是断掉的请求。
|
|
2050
|
+
*/
|
|
2051
|
+
async function claimDailyWelfare(credential, signal) {
|
|
2052
|
+
if (credential.accessKeyId === void 0 || credential.secretAccessKey === void 0) return {
|
|
2053
|
+
state: "failed",
|
|
2054
|
+
amount: 0,
|
|
2055
|
+
message: "no AK/SK to sign"
|
|
2056
|
+
};
|
|
2057
|
+
let campaigns;
|
|
2058
|
+
try {
|
|
2059
|
+
campaigns = await fetchWelfareCampaigns(credential, signal);
|
|
2060
|
+
} catch (error) {
|
|
2061
|
+
return {
|
|
2062
|
+
state: "failed",
|
|
2063
|
+
amount: 0,
|
|
2064
|
+
message: error instanceof Error ? error.message : String(error)
|
|
2065
|
+
};
|
|
2066
|
+
}
|
|
2067
|
+
const target = pickDailyWelfareCampaign(campaigns);
|
|
2068
|
+
if (target === void 0) return {
|
|
2069
|
+
state: "unavailable",
|
|
2070
|
+
amount: 0,
|
|
2071
|
+
message: "no daily check-in campaign"
|
|
2072
|
+
};
|
|
2073
|
+
if (!target.claimable) return isWelfareClaimedStatus(target.status) ? {
|
|
2074
|
+
state: "already",
|
|
2075
|
+
amount: 0,
|
|
2076
|
+
message: ""
|
|
2077
|
+
} : {
|
|
2078
|
+
state: "unavailable",
|
|
2079
|
+
amount: 0,
|
|
2080
|
+
message: target.status
|
|
2081
|
+
};
|
|
2082
|
+
const resp = await welfareRequest(`${SNAP_HOST}${EP_OPS_CLAIM}`, "POST", credential, JSON.stringify({
|
|
2083
|
+
campaignId: target.campaignId,
|
|
2084
|
+
idempotentKey: hex32(),
|
|
2085
|
+
channel: "IDE"
|
|
2086
|
+
}), signal);
|
|
2087
|
+
if (!resp.ok) return {
|
|
2088
|
+
state: "failed",
|
|
2089
|
+
amount: 0,
|
|
2090
|
+
message: resp.message
|
|
2091
|
+
};
|
|
2092
|
+
if (resp.code === 0) return {
|
|
2093
|
+
state: "claimed",
|
|
2094
|
+
amount: target.amount,
|
|
2095
|
+
message: resp.message
|
|
2096
|
+
};
|
|
2097
|
+
return {
|
|
2098
|
+
state: resp.code === WELFARE_CODE_NOT_YET ? "already" : "failed",
|
|
2099
|
+
amount: 0,
|
|
2100
|
+
message: resp.message
|
|
2101
|
+
};
|
|
1918
2102
|
}
|
|
1919
2103
|
//#endregion
|
|
1920
2104
|
//#region src/discovery.ts
|
|
@@ -2220,4 +2404,4 @@ function sumOf(store) {
|
|
|
2220
2404
|
return out;
|
|
2221
2405
|
}
|
|
2222
2406
|
//#endregion
|
|
2223
|
-
export {
|
|
2407
|
+
export { isBenefitModel as C, codeartsAuthPath as D, codeartsAccountsPath as E, startLogin as O, filterEnabledModels as S, CodeArtsCredentialStore as T, pickDailyWelfareCampaign as _, SNAP_HOST as a, CodeArtsCatalog as b, claimDailyWelfare as c, fetchModels as d, fetchWelfareCampaigns as f, maxTokensCeilingFor as g, isWelfareClaimedStatus as h, refreshCatalog as i, degradeTokenCeiling as l, isParamInvalidFrame as m, codeartsUsagePath as n, canonicalModel as o, isConcurrencyCap as p, discoverModels as r, chatStream as s, CodeArtsUsageTracker as t, fetchCallerIdentity as u, prepareChatBody as v, CodeArtsAccountStore as w, FALLBACK_CODEARTS_MODELS as x, signedGet 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.4.
|
|
5
|
+
"version": "0.4.2",
|
|
6
6
|
"author": "elegant01",
|
|
7
7
|
"keywords": [
|
|
8
8
|
"dsh-plugin",
|