@aipanel/dsh-plugin 1.2.20 → 1.2.22

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/dist/index.js +241 -61
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -306,10 +306,10 @@ function isJsFile(filePath) {
306
306
  return JS_EXTENSIONS.has(path.extname(filePath));
307
307
  }
308
308
  var DIAGNOSTICS_TOOL_DESCRIPTION = [
309
- "\u8FD0\u884C ESLint \u4E0E TypeScript \u7C7B\u578B\u8BCA\u65AD\uFF0C\u8FD4\u56DE\u8BCA\u65AD\u7ED3\u679C\u3002",
309
+ "\u8FD0\u884C Lint\uFF08ESLint / oxlint\uFF09\u4E0E TypeScript \u7C7B\u578B\u8BCA\u65AD\uFF0C\u8FD4\u56DE\u8BCA\u65AD\u7ED3\u679C\u3002",
310
310
  "",
311
311
  "**\u652F\u6301\u7684\u6587\u4EF6\u7C7B\u578B**\uFF1A",
312
- `- ESLint\uFF1AJavaScript / TypeScript / Vue \u6E90\u7801\uFF08${[...JS_EXTENSIONS].map((e) => `*${e}`).join(" ")}\uFF09`,
312
+ `- Lint\uFF1AJavaScript / TypeScript / Vue \u6E90\u7801\uFF08${[...JS_EXTENSIONS].map((e) => `*${e}`).join(" ")}\uFF09\uFF1B\u4E24\u5F15\u64CE\u5747\u5B89\u88C5\u65F6\u5E76\u884C\u4E92\u8865\u8FD0\u884C\uFF08\u8BCA\u65AD\u6309\u6765\u6E90\u6807\u6CE8\uFF09`,
313
313
  "- TypeScript \u7C7B\u578B\u68C0\u67E5\uFF1A*.ts *.tsx *.vue",
314
314
  "",
315
315
  "**\u4F55\u65F6\u4F7F\u7528\u6B64\u5DE5\u5177**\uFF1A",
@@ -333,12 +333,68 @@ function loadESLint(workspace) {
333
333
  }
334
334
  async function lintFiles(pattern, cwd, warnLimit = 5) {
335
335
  loadESLint(cwd);
336
- if (!ESLintClass) {
336
+ const [eslintOutput, oxlintOutput] = await Promise.all([
337
+ ESLintClass ? runEslintFiles(pattern, cwd, warnLimit) : Promise.resolve(null),
338
+ runOxlintFiles(pattern, cwd, warnLimit)
339
+ ]);
340
+ const engines = [];
341
+ const texts = [];
342
+ const diagnostics = [];
343
+ for (const output of [eslintOutput, oxlintOutput]) {
344
+ if (!output) continue;
345
+ engines.push(...output.engines ?? []);
346
+ if (output.text) texts.push(output.text);
347
+ diagnostics.push(...output.diagnostics ?? []);
348
+ }
349
+ if (engines.length === 0) {
337
350
  return {
338
- text: `[ESLint] \u672A\u8FD0\u884C\uFF1A\u65E0\u6CD5\u5728 workspace "${cwd}" \u89E3\u6790\u5230 eslint\uFF08\u4EC5\u663E\u793A TypeScript \u8BCA\u65AD\uFF09`,
351
+ text: `[Lint] \u672A\u8FD0\u884C\uFF1A\u65E0\u6CD5\u5728 workspace "${cwd}" \u89E3\u6790\u5230 eslint \u6216 oxlint`,
339
352
  diagnostics: []
340
353
  };
341
354
  }
355
+ return { text: texts.join("\n\n") || void 0, diagnostics, engines };
356
+ }
357
+ function formatLintMessages(messages, engine, warnLimit) {
358
+ if (messages.length === 0) return { engines: [engine.label] };
359
+ const ESLINT_ERROR = 2;
360
+ const ESLINT_WARN = 1;
361
+ const lines = [];
362
+ const errors = messages.filter((m) => m.severity === ESLINT_ERROR);
363
+ const warnings = messages.filter((m) => m.severity === ESLINT_WARN);
364
+ if (errors.length > 0) {
365
+ lines.push(
366
+ ...errors.map(
367
+ (m) => `ERROR [${m.filePath}:${m.line}:${m.column}] ${m.message} (${m.ruleId})`
368
+ )
369
+ );
370
+ }
371
+ if (warnings.length > 0) {
372
+ lines.push(
373
+ ...warnings.slice(0, warnLimit).map((m) => `WARN [${m.filePath}:${m.line}:${m.column}] ${m.message} (${m.ruleId})`)
374
+ );
375
+ if (warnings.length > warnLimit)
376
+ lines.push(`... and ${warnings.length - warnLimit} more warnings`);
377
+ }
378
+ const diagnostics = messages.map((m) => ({
379
+ severity: m.severity === ESLINT_ERROR ? SEVERITY_ERROR : m.severity === ESLINT_WARN ? SEVERITY_WARN : m.severity,
380
+ file: m.filePath,
381
+ range: {
382
+ start: { line: (m.line || 1) - 1, character: (m.column || 1) - 1 },
383
+ end: {
384
+ line: (m.endLine || m.line || 1) - 1,
385
+ character: (m.endColumn || m.column || 1) - 1
386
+ }
387
+ },
388
+ message: `[${engine.label}] ${m.message} (${m.ruleId})`,
389
+ source: engine.source
390
+ }));
391
+ return {
392
+ text: lines.length > 0 ? lines.join("\n") : void 0,
393
+ diagnostics,
394
+ engines: [engine.label]
395
+ };
396
+ }
397
+ async function runEslintFiles(pattern, cwd, warnLimit) {
342
398
  try {
343
399
  const eslint = new ESLintClass({ cwd });
344
400
  const results = await eslint.lintFiles(pattern);
@@ -350,48 +406,111 @@ async function lintFiles(pattern, cwd, warnLimit = 5) {
350
406
  fileCount: results.length,
351
407
  messageCount: messages.length
352
408
  });
353
- if (messages.length === 0) return {};
354
- const ESLINT_ERROR = 2;
355
- const ESLINT_WARN = 1;
356
- const lines = [];
357
- const errors = messages.filter((m) => m.severity === ESLINT_ERROR);
358
- const warnings = messages.filter((m) => m.severity === ESLINT_WARN);
359
- if (errors.length > 0) {
360
- lines.push(
361
- ...errors.map(
362
- (m) => `ERROR [${m.filePath}:${m.line}:${m.column}] ${m.message} (${m.ruleId})`
363
- )
364
- );
365
- }
366
- if (warnings.length > 0) {
367
- lines.push(
368
- ...warnings.slice(0, warnLimit).map((m) => `WARN [${m.filePath}:${m.line}:${m.column}] ${m.message} (${m.ruleId})`)
369
- );
370
- if (warnings.length > warnLimit)
371
- lines.push(`... and ${warnings.length - warnLimit} more warnings`);
372
- }
373
- const diagnostics = messages.map((m) => ({
374
- severity: m.severity === ESLINT_ERROR ? SEVERITY_ERROR : m.severity === ESLINT_WARN ? SEVERITY_WARN : m.severity,
375
- file: m.filePath,
376
- range: {
377
- start: { line: (m.line || 1) - 1, character: (m.column || 1) - 1 },
378
- end: {
379
- line: (m.endLine || m.line || 1) - 1,
380
- character: (m.endColumn || m.column || 1) - 1
381
- }
382
- },
383
- message: `[ESLint] ${m.message} (${m.ruleId})`,
384
- source: "eslint"
385
- }));
386
- return { text: lines.length > 0 ? lines.join("\n") : void 0, diagnostics };
409
+ return formatLintMessages(messages, { label: "ESLint", source: "eslint" }, warnLimit);
387
410
  } catch (err) {
388
411
  log2.warn("ESLint failed", { pattern, error: err.message });
389
412
  return {
390
413
  text: `[ESLint] \u8FD0\u884C\u5931\u8D25\uFF1A${err.message}\uFF08\u4EC5\u663E\u793A TypeScript \u8BCA\u65AD\uFF09`,
391
- diagnostics: []
414
+ diagnostics: [],
415
+ engines: ["ESLint"]
392
416
  };
393
417
  }
394
418
  }
419
+ var _oxlintBin;
420
+ function resolveOxlintBin(workspace) {
421
+ if (_oxlintBin !== void 0) return _oxlintBin;
422
+ try {
423
+ const req = createRequire(path.join(workspace, "package.json"));
424
+ const pkgJsonPath = req.resolve("oxlint/package.json");
425
+ const pkg = JSON.parse(fs.readFileSync(pkgJsonPath, "utf8"));
426
+ const binRel = typeof pkg.bin === "string" ? pkg.bin : pkg.bin?.oxlint;
427
+ _oxlintBin = binRel ? path.join(path.dirname(pkgJsonPath), binRel) : null;
428
+ } catch {
429
+ _oxlintBin = null;
430
+ }
431
+ return _oxlintBin;
432
+ }
433
+ function oxlintRuleName(code) {
434
+ if (!code) return null;
435
+ const match = /\(([^)]*)\)$/.exec(code);
436
+ return match ? match[1] : code;
437
+ }
438
+ function parseOxlintOutput(stdout, cwd) {
439
+ let parsed;
440
+ try {
441
+ parsed = JSON.parse(stdout);
442
+ } catch {
443
+ const start = stdout.indexOf("{");
444
+ const end = stdout.lastIndexOf("}");
445
+ if (start >= 0 && end > start) {
446
+ try {
447
+ parsed = JSON.parse(stdout.slice(start, end + 1));
448
+ } catch {
449
+ parsed = void 0;
450
+ }
451
+ }
452
+ }
453
+ if (!parsed) throw new Error("\u65E0\u6CD5\u89E3\u6790 oxlint JSON \u8F93\u51FA");
454
+ return (parsed.diagnostics ?? []).flatMap((d) => {
455
+ const filePath = d.filename ? path.isAbsolute(d.filename) ? d.filename : path.resolve(cwd, d.filename) : "";
456
+ if (!filePath) return [];
457
+ const span = d.labels?.[0]?.span;
458
+ const line = span?.line ?? 1;
459
+ const column = span?.column ?? 1;
460
+ return [
461
+ {
462
+ // oxlint 无 endLine/endColumn,同行按 span.length 延伸近似
463
+ severity: d.severity === "error" ? 2 : 1,
464
+ line,
465
+ column,
466
+ endLine: line,
467
+ endColumn: column + (span?.length ?? 0),
468
+ message: d.message ?? "\u672A\u77E5\u8BCA\u65AD",
469
+ ruleId: oxlintRuleName(d.code),
470
+ filePath
471
+ }
472
+ ];
473
+ });
474
+ }
475
+ async function runOxlintFiles(pattern, cwd, warnLimit) {
476
+ const bin = resolveOxlintBin(cwd);
477
+ if (!bin) return {};
478
+ return new Promise((resolve) => {
479
+ exec(
480
+ // 与 ESLint 默认行为对齐:忽略 node_modules(oxlint 默认不排除)
481
+ `node "${bin}" --format=json --ignore-pattern node_modules "${pattern}"`,
482
+ { cwd, timeout: 6e4, maxBuffer: 50 * 1024 * 1024 },
483
+ (error, stdout, stderr) => {
484
+ const killed = error?.killed;
485
+ if (killed) {
486
+ log2.warn("oxlint timed out", { pattern });
487
+ resolve({
488
+ text: "[oxlint] \u8FD0\u884C\u5931\u8D25\uFF1A\u68C0\u67E5\u8D85\u65F6\uFF0C\u8BF7\u5C1D\u8BD5\u7F29\u5C0F\u68C0\u67E5\u8303\u56F4\u3002",
489
+ diagnostics: [],
490
+ engines: ["oxlint"]
491
+ });
492
+ return;
493
+ }
494
+ try {
495
+ const messages = parseOxlintOutput(stdout, cwd);
496
+ log2.debug("oxlint lint", {
497
+ pattern,
498
+ messageCount: messages.length,
499
+ stderr: stderr || void 0
500
+ });
501
+ resolve(formatLintMessages(messages, { label: "oxlint", source: "oxlint" }, warnLimit));
502
+ } catch (e) {
503
+ log2.warn("oxlint failed", { pattern, error: e.message });
504
+ resolve({
505
+ text: `[oxlint] \u8FD0\u884C\u5931\u8D25\uFF1A${e.message}`,
506
+ diagnostics: [],
507
+ engines: ["oxlint"]
508
+ });
509
+ }
510
+ }
511
+ );
512
+ });
513
+ }
395
514
  var _vueTscBin;
396
515
  function resolveVueTscBin() {
397
516
  if (_vueTscBin !== void 0) return _vueTscBin;
@@ -403,6 +522,46 @@ function resolveVueTscBin() {
403
522
  }
404
523
  return _vueTscBin;
405
524
  }
525
+ var _tscBinByPkgDir = /* @__PURE__ */ new Map();
526
+ function nearestPackageJsonDir(startDir) {
527
+ let dir = path.resolve(startDir);
528
+ while (true) {
529
+ if (fs.existsSync(path.join(dir, "package.json"))) return dir;
530
+ const parent = path.dirname(dir);
531
+ if (parent === dir) return null;
532
+ dir = parent;
533
+ }
534
+ }
535
+ function isVuePackage(pkgDir) {
536
+ try {
537
+ const pkg = JSON.parse(fs.readFileSync(path.join(pkgDir, "package.json"), "utf8"));
538
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies };
539
+ return "vue" in deps || "nuxt" in deps;
540
+ } catch {
541
+ return false;
542
+ }
543
+ }
544
+ function resolveTypeCheckBin(projectDir) {
545
+ const pkgDir = nearestPackageJsonDir(projectDir);
546
+ if (!pkgDir || isVuePackage(pkgDir)) {
547
+ const bin2 = resolveVueTscBin();
548
+ return bin2 ? { bin: bin2, source: "vue-tsc" } : null;
549
+ }
550
+ let bin = _tscBinByPkgDir.get(pkgDir);
551
+ if (bin === void 0) {
552
+ try {
553
+ const req = createRequire(path.join(pkgDir, "package.json"));
554
+ bin = req.resolve("typescript/bin/tsc");
555
+ } catch {
556
+ bin = null;
557
+ }
558
+ _tscBinByPkgDir.set(pkgDir, bin);
559
+ if (!bin) log2.debug("workspace tsc not resolvable, fallback to vue-tsc", { pkgDir });
560
+ }
561
+ if (bin) return { bin, source: "tsc" };
562
+ const vueBin = resolveVueTscBin();
563
+ return vueBin ? { bin: vueBin, source: "vue-tsc" } : null;
564
+ }
406
565
  function findTsconfigDir(filePath) {
407
566
  const resolved = path.resolve(filePath);
408
567
  let dir = path.dirname(resolved);
@@ -448,7 +607,7 @@ function findAllTsconfigDirs(workspace) {
448
607
  });
449
608
  return dirs;
450
609
  }
451
- function parseTscDiags(rawOutput, filePath, projectDir) {
610
+ function parseTscDiags(rawOutput, filePath, projectDir, source = "tsc") {
452
611
  const errorLinePat = /^(.+?)\((\d+),(\d+)\):\s+(error|warning)\s+TS(\d+):\s+(.+)$/;
453
612
  const diags = [];
454
613
  const resolved = filePath ? path.resolve(filePath) : void 0;
@@ -469,40 +628,40 @@ function parseTscDiags(rawOutput, filePath, projectDir) {
469
628
  end: { line: Number(lineNum) - 1, character: Number(col) - 1 }
470
629
  },
471
630
  message: `[TS${code}] ${message}`,
472
- source: "vue-tsc"
631
+ source
473
632
  });
474
633
  }
475
634
  }
476
635
  return diags;
477
636
  }
478
- async function runVueTsc(filePath, cwd) {
637
+ async function runTypeCheck(filePath, cwd) {
479
638
  const dir = cwd;
480
639
  const projectDir = filePath ? findTsconfigDir(filePath) ?? dir : dir;
481
- log2.debug("runVueTsc", {
640
+ log2.debug("runTypeCheck", {
482
641
  filePath: filePath || "(all)",
483
642
  cwd: dir,
484
643
  projectDir,
485
644
  processCwd: process.cwd()
486
645
  });
487
- const bin = resolveVueTscBin();
488
- if (!bin) {
489
- log2.warn("vue-tsc bin not found", { projectDir });
646
+ const engine = resolveTypeCheckBin(projectDir);
647
+ if (!engine) {
648
+ log2.warn("type-check bin not found", { projectDir });
490
649
  return { rawOutput: "", exitCode: 0 };
491
650
  }
492
651
  const timeout = filePath ? 6e4 : 12e4;
493
652
  const maxBuffer = filePath ? 10 * 1024 * 1024 : 50 * 1024 * 1024;
494
653
  return new Promise((resolve) => {
495
654
  exec(
496
- `node "${bin}" --build --noEmit --pretty false`,
655
+ `node "${engine.bin}" --build --noEmit --pretty false`,
497
656
  { cwd: projectDir, timeout, maxBuffer },
498
657
  (error, stdout, stderr) => {
499
658
  let rawOutput = stdout + stderr;
500
659
  const killed = error?.killed;
501
660
  const exitCode = typeof error?.code === "number" ? error.code : killed ? 1 : 0;
502
661
  if (killed && !rawOutput) {
503
- rawOutput = "vue-tsc \u68C0\u67E5\u8D85\u65F6\uFF0C\u8BF7\u5C1D\u8BD5\u7F29\u5C0F\u68C0\u67E5\u8303\u56F4\u6216\u4F18\u5316\u9879\u76EE\u914D\u7F6E\u3002";
662
+ rawOutput = `${engine.source} \u68C0\u67E5\u8D85\u65F6\uFF0C\u8BF7\u5C1D\u8BD5\u7F29\u5C0F\u68C0\u67E5\u8303\u56F4\u6216\u4F18\u5316\u9879\u76EE\u914D\u7F6E\u3002`;
504
663
  }
505
- const diagnostics = parseTscDiags(rawOutput, filePath, projectDir);
664
+ const diagnostics = parseTscDiags(rawOutput, filePath, projectDir, engine.source);
506
665
  if (filePath) {
507
666
  const resolved = path.resolve(filePath);
508
667
  const errorLinePat = /^(.+?)\((\d+),(\d+)\):\s+(error|warning)\s+TS\d+:/;
@@ -520,12 +679,13 @@ async function runVueTsc(filePath, cwd) {
520
679
  }
521
680
  rawOutput = filtered.join("\n");
522
681
  }
523
- log2.debug("vue-tsc finished", {
682
+ log2.debug("type-check finished", {
683
+ engine: engine.source,
524
684
  filePath: filePath || "(all)",
525
685
  exitCode,
526
686
  outputLength: rawOutput.length
527
687
  });
528
- resolve({ rawOutput, exitCode, diagnostics });
688
+ resolve({ rawOutput, exitCode, diagnostics, source: engine.source });
529
689
  }
530
690
  );
531
691
  });
@@ -534,7 +694,7 @@ async function runAllChecks(pattern, cwd) {
534
694
  log2.debug("runAllChecks", { pattern, cwd });
535
695
  const [eslintOutput, tscOutput] = await Promise.all([
536
696
  lintFiles(pattern, cwd),
537
- runVueTsc(pattern, cwd)
697
+ runTypeCheck(pattern, cwd)
538
698
  ]);
539
699
  return { eslintOutput, tscOutput };
540
700
  }
@@ -543,20 +703,31 @@ async function runProjectDiagnostics(workspace) {
543
703
  log2.debug("Tsc dirs to check", { count: tscDirs.length, dirs: tscDirs });
544
704
  const [eslintOutput, ...tscOutputs] = await Promise.all([
545
705
  lintFiles(".", workspace, 10),
546
- ...tscDirs.map((dir) => runVueTsc(void 0, dir))
706
+ ...tscDirs.map((dir) => runTypeCheck(void 0, dir))
547
707
  ]);
548
708
  const mergedTsc = {
549
709
  rawOutput: tscOutputs.flatMap((o) => o.rawOutput).filter(Boolean).join("\n"),
550
710
  exitCode: tscOutputs.reduce((max, o) => Math.max(max, o.exitCode), 0),
551
- diagnostics: tscOutputs.flatMap((o) => o.diagnostics ?? [])
711
+ diagnostics: tscOutputs.flatMap((o) => o.diagnostics ?? []),
712
+ source: tscOutputs.find((o) => o.source)?.source
552
713
  };
553
714
  return { eslintOutput, tscOutput: mergedTsc };
554
715
  }
716
+ function tscSectionTitle(tscOutput) {
717
+ return tscOutput.source ?? "tsc";
718
+ }
719
+ function lintSectionTitle(lintOutput) {
720
+ return lintOutput.engines?.length ? lintOutput.engines.join(" + ") : "ESLint";
721
+ }
555
722
  function formatDiagnosticsSections(title, eslintOutput, tscOutput) {
556
723
  const parts = [];
557
- parts.push("## ESLint\n\n" + (eslintOutput.text || "\u6CA1\u6709\u53D1\u73B0\u95EE\u9898"));
724
+ parts.push(`## ${lintSectionTitle(eslintOutput)}
725
+
726
+ ` + (eslintOutput.text || "\u6CA1\u6709\u53D1\u73B0\u95EE\u9898"));
558
727
  const tscLines = tscOutput.rawOutput.trim();
559
- parts.push("## vue-tsc\n\n" + (tscLines || "\u6CA1\u6709\u53D1\u73B0\u7C7B\u578B\u9519\u8BEF"));
728
+ parts.push(`## ${tscSectionTitle(tscOutput)}
729
+
730
+ ` + (tscLines || "\u6CA1\u6709\u53D1\u73B0\u7C7B\u578B\u9519\u8BEF"));
560
731
  return `${title}
561
732
 
562
733
  ` + parts.join("\n\n");
@@ -809,7 +980,10 @@ function buildNodeContext(e) {
809
980
  const loc = e.line ? e.column ? `:${e.line}:${e.column}` : `:${e.line}` : "";
810
981
  if (e.filePath) lines.push(`\u6E90\u7801\u6587\u4EF6\u8DEF\u5F84\uFF1A${e.filePath}${loc}`);
811
982
  if (e.description) lines.push(`DOM \u5143\u7D20\u9009\u62E9\u5668\uFF1A${e.description}`);
812
- if (e.innerText) lines.push(`DOM \u5143\u7D20\u5185\u90E8\u6587\u672C\uFF1A${e.innerText.slice(0, 200)}`);
983
+ if (e.innerText) {
984
+ const text = e.innerText.slice(0, 20).replace(/\r?\n/g, "\\n");
985
+ lines.push(`DOM \u5143\u7D20\u5185\u90E8\u6587\u672C\uFF1A${text}`);
986
+ }
813
987
  if (e.previewPageUrl) lines.push(`\u7528\u6237\u9009\u4E2D\u8282\u70B9\u65F6\u7684\u9875\u9762 URL\uFF1A${e.previewPageUrl}`);
814
988
  return lines.join("\n");
815
989
  }
@@ -867,8 +1041,8 @@ function buildDiagnosticsCanonical(title, eslintOutput, tscOutput) {
867
1041
  return {
868
1042
  title,
869
1043
  sections: [
870
- { title: "ESLint", text: eslintOutput.text || "\u6CA1\u6709\u53D1\u73B0\u95EE\u9898" },
871
- { title: "vue-tsc", text: tscOutput.rawOutput.trim() || "\u6CA1\u6709\u53D1\u73B0\u7C7B\u578B\u9519\u8BEF" }
1044
+ { title: lintSectionTitle(eslintOutput), text: eslintOutput.text || "\u6CA1\u6709\u53D1\u73B0\u95EE\u9898" },
1045
+ { title: tscSectionTitle(tscOutput), text: tscOutput.rawOutput.trim() || "\u6CA1\u6709\u53D1\u73B0\u7C7B\u578B\u9519\u8BEF" }
872
1046
  ],
873
1047
  diagnostics: [
874
1048
  ...toDiagnosticEntries(eslintOutput.diagnostics ?? []),
@@ -1071,8 +1245,14 @@ function apply(ctx, config = {}) {
1071
1245
  tscOutput: { rawOutput: "", exitCode: 0 }
1072
1246
  }));
1073
1247
  const parts = [];
1074
- if (tscOutput.rawOutput.trim()) parts.push("## vue-tsc\n\n" + tscOutput.rawOutput.trim());
1075
- if (eslintOutput.text) parts.push("## ESLint\n\n" + eslintOutput.text);
1248
+ if (tscOutput.rawOutput.trim())
1249
+ parts.push(`## ${tscSectionTitle(tscOutput)}
1250
+
1251
+ ` + tscOutput.rawOutput.trim());
1252
+ if (eslintOutput.text)
1253
+ parts.push(`## ${lintSectionTitle(eslintOutput)}
1254
+
1255
+ ` + eslintOutput.text);
1076
1256
  const diagText = parts.join("\n\n");
1077
1257
  if (!diagText) return decision;
1078
1258
  const existing = decision.kind === "accept" && decision.content || result.content;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aipanel/dsh-plugin",
3
- "version": "1.2.20",
3
+ "version": "1.2.22",
4
4
  "type": "module",
5
5
  "description": "AIPanel for DeepSeek Harness (dsh):注入审查工具 run_diagnostics、编辑后自动诊断。",
6
6
  "main": "./dist/index.js",
@@ -25,7 +25,7 @@
25
25
  "@deepseek-ai/dsh-user-questions": "^0.1.5-rc.1",
26
26
  "@deepseek-ai/dsh-util-values": "^0.1.5-rc.1",
27
27
  "esbuild": "^0.25.0",
28
- "@aipanel/core": "1.2.20"
28
+ "@aipanel/core": "1.2.22"
29
29
  },
30
30
  "scripts": {
31
31
  "build": "esbuild src/index.ts --bundle --outfile=dist/index.js --platform=node --format=esm --target=node18 --external:@deepseek-ai/* --external:node:* --external:vue-tsc",