@huaqiu/dsh-huaqiu-about 0.4.10
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/LICENSE +21 -0
- package/README.md +64 -0
- package/cordis.patch.yml +4 -0
- package/lib/client.js +303 -0
- package/lib/client.js.map +1 -0
- package/lib/index.d.mts +12 -0
- package/lib/index.mjs +110 -0
- package/package.json +61 -0
- package/src/client/AboutSection.tsx +270 -0
- package/src/client/HuaqiuBrand.tsx +35 -0
- package/src/client/index.ts +64 -0
- package/src/client/locales.ts +27 -0
- package/src/dsh-version.ts +89 -0
- package/src/index.ts +56 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 深圳华秋智联股份有限公司
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# @huaqiu/dsh-huaqiu-about
|
|
2
|
+
|
|
3
|
+
An installable DSH Web profile plugin that contributes an **About** row to the
|
|
4
|
+
DSH settings page, following the reference prototype
|
|
5
|
+
(`dsh-pcb-eda/reference.html`): the HuaQiu brand mark, the platform slogan, a
|
|
6
|
+
`DSH 运行时 0.1.0` runtime badge, a metadata box (Distribution version, plugin
|
|
7
|
+
type, copy-metadata action, `deepseek-harness` link), and the copyright /
|
|
8
|
+
attribution lines. All text lines are localised (`zh` / `en`).
|
|
9
|
+
|
|
10
|
+
## Install
|
|
11
|
+
|
|
12
|
+
```powershell
|
|
13
|
+
dsh plugin --profile web add file:C:/Downloads/huaqiu-dsh-huaqiu-about-<version>.tgz
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Restart the Web profile after installing. Remove it with:
|
|
17
|
+
|
|
18
|
+
```powershell
|
|
19
|
+
dsh plugin --profile web remove @huaqiu/dsh-huaqiu-about
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## What it renders
|
|
23
|
+
|
|
24
|
+
The row registers into the `settings.section` slot (the same mechanism the
|
|
25
|
+
community `dsh-market` plugin uses for its settings page) and shows, per the
|
|
26
|
+
prototype:
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
[HuaQiu brand mark]
|
|
30
|
+
{电子设计智能体平台 / Electronic Design Agent Platform}
|
|
31
|
+
[DSH 运行时 0.1.0] ← runtime label + this plugin's version
|
|
32
|
+
┌─────────────────────────────────────┐
|
|
33
|
+
│ 发行版本 0.1.5-rc.2 │ ← Distribution label + bundled DSH version
|
|
34
|
+
│ 插件类型 DSH Standalone Plugin │
|
|
35
|
+
│ 复制元数据 deepseek-harness ↗ │
|
|
36
|
+
└─────────────────────────────────────┘
|
|
37
|
+
© 2026 深圳华秋智联股份有限公司
|
|
38
|
+
由 DSH 提供支持
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
The runtime version is this plugin's declared version; the Distribution
|
|
42
|
+
version is the DSH version bundled with the running harness.
|
|
43
|
+
|
|
44
|
+
## Implementation
|
|
45
|
+
|
|
46
|
+
The package is a dual-half plugin:
|
|
47
|
+
|
|
48
|
+
- **Node half** (`src/index.ts`) mounts a same-origin version route on
|
|
49
|
+
`ctx.webServer` (`GET /api/v1/huaqiu/about` → `{ version, dshVersion }`) —
|
|
50
|
+
the same browser→node channel `@huaqiu/dsh-auth` uses for its credential
|
|
51
|
+
routes. `version` is this plugin's own declared version, read from the
|
|
52
|
+
package manifest next to the entry (`../package.json` relative to
|
|
53
|
+
`import.meta.url`); `dshVersion` is resolved the same way the community
|
|
54
|
+
`dsh-market` plugin resolves the host version (walking up from the CLI entry
|
|
55
|
+
for `node_modules/@deepseek-ai/dsh/package.json`, also recognising a
|
|
56
|
+
workspace checkout whose own `package.json` carries the `@deepseek-ai/dsh`
|
|
57
|
+
name, then a `require.resolve` probe, then environment fallbacks).
|
|
58
|
+
- **Browser half** (`src/client/index.ts`) registers the settings section and
|
|
59
|
+
fetches the two versions from the node route when the About row renders. It
|
|
60
|
+
does not depend on cross-end `ctx.provide`/`ctx.get` service sync (which is
|
|
61
|
+
unavailable within a single plugin's two halves).
|
|
62
|
+
|
|
63
|
+
When a version is unreachable, its slot is simply left empty; everything else
|
|
64
|
+
always renders.
|
package/cordis.patch.yml
ADDED
package/lib/client.js
ADDED
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
window.__ModuleLoader__.load({
|
|
2
|
+
id: "@huaqiu/dsh-huaqiu-about",
|
|
3
|
+
factory: (require) => {
|
|
4
|
+
var module = { exports: {} };
|
|
5
|
+
var exports = module.exports;
|
|
6
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
7
|
+
let react = require("react");
|
|
8
|
+
//#region src/client/HuaqiuBrand.tsx
|
|
9
|
+
/**
|
|
10
|
+
* HuaQiu brand mark — self-contained copy (SVG) so the About plugin does not
|
|
11
|
+
* depend on another plugin's client bundle at runtime.
|
|
12
|
+
*/
|
|
13
|
+
function HuaqiuBrandMark({ size, className }) {
|
|
14
|
+
return (0, react.createElement)("svg", {
|
|
15
|
+
"aria-hidden": true,
|
|
16
|
+
className,
|
|
17
|
+
height: size,
|
|
18
|
+
style: {
|
|
19
|
+
display: "block",
|
|
20
|
+
flex: "none"
|
|
21
|
+
},
|
|
22
|
+
viewBox: "0 0 974.25 974.25",
|
|
23
|
+
width: size,
|
|
24
|
+
xmlns: "http://www.w3.org/2000/svg"
|
|
25
|
+
}, (0, react.createElement)("path", {
|
|
26
|
+
d: "M865.67,758.67a107,107,0,1,0,107,107A107,107,0,0,0,865.67,758.67Z",
|
|
27
|
+
fill: "#c7000b",
|
|
28
|
+
fillRule: "evenodd"
|
|
29
|
+
}), (0, react.createElement)("path", {
|
|
30
|
+
d: "M744.11,0h-514C103.56,0,0,103.56,0,230.14v514C0,870.69,103.56,974.25,230.14,974.25h514c3.34,0,6.66-.06,10-.21a155.66,155.66,0,0,1-40-143.56H230.14a86.63,86.63,0,0,1-86.37-86.37v-514a86.63,86.63,0,0,1,86.37-86.37h514a86.61,86.61,0,0,1,86.37,86.37V714.06a156.93,156.93,0,0,1,35.19-4A155.1,155.1,0,0,1,974,754c.15-3.28.21-6.6.21-9.92v-514C974.25,103.56,870.69,0,744.11,0Z",
|
|
31
|
+
fill: "#c7000b",
|
|
32
|
+
fillRule: "evenodd"
|
|
33
|
+
}), (0, react.createElement)("polygon", {
|
|
34
|
+
points: "735.67 735.65 735.67 238.59 591.9 238.59 591.9 415.24 382.39 415.24 382.39 238.59 238.62 238.59 238.62 735.65 382.39 735.65 382.39 559.01 591.9 559.01 591.9 735.65 735.67 735.65",
|
|
35
|
+
fill: "#c7000b",
|
|
36
|
+
fillRule: "evenodd"
|
|
37
|
+
}));
|
|
38
|
+
}
|
|
39
|
+
//#endregion
|
|
40
|
+
//#region src/client/AboutSection.tsx
|
|
41
|
+
/**
|
|
42
|
+
* About row content, following the reference prototype:
|
|
43
|
+
*
|
|
44
|
+
* [HuaQiu brand mark]
|
|
45
|
+
* {slogan}
|
|
46
|
+
* [DSH 运行时 0.1.0] (runtime label + this plugin's version)
|
|
47
|
+
* ┌───────────────────────────┐
|
|
48
|
+
* │ 发行版本 0.1.5-rc.2 │ (Distribution label + bundled DSH version)
|
|
49
|
+
* │ 内置插件版本 0.1.0 │ (Builtin plugin version = plugin version)
|
|
50
|
+
* │ 复制元数据 deepseek-harness ↗ │
|
|
51
|
+
* └───────────────────────────┘
|
|
52
|
+
* © 2026 深圳华秋智联股份有限公司
|
|
53
|
+
* 由 DSH 提供支持
|
|
54
|
+
*
|
|
55
|
+
* The two versions are fetched from the node half's same-origin route
|
|
56
|
+
* (`GET /api/v1/huaqiu/about` → `{ version, dshVersion }`): the DSH Runtime
|
|
57
|
+
* badge and the Builtin plugin version row both show this plugin's declared
|
|
58
|
+
* version, the Distribution version is the DSH version bundled with the
|
|
59
|
+
* running harness. The block is vertically compact like the prototype — it
|
|
60
|
+
* centers as one dense unit instead of stretching across the panel. All text
|
|
61
|
+
* lines are localised.
|
|
62
|
+
*/
|
|
63
|
+
const ROOT = {
|
|
64
|
+
display: "flex",
|
|
65
|
+
flexDirection: "column",
|
|
66
|
+
alignItems: "center",
|
|
67
|
+
justifyContent: "center",
|
|
68
|
+
height: "100%",
|
|
69
|
+
boxSizing: "border-box",
|
|
70
|
+
gap: 14,
|
|
71
|
+
padding: "16px 24px",
|
|
72
|
+
textAlign: "center"
|
|
73
|
+
};
|
|
74
|
+
const TOP = {
|
|
75
|
+
display: "flex",
|
|
76
|
+
flexDirection: "column",
|
|
77
|
+
alignItems: "center",
|
|
78
|
+
gap: 8
|
|
79
|
+
};
|
|
80
|
+
const TITLE = {
|
|
81
|
+
color: "var(--dsw-alias-label-primary)",
|
|
82
|
+
fontSize: 20,
|
|
83
|
+
fontWeight: 700,
|
|
84
|
+
letterSpacing: "0.01em"
|
|
85
|
+
};
|
|
86
|
+
const BADGE = {
|
|
87
|
+
display: "inline-flex",
|
|
88
|
+
alignItems: "center",
|
|
89
|
+
gap: 6,
|
|
90
|
+
padding: "2px 12px",
|
|
91
|
+
borderRadius: 999,
|
|
92
|
+
fontSize: 12,
|
|
93
|
+
fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace",
|
|
94
|
+
color: "var(--dsw-alias-label-secondary)",
|
|
95
|
+
background: "color-mix(in srgb, var(--dsw-alias-label-primary) 5%, transparent)",
|
|
96
|
+
border: "1px solid color-mix(in srgb, var(--dsw-alias-label-primary) 14%, transparent)"
|
|
97
|
+
};
|
|
98
|
+
const BADGE_VALUE = {
|
|
99
|
+
color: "var(--dsw-alias-label-primary)",
|
|
100
|
+
fontWeight: 600
|
|
101
|
+
};
|
|
102
|
+
const META_BOX = {
|
|
103
|
+
width: "100%",
|
|
104
|
+
maxWidth: 360,
|
|
105
|
+
display: "flex",
|
|
106
|
+
flexDirection: "column",
|
|
107
|
+
gap: 8,
|
|
108
|
+
padding: "12px 14px",
|
|
109
|
+
borderRadius: 12,
|
|
110
|
+
fontSize: 12,
|
|
111
|
+
textAlign: "left",
|
|
112
|
+
color: "var(--dsw-alias-label-primary)",
|
|
113
|
+
background: "color-mix(in srgb, var(--dsw-alias-label-primary) 3%, transparent)",
|
|
114
|
+
border: "1px solid color-mix(in srgb, var(--dsw-alias-label-primary) 10%, transparent)",
|
|
115
|
+
boxSizing: "border-box"
|
|
116
|
+
};
|
|
117
|
+
const ROW = {
|
|
118
|
+
display: "flex",
|
|
119
|
+
alignItems: "center",
|
|
120
|
+
justifyContent: "space-between",
|
|
121
|
+
gap: 12
|
|
122
|
+
};
|
|
123
|
+
const ROW_LABEL = { color: "var(--dsw-alias-label-tertiary)" };
|
|
124
|
+
const VERSION_PILL = {
|
|
125
|
+
color: "var(--dsw-alias-label-primary)",
|
|
126
|
+
fontWeight: 500,
|
|
127
|
+
fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace",
|
|
128
|
+
fontSize: 11,
|
|
129
|
+
padding: "1px 8px",
|
|
130
|
+
borderRadius: 6,
|
|
131
|
+
background: "color-mix(in srgb, var(--dsw-alias-label-primary) 6%, transparent)",
|
|
132
|
+
border: "1px solid color-mix(in srgb, var(--dsw-alias-label-primary) 14%, transparent)"
|
|
133
|
+
};
|
|
134
|
+
const ROW_BOTTOM = {
|
|
135
|
+
display: "flex",
|
|
136
|
+
alignItems: "center",
|
|
137
|
+
justifyContent: "space-between",
|
|
138
|
+
gap: 12,
|
|
139
|
+
paddingTop: 8,
|
|
140
|
+
borderTop: "1px solid color-mix(in srgb, var(--dsw-alias-label-primary) 12%, transparent)",
|
|
141
|
+
fontSize: 11
|
|
142
|
+
};
|
|
143
|
+
const ACTION = {
|
|
144
|
+
display: "inline-flex",
|
|
145
|
+
alignItems: "center",
|
|
146
|
+
gap: 6,
|
|
147
|
+
border: "none",
|
|
148
|
+
background: "none",
|
|
149
|
+
padding: 0,
|
|
150
|
+
cursor: "pointer",
|
|
151
|
+
font: "inherit",
|
|
152
|
+
color: "var(--dsw-alias-label-tertiary)"
|
|
153
|
+
};
|
|
154
|
+
const ACTION_COPIED = {
|
|
155
|
+
...ACTION,
|
|
156
|
+
color: "var(--dsw-alias-state-success, #34c759)",
|
|
157
|
+
fontWeight: 500
|
|
158
|
+
};
|
|
159
|
+
const LINK = {
|
|
160
|
+
display: "inline-flex",
|
|
161
|
+
alignItems: "center",
|
|
162
|
+
gap: 6,
|
|
163
|
+
textDecoration: "none",
|
|
164
|
+
color: "var(--dsw-alias-label-tertiary)"
|
|
165
|
+
};
|
|
166
|
+
const FOOTER = {
|
|
167
|
+
display: "flex",
|
|
168
|
+
flexDirection: "column",
|
|
169
|
+
gap: 2
|
|
170
|
+
};
|
|
171
|
+
const COPYRIGHT = {
|
|
172
|
+
fontSize: 12,
|
|
173
|
+
fontWeight: 500,
|
|
174
|
+
color: "var(--dsw-alias-label-secondary)",
|
|
175
|
+
margin: 0
|
|
176
|
+
};
|
|
177
|
+
const POWERED = {
|
|
178
|
+
fontSize: 11,
|
|
179
|
+
color: "var(--dsw-alias-label-tertiary)",
|
|
180
|
+
margin: 0
|
|
181
|
+
};
|
|
182
|
+
/** Same-origin route mounted by the node half (see `src/index.ts`). */
|
|
183
|
+
const ABOUT_ROUTE = "/api/v1/huaqiu/about";
|
|
184
|
+
const GITHUB_URL = "https://github.com/deepseek-ai/deepseek-harness";
|
|
185
|
+
function AboutSection({ t }) {
|
|
186
|
+
const [version, setVersion] = (0, react.useState)(null);
|
|
187
|
+
const [dshVersion, setDshVersion] = (0, react.useState)(null);
|
|
188
|
+
const [copied, setCopied] = (0, react.useState)(false);
|
|
189
|
+
(0, react.useEffect)(() => {
|
|
190
|
+
let alive = true;
|
|
191
|
+
fetch(ABOUT_ROUTE).then((res) => res.ok ? res.json() : null).then((body) => {
|
|
192
|
+
if (!alive) return;
|
|
193
|
+
setVersion(body && typeof body.version === "string" ? body.version : null);
|
|
194
|
+
setDshVersion(body && typeof body.dshVersion === "string" ? body.dshVersion : null);
|
|
195
|
+
}).catch(() => {
|
|
196
|
+
if (alive) {
|
|
197
|
+
setVersion(null);
|
|
198
|
+
setDshVersion(null);
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
return () => {
|
|
202
|
+
alive = false;
|
|
203
|
+
};
|
|
204
|
+
}, []);
|
|
205
|
+
(0, react.useEffect)(() => {
|
|
206
|
+
if (!copied) return;
|
|
207
|
+
const timer = window.setTimeout(() => setCopied(false), 2e3);
|
|
208
|
+
return () => window.clearTimeout(timer);
|
|
209
|
+
}, [copied]);
|
|
210
|
+
const copyMeta = () => {
|
|
211
|
+
const runtime = version ?? "-";
|
|
212
|
+
const dist = dshVersion ?? "-";
|
|
213
|
+
const text = [
|
|
214
|
+
`App: ${t("slogan")}`,
|
|
215
|
+
`DSH Runtime: ${runtime}`,
|
|
216
|
+
`Release: ${dist}`,
|
|
217
|
+
`Copyright: ${t("copyright")}`
|
|
218
|
+
].join("\n");
|
|
219
|
+
navigator.clipboard.writeText(text).catch(() => {});
|
|
220
|
+
setCopied(true);
|
|
221
|
+
};
|
|
222
|
+
return (0, react.createElement)("div", { style: ROOT }, (0, react.createElement)("div", { style: TOP }, (0, react.createElement)(HuaqiuBrandMark, { size: 64 }), (0, react.createElement)("div", { style: TITLE }, t("slogan")), (0, react.createElement)("div", { style: BADGE }, (0, react.createElement)("span", null, t("runtimeLabel")), (0, react.createElement)("span", { style: BADGE_VALUE }, version ?? ""))), (0, react.createElement)("div", { style: META_BOX }, (0, react.createElement)("div", { style: ROW }, (0, react.createElement)("span", { style: ROW_LABEL }, t("distributionLabel")), (0, react.createElement)("span", { style: VERSION_PILL }, dshVersion ?? "")), (0, react.createElement)("div", { style: ROW }, (0, react.createElement)("span", { style: ROW_LABEL }, t("builtinPluginLabel")), (0, react.createElement)("span", { style: VERSION_PILL }, version ?? "")), (0, react.createElement)("div", { style: ROW_BOTTOM }, (0, react.createElement)("button", {
|
|
223
|
+
style: copied ? ACTION_COPIED : ACTION,
|
|
224
|
+
onClick: copyMeta,
|
|
225
|
+
type: "button"
|
|
226
|
+
}, (0, react.createElement)("span", null, copied ? t("copied") : t("copyMetadata"))), (0, react.createElement)("a", {
|
|
227
|
+
style: LINK,
|
|
228
|
+
href: GITHUB_URL,
|
|
229
|
+
target: "_blank",
|
|
230
|
+
rel: "noreferrer"
|
|
231
|
+
}, (0, react.createElement)("span", null, "deepseek-harness"), (0, react.createElement)("span", { style: {
|
|
232
|
+
fontSize: 9,
|
|
233
|
+
opacity: .7
|
|
234
|
+
} }, "↗")))), (0, react.createElement)("div", { style: FOOTER }, (0, react.createElement)("p", { style: COPYRIGHT }, t("copyright")), (0, react.createElement)("p", { style: POWERED }, t("poweredBy"))));
|
|
235
|
+
}
|
|
236
|
+
//#endregion
|
|
237
|
+
//#region src/client/locales.ts
|
|
238
|
+
/** About-section dictionaries. */
|
|
239
|
+
const zh = {
|
|
240
|
+
nav: "关于",
|
|
241
|
+
slogan: "电子设计智能体平台",
|
|
242
|
+
runtimeLabel: "DSH 运行时",
|
|
243
|
+
distributionLabel: "发行版本",
|
|
244
|
+
builtinPluginLabel: "内置插件版本",
|
|
245
|
+
copyMetadata: "复制元数据 (Metadata)",
|
|
246
|
+
copied: "版本信息已复制",
|
|
247
|
+
copyright: "© 2026 深圳华秋智联股份有限公司",
|
|
248
|
+
poweredBy: "由 DSH 提供支持"
|
|
249
|
+
};
|
|
250
|
+
const en = {
|
|
251
|
+
nav: "About",
|
|
252
|
+
slogan: "Electronic Design Agent Platform",
|
|
253
|
+
runtimeLabel: "DSH Runtime",
|
|
254
|
+
distributionLabel: "Distribution",
|
|
255
|
+
builtinPluginLabel: "Builtin plugin version",
|
|
256
|
+
copyMetadata: "Copy metadata",
|
|
257
|
+
copied: "Metadata copied",
|
|
258
|
+
copyright: "© 2026 Shenzhen Huaqiu Zhilian Co., Ltd.",
|
|
259
|
+
poweredBy: "Powered by DSH"
|
|
260
|
+
};
|
|
261
|
+
//#endregion
|
|
262
|
+
//#region src/client/index.ts
|
|
263
|
+
/**
|
|
264
|
+
* `@huaqiu/dsh-huaqiu-about` — browser half.
|
|
265
|
+
*
|
|
266
|
+
* Contributes an "About" row to the DSH settings page through the
|
|
267
|
+
* `settings.section` slot (the same mechanism the community `dsh-market`
|
|
268
|
+
* plugin uses). The row shows the original DSH fish mark, the DSH version
|
|
269
|
+
* bundled with the running harness (fetched from the node half's
|
|
270
|
+
* same-origin route), and the "Powered by DSH" claim.
|
|
271
|
+
*/
|
|
272
|
+
const inject = ["slots", "locale"];
|
|
273
|
+
const ABOUT_NS = "about.huaqiu";
|
|
274
|
+
/**
|
|
275
|
+
* Install the About row on the running client context.
|
|
276
|
+
*/
|
|
277
|
+
function apply(ctx) {
|
|
278
|
+
ctx.effect?.(() => {
|
|
279
|
+
ctx.locale?.register(ABOUT_NS, {
|
|
280
|
+
zh,
|
|
281
|
+
en
|
|
282
|
+
});
|
|
283
|
+
}, "huaqiu about: dictionaries");
|
|
284
|
+
const t = ctx.locale?.bind("about.huaqiu") ?? (() => "About");
|
|
285
|
+
const slots = ctx.slots;
|
|
286
|
+
if (!slots) return;
|
|
287
|
+
slots.inject("settings.section", () => slots.register({
|
|
288
|
+
name: "settings.section",
|
|
289
|
+
id: "huaqiu-about",
|
|
290
|
+
order: 90,
|
|
291
|
+
label: () => t("nav"),
|
|
292
|
+
locale: ABOUT_NS
|
|
293
|
+
}, () => (0, react.createElement)(AboutSection, { t })));
|
|
294
|
+
}
|
|
295
|
+
//#endregion
|
|
296
|
+
exports.ABOUT_NS = ABOUT_NS;
|
|
297
|
+
exports.apply = apply;
|
|
298
|
+
exports.inject = inject;
|
|
299
|
+
return module.exports;
|
|
300
|
+
}
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","names":["createElement","useState","createElement","createElement"],"sources":["../src/client/HuaqiuBrand.tsx","../src/client/AboutSection.tsx","../src/client/locales.ts","../src/client/index.ts"],"sourcesContent":["/**\n * HuaQiu brand mark — self-contained copy (SVG) so the About plugin does not\n * depend on another plugin's client bundle at runtime.\n */\nimport { createElement } from 'react'\n\nexport function HuaqiuBrandMark({ size, className }: { size: number; className?: string }): React.ReactElement {\n return createElement(\n 'svg',\n {\n 'aria-hidden': true,\n className,\n height: size,\n style: { display: 'block', flex: 'none' },\n viewBox: '0 0 974.25 974.25',\n width: size,\n xmlns: 'http://www.w3.org/2000/svg',\n },\n createElement('path', {\n d: 'M865.67,758.67a107,107,0,1,0,107,107A107,107,0,0,0,865.67,758.67Z',\n fill: '#c7000b',\n fillRule: 'evenodd',\n }),\n createElement('path', {\n d: 'M744.11,0h-514C103.56,0,0,103.56,0,230.14v514C0,870.69,103.56,974.25,230.14,974.25h514c3.34,0,6.66-.06,10-.21a155.66,155.66,0,0,1-40-143.56H230.14a86.63,86.63,0,0,1-86.37-86.37v-514a86.63,86.63,0,0,1,86.37-86.37h514a86.61,86.61,0,0,1,86.37,86.37V714.06a156.93,156.93,0,0,1,35.19-4A155.1,155.1,0,0,1,974,754c.15-3.28.21-6.6.21-9.92v-514C974.25,103.56,870.69,0,744.11,0Z',\n fill: '#c7000b',\n fillRule: 'evenodd',\n }),\n createElement('polygon', {\n points: '735.67 735.65 735.67 238.59 591.9 238.59 591.9 415.24 382.39 415.24 382.39 238.59 238.62 238.59 238.62 735.65 382.39 735.65 382.39 559.01 591.9 559.01 591.9 735.65 735.67 735.65',\n fill: '#c7000b',\n fillRule: 'evenodd',\n }),\n )\n}\n","/**\n * About row content, following the reference prototype:\n *\n * [HuaQiu brand mark]\n * {slogan}\n * [DSH 运行时 0.1.0] (runtime label + this plugin's version)\n * ┌───────────────────────────┐\n * │ 发行版本 0.1.5-rc.2 │ (Distribution label + bundled DSH version)\n * │ 内置插件版本 0.1.0 │ (Builtin plugin version = plugin version)\n * │ 复制元数据 deepseek-harness ↗ │\n * └───────────────────────────┘\n * © 2026 深圳华秋智联股份有限公司\n * 由 DSH 提供支持\n *\n * The two versions are fetched from the node half's same-origin route\n * (`GET /api/v1/huaqiu/about` → `{ version, dshVersion }`): the DSH Runtime\n * badge and the Builtin plugin version row both show this plugin's declared\n * version, the Distribution version is the DSH version bundled with the\n * running harness. The block is vertically compact like the prototype — it\n * centers as one dense unit instead of stretching across the panel. All text\n * lines are localised.\n */\nimport { createElement, useEffect, useState, type CSSProperties, type ReactElement } from 'react'\nimport { HuaqiuBrandMark } from './HuaqiuBrand'\n\nconst ROOT: CSSProperties = {\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n height: '100%',\n boxSizing: 'border-box',\n gap: 14,\n padding: '16px 24px',\n textAlign: 'center',\n}\n\nconst TOP: CSSProperties = {\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n gap: 8,\n}\n\nconst TITLE: CSSProperties = {\n color: 'var(--dsw-alias-label-primary)',\n fontSize: 20,\n fontWeight: 700,\n letterSpacing: '0.01em',\n}\n\nconst BADGE: CSSProperties = {\n display: 'inline-flex',\n alignItems: 'center',\n gap: 6,\n padding: '2px 12px',\n borderRadius: 999,\n fontSize: 12,\n fontFamily: 'ui-monospace, SFMono-Regular, Menlo, monospace',\n color: 'var(--dsw-alias-label-secondary)',\n background: 'color-mix(in srgb, var(--dsw-alias-label-primary) 5%, transparent)',\n border: '1px solid color-mix(in srgb, var(--dsw-alias-label-primary) 14%, transparent)',\n}\n\nconst BADGE_VALUE: CSSProperties = {\n color: 'var(--dsw-alias-label-primary)',\n fontWeight: 600,\n}\n\nconst META_BOX: CSSProperties = {\n width: '100%',\n maxWidth: 360,\n display: 'flex',\n flexDirection: 'column',\n gap: 8,\n padding: '12px 14px',\n borderRadius: 12,\n fontSize: 12,\n textAlign: 'left',\n color: 'var(--dsw-alias-label-primary)',\n background: 'color-mix(in srgb, var(--dsw-alias-label-primary) 3%, transparent)',\n border: '1px solid color-mix(in srgb, var(--dsw-alias-label-primary) 10%, transparent)',\n boxSizing: 'border-box',\n}\n\nconst ROW: CSSProperties = {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n gap: 12,\n}\n\nconst ROW_LABEL: CSSProperties = {\n color: 'var(--dsw-alias-label-tertiary)',\n}\n\nconst VERSION_PILL: CSSProperties = {\n color: 'var(--dsw-alias-label-primary)',\n fontWeight: 500,\n fontFamily: 'ui-monospace, SFMono-Regular, Menlo, monospace',\n fontSize: 11,\n padding: '1px 8px',\n borderRadius: 6,\n background: 'color-mix(in srgb, var(--dsw-alias-label-primary) 6%, transparent)',\n border: '1px solid color-mix(in srgb, var(--dsw-alias-label-primary) 14%, transparent)',\n}\n\nconst ROW_BOTTOM: CSSProperties = {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n gap: 12,\n paddingTop: 8,\n borderTop: '1px solid color-mix(in srgb, var(--dsw-alias-label-primary) 12%, transparent)',\n fontSize: 11,\n}\n\nconst ACTION: CSSProperties = {\n display: 'inline-flex',\n alignItems: 'center',\n gap: 6,\n border: 'none',\n background: 'none',\n padding: 0,\n cursor: 'pointer',\n font: 'inherit',\n color: 'var(--dsw-alias-label-tertiary)',\n}\n\nconst ACTION_COPIED: CSSProperties = {\n ...ACTION,\n color: 'var(--dsw-alias-state-success, #34c759)',\n fontWeight: 500,\n}\n\nconst LINK: CSSProperties = {\n display: 'inline-flex',\n alignItems: 'center',\n gap: 6,\n textDecoration: 'none',\n color: 'var(--dsw-alias-label-tertiary)',\n}\n\nconst FOOTER: CSSProperties = {\n display: 'flex',\n flexDirection: 'column',\n gap: 2,\n}\n\nconst COPYRIGHT: CSSProperties = {\n fontSize: 12,\n fontWeight: 500,\n color: 'var(--dsw-alias-label-secondary)',\n margin: 0,\n}\n\nconst POWERED: CSSProperties = {\n fontSize: 11,\n color: 'var(--dsw-alias-label-tertiary)',\n margin: 0,\n}\n\n/** Same-origin route mounted by the node half (see `src/index.ts`). */\nconst ABOUT_ROUTE = '/api/v1/huaqiu/about'\n\nconst GITHUB_URL = 'https://github.com/deepseek-ai/deepseek-harness'\n\ninterface AboutPayload {\n version?: unknown\n dshVersion?: unknown\n}\n\nexport interface AboutSectionProps {\n /** Bound locale dictionary (injected by the client entry). */\n t: (key: string) => string\n}\n\nexport function AboutSection({ t }: AboutSectionProps): ReactElement {\n const [version, setVersion] = useState<string | null>(null)\n const [dshVersion, setDshVersion] = useState<string | null>(null)\n const [copied, setCopied] = useState(false)\n\n useEffect(() => {\n let alive = true\n void fetch(ABOUT_ROUTE)\n .then((res) => (res.ok ? res.json() as Promise<AboutPayload> : null))\n .then((body) => {\n if (!alive) return\n setVersion(body && typeof body.version === 'string' ? body.version : null)\n setDshVersion(\n body && typeof body.dshVersion === 'string' ? body.dshVersion : null,\n )\n })\n .catch(() => { if (alive) { setVersion(null); setDshVersion(null) } })\n return () => { alive = false }\n }, [])\n\n useEffect(() => {\n if (!copied) return\n const timer = window.setTimeout(() => setCopied(false), 2000)\n return () => window.clearTimeout(timer)\n }, [copied])\n\n const copyMeta = (): void => {\n const runtime = version ?? '-'\n const dist = dshVersion ?? '-'\n const text = [\n `App: ${t('slogan')}`,\n `DSH Runtime: ${runtime}`,\n `Release: ${dist}`,\n `Copyright: ${t('copyright')}`,\n ].join('\\n')\n void navigator.clipboard.writeText(text).catch(() => {})\n setCopied(true)\n }\n\n return createElement(\n 'div',\n { style: ROOT },\n createElement(\n 'div',\n { style: TOP },\n createElement(HuaqiuBrandMark, { size: 64 }),\n createElement('div', { style: TITLE }, t('slogan')),\n createElement(\n 'div',\n { style: BADGE },\n createElement('span', null, t('runtimeLabel')),\n createElement('span', { style: BADGE_VALUE }, version ?? ''),\n ),\n ),\n createElement(\n 'div',\n { style: META_BOX },\n createElement(\n 'div',\n { style: ROW },\n createElement('span', { style: ROW_LABEL }, t('distributionLabel')),\n createElement('span', { style: VERSION_PILL }, dshVersion ?? ''),\n ),\n createElement(\n 'div',\n { style: ROW },\n createElement('span', { style: ROW_LABEL }, t('builtinPluginLabel')),\n createElement('span', { style: VERSION_PILL }, version ?? ''),\n ),\n createElement(\n 'div',\n { style: ROW_BOTTOM },\n createElement(\n 'button',\n { style: copied ? ACTION_COPIED : ACTION, onClick: copyMeta, type: 'button' },\n createElement('span', null, copied ? t('copied') : t('copyMetadata')),\n ),\n createElement(\n 'a',\n { style: LINK, href: GITHUB_URL, target: '_blank', rel: 'noreferrer' },\n createElement('span', null, 'deepseek-harness'),\n createElement('span', { style: { fontSize: 9, opacity: 0.7 } }, '↗'),\n ),\n ),\n ),\n createElement(\n 'div',\n { style: FOOTER },\n createElement('p', { style: COPYRIGHT }, t('copyright')),\n createElement('p', { style: POWERED }, t('poweredBy')),\n ),\n )\n}\n","/** About-section dictionaries. */\n\nexport const zh = {\n nav: '关于',\n slogan: '电子设计智能体平台',\n runtimeLabel: 'DSH 运行时',\n distributionLabel: '发行版本',\n builtinPluginLabel: '内置插件版本',\n copyMetadata: '复制元数据 (Metadata)',\n copied: '版本信息已复制',\n copyright: '© 2026 深圳华秋智联股份有限公司',\n poweredBy: '由 DSH 提供支持',\n} as const\n\nexport type AboutKey = keyof typeof zh\n\nexport const en: Record<AboutKey, string> = {\n nav: 'About',\n slogan: 'Electronic Design Agent Platform',\n runtimeLabel: 'DSH Runtime',\n distributionLabel: 'Distribution',\n builtinPluginLabel: 'Builtin plugin version',\n copyMetadata: 'Copy metadata',\n copied: 'Metadata copied',\n copyright: '© 2026 Shenzhen Huaqiu Zhilian Co., Ltd.',\n poweredBy: 'Powered by DSH',\n}\n","/**\n * `@huaqiu/dsh-huaqiu-about` — browser half.\n *\n * Contributes an \"About\" row to the DSH settings page through the\n * `settings.section` slot (the same mechanism the community `dsh-market`\n * plugin uses). The row shows the original DSH fish mark, the DSH version\n * bundled with the running harness (fetched from the node half's\n * same-origin route), and the \"Powered by DSH\" claim.\n */\nimport { createElement } from 'react'\nimport type {} from '@deepseek-ai/dsh-client-ui-slots'\nimport { AboutSection } from './AboutSection'\nimport { en, zh, type AboutKey } from './locales'\n\nexport const inject = ['slots', 'locale'] as const\n\nexport const ABOUT_NS = 'about.huaqiu'\n\ndeclare module '@deepseek-ai/dsh-client-ui-slots' {\n interface LocaleNamespaceMap {\n 'about.huaqiu': AboutKey\n }\n}\n\n/**\n * Minimal structural client context (the DSH client runtime provides these\n * faces). Declared structurally, never imported, so the package stays\n * independently installable — the same pattern as\n * `@huaqiu/dsh-tool-schematic-gen`.\n */\nexport interface ClientContext {\n slots?: {\n inject(key: string, callback: () => () => void): () => void\n register(spec: {\n name: string\n id?: string\n order?: number\n label?: () => string\n locale?: string\n }, component: unknown): () => void\n }\n locale?: {\n register(namespace: string, dictionaries: unknown): unknown\n bind(namespace: string): (key: string) => string\n }\n effect?(fn: () => (() => void) | void, label?: string): void\n}\n\n/**\n * Install the About row on the running client context.\n */\nexport function apply(ctx: ClientContext): void {\n ctx.effect?.(() => { ctx.locale?.register(ABOUT_NS, { zh, en }) }, 'huaqiu about: dictionaries')\n const t = ctx.locale?.bind(ABOUT_NS) ?? (() => 'About')\n const slots = ctx.slots\n if (!slots) return\n slots.inject('settings.section', () => slots.register({\n name: 'settings.section',\n id: 'huaqiu-about',\n order: 90,\n label: () => t('nav'),\n locale: ABOUT_NS,\n }, () => createElement(AboutSection, { t })))\n}\n"],"mappings":"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"}
|
package/lib/index.d.mts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Context } from "@deepseek-ai/cordis";
|
|
2
|
+
//#region src/index.d.ts
|
|
3
|
+
declare const inject: readonly ["webServer"];
|
|
4
|
+
declare const ABOUT_ROUTE_PREFIX = "/api/v1/huaqiu/about";
|
|
5
|
+
/** This plugin's declared version from `package.json`, or null when unreadable. */
|
|
6
|
+
declare function pluginVersion(): string | null;
|
|
7
|
+
/**
|
|
8
|
+
* Install the About version route on the running context.
|
|
9
|
+
*/
|
|
10
|
+
declare function apply(ctx: Context): void;
|
|
11
|
+
//#endregion
|
|
12
|
+
export { ABOUT_ROUTE_PREFIX, apply, inject, pluginVersion };
|
package/lib/index.mjs
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { dirname, join, resolve } from "node:path";
|
|
5
|
+
//#region src/dsh-version.ts
|
|
6
|
+
/**
|
|
7
|
+
* Resolve the DSH version bundled with the running harness.
|
|
8
|
+
*
|
|
9
|
+
* The community `dsh-market` plugin resolves the host version by walking up
|
|
10
|
+
* from the CLI entry for `node_modules/@deepseek-ai/dsh/package.json`. We do
|
|
11
|
+
* the same, plus:
|
|
12
|
+
* - a workspace checkout whose own `package.json` carries the
|
|
13
|
+
* `@deepseek-ai/dsh` name (local harness development);
|
|
14
|
+
* - a `require.resolve` probe;
|
|
15
|
+
* - environment fallbacks (`DSH_CLIENT_VERSION` / `DSH_VERSION`).
|
|
16
|
+
*/
|
|
17
|
+
const DSH_PACKAGE_REL = join("node_modules", "@deepseek-ai", "dsh", "package.json");
|
|
18
|
+
function readVersionAt(packageJsonPath) {
|
|
19
|
+
try {
|
|
20
|
+
const manifest = JSON.parse(readFileSync(packageJsonPath, "utf8"));
|
|
21
|
+
return typeof manifest.version === "string" && manifest.version.length > 0 ? manifest.version : null;
|
|
22
|
+
} catch {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/** Read `package.json` and return its version when it IS the DSH package. */
|
|
27
|
+
function readDshManifestVersionAt(packageJsonPath) {
|
|
28
|
+
try {
|
|
29
|
+
const manifest = JSON.parse(readFileSync(packageJsonPath, "utf8"));
|
|
30
|
+
if (manifest.name !== "@deepseek-ai/dsh") return null;
|
|
31
|
+
return typeof manifest.version === "string" && manifest.version.length > 0 ? manifest.version : null;
|
|
32
|
+
} catch {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Walk up from `start` (a directory) looking for the DSH package manifest —
|
|
38
|
+
* either an installed `node_modules/@deepseek-ai/dsh` or a workspace checkout
|
|
39
|
+
* whose own `package.json` carries the `@deepseek-ai/dsh` name. Returns the
|
|
40
|
+
* declared version, or null when no manifest is found.
|
|
41
|
+
*/
|
|
42
|
+
function findDshVersionFrom(start) {
|
|
43
|
+
let directory = start;
|
|
44
|
+
for (let depth = 0; depth < 12; depth += 1) {
|
|
45
|
+
const installed = readVersionAt(join(directory, DSH_PACKAGE_REL));
|
|
46
|
+
if (installed !== null) return installed;
|
|
47
|
+
const workspace = readDshManifestVersionAt(join(directory, "package.json"));
|
|
48
|
+
if (workspace !== null) return workspace;
|
|
49
|
+
const parent = dirname(directory);
|
|
50
|
+
if (parent === directory) break;
|
|
51
|
+
directory = parent;
|
|
52
|
+
}
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Resolve the DSH version for the current process: walk up from the CLI entry
|
|
57
|
+
* (`process.argv[1]`), then probe `require.resolve('@deepseek-ai/dsh/package.json')`,
|
|
58
|
+
* then environment fallbacks. Returns null when nothing is resolvable.
|
|
59
|
+
*/
|
|
60
|
+
function resolveDshVersion() {
|
|
61
|
+
const entry = typeof process.argv[1] === "string" ? process.argv[1] : null;
|
|
62
|
+
if (entry) {
|
|
63
|
+
const fromEntry = findDshVersionFrom(dirname(resolve(entry)));
|
|
64
|
+
if (fromEntry !== null) return fromEntry;
|
|
65
|
+
}
|
|
66
|
+
try {
|
|
67
|
+
const manifestPath = createRequire(import.meta.url).resolve("@deepseek-ai/dsh/package.json");
|
|
68
|
+
if (existsSync(manifestPath)) {
|
|
69
|
+
const version = readVersionAt(manifestPath);
|
|
70
|
+
if (version !== null) return version;
|
|
71
|
+
}
|
|
72
|
+
} catch {}
|
|
73
|
+
const fromEnv = process.env.DSH_CLIENT_VERSION ?? process.env.DSH_VERSION;
|
|
74
|
+
return fromEnv && fromEnv.length > 0 ? fromEnv : null;
|
|
75
|
+
}
|
|
76
|
+
//#endregion
|
|
77
|
+
//#region src/index.ts
|
|
78
|
+
const inject = ["webServer"];
|
|
79
|
+
const ABOUT_ROUTE_PREFIX = "/api/v1/huaqiu/about";
|
|
80
|
+
function sendJson(res, status, body) {
|
|
81
|
+
res.writeHead(status, { "content-type": "application/json; charset=utf-8" });
|
|
82
|
+
res.end(JSON.stringify(body));
|
|
83
|
+
}
|
|
84
|
+
/** This plugin's declared version from `package.json`, or null when unreadable. */
|
|
85
|
+
function pluginVersion() {
|
|
86
|
+
try {
|
|
87
|
+
const manifestUrl = new URL("../package.json", import.meta.url);
|
|
88
|
+
const manifest = JSON.parse(readFileSync(fileURLToPath(manifestUrl), "utf8"));
|
|
89
|
+
return typeof manifest.version === "string" && manifest.version.length > 0 ? manifest.version : null;
|
|
90
|
+
} catch {
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Install the About version route on the running context.
|
|
96
|
+
*/
|
|
97
|
+
function apply(ctx) {
|
|
98
|
+
ctx.effect(() => ctx.webServer.register({
|
|
99
|
+
kind: "prefix",
|
|
100
|
+
path: ABOUT_ROUTE_PREFIX,
|
|
101
|
+
handler: (_req, res) => {
|
|
102
|
+
sendJson(res, 200, {
|
|
103
|
+
version: pluginVersion(),
|
|
104
|
+
dshVersion: resolveDshVersion()
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
}), "huaqiu about: plugin + DSH version route");
|
|
108
|
+
}
|
|
109
|
+
//#endregion
|
|
110
|
+
export { ABOUT_ROUTE_PREFIX, apply, inject, pluginVersion };
|
package/package.json
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@huaqiu/dsh-huaqiu-about",
|
|
3
|
+
"version": "0.4.10",
|
|
4
|
+
"description": "HuaQiu About section in the DSH settings page: original DSH mark, bundled DSH version and the Powered-by-DSH claim.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./lib/index.mjs",
|
|
7
|
+
"types": "./lib/index.d.mts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./lib/index.d.mts",
|
|
11
|
+
"default": "./lib/index.mjs"
|
|
12
|
+
},
|
|
13
|
+
"./client": {
|
|
14
|
+
"default": "./lib/client.js"
|
|
15
|
+
},
|
|
16
|
+
"./cordis.patch.yml": "./cordis.patch.yml",
|
|
17
|
+
"./package.json": "./package.json"
|
|
18
|
+
},
|
|
19
|
+
"dsh": {
|
|
20
|
+
"bundle": {
|
|
21
|
+
"patch": "./cordis.patch.yml"
|
|
22
|
+
},
|
|
23
|
+
"client": {
|
|
24
|
+
"platform": "web",
|
|
25
|
+
"inject": [
|
|
26
|
+
"@deepseek-ai/dsh-client-locale",
|
|
27
|
+
"@deepseek-ai/dsh-client-ui-primitives",
|
|
28
|
+
"@deepseek-ai/dsh-client-ui-slots"
|
|
29
|
+
]
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"peerDependencies": {
|
|
33
|
+
"@deepseek-ai/cordis": "^4.0.2",
|
|
34
|
+
"@deepseek-ai/dsh-host-webserver": "^0.1.0-rc.0"
|
|
35
|
+
},
|
|
36
|
+
"files": [
|
|
37
|
+
"lib",
|
|
38
|
+
"src",
|
|
39
|
+
"cordis.patch.yml",
|
|
40
|
+
"README.md"
|
|
41
|
+
],
|
|
42
|
+
"publishConfig": {
|
|
43
|
+
"access": "public"
|
|
44
|
+
},
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"@deepseek-ai/cordis": "^4.0.2",
|
|
47
|
+
"@deepseek-ai/dsh-client-locale": "^0.1.5-rc.2",
|
|
48
|
+
"@deepseek-ai/dsh-client-ui-primitives": "^0.1.5-rc.2",
|
|
49
|
+
"@deepseek-ai/dsh-client-ui-settings": "^0.1.5-rc.2",
|
|
50
|
+
"@deepseek-ai/dsh-client-ui-slots": "^0.1.5-rc.2",
|
|
51
|
+
"@deepseek-ai/dsh-host-webserver": "^0.1.0-rc.0",
|
|
52
|
+
"@types/react": "~18.3.1",
|
|
53
|
+
"react": "^18.3.1",
|
|
54
|
+
"react-dom": "^18.3.1"
|
|
55
|
+
},
|
|
56
|
+
"scripts": {
|
|
57
|
+
"typecheck": "tsc --noEmit",
|
|
58
|
+
"build": "tsdown",
|
|
59
|
+
"test": "vitest run"
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* About row content, following the reference prototype:
|
|
3
|
+
*
|
|
4
|
+
* [HuaQiu brand mark]
|
|
5
|
+
* {slogan}
|
|
6
|
+
* [DSH 运行时 0.1.0] (runtime label + this plugin's version)
|
|
7
|
+
* ┌───────────────────────────┐
|
|
8
|
+
* │ 发行版本 0.1.5-rc.2 │ (Distribution label + bundled DSH version)
|
|
9
|
+
* │ 内置插件版本 0.1.0 │ (Builtin plugin version = plugin version)
|
|
10
|
+
* │ 复制元数据 deepseek-harness ↗ │
|
|
11
|
+
* └───────────────────────────┘
|
|
12
|
+
* © 2026 深圳华秋智联股份有限公司
|
|
13
|
+
* 由 DSH 提供支持
|
|
14
|
+
*
|
|
15
|
+
* The two versions are fetched from the node half's same-origin route
|
|
16
|
+
* (`GET /api/v1/huaqiu/about` → `{ version, dshVersion }`): the DSH Runtime
|
|
17
|
+
* badge and the Builtin plugin version row both show this plugin's declared
|
|
18
|
+
* version, the Distribution version is the DSH version bundled with the
|
|
19
|
+
* running harness. The block is vertically compact like the prototype — it
|
|
20
|
+
* centers as one dense unit instead of stretching across the panel. All text
|
|
21
|
+
* lines are localised.
|
|
22
|
+
*/
|
|
23
|
+
import { createElement, useEffect, useState, type CSSProperties, type ReactElement } from 'react'
|
|
24
|
+
import { HuaqiuBrandMark } from './HuaqiuBrand'
|
|
25
|
+
|
|
26
|
+
const ROOT: CSSProperties = {
|
|
27
|
+
display: 'flex',
|
|
28
|
+
flexDirection: 'column',
|
|
29
|
+
alignItems: 'center',
|
|
30
|
+
justifyContent: 'center',
|
|
31
|
+
height: '100%',
|
|
32
|
+
boxSizing: 'border-box',
|
|
33
|
+
gap: 14,
|
|
34
|
+
padding: '16px 24px',
|
|
35
|
+
textAlign: 'center',
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const TOP: CSSProperties = {
|
|
39
|
+
display: 'flex',
|
|
40
|
+
flexDirection: 'column',
|
|
41
|
+
alignItems: 'center',
|
|
42
|
+
gap: 8,
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const TITLE: CSSProperties = {
|
|
46
|
+
color: 'var(--dsw-alias-label-primary)',
|
|
47
|
+
fontSize: 20,
|
|
48
|
+
fontWeight: 700,
|
|
49
|
+
letterSpacing: '0.01em',
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const BADGE: CSSProperties = {
|
|
53
|
+
display: 'inline-flex',
|
|
54
|
+
alignItems: 'center',
|
|
55
|
+
gap: 6,
|
|
56
|
+
padding: '2px 12px',
|
|
57
|
+
borderRadius: 999,
|
|
58
|
+
fontSize: 12,
|
|
59
|
+
fontFamily: 'ui-monospace, SFMono-Regular, Menlo, monospace',
|
|
60
|
+
color: 'var(--dsw-alias-label-secondary)',
|
|
61
|
+
background: 'color-mix(in srgb, var(--dsw-alias-label-primary) 5%, transparent)',
|
|
62
|
+
border: '1px solid color-mix(in srgb, var(--dsw-alias-label-primary) 14%, transparent)',
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const BADGE_VALUE: CSSProperties = {
|
|
66
|
+
color: 'var(--dsw-alias-label-primary)',
|
|
67
|
+
fontWeight: 600,
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const META_BOX: CSSProperties = {
|
|
71
|
+
width: '100%',
|
|
72
|
+
maxWidth: 360,
|
|
73
|
+
display: 'flex',
|
|
74
|
+
flexDirection: 'column',
|
|
75
|
+
gap: 8,
|
|
76
|
+
padding: '12px 14px',
|
|
77
|
+
borderRadius: 12,
|
|
78
|
+
fontSize: 12,
|
|
79
|
+
textAlign: 'left',
|
|
80
|
+
color: 'var(--dsw-alias-label-primary)',
|
|
81
|
+
background: 'color-mix(in srgb, var(--dsw-alias-label-primary) 3%, transparent)',
|
|
82
|
+
border: '1px solid color-mix(in srgb, var(--dsw-alias-label-primary) 10%, transparent)',
|
|
83
|
+
boxSizing: 'border-box',
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const ROW: CSSProperties = {
|
|
87
|
+
display: 'flex',
|
|
88
|
+
alignItems: 'center',
|
|
89
|
+
justifyContent: 'space-between',
|
|
90
|
+
gap: 12,
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const ROW_LABEL: CSSProperties = {
|
|
94
|
+
color: 'var(--dsw-alias-label-tertiary)',
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const VERSION_PILL: CSSProperties = {
|
|
98
|
+
color: 'var(--dsw-alias-label-primary)',
|
|
99
|
+
fontWeight: 500,
|
|
100
|
+
fontFamily: 'ui-monospace, SFMono-Regular, Menlo, monospace',
|
|
101
|
+
fontSize: 11,
|
|
102
|
+
padding: '1px 8px',
|
|
103
|
+
borderRadius: 6,
|
|
104
|
+
background: 'color-mix(in srgb, var(--dsw-alias-label-primary) 6%, transparent)',
|
|
105
|
+
border: '1px solid color-mix(in srgb, var(--dsw-alias-label-primary) 14%, transparent)',
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const ROW_BOTTOM: CSSProperties = {
|
|
109
|
+
display: 'flex',
|
|
110
|
+
alignItems: 'center',
|
|
111
|
+
justifyContent: 'space-between',
|
|
112
|
+
gap: 12,
|
|
113
|
+
paddingTop: 8,
|
|
114
|
+
borderTop: '1px solid color-mix(in srgb, var(--dsw-alias-label-primary) 12%, transparent)',
|
|
115
|
+
fontSize: 11,
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const ACTION: CSSProperties = {
|
|
119
|
+
display: 'inline-flex',
|
|
120
|
+
alignItems: 'center',
|
|
121
|
+
gap: 6,
|
|
122
|
+
border: 'none',
|
|
123
|
+
background: 'none',
|
|
124
|
+
padding: 0,
|
|
125
|
+
cursor: 'pointer',
|
|
126
|
+
font: 'inherit',
|
|
127
|
+
color: 'var(--dsw-alias-label-tertiary)',
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const ACTION_COPIED: CSSProperties = {
|
|
131
|
+
...ACTION,
|
|
132
|
+
color: 'var(--dsw-alias-state-success, #34c759)',
|
|
133
|
+
fontWeight: 500,
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const LINK: CSSProperties = {
|
|
137
|
+
display: 'inline-flex',
|
|
138
|
+
alignItems: 'center',
|
|
139
|
+
gap: 6,
|
|
140
|
+
textDecoration: 'none',
|
|
141
|
+
color: 'var(--dsw-alias-label-tertiary)',
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const FOOTER: CSSProperties = {
|
|
145
|
+
display: 'flex',
|
|
146
|
+
flexDirection: 'column',
|
|
147
|
+
gap: 2,
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const COPYRIGHT: CSSProperties = {
|
|
151
|
+
fontSize: 12,
|
|
152
|
+
fontWeight: 500,
|
|
153
|
+
color: 'var(--dsw-alias-label-secondary)',
|
|
154
|
+
margin: 0,
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const POWERED: CSSProperties = {
|
|
158
|
+
fontSize: 11,
|
|
159
|
+
color: 'var(--dsw-alias-label-tertiary)',
|
|
160
|
+
margin: 0,
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/** Same-origin route mounted by the node half (see `src/index.ts`). */
|
|
164
|
+
const ABOUT_ROUTE = '/api/v1/huaqiu/about'
|
|
165
|
+
|
|
166
|
+
const GITHUB_URL = 'https://github.com/deepseek-ai/deepseek-harness'
|
|
167
|
+
|
|
168
|
+
interface AboutPayload {
|
|
169
|
+
version?: unknown
|
|
170
|
+
dshVersion?: unknown
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export interface AboutSectionProps {
|
|
174
|
+
/** Bound locale dictionary (injected by the client entry). */
|
|
175
|
+
t: (key: string) => string
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export function AboutSection({ t }: AboutSectionProps): ReactElement {
|
|
179
|
+
const [version, setVersion] = useState<string | null>(null)
|
|
180
|
+
const [dshVersion, setDshVersion] = useState<string | null>(null)
|
|
181
|
+
const [copied, setCopied] = useState(false)
|
|
182
|
+
|
|
183
|
+
useEffect(() => {
|
|
184
|
+
let alive = true
|
|
185
|
+
void fetch(ABOUT_ROUTE)
|
|
186
|
+
.then((res) => (res.ok ? res.json() as Promise<AboutPayload> : null))
|
|
187
|
+
.then((body) => {
|
|
188
|
+
if (!alive) return
|
|
189
|
+
setVersion(body && typeof body.version === 'string' ? body.version : null)
|
|
190
|
+
setDshVersion(
|
|
191
|
+
body && typeof body.dshVersion === 'string' ? body.dshVersion : null,
|
|
192
|
+
)
|
|
193
|
+
})
|
|
194
|
+
.catch(() => { if (alive) { setVersion(null); setDshVersion(null) } })
|
|
195
|
+
return () => { alive = false }
|
|
196
|
+
}, [])
|
|
197
|
+
|
|
198
|
+
useEffect(() => {
|
|
199
|
+
if (!copied) return
|
|
200
|
+
const timer = window.setTimeout(() => setCopied(false), 2000)
|
|
201
|
+
return () => window.clearTimeout(timer)
|
|
202
|
+
}, [copied])
|
|
203
|
+
|
|
204
|
+
const copyMeta = (): void => {
|
|
205
|
+
const runtime = version ?? '-'
|
|
206
|
+
const dist = dshVersion ?? '-'
|
|
207
|
+
const text = [
|
|
208
|
+
`App: ${t('slogan')}`,
|
|
209
|
+
`DSH Runtime: ${runtime}`,
|
|
210
|
+
`Release: ${dist}`,
|
|
211
|
+
`Copyright: ${t('copyright')}`,
|
|
212
|
+
].join('\n')
|
|
213
|
+
void navigator.clipboard.writeText(text).catch(() => {})
|
|
214
|
+
setCopied(true)
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
return createElement(
|
|
218
|
+
'div',
|
|
219
|
+
{ style: ROOT },
|
|
220
|
+
createElement(
|
|
221
|
+
'div',
|
|
222
|
+
{ style: TOP },
|
|
223
|
+
createElement(HuaqiuBrandMark, { size: 64 }),
|
|
224
|
+
createElement('div', { style: TITLE }, t('slogan')),
|
|
225
|
+
createElement(
|
|
226
|
+
'div',
|
|
227
|
+
{ style: BADGE },
|
|
228
|
+
createElement('span', null, t('runtimeLabel')),
|
|
229
|
+
createElement('span', { style: BADGE_VALUE }, version ?? ''),
|
|
230
|
+
),
|
|
231
|
+
),
|
|
232
|
+
createElement(
|
|
233
|
+
'div',
|
|
234
|
+
{ style: META_BOX },
|
|
235
|
+
createElement(
|
|
236
|
+
'div',
|
|
237
|
+
{ style: ROW },
|
|
238
|
+
createElement('span', { style: ROW_LABEL }, t('distributionLabel')),
|
|
239
|
+
createElement('span', { style: VERSION_PILL }, dshVersion ?? ''),
|
|
240
|
+
),
|
|
241
|
+
createElement(
|
|
242
|
+
'div',
|
|
243
|
+
{ style: ROW },
|
|
244
|
+
createElement('span', { style: ROW_LABEL }, t('builtinPluginLabel')),
|
|
245
|
+
createElement('span', { style: VERSION_PILL }, version ?? ''),
|
|
246
|
+
),
|
|
247
|
+
createElement(
|
|
248
|
+
'div',
|
|
249
|
+
{ style: ROW_BOTTOM },
|
|
250
|
+
createElement(
|
|
251
|
+
'button',
|
|
252
|
+
{ style: copied ? ACTION_COPIED : ACTION, onClick: copyMeta, type: 'button' },
|
|
253
|
+
createElement('span', null, copied ? t('copied') : t('copyMetadata')),
|
|
254
|
+
),
|
|
255
|
+
createElement(
|
|
256
|
+
'a',
|
|
257
|
+
{ style: LINK, href: GITHUB_URL, target: '_blank', rel: 'noreferrer' },
|
|
258
|
+
createElement('span', null, 'deepseek-harness'),
|
|
259
|
+
createElement('span', { style: { fontSize: 9, opacity: 0.7 } }, '↗'),
|
|
260
|
+
),
|
|
261
|
+
),
|
|
262
|
+
),
|
|
263
|
+
createElement(
|
|
264
|
+
'div',
|
|
265
|
+
{ style: FOOTER },
|
|
266
|
+
createElement('p', { style: COPYRIGHT }, t('copyright')),
|
|
267
|
+
createElement('p', { style: POWERED }, t('poweredBy')),
|
|
268
|
+
),
|
|
269
|
+
)
|
|
270
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HuaQiu brand mark — self-contained copy (SVG) so the About plugin does not
|
|
3
|
+
* depend on another plugin's client bundle at runtime.
|
|
4
|
+
*/
|
|
5
|
+
import { createElement } from 'react'
|
|
6
|
+
|
|
7
|
+
export function HuaqiuBrandMark({ size, className }: { size: number; className?: string }): React.ReactElement {
|
|
8
|
+
return createElement(
|
|
9
|
+
'svg',
|
|
10
|
+
{
|
|
11
|
+
'aria-hidden': true,
|
|
12
|
+
className,
|
|
13
|
+
height: size,
|
|
14
|
+
style: { display: 'block', flex: 'none' },
|
|
15
|
+
viewBox: '0 0 974.25 974.25',
|
|
16
|
+
width: size,
|
|
17
|
+
xmlns: 'http://www.w3.org/2000/svg',
|
|
18
|
+
},
|
|
19
|
+
createElement('path', {
|
|
20
|
+
d: 'M865.67,758.67a107,107,0,1,0,107,107A107,107,0,0,0,865.67,758.67Z',
|
|
21
|
+
fill: '#c7000b',
|
|
22
|
+
fillRule: 'evenodd',
|
|
23
|
+
}),
|
|
24
|
+
createElement('path', {
|
|
25
|
+
d: 'M744.11,0h-514C103.56,0,0,103.56,0,230.14v514C0,870.69,103.56,974.25,230.14,974.25h514c3.34,0,6.66-.06,10-.21a155.66,155.66,0,0,1-40-143.56H230.14a86.63,86.63,0,0,1-86.37-86.37v-514a86.63,86.63,0,0,1,86.37-86.37h514a86.61,86.61,0,0,1,86.37,86.37V714.06a156.93,156.93,0,0,1,35.19-4A155.1,155.1,0,0,1,974,754c.15-3.28.21-6.6.21-9.92v-514C974.25,103.56,870.69,0,744.11,0Z',
|
|
26
|
+
fill: '#c7000b',
|
|
27
|
+
fillRule: 'evenodd',
|
|
28
|
+
}),
|
|
29
|
+
createElement('polygon', {
|
|
30
|
+
points: '735.67 735.65 735.67 238.59 591.9 238.59 591.9 415.24 382.39 415.24 382.39 238.59 238.62 238.59 238.62 735.65 382.39 735.65 382.39 559.01 591.9 559.01 591.9 735.65 735.67 735.65',
|
|
31
|
+
fill: '#c7000b',
|
|
32
|
+
fillRule: 'evenodd',
|
|
33
|
+
}),
|
|
34
|
+
)
|
|
35
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@huaqiu/dsh-huaqiu-about` — browser half.
|
|
3
|
+
*
|
|
4
|
+
* Contributes an "About" row to the DSH settings page through the
|
|
5
|
+
* `settings.section` slot (the same mechanism the community `dsh-market`
|
|
6
|
+
* plugin uses). The row shows the original DSH fish mark, the DSH version
|
|
7
|
+
* bundled with the running harness (fetched from the node half's
|
|
8
|
+
* same-origin route), and the "Powered by DSH" claim.
|
|
9
|
+
*/
|
|
10
|
+
import { createElement } from 'react'
|
|
11
|
+
import type {} from '@deepseek-ai/dsh-client-ui-slots'
|
|
12
|
+
import { AboutSection } from './AboutSection'
|
|
13
|
+
import { en, zh, type AboutKey } from './locales'
|
|
14
|
+
|
|
15
|
+
export const inject = ['slots', 'locale'] as const
|
|
16
|
+
|
|
17
|
+
export const ABOUT_NS = 'about.huaqiu'
|
|
18
|
+
|
|
19
|
+
declare module '@deepseek-ai/dsh-client-ui-slots' {
|
|
20
|
+
interface LocaleNamespaceMap {
|
|
21
|
+
'about.huaqiu': AboutKey
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Minimal structural client context (the DSH client runtime provides these
|
|
27
|
+
* faces). Declared structurally, never imported, so the package stays
|
|
28
|
+
* independently installable — the same pattern as
|
|
29
|
+
* `@huaqiu/dsh-tool-schematic-gen`.
|
|
30
|
+
*/
|
|
31
|
+
export interface ClientContext {
|
|
32
|
+
slots?: {
|
|
33
|
+
inject(key: string, callback: () => () => void): () => void
|
|
34
|
+
register(spec: {
|
|
35
|
+
name: string
|
|
36
|
+
id?: string
|
|
37
|
+
order?: number
|
|
38
|
+
label?: () => string
|
|
39
|
+
locale?: string
|
|
40
|
+
}, component: unknown): () => void
|
|
41
|
+
}
|
|
42
|
+
locale?: {
|
|
43
|
+
register(namespace: string, dictionaries: unknown): unknown
|
|
44
|
+
bind(namespace: string): (key: string) => string
|
|
45
|
+
}
|
|
46
|
+
effect?(fn: () => (() => void) | void, label?: string): void
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Install the About row on the running client context.
|
|
51
|
+
*/
|
|
52
|
+
export function apply(ctx: ClientContext): void {
|
|
53
|
+
ctx.effect?.(() => { ctx.locale?.register(ABOUT_NS, { zh, en }) }, 'huaqiu about: dictionaries')
|
|
54
|
+
const t = ctx.locale?.bind(ABOUT_NS) ?? (() => 'About')
|
|
55
|
+
const slots = ctx.slots
|
|
56
|
+
if (!slots) return
|
|
57
|
+
slots.inject('settings.section', () => slots.register({
|
|
58
|
+
name: 'settings.section',
|
|
59
|
+
id: 'huaqiu-about',
|
|
60
|
+
order: 90,
|
|
61
|
+
label: () => t('nav'),
|
|
62
|
+
locale: ABOUT_NS,
|
|
63
|
+
}, () => createElement(AboutSection, { t })))
|
|
64
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/** About-section dictionaries. */
|
|
2
|
+
|
|
3
|
+
export const zh = {
|
|
4
|
+
nav: '关于',
|
|
5
|
+
slogan: '电子设计智能体平台',
|
|
6
|
+
runtimeLabel: 'DSH 运行时',
|
|
7
|
+
distributionLabel: '发行版本',
|
|
8
|
+
builtinPluginLabel: '内置插件版本',
|
|
9
|
+
copyMetadata: '复制元数据 (Metadata)',
|
|
10
|
+
copied: '版本信息已复制',
|
|
11
|
+
copyright: '© 2026 深圳华秋智联股份有限公司',
|
|
12
|
+
poweredBy: '由 DSH 提供支持',
|
|
13
|
+
} as const
|
|
14
|
+
|
|
15
|
+
export type AboutKey = keyof typeof zh
|
|
16
|
+
|
|
17
|
+
export const en: Record<AboutKey, string> = {
|
|
18
|
+
nav: 'About',
|
|
19
|
+
slogan: 'Electronic Design Agent Platform',
|
|
20
|
+
runtimeLabel: 'DSH Runtime',
|
|
21
|
+
distributionLabel: 'Distribution',
|
|
22
|
+
builtinPluginLabel: 'Builtin plugin version',
|
|
23
|
+
copyMetadata: 'Copy metadata',
|
|
24
|
+
copied: 'Metadata copied',
|
|
25
|
+
copyright: '© 2026 Shenzhen Huaqiu Zhilian Co., Ltd.',
|
|
26
|
+
poweredBy: 'Powered by DSH',
|
|
27
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve the DSH version bundled with the running harness.
|
|
3
|
+
*
|
|
4
|
+
* The community `dsh-market` plugin resolves the host version by walking up
|
|
5
|
+
* from the CLI entry for `node_modules/@deepseek-ai/dsh/package.json`. We do
|
|
6
|
+
* the same, plus:
|
|
7
|
+
* - a workspace checkout whose own `package.json` carries the
|
|
8
|
+
* `@deepseek-ai/dsh` name (local harness development);
|
|
9
|
+
* - a `require.resolve` probe;
|
|
10
|
+
* - environment fallbacks (`DSH_CLIENT_VERSION` / `DSH_VERSION`).
|
|
11
|
+
*/
|
|
12
|
+
import { existsSync, readFileSync } from 'node:fs'
|
|
13
|
+
import { createRequire } from 'node:module'
|
|
14
|
+
import { dirname, join, resolve } from 'node:path'
|
|
15
|
+
|
|
16
|
+
const DSH_PACKAGE_REL = join('node_modules', '@deepseek-ai', 'dsh', 'package.json')
|
|
17
|
+
|
|
18
|
+
function readVersionAt(packageJsonPath: string): string | null {
|
|
19
|
+
try {
|
|
20
|
+
const manifest = JSON.parse(readFileSync(packageJsonPath, 'utf8')) as { version?: unknown }
|
|
21
|
+
return typeof manifest.version === 'string' && manifest.version.length > 0
|
|
22
|
+
? manifest.version
|
|
23
|
+
: null
|
|
24
|
+
} catch {
|
|
25
|
+
return null
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** Read `package.json` and return its version when it IS the DSH package. */
|
|
30
|
+
function readDshManifestVersionAt(packageJsonPath: string): string | null {
|
|
31
|
+
try {
|
|
32
|
+
const manifest = JSON.parse(readFileSync(packageJsonPath, 'utf8')) as {
|
|
33
|
+
name?: unknown
|
|
34
|
+
version?: unknown
|
|
35
|
+
}
|
|
36
|
+
if (manifest.name !== '@deepseek-ai/dsh') return null
|
|
37
|
+
return typeof manifest.version === 'string' && manifest.version.length > 0
|
|
38
|
+
? manifest.version
|
|
39
|
+
: null
|
|
40
|
+
} catch {
|
|
41
|
+
return null
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Walk up from `start` (a directory) looking for the DSH package manifest —
|
|
47
|
+
* either an installed `node_modules/@deepseek-ai/dsh` or a workspace checkout
|
|
48
|
+
* whose own `package.json` carries the `@deepseek-ai/dsh` name. Returns the
|
|
49
|
+
* declared version, or null when no manifest is found.
|
|
50
|
+
*/
|
|
51
|
+
export function findDshVersionFrom(start: string): string | null {
|
|
52
|
+
let directory = start
|
|
53
|
+
for (let depth = 0; depth < 12; depth += 1) {
|
|
54
|
+
const installed = readVersionAt(join(directory, DSH_PACKAGE_REL))
|
|
55
|
+
if (installed !== null) return installed
|
|
56
|
+
const workspace = readDshManifestVersionAt(join(directory, 'package.json'))
|
|
57
|
+
if (workspace !== null) return workspace
|
|
58
|
+
const parent = dirname(directory)
|
|
59
|
+
if (parent === directory) break
|
|
60
|
+
directory = parent
|
|
61
|
+
}
|
|
62
|
+
return null
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Resolve the DSH version for the current process: walk up from the CLI entry
|
|
67
|
+
* (`process.argv[1]`), then probe `require.resolve('@deepseek-ai/dsh/package.json')`,
|
|
68
|
+
* then environment fallbacks. Returns null when nothing is resolvable.
|
|
69
|
+
*/
|
|
70
|
+
export function resolveDshVersion(): string | null {
|
|
71
|
+
const entry = typeof process.argv[1] === 'string' ? process.argv[1] : null
|
|
72
|
+
if (entry) {
|
|
73
|
+
const fromEntry = findDshVersionFrom(dirname(resolve(entry)))
|
|
74
|
+
if (fromEntry !== null) return fromEntry
|
|
75
|
+
}
|
|
76
|
+
try {
|
|
77
|
+
const manifestPath = createRequire(import.meta.url).resolve(
|
|
78
|
+
'@deepseek-ai/dsh/package.json',
|
|
79
|
+
)
|
|
80
|
+
if (existsSync(manifestPath)) {
|
|
81
|
+
const version = readVersionAt(manifestPath)
|
|
82
|
+
if (version !== null) return version
|
|
83
|
+
}
|
|
84
|
+
} catch {
|
|
85
|
+
// fall through to environment fallbacks
|
|
86
|
+
}
|
|
87
|
+
const fromEnv = process.env.DSH_CLIENT_VERSION ?? process.env.DSH_VERSION
|
|
88
|
+
return fromEnv && fromEnv.length > 0 ? fromEnv : null
|
|
89
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Node-side Loader seat for the browser-only About plugin.
|
|
3
|
+
*
|
|
4
|
+
* Mounts a same-origin version route on `ctx.webServer` (the same channel
|
|
5
|
+
* `@huaqiu/dsh-auth` uses for its credential routes): `GET
|
|
6
|
+
* /api/v1/huaqiu/about` returns `{ version, dshVersion }` — this plugin's own
|
|
7
|
+
* declared version (read from the package manifest next to this entry) and the
|
|
8
|
+
* DSH version bundled with the running harness. The browser half fetches them
|
|
9
|
+
* when the About row renders.
|
|
10
|
+
*/
|
|
11
|
+
import type { Context } from '@deepseek-ai/cordis'
|
|
12
|
+
import type {} from '@deepseek-ai/dsh-host-webserver'
|
|
13
|
+
import { readFileSync } from 'node:fs'
|
|
14
|
+
import type { IncomingMessage, ServerResponse } from 'node:http'
|
|
15
|
+
import { fileURLToPath } from 'node:url'
|
|
16
|
+
import { resolveDshVersion } from './dsh-version'
|
|
17
|
+
|
|
18
|
+
export const inject = ['webServer'] as const
|
|
19
|
+
|
|
20
|
+
export const ABOUT_ROUTE_PREFIX = '/api/v1/huaqiu/about'
|
|
21
|
+
|
|
22
|
+
function sendJson(res: ServerResponse, status: number, body: unknown): void {
|
|
23
|
+
res.writeHead(status, { 'content-type': 'application/json; charset=utf-8' })
|
|
24
|
+
res.end(JSON.stringify(body))
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** This plugin's declared version from `package.json`, or null when unreadable. */
|
|
28
|
+
export function pluginVersion(): string | null {
|
|
29
|
+
try {
|
|
30
|
+
const manifestUrl = new URL('../package.json', import.meta.url)
|
|
31
|
+
const manifest = JSON.parse(readFileSync(fileURLToPath(manifestUrl), 'utf8')) as {
|
|
32
|
+
version?: unknown
|
|
33
|
+
}
|
|
34
|
+
return typeof manifest.version === 'string' && manifest.version.length > 0
|
|
35
|
+
? manifest.version
|
|
36
|
+
: null
|
|
37
|
+
} catch {
|
|
38
|
+
return null
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Install the About version route on the running context.
|
|
44
|
+
*/
|
|
45
|
+
export function apply(ctx: Context): void {
|
|
46
|
+
ctx.effect(() => ctx.webServer.register({
|
|
47
|
+
kind: 'prefix',
|
|
48
|
+
path: ABOUT_ROUTE_PREFIX,
|
|
49
|
+
handler: (_req: IncomingMessage, res: ServerResponse) => {
|
|
50
|
+
sendJson(res, 200, {
|
|
51
|
+
version: pluginVersion(),
|
|
52
|
+
dshVersion: resolveDshVersion(),
|
|
53
|
+
})
|
|
54
|
+
},
|
|
55
|
+
}), 'huaqiu about: plugin + DSH version route')
|
|
56
|
+
}
|