@aipanel/dsh-client 1.2.9 → 1.2.11

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 +76 -17
  2. package/package.json +2 -2
package/lib/client.js CHANGED
@@ -67,6 +67,20 @@ var WIDGET_MSG = {
67
67
  SESSION_READY: "AIPANEL_SESSION_READY"
68
68
  };
69
69
 
70
+ // ../../core/es/common/utils.mjs
71
+ function ensureNodeId(element) {
72
+ if (element.id) return element.id;
73
+ const random = typeof crypto !== "undefined" && typeof crypto.randomUUID === "function" ? crypto.randomUUID().replace(/-/g, "").slice(0, 8) : Math.random().toString(36).slice(2, 10);
74
+ element.id = `n${random}`;
75
+ return element.id;
76
+ }
77
+ function toNodeMention(id) {
78
+ return `@\u8282\u70B9[${id}]`;
79
+ }
80
+ function widgetEnvelope(type, data) {
81
+ return { type, ...data };
82
+ }
83
+
70
84
  // dsh-client/src/client/diagnostics-view.tsx
71
85
  var import_react = require("react");
72
86
  var import_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
@@ -74,12 +88,39 @@ var import_jsx_runtime = require("react/jsx-runtime");
74
88
  function isSettledToolResult(block) {
75
89
  return typeof block === "object" && block !== null && "kind" in block && block.kind === "tool-result";
76
90
  }
91
+ var TEXT_ESLINT_RE = /^[ \t]*(ERROR|WARN) \[([^\]\r\n]+?):(\d+):(\d+)\] (.*)$/gm;
92
+ var TEXT_TSC_RE = /^[ \t]*([^():\r\n]+)\((\d+),(\d+)\):\s*(error|warning)\s+(.*)$/gm;
93
+ function parseTextDiagnostics(text) {
94
+ const out = [];
95
+ if (!text) return out;
96
+ for (const m of text.matchAll(TEXT_ESLINT_RE)) {
97
+ out.push({
98
+ file: m[2],
99
+ line: Number(m[3]),
100
+ column: Number(m[4]),
101
+ severity: m[1].toLowerCase(),
102
+ message: m[5].trim()
103
+ });
104
+ }
105
+ for (const m of text.matchAll(TEXT_TSC_RE)) {
106
+ out.push({
107
+ file: m[1].trim(),
108
+ line: Number(m[2]),
109
+ column: Number(m[3]),
110
+ severity: m[4],
111
+ message: m[5].trim()
112
+ });
113
+ }
114
+ return out;
115
+ }
77
116
  function readDiagnostics(block) {
78
117
  if (!isSettledToolResult(block)) return void 0;
79
118
  const meta = block.meta;
80
- const diagnostics = meta?.diagnostics;
81
- if (!Array.isArray(diagnostics)) return void 0;
82
- return diagnostics.every(isEntry) ? diagnostics : void 0;
119
+ if (Array.isArray(meta?.diagnostics) && meta.diagnostics.every(isEntry)) {
120
+ return meta.diagnostics;
121
+ }
122
+ const parsed = parseTextDiagnostics(extractBlockText(block));
123
+ return parsed.length > 0 ? parsed : void 0;
83
124
  }
84
125
  function extractBlockText(block) {
85
126
  if (!isSettledToolResult(block)) return "";
@@ -214,6 +255,7 @@ function DiagnosticsRow({ block, cwd, toolName, openFile }) {
214
255
  const errors = (diagnostics ?? []).filter((d) => d.severity === "error");
215
256
  const warnings = (diagnostics ?? []).filter((d) => d.severity === "warning");
216
257
  const contentText = extractBlockText(block);
258
+ const textHasIssues = /^[ \t]*(?:ERROR|WARN)\s+\[/m.test(contentText);
217
259
  const firstLine = (contentText.split("\n")[0] || "").trim();
218
260
  const isFullProject = /^全量诊断结果/.test(firstLine);
219
261
  const scope = isFullProject ? "project" : "file";
@@ -250,7 +292,7 @@ function DiagnosticsRow({ block, cwd, toolName, openFile }) {
250
292
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: styles.sep, "aria-hidden": true }),
251
293
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: styles.summary, children: "\u8BCA\u65AD\u8FD0\u884C\u4E2D\u2026" })
252
294
  ] });
253
- } else if (diagnostics && diagnostics.length === 0) {
295
+ } else if (diagnostics && diagnostics.length === 0 && !textHasIssues) {
254
296
  collapsed = /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
255
297
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: styles.sep, "aria-hidden": true }),
256
298
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { style: styles.summary, children: [
@@ -322,12 +364,7 @@ var MSG = WIDGET_MSG;
322
364
  var inject = ["slots", "sessions", "inputTriggers", "conversation"];
323
365
  var SESSION_SETTLE_MS = 400;
324
366
  var FOCUS_OPEN_MAX_ATTEMPTS = 3;
325
- function ensureNodeId(e) {
326
- if (e.id) return e.id;
327
- const random = typeof crypto !== "undefined" && typeof crypto.randomUUID === "function" ? crypto.randomUUID().replace(/-/g, "").slice(0, 8) : Math.random().toString(36).slice(2, 10);
328
- e.id = `n${random}`;
329
- return e.id;
330
- }
367
+ var FOCUS_INFLIGHT_TIMEOUT_MS = 1e4;
331
368
  function elementContextRef(e) {
332
369
  return JSON.stringify(e);
333
370
  }
@@ -335,7 +372,7 @@ function serializeElement(ref) {
335
372
  try {
336
373
  const e = JSON.parse(ref);
337
374
  if (!e || typeof e !== "object") throw new Error("not an element payload");
338
- return `@\u8282\u70B9[${ensureNodeId(e)}]`;
375
+ return toNodeMention(ensureNodeId(e));
339
376
  } catch {
340
377
  return `@${ref}`;
341
378
  }
@@ -360,7 +397,7 @@ function isEmbedded() {
360
397
  function postToHost(type, data = {}) {
361
398
  if (!isEmbedded()) return;
362
399
  try {
363
- window.parent.postMessage({ type, ...data }, "*");
400
+ window.parent.postMessage(widgetEnvelope(type, data), "*");
364
401
  } catch {
365
402
  }
366
403
  }
@@ -376,6 +413,7 @@ function apply(ctx, config = {}) {
376
413
  let lastCurrent;
377
414
  let settleTimer = null;
378
415
  let targetSessionId;
416
+ let focusDeadline = 0;
379
417
  let pendingFocusId;
380
418
  let focusAttempts = 0;
381
419
  let refreshing = false;
@@ -395,6 +433,10 @@ function apply(ctx, config = {}) {
395
433
  if (!id) return;
396
434
  const snap = sessions.list.getSnapshot();
397
435
  if (!hasBaseline(snap)) return;
436
+ if (Date.now() >= focusDeadline) {
437
+ clearFocusTarget();
438
+ return;
439
+ }
398
440
  pendingFocusId = void 0;
399
441
  focusAttempts = 0;
400
442
  void tryOpenTarget(id);
@@ -403,7 +445,10 @@ function apply(ctx, config = {}) {
403
445
  if (focusAttempts >= FOCUS_OPEN_MAX_ATTEMPTS) return;
404
446
  focusAttempts += 1;
405
447
  const snap = sessions.list.getSnapshot();
406
- if (snap.current === id) return;
448
+ if (snap.current === id) {
449
+ clearFocusTarget();
450
+ return;
451
+ }
407
452
  if (!listContains(snap, id) && !refreshing) {
408
453
  refreshing = true;
409
454
  try {
@@ -423,8 +468,16 @@ function apply(ctx, config = {}) {
423
468
  } catch {
424
469
  }
425
470
  };
426
- const handleFocus = (sessionId) => {
471
+ const clearFocusTarget = () => {
472
+ targetSessionId = void 0;
473
+ focusDeadline = 0;
474
+ pendingFocusId = void 0;
475
+ };
476
+ const handleFocus = (sessionId, source2 = "host") => {
427
477
  targetSessionId = sessionId;
478
+ if (source2 === "host") {
479
+ focusDeadline = Date.now() + FOCUS_INFLIGHT_TIMEOUT_MS;
480
+ }
428
481
  const snap = sessions.list.getSnapshot();
429
482
  if (!hasBaseline(snap)) {
430
483
  pendingFocusId = sessionId;
@@ -451,8 +504,14 @@ function apply(ctx, config = {}) {
451
504
  settleTimer = null;
452
505
  if (sessions.list?.getSnapshot?.()?.current === current) {
453
506
  notifyReady(current);
454
- if (targetSessionId && targetSessionId !== current) {
455
- handleFocus(targetSessionId);
507
+ if (targetSessionId) {
508
+ if (current === targetSessionId) {
509
+ clearFocusTarget();
510
+ } else if (Date.now() < focusDeadline) {
511
+ handleFocus(targetSessionId, "refocus");
512
+ } else {
513
+ clearFocusTarget();
514
+ }
456
515
  }
457
516
  }
458
517
  }, SESSION_SETTLE_MS);
@@ -568,7 +627,7 @@ function apply(ctx, config = {}) {
568
627
  if (data.type === MSG.SET_THEME && typeof data.theme === "string") {
569
628
  applyThemeFromHost(data.theme);
570
629
  } else if (data.type === MSG.FOCUS_SESSION && typeof data.sessionId === "string") {
571
- handleFocus(data.sessionId);
630
+ handleFocus(data.sessionId, "host");
572
631
  } else if (data.type === MSG.INSERT_FILE_PART && data.element) {
573
632
  insertElement(data.element);
574
633
  } else if (data.type === MSG.SELECT_MODE_CHANGE) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aipanel/dsh-client",
3
- "version": "1.2.9",
3
+ "version": "1.2.11",
4
4
  "type": "module",
5
5
  "description": "AIPanel 浏览器侧插件(dsh web Web Client):注册 @aipanel 文件引用 source,选中元素以 file chip 高亮插入并可供模型解析。",
6
6
  "publishConfig": {
@@ -22,7 +22,7 @@
22
22
  "@types/react": "^18.3.0",
23
23
  "esbuild": "^0.25.0",
24
24
  "react": "^18.3.0",
25
- "@aipanel/core": "1.2.9"
25
+ "@aipanel/core": "1.2.11"
26
26
  },
27
27
  "exports": {
28
28
  ".": "./lib/index.js",