dsh-plugin-codegraph-panel 0.0.0-stage → 0.3.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/README.md +22 -2
- package/lib/client.js +404 -0
- package/package.json +45 -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/README.md
CHANGED
|
@@ -1,3 +1,23 @@
|
|
|
1
|
-
#
|
|
1
|
+
# dsh-plugin-codegraph-panel
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Browser half of **[dsh-plugin-codegraph](https://github.com/CC19990113/dsh-plugin-codegraph)** — the **Settings › 代码图谱** tab.
|
|
4
|
+
|
|
5
|
+
它只在 DSH 客户端里跑,零构建、零 npm 依赖(`react` 由宿主注入):`lib/client.js` 通过
|
|
6
|
+
`window.__ModuleLoader__.load({ id, factory })` 注册一个 `settings.section` 槽位(id `codegraph`、
|
|
7
|
+
order 30、label `代码图谱`),组件里只有一个工作区路径输入框和「刷新」「重建索引」两个按钮。
|
|
8
|
+
|
|
9
|
+
所有数字都来自宿主半侧的 HTTP 路由,本包自己不开服务、不读磁盘:
|
|
10
|
+
|
|
11
|
+
| 请求 | 作用 |
|
|
12
|
+
| --- | --- |
|
|
13
|
+
| `GET /dsh-plugin-codegraph/api/state?root=<abs path>` | 读 `<root>/.codegraph/status.json`,返回 `{ ok, status }` 或 `{ ok:false, message }` |
|
|
14
|
+
| `POST /dsh-plugin-codegraph/api/reindex`,body `{ "root": "<abs path>" }` | 重建该工作区的图,返回 `{ ok, message }` |
|
|
15
|
+
|
|
16
|
+
工作区路径记在 `localStorage['codegraph.panel.root']`,刷新页面还在;请求失败只在面板里显示一行
|
|
17
|
+
错误文本,不抛异常、不白屏。
|
|
18
|
+
|
|
19
|
+
安装方式与配置见[项目 README](https://github.com/CC19990113/dsh-plugin-codegraph#readme)。
|
|
20
|
+
|
|
21
|
+
## License
|
|
22
|
+
|
|
23
|
+
[MIT](LICENSE)
|
package/lib/client.js
ADDED
|
@@ -0,0 +1,404 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dsh-plugin-codegraph-panel · 浏览器端入口:设置页「代码图谱」tab
|
|
3
|
+
*
|
|
4
|
+
* 为什么单独一个文件:本包只有客户端半侧,宿主负责把客户端模块下发给浏览器;
|
|
5
|
+
* 所以这里走 CJS factory 包装,靠宿主注入的 require 取 react,不引任何 npm 包
|
|
6
|
+
* (没有构建步骤、也没有 import 语句)。
|
|
7
|
+
*
|
|
8
|
+
* 数据全走同源 /dsh-plugin-codegraph/api/*,无 token:面板只在用户点「刷新」或
|
|
9
|
+
* 「重建索引」时请求,不轮询 —— 索引结果的变化由用户主动触发,面板不做后台任务。
|
|
10
|
+
*/
|
|
11
|
+
window.__ModuleLoader__.load({
|
|
12
|
+
id: "dsh-plugin-codegraph-panel",
|
|
13
|
+
factory: (require) => {
|
|
14
|
+
var module = { exports: {} };
|
|
15
|
+
var exports = module.exports;
|
|
16
|
+
|
|
17
|
+
const React = require("react");
|
|
18
|
+
/** 免 JSX 写组件(产物风格同官方插件) */
|
|
19
|
+
const h = React.createElement;
|
|
20
|
+
|
|
21
|
+
/** 宿主侧路由前缀;改这里要同步改 packages/tool/src/panel.ts */
|
|
22
|
+
const API = "/dsh-plugin-codegraph/api";
|
|
23
|
+
/** 工作区路径的记忆键:刷新页面还在 */
|
|
24
|
+
const STORAGE_KEY = "codegraph.panel.root";
|
|
25
|
+
const MONO = "ui-monospace, SFMono-Regular, Menlo, monospace";
|
|
26
|
+
|
|
27
|
+
/** 宿主主题变量优先,取不到就退中性色 */
|
|
28
|
+
const C = {
|
|
29
|
+
primary: "var(--dsw-alias-label-primary, #1f2328)",
|
|
30
|
+
secondary: "var(--dsw-alias-label-secondary, #6e7781)",
|
|
31
|
+
tertiary: "var(--dsw-alias-label-tertiary, #8c959f)",
|
|
32
|
+
border: "var(--dsw-alias-border-l2, rgba(0, 0, 0, 0.12))",
|
|
33
|
+
bg: "var(--dsw-alias-bg-l1, rgba(0, 0, 0, 0.03))",
|
|
34
|
+
danger: "#d9534f",
|
|
35
|
+
ok: "#2e7d32",
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const BTN = {
|
|
39
|
+
font: "inherit",
|
|
40
|
+
fontSize: 12,
|
|
41
|
+
lineHeight: "20px",
|
|
42
|
+
padding: "2px 10px",
|
|
43
|
+
borderRadius: 4,
|
|
44
|
+
border: "1px solid " + C.border,
|
|
45
|
+
background: "transparent",
|
|
46
|
+
color: C.primary,
|
|
47
|
+
cursor: "pointer",
|
|
48
|
+
whiteSpace: "nowrap",
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const S = {
|
|
52
|
+
root: {
|
|
53
|
+
padding: "16px 20px",
|
|
54
|
+
fontSize: 13,
|
|
55
|
+
lineHeight: 1.5,
|
|
56
|
+
color: C.primary,
|
|
57
|
+
display: "flex",
|
|
58
|
+
flexDirection: "column",
|
|
59
|
+
gap: 14,
|
|
60
|
+
},
|
|
61
|
+
block: { display: "flex", flexDirection: "column", gap: 8, minWidth: 0 },
|
|
62
|
+
headRow: { display: "flex", alignItems: "center", gap: 12, flexWrap: "wrap" },
|
|
63
|
+
h1: { margin: 0, fontSize: 14, fontWeight: 600, lineHeight: 1.5, whiteSpace: "nowrap" },
|
|
64
|
+
h3: { margin: 0, fontSize: 13, fontWeight: 600, lineHeight: 1.5 },
|
|
65
|
+
hint: { color: C.tertiary, fontSize: 12 },
|
|
66
|
+
actions: { display: "flex", alignItems: "center", gap: 8, minWidth: 0, flex: 1 },
|
|
67
|
+
input: {
|
|
68
|
+
flex: 1,
|
|
69
|
+
minWidth: 220,
|
|
70
|
+
boxSizing: "border-box",
|
|
71
|
+
padding: "4px 8px",
|
|
72
|
+
border: "1px solid " + C.border,
|
|
73
|
+
borderRadius: 4,
|
|
74
|
+
background: C.bg,
|
|
75
|
+
color: C.primary,
|
|
76
|
+
fontFamily: MONO,
|
|
77
|
+
fontSize: 12,
|
|
78
|
+
lineHeight: "20px",
|
|
79
|
+
outline: "none",
|
|
80
|
+
},
|
|
81
|
+
btn: BTN,
|
|
82
|
+
btnOff: { ...BTN, color: C.tertiary, cursor: "default" },
|
|
83
|
+
btnStrong: { ...BTN, fontWeight: 600 },
|
|
84
|
+
meta: { display: "flex", flexWrap: "wrap", gap: "2px 18px", color: C.secondary, fontSize: 12 },
|
|
85
|
+
metaItem: { display: "inline-flex", gap: 6, alignItems: "baseline", minWidth: 0 },
|
|
86
|
+
metaLabel: { color: C.tertiary },
|
|
87
|
+
mono: {
|
|
88
|
+
fontFamily: MONO,
|
|
89
|
+
fontSize: 12,
|
|
90
|
+
overflow: "hidden",
|
|
91
|
+
textOverflow: "ellipsis",
|
|
92
|
+
whiteSpace: "nowrap",
|
|
93
|
+
},
|
|
94
|
+
danger: { color: C.danger, fontSize: 12, whiteSpace: "pre-wrap" },
|
|
95
|
+
okText: { color: C.ok, fontSize: 12, whiteSpace: "pre-wrap" },
|
|
96
|
+
muted: { color: C.tertiary, fontSize: 12 },
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
/** localStorage 可能被隐私模式/宿主策略禁掉,读写都吞掉异常,绝不拖垮 tab */
|
|
100
|
+
function readStoredRoot() {
|
|
101
|
+
try {
|
|
102
|
+
if (typeof localStorage === "undefined") return "";
|
|
103
|
+
const value = localStorage.getItem(STORAGE_KEY);
|
|
104
|
+
return typeof value === "string" ? value : "";
|
|
105
|
+
} catch (err) {
|
|
106
|
+
return "";
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function writeStoredRoot(value) {
|
|
111
|
+
try {
|
|
112
|
+
if (typeof localStorage === "undefined") return;
|
|
113
|
+
localStorage.setItem(STORAGE_KEY, value);
|
|
114
|
+
} catch (err) {
|
|
115
|
+
// 写不进去只意味着下次打开要重填,不影响本次操作
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/** 数字字段兜底,坏数据只显示 0 不崩 */
|
|
120
|
+
function num(value) {
|
|
121
|
+
const parsed = Number(value);
|
|
122
|
+
return Number.isFinite(parsed) ? parsed : 0;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/** epoch 毫秒 → 本地时间 2026-11-03 10:37;无效值显示 — */
|
|
126
|
+
function formatTime(value) {
|
|
127
|
+
const ms = Number(value);
|
|
128
|
+
if (!Number.isFinite(ms) || ms <= 0) return "—";
|
|
129
|
+
const date = new Date(ms);
|
|
130
|
+
const pad = (part) => (part < 10 ? "0" + part : String(part));
|
|
131
|
+
return (
|
|
132
|
+
date.getFullYear() +
|
|
133
|
+
"-" +
|
|
134
|
+
pad(date.getMonth() + 1) +
|
|
135
|
+
"-" +
|
|
136
|
+
pad(date.getDate()) +
|
|
137
|
+
" " +
|
|
138
|
+
pad(date.getHours()) +
|
|
139
|
+
":" +
|
|
140
|
+
pad(date.getMinutes())
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/** 状态查询 URL;root 必须编码,路径里的空格/中文不能破坏 query */
|
|
145
|
+
function stateUrl(root) {
|
|
146
|
+
return API + "/state?root=" + encodeURIComponent(root);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* 统一 fetch:把网络错误、非 2xx、以及 200 里 ok:false 都收敛成 { ok, message }。
|
|
151
|
+
* 组件层面只读 ok/message,任何异常都不会冒成渲染错误。
|
|
152
|
+
*/
|
|
153
|
+
async function call(url, init) {
|
|
154
|
+
try {
|
|
155
|
+
const res = await fetch(url, init);
|
|
156
|
+
let body = null;
|
|
157
|
+
try {
|
|
158
|
+
body = await res.json();
|
|
159
|
+
} catch (err) {
|
|
160
|
+
body = null; // 非 JSON 也不该吞掉状态码,下面按 HTTP 报
|
|
161
|
+
}
|
|
162
|
+
if (!res.ok || (body && body.ok === false)) {
|
|
163
|
+
return { ok: false, message: (body && body.message) || "HTTP " + res.status };
|
|
164
|
+
}
|
|
165
|
+
return { ok: true, data: body };
|
|
166
|
+
} catch (err) {
|
|
167
|
+
return { ok: false, message: "请求失败:" + (err && err.message ? err.message : err) };
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function metaItem(key, label, value) {
|
|
172
|
+
return h(
|
|
173
|
+
"span",
|
|
174
|
+
{ key: key, style: S.metaItem },
|
|
175
|
+
h("span", { style: S.metaLabel }, label),
|
|
176
|
+
h("span", { style: S.mono }, value),
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/** 索引状态:字段来自 <root>/.codegraph/status.json(IndexStatusFile) */
|
|
181
|
+
function renderStatus(status) {
|
|
182
|
+
const rows = [
|
|
183
|
+
h(
|
|
184
|
+
"div",
|
|
185
|
+
{ key: "meta", style: S.meta },
|
|
186
|
+
metaItem("files", "文件", String(num(status.filesIndexed))),
|
|
187
|
+
metaItem("nodes", "声明", String(num(status.nodeCount))),
|
|
188
|
+
metaItem("edges", "关系", String(num(status.edgeCount))),
|
|
189
|
+
metaItem("unresolved", "未解析", String(num(status.unresolvedCount))),
|
|
190
|
+
metaItem("internal", "疑似内部缺口", String(num(status.unresolvedLikelyInternalCount))),
|
|
191
|
+
metaItem("minified", "跳过生成文件", String(num(status.filesMinified))),
|
|
192
|
+
metaItem("time", "索引时间", formatTime(status.indexedAt)),
|
|
193
|
+
),
|
|
194
|
+
];
|
|
195
|
+
|
|
196
|
+
// 语言分布是可选字段:宿主没给就不摆一行空标签
|
|
197
|
+
const languages = Array.isArray(status.languages) ? status.languages : [];
|
|
198
|
+
if (languages.length > 0) {
|
|
199
|
+
rows.push(
|
|
200
|
+
h(
|
|
201
|
+
"div",
|
|
202
|
+
{ key: "languages", style: S.meta },
|
|
203
|
+
h("span", { style: S.metaLabel }, "语言分布"),
|
|
204
|
+
languages.slice(0, 12).map((row, index) =>
|
|
205
|
+
h(
|
|
206
|
+
"span",
|
|
207
|
+
{ key: "lang-" + index, style: S.metaItem },
|
|
208
|
+
h(
|
|
209
|
+
"span",
|
|
210
|
+
{ style: S.mono },
|
|
211
|
+
(row && row.language ? String(row.language) : "?") + " " + num(row && row.fileCount),
|
|
212
|
+
),
|
|
213
|
+
),
|
|
214
|
+
),
|
|
215
|
+
),
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
return h("div", { style: S.block }, h("h3", { style: S.h3 }, "索引状态"), rows);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function CodegraphSection() {
|
|
223
|
+
const [root, setRoot] = React.useState(readStoredRoot);
|
|
224
|
+
const [status, setStatus] = React.useState(null);
|
|
225
|
+
const [error, setError] = React.useState(null);
|
|
226
|
+
const [notice, setNotice] = React.useState(null);
|
|
227
|
+
/** null | "refresh" | "reindex":同时只跑一个操作 */
|
|
228
|
+
const [busy, setBusy] = React.useState(null);
|
|
229
|
+
/** 是否成功读过一次;用来区分「还没读」和「读到了但没 status」 */
|
|
230
|
+
const [loaded, setLoaded] = React.useState(false);
|
|
231
|
+
|
|
232
|
+
const trimmed = root.trim();
|
|
233
|
+
|
|
234
|
+
/** 所有错误都走 state,不 throw —— 一个 tab 不该把设置页打白 */
|
|
235
|
+
async function loadStatus() {
|
|
236
|
+
const result = await call(stateUrl(root.trim()));
|
|
237
|
+
if (!result.ok) {
|
|
238
|
+
setError(result.message);
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
setError(null);
|
|
242
|
+
setStatus(result.data && result.data.status ? result.data.status : null);
|
|
243
|
+
setLoaded(true);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
async function onRefresh() {
|
|
247
|
+
if (busy !== null) return;
|
|
248
|
+
if (trimmed === "") {
|
|
249
|
+
setError("填一个工作区路径");
|
|
250
|
+
setStatus(null);
|
|
251
|
+
setNotice(null);
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
setBusy("refresh");
|
|
255
|
+
setError(null);
|
|
256
|
+
setNotice(null);
|
|
257
|
+
await loadStatus();
|
|
258
|
+
setBusy(null);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
async function onReindex() {
|
|
262
|
+
if (busy !== null) return;
|
|
263
|
+
if (trimmed === "") {
|
|
264
|
+
setError("填一个工作区路径");
|
|
265
|
+
setStatus(null);
|
|
266
|
+
setNotice(null);
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
setBusy("reindex");
|
|
270
|
+
setError(null);
|
|
271
|
+
setNotice(null);
|
|
272
|
+
const result = await call(API + "/reindex", {
|
|
273
|
+
method: "POST",
|
|
274
|
+
headers: { "content-type": "application/json" },
|
|
275
|
+
body: JSON.stringify({ root: root.trim() }),
|
|
276
|
+
});
|
|
277
|
+
if (!result.ok) {
|
|
278
|
+
setError(result.message);
|
|
279
|
+
setBusy(null);
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
const data = result.data || {};
|
|
283
|
+
setNotice(typeof data.message === "string" && data.message ? data.message : "已重建索引");
|
|
284
|
+
// 重建后数字变了,顺手刷新一次;状态没读成只影响错误行,不影响已显示的 message
|
|
285
|
+
await loadStatus();
|
|
286
|
+
setBusy(null);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
const refreshButton = h(
|
|
290
|
+
"button",
|
|
291
|
+
{
|
|
292
|
+
type: "button",
|
|
293
|
+
style: busy !== null ? S.btnOff : S.btn,
|
|
294
|
+
disabled: busy !== null,
|
|
295
|
+
title: "重新读取这个工作区的索引状态",
|
|
296
|
+
onClick: onRefresh,
|
|
297
|
+
},
|
|
298
|
+
busy === "refresh" ? "刷新中…" : "刷新",
|
|
299
|
+
);
|
|
300
|
+
|
|
301
|
+
const reindexButton = h(
|
|
302
|
+
"button",
|
|
303
|
+
{
|
|
304
|
+
type: "button",
|
|
305
|
+
style: busy !== null ? S.btnOff : S.btnStrong,
|
|
306
|
+
disabled: busy !== null,
|
|
307
|
+
title: "重新索引这个工作区(会花一会儿)",
|
|
308
|
+
onClick: onReindex,
|
|
309
|
+
},
|
|
310
|
+
busy === "reindex" ? "重建中…" : "重建索引",
|
|
311
|
+
);
|
|
312
|
+
|
|
313
|
+
const header = h(
|
|
314
|
+
"div",
|
|
315
|
+
{ style: S.block },
|
|
316
|
+
h(
|
|
317
|
+
"div",
|
|
318
|
+
{ style: S.headRow },
|
|
319
|
+
h("h2", { style: S.h1 }, "代码图谱"),
|
|
320
|
+
h(
|
|
321
|
+
"div",
|
|
322
|
+
{ style: S.actions },
|
|
323
|
+
h("input", {
|
|
324
|
+
style: S.input,
|
|
325
|
+
type: "text",
|
|
326
|
+
value: root,
|
|
327
|
+
spellCheck: false,
|
|
328
|
+
placeholder: "工作区路径,例如 /Users/you/project",
|
|
329
|
+
title: "要查看索引状态的绝对路径",
|
|
330
|
+
onChange: (event) => {
|
|
331
|
+
const value = event.target.value;
|
|
332
|
+
setRoot(value);
|
|
333
|
+
writeStoredRoot(value);
|
|
334
|
+
},
|
|
335
|
+
onKeyDown: (event) => {
|
|
336
|
+
if (event.key === "Enter") {
|
|
337
|
+
event.preventDefault();
|
|
338
|
+
onRefresh();
|
|
339
|
+
}
|
|
340
|
+
},
|
|
341
|
+
}),
|
|
342
|
+
refreshButton,
|
|
343
|
+
reindexButton,
|
|
344
|
+
),
|
|
345
|
+
),
|
|
346
|
+
h(
|
|
347
|
+
"div",
|
|
348
|
+
{ style: S.hint },
|
|
349
|
+
"数据来自宿主 /dsh-plugin-codegraph/api/*;路径留空会提示先填路径。",
|
|
350
|
+
),
|
|
351
|
+
);
|
|
352
|
+
|
|
353
|
+
const statusBlock = status
|
|
354
|
+
? renderStatus(status)
|
|
355
|
+
: loaded
|
|
356
|
+
? h("div", { style: S.muted }, "宿主没有返回索引状态。")
|
|
357
|
+
: h("div", { style: S.muted }, "还没有读取状态。");
|
|
358
|
+
|
|
359
|
+
return h(
|
|
360
|
+
"div",
|
|
361
|
+
{ style: S.root, "data-codegraph-panel": "" },
|
|
362
|
+
header,
|
|
363
|
+
error ? h("div", { style: S.danger, role: "alert" }, error) : null,
|
|
364
|
+
notice ? h("div", { style: S.okText, role: "status" }, notice) : null,
|
|
365
|
+
busy !== null ? h("div", { style: S.muted }, busy === "refresh" ? "读取状态中…" : "重建索引中,稍等…") : null,
|
|
366
|
+
statusBlock,
|
|
367
|
+
);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* 注册「代码图谱」tab。
|
|
372
|
+
*
|
|
373
|
+
* 两处都单独 try/catch:注册抛错会让 DSH 把 web 判成 failed,
|
|
374
|
+
* 一个 tab 不该拖垮整个客户端。
|
|
375
|
+
*/
|
|
376
|
+
function apply(ctx) {
|
|
377
|
+
try {
|
|
378
|
+
ctx.slots.inject("settings.section", () => {
|
|
379
|
+
try {
|
|
380
|
+
return ctx.slots.register(
|
|
381
|
+
{
|
|
382
|
+
name: "settings.section",
|
|
383
|
+
id: "codegraph",
|
|
384
|
+
order: 30,
|
|
385
|
+
label: () => "代码图谱",
|
|
386
|
+
},
|
|
387
|
+
CodegraphSection,
|
|
388
|
+
);
|
|
389
|
+
} catch (err) {
|
|
390
|
+
console.warn("[codegraph] 注册 settings.section 失败:", err);
|
|
391
|
+
return null;
|
|
392
|
+
}
|
|
393
|
+
});
|
|
394
|
+
} catch (err) {
|
|
395
|
+
console.warn("[codegraph] 注入 settings.section 失败:", err);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
exports.name = "codegraph-panel-client";
|
|
400
|
+
exports.inject = ["slots"];
|
|
401
|
+
exports.apply = apply;
|
|
402
|
+
return module.exports;
|
|
403
|
+
},
|
|
404
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,48 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-plugin-codegraph-panel",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "Settings-page panel for dsh-plugin-codegraph: a 代码图谱 tab that shows one workspace's index status and can rebuild it. Browser half only — every number comes from the host's /dsh-plugin-codegraph/api/* routes.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"dsh",
|
|
7
|
+
"dsh-plugin",
|
|
8
|
+
"deepseek-harness",
|
|
9
|
+
"cordis",
|
|
10
|
+
"codegraph",
|
|
11
|
+
"code-graph",
|
|
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-codegraph.git",
|
|
21
|
+
"directory": "packages/panel"
|
|
22
|
+
},
|
|
23
|
+
"homepage": "https://github.com/CC19990113/dsh-plugin-codegraph#readme",
|
|
24
|
+
"bugs": "https://github.com/CC19990113/dsh-plugin-codegraph/issues",
|
|
25
|
+
"type": "module",
|
|
26
|
+
"main": "lib/client.js",
|
|
27
|
+
"exports": {
|
|
28
|
+
"./client": {
|
|
29
|
+
"default": "./lib/client.js"
|
|
30
|
+
},
|
|
31
|
+
"./package.json": "./package.json"
|
|
32
|
+
},
|
|
33
|
+
"files": [
|
|
34
|
+
"lib/**/*.js"
|
|
35
|
+
],
|
|
36
|
+
"peerDependencies": {
|
|
37
|
+
"react": ">=18"
|
|
38
|
+
},
|
|
39
|
+
"dsh": {
|
|
40
|
+
"client": {
|
|
41
|
+
"immediately": true,
|
|
42
|
+
"inject": [
|
|
43
|
+
"@deepseek-ai/dsh-client-ui-settings"
|
|
44
|
+
],
|
|
45
|
+
"platform": "web"
|
|
46
|
+
}
|
|
47
|
+
}
|
|
6
48
|
}
|