dsh-plugin-sessiongraph-panel 0.0.0-stage → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/lib/client.js +326 -0
- package/lib/host.js +21 -0
- package/package.json +52 -3
- package/README.md +0 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 CC ZHAO
|
|
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/lib/client.js
ADDED
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dsh-plugin-sessiongraph-panel · 浏览器端入口:设置页「会话检索」tab
|
|
3
|
+
*
|
|
4
|
+
* 为什么单独一个文件:本包只有客户端半侧,宿主负责把客户端模块下发给浏览器;所以这里走
|
|
5
|
+
* CJS factory 包装,靠宿主注入的 require 取 react,不引任何 npm 包(没有构建步骤、也没有
|
|
6
|
+
* import 语句)。
|
|
7
|
+
*
|
|
8
|
+
* 这一个 tab 只做一件事:在 `sessiongraph` / `kernel` / `both` 之间切换「哪些会话检索工具
|
|
9
|
+
* 对模型可见」。数据全走同源 `/dsh-plugin-sessiongraph/api/tools`,无 token、无轮询——
|
|
10
|
+
* 值只有用户点「保存」时才会变。
|
|
11
|
+
*/
|
|
12
|
+
window.__ModuleLoader__.load({
|
|
13
|
+
id: "dsh-plugin-sessiongraph-panel",
|
|
14
|
+
factory: (require) => {
|
|
15
|
+
var module = { exports: {} };
|
|
16
|
+
var exports = module.exports;
|
|
17
|
+
|
|
18
|
+
const React = require("react");
|
|
19
|
+
/** 免 JSX 写组件(产物风格同官方插件) */
|
|
20
|
+
const h = React.createElement;
|
|
21
|
+
|
|
22
|
+
/** 宿主侧路由前缀;改这里要同步改 packages/tool/src/panel.ts */
|
|
23
|
+
const API = "/dsh-plugin-sessiongraph/api";
|
|
24
|
+
const MONO = "ui-monospace, SFMono-Regular, Menlo, monospace";
|
|
25
|
+
|
|
26
|
+
/** 宿主主题变量优先,取不到就退中性色 */
|
|
27
|
+
const C = {
|
|
28
|
+
primary: "var(--dsw-alias-label-primary, #1f2328)",
|
|
29
|
+
secondary: "var(--dsw-alias-label-secondary, #6e7781)",
|
|
30
|
+
tertiary: "var(--dsw-alias-label-tertiary, #8c959f)",
|
|
31
|
+
border: "var(--dsw-alias-border-l2, rgba(0, 0, 0, 0.12))",
|
|
32
|
+
bg: "var(--dsw-alias-bg-l1, rgba(0, 0, 0, 0.03))",
|
|
33
|
+
danger: "var(--dsw-alias-state-error-primary, #d9534f)",
|
|
34
|
+
ok: "var(--dsw-alias-state-success-primary, #2e7d32)",
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const BTN = {
|
|
38
|
+
font: "inherit",
|
|
39
|
+
fontSize: 12,
|
|
40
|
+
lineHeight: "20px",
|
|
41
|
+
padding: "2px 10px",
|
|
42
|
+
borderRadius: 4,
|
|
43
|
+
border: "1px solid " + C.border,
|
|
44
|
+
background: "transparent",
|
|
45
|
+
color: C.primary,
|
|
46
|
+
cursor: "pointer",
|
|
47
|
+
whiteSpace: "nowrap",
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const S = {
|
|
51
|
+
root: {
|
|
52
|
+
padding: "16px 20px",
|
|
53
|
+
fontSize: "var(--dsh-content-font-size, 13px)",
|
|
54
|
+
lineHeight: 1.5,
|
|
55
|
+
color: C.primary,
|
|
56
|
+
display: "flex",
|
|
57
|
+
flexDirection: "column",
|
|
58
|
+
gap: 14,
|
|
59
|
+
},
|
|
60
|
+
block: { display: "flex", flexDirection: "column", gap: 8, minWidth: 0 },
|
|
61
|
+
headRow: { display: "flex", alignItems: "center", gap: 12, flexWrap: "wrap" },
|
|
62
|
+
h1: { margin: 0, fontSize: 14, fontWeight: 600, lineHeight: 1.5, whiteSpace: "nowrap" },
|
|
63
|
+
hint: { color: C.tertiary, fontSize: 12 },
|
|
64
|
+
row: { display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap" },
|
|
65
|
+
label: { color: C.secondary, fontSize: 12, whiteSpace: "nowrap" },
|
|
66
|
+
select: {
|
|
67
|
+
boxSizing: "border-box",
|
|
68
|
+
minWidth: 220,
|
|
69
|
+
padding: "4px 8px",
|
|
70
|
+
border: "1px solid " + C.border,
|
|
71
|
+
borderRadius: 4,
|
|
72
|
+
background: C.bg,
|
|
73
|
+
color: C.primary,
|
|
74
|
+
font: "inherit",
|
|
75
|
+
fontSize: 12,
|
|
76
|
+
lineHeight: "20px",
|
|
77
|
+
outline: "none",
|
|
78
|
+
},
|
|
79
|
+
btn: BTN,
|
|
80
|
+
btnOff: { ...BTN, color: C.tertiary, cursor: "default" },
|
|
81
|
+
okText: { color: C.ok, fontSize: 12, whiteSpace: "pre-wrap" },
|
|
82
|
+
danger: { color: C.danger, fontSize: 12, whiteSpace: "pre-wrap" },
|
|
83
|
+
muted: { color: C.tertiary, fontSize: 12 },
|
|
84
|
+
mono: {
|
|
85
|
+
fontFamily: MONO,
|
|
86
|
+
fontSize: 12,
|
|
87
|
+
overflow: "hidden",
|
|
88
|
+
textOverflow: "ellipsis",
|
|
89
|
+
whiteSpace: "nowrap",
|
|
90
|
+
},
|
|
91
|
+
options: { display: "flex", flexDirection: "column", gap: 4, margin: 0, padding: 0 },
|
|
92
|
+
option: { color: C.secondary, fontSize: 12, lineHeight: 1.6 },
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* 三个选项的说明。值是契约的一部分(宿主侧的 ToolSet 联合类型),文案只是给人看的:
|
|
97
|
+
* 每个选项后面那句话回答的是「模型会因此少看到什么」,而不是复述名字。
|
|
98
|
+
*/
|
|
99
|
+
const OPTIONS = [
|
|
100
|
+
{
|
|
101
|
+
value: "sessiongraph",
|
|
102
|
+
label: "sessiongraph(推荐)",
|
|
103
|
+
note: "隐藏内核的 5 个会话工具,只留 sessiongraph:答案来自预建索引,更快也更完整。",
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
value: "kernel",
|
|
107
|
+
label: "kernel",
|
|
108
|
+
note: "隐藏本插件的 sessiongraph,只留宿主自带的 session_* 工具。",
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
value: "both",
|
|
112
|
+
label: "both",
|
|
113
|
+
note: "两套都暴露。模型可能同一件事查两遍,也更占上下文。",
|
|
114
|
+
},
|
|
115
|
+
];
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* 统一 fetch:把网络错误、非 2xx、以及 200 里 ok:false 都收敛成 { ok, message }。
|
|
119
|
+
* 组件层面只读 ok/message,任何异常都不会冒成渲染错误。
|
|
120
|
+
*/
|
|
121
|
+
async function call(url, init) {
|
|
122
|
+
try {
|
|
123
|
+
const res = await fetch(url, init);
|
|
124
|
+
let body = null;
|
|
125
|
+
try {
|
|
126
|
+
body = await res.json();
|
|
127
|
+
} catch (err) {
|
|
128
|
+
body = null; // 非 JSON 也不该吞掉状态码,下面按 HTTP 报
|
|
129
|
+
}
|
|
130
|
+
if (!res.ok || (body && body.ok === false)) {
|
|
131
|
+
return { ok: false, message: (body && body.message) || "HTTP " + res.status };
|
|
132
|
+
}
|
|
133
|
+
return { ok: true, data: body };
|
|
134
|
+
} catch (err) {
|
|
135
|
+
return { ok: false, message: "请求失败:" + (err && err.message ? err.message : err) };
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/** 宿主返回的 toolSet 只认这三个值;其它一律当作还没读到 */
|
|
140
|
+
function knownToolSet(value) {
|
|
141
|
+
return value === "sessiongraph" || value === "kernel" || value === "both" ? value : null;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/** 一行「检测到什么」的说明:没检测到比检测到更值得说,因为它意味着选了也不生效 */
|
|
145
|
+
function availabilityText(available) {
|
|
146
|
+
if (!available) return null;
|
|
147
|
+
const kernel = Array.isArray(available.kernel) ? available.kernel : [];
|
|
148
|
+
const parts = [];
|
|
149
|
+
parts.push("内核会话工具:" + (kernel.length > 0 ? kernel.join("、") : "未检测到"));
|
|
150
|
+
parts.push("sessiongraph:" + (available.sessiongraph === false ? "未检测到" : "已注册"));
|
|
151
|
+
return parts.join(" | ");
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function SessiongraphSection() {
|
|
155
|
+
const [toolSet, setToolSet] = React.useState(null);
|
|
156
|
+
const [draft, setDraft] = React.useState("sessiongraph");
|
|
157
|
+
const [available, setAvailable] = React.useState(null);
|
|
158
|
+
const [error, setError] = React.useState(null);
|
|
159
|
+
const [notice, setNotice] = React.useState(null);
|
|
160
|
+
/** null | "load" | "save":同时只跑一个请求 */
|
|
161
|
+
const [busy, setBusy] = React.useState(null);
|
|
162
|
+
/** 是否成功读过一次;用来区分「还没读」和「读到了但值是空的」 */
|
|
163
|
+
const [loaded, setLoaded] = React.useState(false);
|
|
164
|
+
|
|
165
|
+
// 打开就自动读一次当前值。设置页是用户主动打开的地方,一次同源 GET 的代价可以忽略。
|
|
166
|
+
React.useEffect(function () {
|
|
167
|
+
load();
|
|
168
|
+
// 只在挂载时跑:之后由「保存」按钮驱动
|
|
169
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
170
|
+
}, []);
|
|
171
|
+
|
|
172
|
+
/** 所有错误都走 state,不 throw —— 一个 tab 不该把设置页打白 */
|
|
173
|
+
async function load() {
|
|
174
|
+
setBusy("load");
|
|
175
|
+
const result = await call(API + "/tools");
|
|
176
|
+
setBusy(null);
|
|
177
|
+
if (!result.ok) {
|
|
178
|
+
setError(result.message);
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
const data = result.data || {};
|
|
182
|
+
setError(null);
|
|
183
|
+
setAvailable(data.available || null);
|
|
184
|
+
const current = knownToolSet(data.toolSet) || "sessiongraph";
|
|
185
|
+
setToolSet(current);
|
|
186
|
+
setDraft(current);
|
|
187
|
+
setLoaded(true);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
async function onSave() {
|
|
191
|
+
if (busy !== null) return;
|
|
192
|
+
setBusy("save");
|
|
193
|
+
setError(null);
|
|
194
|
+
setNotice(null);
|
|
195
|
+
const result = await call(API + "/tools", {
|
|
196
|
+
method: "POST",
|
|
197
|
+
headers: { "content-type": "application/json" },
|
|
198
|
+
body: JSON.stringify({ toolSet: draft }),
|
|
199
|
+
});
|
|
200
|
+
setBusy(null);
|
|
201
|
+
if (!result.ok) {
|
|
202
|
+
setError(result.message);
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
const data = result.data || {};
|
|
206
|
+
const saved = knownToolSet(data.toolSet) || draft;
|
|
207
|
+
setToolSet(saved);
|
|
208
|
+
setDraft(saved);
|
|
209
|
+
if (data.available) setAvailable(data.available);
|
|
210
|
+
setNotice("已保存:" + saved + "。新值对之后创建的会话立即生效,已在跑的会话在下一步重新读取工具表。");
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const dirty = loaded && toolSet !== null && draft !== toolSet;
|
|
214
|
+
|
|
215
|
+
const options = OPTIONS.map((option) =>
|
|
216
|
+
h("option", { key: option.value, value: option.value }, option.label),
|
|
217
|
+
);
|
|
218
|
+
|
|
219
|
+
const header = h(
|
|
220
|
+
"div",
|
|
221
|
+
{ style: S.block },
|
|
222
|
+
h(
|
|
223
|
+
"div",
|
|
224
|
+
{ style: S.headRow },
|
|
225
|
+
h("h2", { style: S.h1 }, "会话检索"),
|
|
226
|
+
h(
|
|
227
|
+
"div",
|
|
228
|
+
{ style: S.row },
|
|
229
|
+
h("span", { style: S.label }, "工具集"),
|
|
230
|
+
h(
|
|
231
|
+
"select",
|
|
232
|
+
{
|
|
233
|
+
style: S.select,
|
|
234
|
+
value: draft,
|
|
235
|
+
title: "决定哪些会话检索工具对模型可见",
|
|
236
|
+
disabled: busy === "save",
|
|
237
|
+
onChange: (event) => {
|
|
238
|
+
setDraft(event.target.value);
|
|
239
|
+
setNotice(null);
|
|
240
|
+
},
|
|
241
|
+
},
|
|
242
|
+
options,
|
|
243
|
+
),
|
|
244
|
+
h(
|
|
245
|
+
"button",
|
|
246
|
+
{
|
|
247
|
+
type: "button",
|
|
248
|
+
style: busy !== null ? S.btnOff : S.btn,
|
|
249
|
+
disabled: busy !== null,
|
|
250
|
+
title: "保存并立即应用",
|
|
251
|
+
onClick: onSave,
|
|
252
|
+
},
|
|
253
|
+
busy === "save" ? "保存中…" : "保存",
|
|
254
|
+
),
|
|
255
|
+
),
|
|
256
|
+
),
|
|
257
|
+
h(
|
|
258
|
+
"div",
|
|
259
|
+
{ style: S.hint },
|
|
260
|
+
"决定哪些会话检索工具对模型可见:切到 sessiongraph 会隐藏宿主的 session_search 系列,"
|
|
261
|
+
+ "切到 kernel 会隐藏本插件的 sessiongraph,both 两个都留。改动立刻生效,不需重启。",
|
|
262
|
+
),
|
|
263
|
+
);
|
|
264
|
+
|
|
265
|
+
const notes = h(
|
|
266
|
+
"div",
|
|
267
|
+
{ style: S.options },
|
|
268
|
+
OPTIONS.map((option) =>
|
|
269
|
+
h(
|
|
270
|
+
"div",
|
|
271
|
+
{ key: option.value, style: option.value === draft ? S.option : S.muted },
|
|
272
|
+
option.value + " — " + option.note,
|
|
273
|
+
),
|
|
274
|
+
),
|
|
275
|
+
);
|
|
276
|
+
|
|
277
|
+
const status = availabilityText(available);
|
|
278
|
+
|
|
279
|
+
return h(
|
|
280
|
+
"div",
|
|
281
|
+
{ style: S.root, "data-sessiongraph-panel": "" },
|
|
282
|
+
header,
|
|
283
|
+
notes,
|
|
284
|
+
status ? h("div", { style: S.mono }, status) : null,
|
|
285
|
+
error ? h("div", { style: S.danger, role: "alert" }, error) : null,
|
|
286
|
+
notice ? h("div", { style: S.okText, role: "status" }, notice) : null,
|
|
287
|
+
busy === "load" ? h("div", { style: S.muted }, "读取当前设置…") : null,
|
|
288
|
+
dirty ? h("div", { style: S.muted }, "有未保存的改动。") : null,
|
|
289
|
+
);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* 注册「会话检索」tab。
|
|
294
|
+
*
|
|
295
|
+
* 两处都单独 try/catch:注册抛错会让 DSH 把 web 判成 failed,
|
|
296
|
+
* 一个 tab 不该拖垮整个客户端。
|
|
297
|
+
*/
|
|
298
|
+
function apply(ctx) {
|
|
299
|
+
try {
|
|
300
|
+
ctx.slots.inject("settings.section", () => {
|
|
301
|
+
try {
|
|
302
|
+
return ctx.slots.register(
|
|
303
|
+
{
|
|
304
|
+
name: "settings.section",
|
|
305
|
+
id: "sessiongraph",
|
|
306
|
+
order: 31,
|
|
307
|
+
label: () => "会话检索",
|
|
308
|
+
},
|
|
309
|
+
SessiongraphSection,
|
|
310
|
+
);
|
|
311
|
+
} catch (err) {
|
|
312
|
+
console.warn("[sessiongraph] 注册 settings.section 失败:", err);
|
|
313
|
+
return null;
|
|
314
|
+
}
|
|
315
|
+
});
|
|
316
|
+
} catch (err) {
|
|
317
|
+
console.warn("[sessiongraph] 注入 settings.section 失败:", err);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
exports.name = "sessiongraph-panel-client";
|
|
322
|
+
exports.inject = ["slots"];
|
|
323
|
+
exports.apply = apply;
|
|
324
|
+
return module.exports;
|
|
325
|
+
},
|
|
326
|
+
});
|
package/lib/host.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dsh-plugin-sessiongraph-panel · 宿主端入口(空实现)
|
|
3
|
+
*
|
|
4
|
+
* 为什么需要它:cordis loader 按包的宿主入口加载一行插件,插件列表里那颗「运行中 / 未运行」
|
|
5
|
+
* 的指示灯就是这一步的结论。本包只有浏览器半边——`lib/client.js` 是给
|
|
6
|
+
* `window.__ModuleLoader__` 的 CJS factory,在 Node 里一 import 就碰 `window` 直接抛错——
|
|
7
|
+
* 所以宿主入口必须是一个能 import、什么都不做的空模块。没有它,整行就是「未运行」。
|
|
8
|
+
*
|
|
9
|
+
* 浏览器半边不靠这个入口:它由 package.json 的 `dsh.client` 声明发现,宿主把客户端模块
|
|
10
|
+
* 下发给浏览器,和这里无关。宿主侧真正提供数据的是 `packages/tool/src/panel.ts` 注册的
|
|
11
|
+
* `/dsh-plugin-sessiongraph/api/*` 路由。
|
|
12
|
+
* @module dsh-plugin-sessiongraph-panel/host
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Host plugin body — this package has no host-side behavior.
|
|
17
|
+
*/
|
|
18
|
+
export function apply() {
|
|
19
|
+
// Intentionally empty. The package exists for its browser half; this function only makes the
|
|
20
|
+
// package loadable so the loader can report it as running.
|
|
21
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,55 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-plugin-sessiongraph-panel",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Settings-page panel for dsh-plugin-sessiongraph: a 会话检索 tab that switches which session-reading tools the model can see (sessiongraph / kernel / both). Browser half only — every value comes from the host's /dsh-plugin-sessiongraph/api/* routes.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"dsh",
|
|
7
|
+
"dsh-plugin",
|
|
8
|
+
"deepseek-harness",
|
|
9
|
+
"cordis",
|
|
10
|
+
"sessiongraph",
|
|
11
|
+
"session-history",
|
|
12
|
+
"settings",
|
|
13
|
+
"panel",
|
|
14
|
+
"web-ui"
|
|
15
|
+
],
|
|
16
|
+
"license": "MIT",
|
|
17
|
+
"author": "CC ZHAO",
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "git+https://github.com/CC19990113/dsh-plugin-sessiongraph.git",
|
|
21
|
+
"directory": "packages/panel"
|
|
22
|
+
},
|
|
23
|
+
"homepage": "https://github.com/CC19990113/dsh-plugin-sessiongraph#readme",
|
|
24
|
+
"bugs": "https://github.com/CC19990113/dsh-plugin-sessiongraph/issues",
|
|
25
|
+
"type": "module",
|
|
26
|
+
"main": "lib/host.js",
|
|
27
|
+
"exports": {
|
|
28
|
+
".": {
|
|
29
|
+
"default": "./lib/host.js"
|
|
30
|
+
},
|
|
31
|
+
"./client": {
|
|
32
|
+
"default": "./lib/client.js"
|
|
33
|
+
},
|
|
34
|
+
"./package.json": "./package.json"
|
|
35
|
+
},
|
|
36
|
+
"files": [
|
|
37
|
+
"lib/**/*.js"
|
|
38
|
+
],
|
|
39
|
+
"peerDependencies": {
|
|
40
|
+
"react": ">=18"
|
|
41
|
+
},
|
|
42
|
+
"publishConfig": {
|
|
43
|
+
"access": "public",
|
|
44
|
+
"provenance": false
|
|
45
|
+
},
|
|
46
|
+
"dsh": {
|
|
47
|
+
"client": {
|
|
48
|
+
"immediately": true,
|
|
49
|
+
"inject": [
|
|
50
|
+
"@deepseek-ai/dsh-client-ui-settings"
|
|
51
|
+
],
|
|
52
|
+
"platform": "web"
|
|
53
|
+
}
|
|
54
|
+
}
|
|
6
55
|
}
|
package/README.md
DELETED