@aipanel/dsh-client 1.2.5 → 1.2.7

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.
Files changed (2) hide show
  1. package/lib/client.js +262 -3
  2. package/package.json +8 -4
package/lib/client.js CHANGED
@@ -26,10 +26,266 @@ var index_exports = {};
26
26
  __export(index_exports, {
27
27
  INSERT_ELEMENT_EVENT: () => INSERT_ELEMENT_EVENT,
28
28
  SESSION_READY_EVENT: () => SESSION_READY_EVENT,
29
- apply: () => apply
29
+ apply: () => apply,
30
+ inject: () => inject
30
31
  });
31
32
  module.exports = __toCommonJS(index_exports);
33
+
34
+ // dsh-client/src/client/diagnostics-view.tsx
35
+ var import_react = require("react");
36
+ var import_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
37
+ var import_jsx_runtime = require("react/jsx-runtime");
38
+ var DIAGNOSTICS_STORAGE_KEY = "dsh.bridge.diagnostics.enabled";
39
+ function readDiagnostics(block) {
40
+ if (typeof block !== "object" || block === null) return void 0;
41
+ const settled = block;
42
+ if (settled.kind !== "tool-result") return void 0;
43
+ const meta = settled.meta;
44
+ const diagnostics = meta?.diagnostics;
45
+ if (!Array.isArray(diagnostics)) return void 0;
46
+ return diagnostics.every(isEntry) ? diagnostics : void 0;
47
+ }
48
+ function extractBlockText(block) {
49
+ if (typeof block !== "object" || block === null) return "";
50
+ const settled = block;
51
+ if (!Array.isArray(settled.content)) return "";
52
+ return (settled.content ?? []).filter((b) => b.type === "text" && typeof b.text === "string").map((b) => b.text).join("\n");
53
+ }
54
+ function isEntry(d) {
55
+ const e = d;
56
+ return !!e && typeof e.file === "string" && typeof e.line === "number" && typeof e.column === "number" && (e.severity === "error" || e.severity === "warning") && typeof e.message === "string";
57
+ }
58
+ function relativize(path, cwd) {
59
+ if (!cwd) return path;
60
+ const root = cwd.replace(/[/\\]+$/, "");
61
+ if (path.startsWith(`${root}/`) || path.startsWith(`${root}\\`)) {
62
+ return path.slice(root.length + 1);
63
+ }
64
+ return path;
65
+ }
66
+ var styles = {
67
+ sep: {
68
+ background: "var(--dsw-alias-label-caption)",
69
+ borderRadius: 1,
70
+ flex: "none",
71
+ width: 2,
72
+ height: 2,
73
+ margin: "0 8px"
74
+ },
75
+ summary: {
76
+ textOverflow: "ellipsis",
77
+ whiteSpace: "nowrap",
78
+ minWidth: 0,
79
+ color: "var(--dsw-alias-label-tertiary)",
80
+ flex: "auto",
81
+ fontSize: 12,
82
+ lineHeight: 24,
83
+ overflow: "hidden"
84
+ },
85
+ diagnostic: {
86
+ display: "flex",
87
+ alignItems: "flex-start",
88
+ gap: 8,
89
+ padding: "5px 0 5px 4px"
90
+ },
91
+ card: {
92
+ display: "flex",
93
+ flexDirection: "column",
94
+ gap: 2,
95
+ margin: "4px 0 4px 4px",
96
+ padding: "8px 12px",
97
+ borderRadius: 12,
98
+ background: "var(--dsw-alias-markdown-code-block)"
99
+ },
100
+ cardHead: {
101
+ display: "flex",
102
+ alignItems: "center",
103
+ justifyContent: "space-between",
104
+ gap: 8,
105
+ paddingBottom: 6,
106
+ marginBottom: 4,
107
+ borderBottom: "1px solid var(--dsw-alias-border-l1)"
108
+ },
109
+ cardTitle: {
110
+ color: "var(--dsw-alias-label-primary)",
111
+ fontWeight: 600,
112
+ fontSize: 12,
113
+ lineHeight: 1.4
114
+ },
115
+ scopeBadge: {
116
+ color: "var(--dsw-alias-label-secondary)",
117
+ fontSize: 11,
118
+ lineHeight: 1,
119
+ padding: "3px 8px",
120
+ borderRadius: 999,
121
+ border: "1px solid var(--dsw-alias-border-l2)"
122
+ },
123
+ target: {
124
+ display: "block",
125
+ width: "100%",
126
+ textAlign: "left",
127
+ border: "none",
128
+ background: "none",
129
+ padding: "0 0 4px 0",
130
+ margin: "0 0 4px 0",
131
+ color: "var(--dsw-alias-label-secondary)",
132
+ fontSize: 12,
133
+ fontFamily: "var(--ds-font-family-code, ui-monospace, SFMono-Regular, Menlo, monospace)",
134
+ cursor: "pointer",
135
+ textDecoration: "underline"
136
+ },
137
+ targetText: {
138
+ display: "block",
139
+ padding: "0 0 4px 0",
140
+ margin: "0 0 4px 0",
141
+ color: "var(--dsw-alias-label-secondary)",
142
+ fontSize: 12,
143
+ fontFamily: "var(--ds-font-family-code, ui-monospace, SFMono-Regular, Menlo, monospace)"
144
+ },
145
+ marker: { flex: "0 0 auto", width: 14, textAlign: "center", fontSize: 12, lineHeight: 1.6 },
146
+ diagBody: {
147
+ flex: 1,
148
+ minWidth: 0,
149
+ display: "flex",
150
+ flexDirection: "column",
151
+ gap: 3
152
+ },
153
+ loc: {
154
+ color: "var(--dsw-alias-label-tertiary)",
155
+ fontSize: 12,
156
+ lineHeight: 1.4
157
+ },
158
+ msg: {
159
+ color: "var(--dsw-alias-label-primary)",
160
+ fontSize: 12,
161
+ lineHeight: 1.6,
162
+ whiteSpace: "pre-wrap",
163
+ wordBreak: "break-word"
164
+ },
165
+ successMsg: {
166
+ color: "var(--dsw-alias-state-success-primary)",
167
+ fontSize: 12,
168
+ lineHeight: 1.6
169
+ }
170
+ };
171
+ function DiagnosticsRow({ block, cwd, toolName, openFile }) {
172
+ const diagnostics = readDiagnostics(block);
173
+ const [expanded, setExpanded] = (0, import_react.useState)(false);
174
+ const isSettled = block?.kind === "tool-result";
175
+ const hasDiagnostics = typeof diagnostics !== "undefined" && diagnostics.length > 0;
176
+ const errors = (diagnostics ?? []).filter((d) => d.severity === "error");
177
+ const warnings = (diagnostics ?? []).filter((d) => d.severity === "warning");
178
+ const contentText = extractBlockText(block);
179
+ const firstLine = (contentText.split("\n")[0] || "").trim();
180
+ const isFullProject = /^全量诊断结果/.test(firstLine);
181
+ const scope = isFullProject ? "project" : "file";
182
+ const scopeLabel = isFullProject ? "\u5168\u91CF" : "\u5355\u6587\u4EF6";
183
+ const cardTitle = "\u8BCA\u65AD\u7ED3\u679C";
184
+ const titleFileMatch = /^诊断结果:\s*(.+)$/.exec(firstLine);
185
+ const targetFile = scope === "file" && diagnostics && diagnostics.length > 0 ? diagnostics[0].file : null;
186
+ const targetDisplay = scope === "file" ? targetFile ? relativize(targetFile, cwd) : titleFileMatch ? titleFileMatch[1].trim() : null : null;
187
+ const errColor = "var(--dsw-alias-state-error-primary)";
188
+ const warnColor = "var(--dsw-alias-state-warn-primary)";
189
+ const state = !isSettled ? "ongoing" : errors.length > 0 ? "error" : warnings.length > 0 ? "warning" : "done";
190
+ const expandable = isSettled;
191
+ let collapsed;
192
+ if (hasDiagnostics) {
193
+ collapsed = /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
194
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: styles.sep, "aria-hidden": true }),
195
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { style: styles.summary, children: [
196
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { color: "var(--dsw-alias-label-tertiary)" }, children: scopeLabel }),
197
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { "aria-hidden": true, children: " \xB7 " }),
198
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { style: { color: errColor }, children: [
199
+ errors.length,
200
+ " \u9519\u8BEF"
201
+ ] }),
202
+ " \xB7",
203
+ " ",
204
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { style: { color: warnColor }, children: [
205
+ warnings.length,
206
+ " \u8B66\u544A"
207
+ ] })
208
+ ] })
209
+ ] });
210
+ } else if (!isSettled) {
211
+ collapsed = /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
212
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: styles.sep, "aria-hidden": true }),
213
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: styles.summary, children: "\u8BCA\u65AD\u8FD0\u884C\u4E2D\u2026" })
214
+ ] });
215
+ } else if (diagnostics && diagnostics.length === 0) {
216
+ collapsed = /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
217
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: styles.sep, "aria-hidden": true }),
218
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { style: styles.summary, children: [
219
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { color: "var(--dsw-alias-label-tertiary)" }, children: scopeLabel }),
220
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { "aria-hidden": true, children: " \xB7 " }),
221
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { color: "var(--dsw-alias-state-success-primary)" }, children: "\u672A\u53D1\u73B0\u95EE\u9898" })
222
+ ] })
223
+ ] });
224
+ } else {
225
+ collapsed = /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
226
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: styles.sep, "aria-hidden": true }),
227
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: styles.summary, children: extractBlockText(block) || "\u65E0\u8F93\u51FA" })
228
+ ] });
229
+ }
230
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
231
+ import_dsh_client_ui_primitives.DisclosureRow,
232
+ {
233
+ icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.StateDot, { state }),
234
+ title: toolName,
235
+ open: expanded,
236
+ expandable,
237
+ expandOnRowClick: expandable,
238
+ keepContentWhenOpen: true,
239
+ onToggle: () => setExpanded((v) => !v),
240
+ collapsedContent: collapsed,
241
+ children: expandable && expanded ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.card, children: [
242
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.cardHead, children: [
243
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: styles.cardTitle, children: cardTitle }),
244
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: styles.scopeBadge, children: scopeLabel })
245
+ ] }),
246
+ scope === "file" && targetDisplay ? targetFile && typeof openFile === "function" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", style: styles.target, onClick: () => openFile(targetFile), children: targetDisplay }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: styles.targetText, children: targetDisplay }) : null,
247
+ hasDiagnostics ? diagnostics.map((d, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.diagnostic, children: [
248
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
249
+ "span",
250
+ {
251
+ style: {
252
+ ...styles.marker,
253
+ color: d.severity === "error" ? errColor : warnColor
254
+ },
255
+ children: d.severity === "error" ? "\u2716" : "\u26A0"
256
+ }
257
+ ),
258
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.diagBody, children: [
259
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { style: styles.loc, children: [
260
+ relativize(d.file, cwd),
261
+ ":",
262
+ d.line,
263
+ ":",
264
+ d.column
265
+ ] }),
266
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: styles.msg, children: d.message })
267
+ ] })
268
+ ] }, i)) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: styles.successMsg, children: "\u672A\u53D1\u73B0\u95EE\u9898" })
269
+ ] }) : null
270
+ }
271
+ );
272
+ }
273
+ function registerDiagnosticsView(ctx) {
274
+ try {
275
+ if (localStorage.getItem(DIAGNOSTICS_STORAGE_KEY) !== "1") return;
276
+ } catch {
277
+ return;
278
+ }
279
+ const slots = ctx.slots;
280
+ if (!slots) return;
281
+ slots.inject("tool.call.toolview", function* () {
282
+ yield slots.register({ name: "tool.call.toolview", key: "run_diagnostics" }, DiagnosticsRow);
283
+ });
284
+ }
285
+
286
+ // dsh-client/src/client/index.ts
32
287
  var SELECTION_STORAGE_KEY = "dsh.bridge.selection";
288
+ var inject = ["slots"];
33
289
  var SESSION_READY_EVENT = "aipanel:session-ready";
34
290
  var INSERT_ELEMENT_EVENT = "aipanel:insert-element";
35
291
  var SESSION_SETTLE_MS = 400;
@@ -86,6 +342,7 @@ function readSelectionCandidates() {
86
342
  }
87
343
  }
88
344
  function apply(ctx) {
345
+ registerDiagnosticsView(ctx);
89
346
  const inputTriggers = ctx.get("inputTriggers");
90
347
  if (!inputTriggers) return;
91
348
  const source = {
@@ -181,7 +438,8 @@ function apply(ctx) {
181
438
  const current = sessions?.list?.getSnapshot()?.current;
182
439
  if (!current) return;
183
440
  try {
184
- const actx = sessions.scope?.(current);
441
+ const actx = sessions?.scope?.(current);
442
+ if (!actx) return;
185
443
  const input = conversation?.input?.for?.(actx);
186
444
  if (!input || typeof input.insertReference !== "function") return;
187
445
  const snapshot = input.state?.getSnapshot?.();
@@ -203,9 +461,10 @@ function apply(ctx) {
203
461
  const insertedLen = reference.clipboardText.length + gap;
204
462
  let leadingSpace = 0;
205
463
  let rev = snapshot.draftRev;
464
+ const insertable = input;
206
465
  if (start > 0 && !/\s/.test(snapshot.draft[start - 1])) {
207
466
  try {
208
- if (input.insertText?.(" ", { start, end, draftRev: rev })) {
467
+ if (insertable.insertText?.(" ", { start, end, draftRev: rev })) {
209
468
  const next = input.state?.getSnapshot?.();
210
469
  if (next) {
211
470
  leadingSpace = 1;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aipanel/dsh-client",
3
- "version": "1.2.5",
3
+ "version": "1.2.7",
4
4
  "type": "module",
5
5
  "description": "AIPanel 浏览器侧插件(dsh web Web Client):注册 @aipanel 文件引用 source,选中元素以 file chip 高亮插入并可供模型解析。",
6
6
  "publishConfig": {
@@ -10,11 +10,13 @@
10
10
  "files": [
11
11
  "lib"
12
12
  ],
13
- "dependencies": {},
14
13
  "devDependencies": {
15
14
  "@deepseek-ai/cordis": "^4.0.1",
16
15
  "@deepseek-ai/dsh-client-ui-input-trigger": "^0.1.1-rc.2",
17
- "esbuild": "^0.25.0"
16
+ "@deepseek-ai/dsh-client-ui-primitives": "^0.0.1-rc.1",
17
+ "@types/react": "^18.3.0",
18
+ "esbuild": "^0.25.0",
19
+ "react": "^18.3.0"
18
20
  },
19
21
  "exports": {
20
22
  ".": "./lib/index.js",
@@ -24,7 +26,9 @@
24
26
  "dsh": {
25
27
  "client": {
26
28
  "platform": "web",
27
- "inject": []
29
+ "inject": [
30
+ "slots"
31
+ ]
28
32
  }
29
33
  },
30
34
  "scripts": {