@aipanel/core 1.2.21 → 1.2.23

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.
@@ -27,10 +27,14 @@ export interface TscResult {
27
27
  rawOutput: string;
28
28
  exitCode: number;
29
29
  diagnostics?: DiagnosticItem[];
30
+ /** 实际使用的类型检查引擎名("tsc" / "vue-tsc"),用于分区标题;解析失败等极端场景缺省 */
31
+ source?: string;
30
32
  }
31
33
  export interface EslintOutput {
32
34
  text?: string;
33
35
  diagnostics?: DiagnosticItem[];
36
+ /** 实际运行的 lint 引擎("ESLint" / "oxlint");缺省视为 ESLint(兼容旧调用方) */
37
+ engines?: string[];
34
38
  }
35
39
  export interface DiagnosticsResult {
36
40
  eslintOutput: EslintOutput;
@@ -45,14 +49,18 @@ export declare function lintFiles(pattern: string, cwd: string, warnLimit?: numb
45
49
  export declare function findTsconfigDir(filePath: string): string | null;
46
50
  /** 在工作区子目录中查找 tsconfig.json(不包括根目录;调用方已处理根目录场景) */
47
51
  export declare function findAllTsconfigDirs(workspace: string): string[];
48
- /** 运行 vue-tsc --build --noEmit,返回原始输出 */
49
- export declare function runVueTsc(filePath: string | undefined, cwd: string): Promise<TscResult>;
50
- /** 并行运行 ESLint + vue-tsc 检查(单文件或 glob) */
52
+ /** 运行 TypeScript 类型检查(tsc / vue-tsc 按项目自动选择)--build --noEmit,返回原始输出 */
53
+ export declare function runTypeCheck(filePath: string | undefined, cwd: string): Promise<TscResult>;
54
+ /** 并行运行 ESLint + 类型检查(单文件或 glob) */
51
55
  export declare function runAllChecks(pattern: string, cwd: string): Promise<DiagnosticsResult>;
52
56
  /**
53
- * 全量项目诊断:优先从根 tsconfig 运行一次 vue-tsc --build,
57
+ * 全量项目诊断:优先从根 tsconfig 运行一次类型检查 --build,
54
58
  * 根无 tsconfig 时回退到逐个子目录 build;ESLint 以 "." 全量扫描。
55
59
  */
56
60
  export declare function runProjectDiagnostics(workspace: string): Promise<DiagnosticsResult>;
57
- /** 组装统一的分区诊断文本(ESLint / vue-tsc,空结果显示占位文案) */
61
+ /** 类型检查分区标题(单一来源:跟随实际引擎 tsc / vue-tsc */
62
+ export declare function tscSectionTitle(tscOutput: TscResult): string;
63
+ /** Lint 分区标题(单一来源:跟随实际运行的引擎组合,如 "ESLint + oxlint") */
64
+ export declare function lintSectionTitle(lintOutput: EslintOutput): string;
65
+ /** 组装统一的分区诊断文本(Lint / 类型检查,空结果显示占位文案) */
58
66
  export declare function formatDiagnosticsSections(title: string, eslintOutput: EslintOutput, tscOutput: TscResult): string;
@@ -20,10 +20,10 @@ function isJsFile(filePath) {
20
20
  return JS_EXTENSIONS.has(path.extname(filePath));
21
21
  }
22
22
  const DIAGNOSTICS_TOOL_DESCRIPTION = [
23
- "\u8FD0\u884C ESLint \u4E0E TypeScript \u7C7B\u578B\u8BCA\u65AD\uFF0C\u8FD4\u56DE\u8BCA\u65AD\u7ED3\u679C\u3002",
23
+ "\u8FD0\u884C Lint\uFF08ESLint / oxlint\uFF09\u4E0E TypeScript \u7C7B\u578B\u8BCA\u65AD\uFF0C\u8FD4\u56DE\u8BCA\u65AD\u7ED3\u679C\u3002",
24
24
  "",
25
25
  "**\u652F\u6301\u7684\u6587\u4EF6\u7C7B\u578B**\uFF1A",
26
- `- ESLint\uFF1AJavaScript / TypeScript / Vue \u6E90\u7801\uFF08${[...JS_EXTENSIONS].map((e) => `*${e}`).join(" ")}\uFF09`,
26
+ `- 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`,
27
27
  "- TypeScript \u7C7B\u578B\u68C0\u67E5\uFF1A*.ts *.tsx *.vue",
28
28
  "",
29
29
  "**\u4F55\u65F6\u4F7F\u7528\u6B64\u5DE5\u5177**\uFF1A",
@@ -47,12 +47,68 @@ function loadESLint(workspace) {
47
47
  }
48
48
  async function lintFiles(pattern, cwd, warnLimit = 5) {
49
49
  loadESLint(cwd);
50
- if (!ESLintClass) {
50
+ const [eslintOutput, oxlintOutput] = await Promise.all([
51
+ ESLintClass ? runEslintFiles(pattern, cwd, warnLimit) : Promise.resolve(null),
52
+ runOxlintFiles(pattern, cwd, warnLimit)
53
+ ]);
54
+ const engines = [];
55
+ const texts = [];
56
+ const diagnostics = [];
57
+ for (const output of [eslintOutput, oxlintOutput]) {
58
+ if (!output) continue;
59
+ engines.push(...output.engines ?? []);
60
+ if (output.text) texts.push(output.text);
61
+ diagnostics.push(...output.diagnostics ?? []);
62
+ }
63
+ if (engines.length === 0) {
51
64
  return {
52
- text: `[ESLint] \u672A\u8FD0\u884C\uFF1A\u65E0\u6CD5\u5728 workspace "${cwd}" \u89E3\u6790\u5230 eslint\uFF08\u4EC5\u663E\u793A TypeScript \u8BCA\u65AD\uFF09`,
65
+ text: `[Lint] \u672A\u8FD0\u884C\uFF1A\u65E0\u6CD5\u5728 workspace "${cwd}" \u89E3\u6790\u5230 eslint \u6216 oxlint`,
53
66
  diagnostics: []
54
67
  };
55
68
  }
69
+ return { text: texts.join("\n\n") || void 0, diagnostics, engines };
70
+ }
71
+ function formatLintMessages(messages, engine, warnLimit) {
72
+ if (messages.length === 0) return { engines: [engine.label] };
73
+ const ESLINT_ERROR = 2;
74
+ const ESLINT_WARN = 1;
75
+ const lines = [];
76
+ const errors = messages.filter((m) => m.severity === ESLINT_ERROR);
77
+ const warnings = messages.filter((m) => m.severity === ESLINT_WARN);
78
+ if (errors.length > 0) {
79
+ lines.push(
80
+ ...errors.map(
81
+ (m) => `ERROR [${m.filePath}:${m.line}:${m.column}] ${m.message} (${m.ruleId})`
82
+ )
83
+ );
84
+ }
85
+ if (warnings.length > 0) {
86
+ lines.push(
87
+ ...warnings.slice(0, warnLimit).map((m) => `WARN [${m.filePath}:${m.line}:${m.column}] ${m.message} (${m.ruleId})`)
88
+ );
89
+ if (warnings.length > warnLimit)
90
+ lines.push(`... and ${warnings.length - warnLimit} more warnings`);
91
+ }
92
+ const diagnostics = messages.map((m) => ({
93
+ severity: m.severity === ESLINT_ERROR ? SEVERITY_ERROR : m.severity === ESLINT_WARN ? SEVERITY_WARN : m.severity,
94
+ file: m.filePath,
95
+ range: {
96
+ start: { line: (m.line || 1) - 1, character: (m.column || 1) - 1 },
97
+ end: {
98
+ line: (m.endLine || m.line || 1) - 1,
99
+ character: (m.endColumn || m.column || 1) - 1
100
+ }
101
+ },
102
+ message: `[${engine.label}] ${m.message} (${m.ruleId})`,
103
+ source: engine.source
104
+ }));
105
+ return {
106
+ text: lines.length > 0 ? lines.join("\n") : void 0,
107
+ diagnostics,
108
+ engines: [engine.label]
109
+ };
110
+ }
111
+ async function runEslintFiles(pattern, cwd, warnLimit) {
56
112
  try {
57
113
  const eslint = new ESLintClass({ cwd });
58
114
  const results = await eslint.lintFiles(pattern);
@@ -64,48 +120,111 @@ async function lintFiles(pattern, cwd, warnLimit = 5) {
64
120
  fileCount: results.length,
65
121
  messageCount: messages.length
66
122
  });
67
- if (messages.length === 0) return {};
68
- const ESLINT_ERROR = 2;
69
- const ESLINT_WARN = 1;
70
- const lines = [];
71
- const errors = messages.filter((m) => m.severity === ESLINT_ERROR);
72
- const warnings = messages.filter((m) => m.severity === ESLINT_WARN);
73
- if (errors.length > 0) {
74
- lines.push(
75
- ...errors.map(
76
- (m) => `ERROR [${m.filePath}:${m.line}:${m.column}] ${m.message} (${m.ruleId})`
77
- )
78
- );
79
- }
80
- if (warnings.length > 0) {
81
- lines.push(
82
- ...warnings.slice(0, warnLimit).map((m) => `WARN [${m.filePath}:${m.line}:${m.column}] ${m.message} (${m.ruleId})`)
83
- );
84
- if (warnings.length > warnLimit)
85
- lines.push(`... and ${warnings.length - warnLimit} more warnings`);
86
- }
87
- const diagnostics = messages.map((m) => ({
88
- severity: m.severity === ESLINT_ERROR ? SEVERITY_ERROR : m.severity === ESLINT_WARN ? SEVERITY_WARN : m.severity,
89
- file: m.filePath,
90
- range: {
91
- start: { line: (m.line || 1) - 1, character: (m.column || 1) - 1 },
92
- end: {
93
- line: (m.endLine || m.line || 1) - 1,
94
- character: (m.endColumn || m.column || 1) - 1
95
- }
96
- },
97
- message: `[ESLint] ${m.message} (${m.ruleId})`,
98
- source: "eslint"
99
- }));
100
- return { text: lines.length > 0 ? lines.join("\n") : void 0, diagnostics };
123
+ return formatLintMessages(messages, { label: "ESLint", source: "eslint" }, warnLimit);
101
124
  } catch (err) {
102
125
  log.warn("ESLint failed", { pattern, error: err.message });
103
126
  return {
104
127
  text: `[ESLint] \u8FD0\u884C\u5931\u8D25\uFF1A${err.message}\uFF08\u4EC5\u663E\u793A TypeScript \u8BCA\u65AD\uFF09`,
105
- diagnostics: []
128
+ diagnostics: [],
129
+ engines: ["ESLint"]
106
130
  };
107
131
  }
108
132
  }
133
+ let _oxlintBin;
134
+ function resolveOxlintBin(workspace) {
135
+ if (_oxlintBin !== void 0) return _oxlintBin;
136
+ try {
137
+ const req = createRequire(path.join(workspace, "package.json"));
138
+ const pkgJsonPath = req.resolve("oxlint/package.json");
139
+ const pkg = JSON.parse(fs.readFileSync(pkgJsonPath, "utf8"));
140
+ const binRel = typeof pkg.bin === "string" ? pkg.bin : pkg.bin?.oxlint;
141
+ _oxlintBin = binRel ? path.join(path.dirname(pkgJsonPath), binRel) : null;
142
+ } catch {
143
+ _oxlintBin = null;
144
+ }
145
+ return _oxlintBin;
146
+ }
147
+ function oxlintRuleName(code) {
148
+ if (!code) return null;
149
+ const match = /\(([^)]*)\)$/.exec(code);
150
+ return match ? match[1] : code;
151
+ }
152
+ function parseOxlintOutput(stdout, cwd) {
153
+ let parsed;
154
+ try {
155
+ parsed = JSON.parse(stdout);
156
+ } catch {
157
+ const start = stdout.indexOf("{");
158
+ const end = stdout.lastIndexOf("}");
159
+ if (start >= 0 && end > start) {
160
+ try {
161
+ parsed = JSON.parse(stdout.slice(start, end + 1));
162
+ } catch {
163
+ parsed = void 0;
164
+ }
165
+ }
166
+ }
167
+ if (!parsed) throw new Error("\u65E0\u6CD5\u89E3\u6790 oxlint JSON \u8F93\u51FA");
168
+ return (parsed.diagnostics ?? []).flatMap((d) => {
169
+ const filePath = d.filename ? path.isAbsolute(d.filename) ? d.filename : path.resolve(cwd, d.filename) : "";
170
+ if (!filePath) return [];
171
+ const span = d.labels?.[0]?.span;
172
+ const line = span?.line ?? 1;
173
+ const column = span?.column ?? 1;
174
+ return [
175
+ {
176
+ // oxlint 无 endLine/endColumn,同行按 span.length 延伸近似
177
+ severity: d.severity === "error" ? 2 : 1,
178
+ line,
179
+ column,
180
+ endLine: line,
181
+ endColumn: column + (span?.length ?? 0),
182
+ message: d.message ?? "\u672A\u77E5\u8BCA\u65AD",
183
+ ruleId: oxlintRuleName(d.code),
184
+ filePath
185
+ }
186
+ ];
187
+ });
188
+ }
189
+ async function runOxlintFiles(pattern, cwd, warnLimit) {
190
+ const bin = resolveOxlintBin(cwd);
191
+ if (!bin) return {};
192
+ return new Promise((resolve) => {
193
+ exec(
194
+ // 与 ESLint 默认行为对齐:忽略 node_modules(oxlint 默认不排除)
195
+ `node "${bin}" --format=json --ignore-pattern node_modules "${pattern}"`,
196
+ { cwd, timeout: 6e4, maxBuffer: 50 * 1024 * 1024 },
197
+ (error, stdout, stderr) => {
198
+ const killed = error?.killed;
199
+ if (killed) {
200
+ log.warn("oxlint timed out", { pattern });
201
+ resolve({
202
+ text: "[oxlint] \u8FD0\u884C\u5931\u8D25\uFF1A\u68C0\u67E5\u8D85\u65F6\uFF0C\u8BF7\u5C1D\u8BD5\u7F29\u5C0F\u68C0\u67E5\u8303\u56F4\u3002",
203
+ diagnostics: [],
204
+ engines: ["oxlint"]
205
+ });
206
+ return;
207
+ }
208
+ try {
209
+ const messages = parseOxlintOutput(stdout, cwd);
210
+ log.debug("oxlint lint", {
211
+ pattern,
212
+ messageCount: messages.length,
213
+ stderr: stderr || void 0
214
+ });
215
+ resolve(formatLintMessages(messages, { label: "oxlint", source: "oxlint" }, warnLimit));
216
+ } catch (e) {
217
+ log.warn("oxlint failed", { pattern, error: e.message });
218
+ resolve({
219
+ text: `[oxlint] \u8FD0\u884C\u5931\u8D25\uFF1A${e.message}`,
220
+ diagnostics: [],
221
+ engines: ["oxlint"]
222
+ });
223
+ }
224
+ }
225
+ );
226
+ });
227
+ }
109
228
  let _vueTscBin;
110
229
  function resolveVueTscBin() {
111
230
  if (_vueTscBin !== void 0) return _vueTscBin;
@@ -117,6 +236,46 @@ function resolveVueTscBin() {
117
236
  }
118
237
  return _vueTscBin;
119
238
  }
239
+ const _tscBinByPkgDir = /* @__PURE__ */ new Map();
240
+ function nearestPackageJsonDir(startDir) {
241
+ let dir = path.resolve(startDir);
242
+ while (true) {
243
+ if (fs.existsSync(path.join(dir, "package.json"))) return dir;
244
+ const parent = path.dirname(dir);
245
+ if (parent === dir) return null;
246
+ dir = parent;
247
+ }
248
+ }
249
+ function isVuePackage(pkgDir) {
250
+ try {
251
+ const pkg = JSON.parse(fs.readFileSync(path.join(pkgDir, "package.json"), "utf8"));
252
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies };
253
+ return "vue" in deps || "nuxt" in deps;
254
+ } catch {
255
+ return false;
256
+ }
257
+ }
258
+ function resolveTypeCheckBin(projectDir) {
259
+ const pkgDir = nearestPackageJsonDir(projectDir);
260
+ if (!pkgDir || isVuePackage(pkgDir)) {
261
+ const bin2 = resolveVueTscBin();
262
+ return bin2 ? { bin: bin2, source: "vue-tsc" } : null;
263
+ }
264
+ let bin = _tscBinByPkgDir.get(pkgDir);
265
+ if (bin === void 0) {
266
+ try {
267
+ const req = createRequire(path.join(pkgDir, "package.json"));
268
+ bin = req.resolve("typescript/bin/tsc");
269
+ } catch {
270
+ bin = null;
271
+ }
272
+ _tscBinByPkgDir.set(pkgDir, bin);
273
+ if (!bin) log.debug("workspace tsc not resolvable, fallback to vue-tsc", { pkgDir });
274
+ }
275
+ if (bin) return { bin, source: "tsc" };
276
+ const vueBin = resolveVueTscBin();
277
+ return vueBin ? { bin: vueBin, source: "vue-tsc" } : null;
278
+ }
120
279
  function findTsconfigDir(filePath) {
121
280
  const resolved = path.resolve(filePath);
122
281
  let dir = path.dirname(resolved);
@@ -162,7 +321,7 @@ function findAllTsconfigDirs(workspace) {
162
321
  });
163
322
  return dirs;
164
323
  }
165
- function parseTscDiags(rawOutput, filePath, projectDir) {
324
+ function parseTscDiags(rawOutput, filePath, projectDir, source = "tsc") {
166
325
  const errorLinePat = /^(.+?)\((\d+),(\d+)\):\s+(error|warning)\s+TS(\d+):\s+(.+)$/;
167
326
  const diags = [];
168
327
  const resolved = filePath ? path.resolve(filePath) : void 0;
@@ -183,40 +342,40 @@ function parseTscDiags(rawOutput, filePath, projectDir) {
183
342
  end: { line: Number(lineNum) - 1, character: Number(col) - 1 }
184
343
  },
185
344
  message: `[TS${code}] ${message}`,
186
- source: "vue-tsc"
345
+ source
187
346
  });
188
347
  }
189
348
  }
190
349
  return diags;
191
350
  }
192
- async function runVueTsc(filePath, cwd) {
351
+ async function runTypeCheck(filePath, cwd) {
193
352
  const dir = cwd;
194
353
  const projectDir = filePath ? findTsconfigDir(filePath) ?? dir : dir;
195
- log.debug("runVueTsc", {
354
+ log.debug("runTypeCheck", {
196
355
  filePath: filePath || "(all)",
197
356
  cwd: dir,
198
357
  projectDir,
199
358
  processCwd: process.cwd()
200
359
  });
201
- const bin = resolveVueTscBin();
202
- if (!bin) {
203
- log.warn("vue-tsc bin not found", { projectDir });
360
+ const engine = resolveTypeCheckBin(projectDir);
361
+ if (!engine) {
362
+ log.warn("type-check bin not found", { projectDir });
204
363
  return { rawOutput: "", exitCode: 0 };
205
364
  }
206
365
  const timeout = filePath ? 6e4 : 12e4;
207
366
  const maxBuffer = filePath ? 10 * 1024 * 1024 : 50 * 1024 * 1024;
208
367
  return new Promise((resolve) => {
209
368
  exec(
210
- `node "${bin}" --build --noEmit --pretty false`,
369
+ `node "${engine.bin}" --build --noEmit --pretty false`,
211
370
  { cwd: projectDir, timeout, maxBuffer },
212
371
  (error, stdout, stderr) => {
213
372
  let rawOutput = stdout + stderr;
214
373
  const killed = error?.killed;
215
374
  const exitCode = typeof error?.code === "number" ? error.code : killed ? 1 : 0;
216
375
  if (killed && !rawOutput) {
217
- 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";
376
+ 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`;
218
377
  }
219
- const diagnostics = parseTscDiags(rawOutput, filePath, projectDir);
378
+ const diagnostics = parseTscDiags(rawOutput, filePath, projectDir, engine.source);
220
379
  if (filePath) {
221
380
  const resolved = path.resolve(filePath);
222
381
  const errorLinePat = /^(.+?)\((\d+),(\d+)\):\s+(error|warning)\s+TS\d+:/;
@@ -234,12 +393,13 @@ async function runVueTsc(filePath, cwd) {
234
393
  }
235
394
  rawOutput = filtered.join("\n");
236
395
  }
237
- log.debug("vue-tsc finished", {
396
+ log.debug("type-check finished", {
397
+ engine: engine.source,
238
398
  filePath: filePath || "(all)",
239
399
  exitCode,
240
400
  outputLength: rawOutput.length
241
401
  });
242
- resolve({ rawOutput, exitCode, diagnostics });
402
+ resolve({ rawOutput, exitCode, diagnostics, source: engine.source });
243
403
  }
244
404
  );
245
405
  });
@@ -248,7 +408,7 @@ async function runAllChecks(pattern, cwd) {
248
408
  log.debug("runAllChecks", { pattern, cwd });
249
409
  const [eslintOutput, tscOutput] = await Promise.all([
250
410
  lintFiles(pattern, cwd),
251
- runVueTsc(pattern, cwd)
411
+ runTypeCheck(pattern, cwd)
252
412
  ]);
253
413
  return { eslintOutput, tscOutput };
254
414
  }
@@ -257,20 +417,31 @@ async function runProjectDiagnostics(workspace) {
257
417
  log.debug("Tsc dirs to check", { count: tscDirs.length, dirs: tscDirs });
258
418
  const [eslintOutput, ...tscOutputs] = await Promise.all([
259
419
  lintFiles(".", workspace, 10),
260
- ...tscDirs.map((dir) => runVueTsc(void 0, dir))
420
+ ...tscDirs.map((dir) => runTypeCheck(void 0, dir))
261
421
  ]);
262
422
  const mergedTsc = {
263
423
  rawOutput: tscOutputs.flatMap((o) => o.rawOutput).filter(Boolean).join("\n"),
264
424
  exitCode: tscOutputs.reduce((max, o) => Math.max(max, o.exitCode), 0),
265
- diagnostics: tscOutputs.flatMap((o) => o.diagnostics ?? [])
425
+ diagnostics: tscOutputs.flatMap((o) => o.diagnostics ?? []),
426
+ source: tscOutputs.find((o) => o.source)?.source
266
427
  };
267
428
  return { eslintOutput, tscOutput: mergedTsc };
268
429
  }
430
+ function tscSectionTitle(tscOutput) {
431
+ return tscOutput.source ?? "tsc";
432
+ }
433
+ function lintSectionTitle(lintOutput) {
434
+ return lintOutput.engines?.length ? lintOutput.engines.join(" + ") : "ESLint";
435
+ }
269
436
  function formatDiagnosticsSections(title, eslintOutput, tscOutput) {
270
437
  const parts = [];
271
- parts.push("## ESLint\n\n" + (eslintOutput.text || "\u6CA1\u6709\u53D1\u73B0\u95EE\u9898"));
438
+ parts.push(`## ${lintSectionTitle(eslintOutput)}
439
+
440
+ ` + (eslintOutput.text || "\u6CA1\u6709\u53D1\u73B0\u95EE\u9898"));
272
441
  const tscLines = tscOutput.rawOutput.trim();
273
- parts.push("## vue-tsc\n\n" + (tscLines || "\u6CA1\u6709\u53D1\u73B0\u7C7B\u578B\u9519\u8BEF"));
442
+ parts.push(`## ${tscSectionTitle(tscOutput)}
443
+
444
+ ` + (tscLines || "\u6CA1\u6709\u53D1\u73B0\u7C7B\u578B\u9519\u8BEF"));
274
445
  return `${title}
275
446
 
276
447
  ` + parts.join("\n\n");
@@ -282,7 +453,9 @@ export {
282
453
  formatDiagnosticsSections,
283
454
  isJsFile,
284
455
  lintFiles,
456
+ lintSectionTitle,
285
457
  runAllChecks,
286
458
  runProjectDiagnostics,
287
- runVueTsc
459
+ runTypeCheck,
460
+ tscSectionTitle
288
461
  };
@@ -33,9 +33,11 @@ __export(diagnostics_exports, {
33
33
  formatDiagnosticsSections: () => formatDiagnosticsSections,
34
34
  isJsFile: () => isJsFile,
35
35
  lintFiles: () => lintFiles,
36
+ lintSectionTitle: () => lintSectionTitle,
36
37
  runAllChecks: () => runAllChecks,
37
38
  runProjectDiagnostics: () => runProjectDiagnostics,
38
- runVueTsc: () => runVueTsc
39
+ runTypeCheck: () => runTypeCheck,
40
+ tscSectionTitle: () => tscSectionTitle
39
41
  });
40
42
  module.exports = __toCommonJS(diagnostics_exports);
41
43
  var import_node_fs = __toESM(require("node:fs"));
@@ -61,10 +63,10 @@ function isJsFile(filePath) {
61
63
  return JS_EXTENSIONS.has(import_node_path.default.extname(filePath));
62
64
  }
63
65
  const DIAGNOSTICS_TOOL_DESCRIPTION = [
64
- "\u8FD0\u884C ESLint \u4E0E TypeScript \u7C7B\u578B\u8BCA\u65AD\uFF0C\u8FD4\u56DE\u8BCA\u65AD\u7ED3\u679C\u3002",
66
+ "\u8FD0\u884C Lint\uFF08ESLint / oxlint\uFF09\u4E0E TypeScript \u7C7B\u578B\u8BCA\u65AD\uFF0C\u8FD4\u56DE\u8BCA\u65AD\u7ED3\u679C\u3002",
65
67
  "",
66
68
  "**\u652F\u6301\u7684\u6587\u4EF6\u7C7B\u578B**\uFF1A",
67
- `- ESLint\uFF1AJavaScript / TypeScript / Vue \u6E90\u7801\uFF08${[...JS_EXTENSIONS].map((e) => `*${e}`).join(" ")}\uFF09`,
69
+ `- 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`,
68
70
  "- TypeScript \u7C7B\u578B\u68C0\u67E5\uFF1A*.ts *.tsx *.vue",
69
71
  "",
70
72
  "**\u4F55\u65F6\u4F7F\u7528\u6B64\u5DE5\u5177**\uFF1A",
@@ -88,12 +90,68 @@ function loadESLint(workspace) {
88
90
  }
89
91
  async function lintFiles(pattern, cwd, warnLimit = 5) {
90
92
  loadESLint(cwd);
91
- if (!ESLintClass) {
93
+ const [eslintOutput, oxlintOutput] = await Promise.all([
94
+ ESLintClass ? runEslintFiles(pattern, cwd, warnLimit) : Promise.resolve(null),
95
+ runOxlintFiles(pattern, cwd, warnLimit)
96
+ ]);
97
+ const engines = [];
98
+ const texts = [];
99
+ const diagnostics = [];
100
+ for (const output of [eslintOutput, oxlintOutput]) {
101
+ if (!output) continue;
102
+ engines.push(...output.engines ?? []);
103
+ if (output.text) texts.push(output.text);
104
+ diagnostics.push(...output.diagnostics ?? []);
105
+ }
106
+ if (engines.length === 0) {
92
107
  return {
93
- text: `[ESLint] \u672A\u8FD0\u884C\uFF1A\u65E0\u6CD5\u5728 workspace "${cwd}" \u89E3\u6790\u5230 eslint\uFF08\u4EC5\u663E\u793A TypeScript \u8BCA\u65AD\uFF09`,
108
+ text: `[Lint] \u672A\u8FD0\u884C\uFF1A\u65E0\u6CD5\u5728 workspace "${cwd}" \u89E3\u6790\u5230 eslint \u6216 oxlint`,
94
109
  diagnostics: []
95
110
  };
96
111
  }
112
+ return { text: texts.join("\n\n") || void 0, diagnostics, engines };
113
+ }
114
+ function formatLintMessages(messages, engine, warnLimit) {
115
+ if (messages.length === 0) return { engines: [engine.label] };
116
+ const ESLINT_ERROR = 2;
117
+ const ESLINT_WARN = 1;
118
+ const lines = [];
119
+ const errors = messages.filter((m) => m.severity === ESLINT_ERROR);
120
+ const warnings = messages.filter((m) => m.severity === ESLINT_WARN);
121
+ if (errors.length > 0) {
122
+ lines.push(
123
+ ...errors.map(
124
+ (m) => `ERROR [${m.filePath}:${m.line}:${m.column}] ${m.message} (${m.ruleId})`
125
+ )
126
+ );
127
+ }
128
+ if (warnings.length > 0) {
129
+ lines.push(
130
+ ...warnings.slice(0, warnLimit).map((m) => `WARN [${m.filePath}:${m.line}:${m.column}] ${m.message} (${m.ruleId})`)
131
+ );
132
+ if (warnings.length > warnLimit)
133
+ lines.push(`... and ${warnings.length - warnLimit} more warnings`);
134
+ }
135
+ const diagnostics = messages.map((m) => ({
136
+ severity: m.severity === ESLINT_ERROR ? import_constants.SEVERITY_ERROR : m.severity === ESLINT_WARN ? import_constants.SEVERITY_WARN : m.severity,
137
+ file: m.filePath,
138
+ range: {
139
+ start: { line: (m.line || 1) - 1, character: (m.column || 1) - 1 },
140
+ end: {
141
+ line: (m.endLine || m.line || 1) - 1,
142
+ character: (m.endColumn || m.column || 1) - 1
143
+ }
144
+ },
145
+ message: `[${engine.label}] ${m.message} (${m.ruleId})`,
146
+ source: engine.source
147
+ }));
148
+ return {
149
+ text: lines.length > 0 ? lines.join("\n") : void 0,
150
+ diagnostics,
151
+ engines: [engine.label]
152
+ };
153
+ }
154
+ async function runEslintFiles(pattern, cwd, warnLimit) {
97
155
  try {
98
156
  const eslint = new ESLintClass({ cwd });
99
157
  const results = await eslint.lintFiles(pattern);
@@ -105,48 +163,111 @@ async function lintFiles(pattern, cwd, warnLimit = 5) {
105
163
  fileCount: results.length,
106
164
  messageCount: messages.length
107
165
  });
108
- if (messages.length === 0) return {};
109
- const ESLINT_ERROR = 2;
110
- const ESLINT_WARN = 1;
111
- const lines = [];
112
- const errors = messages.filter((m) => m.severity === ESLINT_ERROR);
113
- const warnings = messages.filter((m) => m.severity === ESLINT_WARN);
114
- if (errors.length > 0) {
115
- lines.push(
116
- ...errors.map(
117
- (m) => `ERROR [${m.filePath}:${m.line}:${m.column}] ${m.message} (${m.ruleId})`
118
- )
119
- );
120
- }
121
- if (warnings.length > 0) {
122
- lines.push(
123
- ...warnings.slice(0, warnLimit).map((m) => `WARN [${m.filePath}:${m.line}:${m.column}] ${m.message} (${m.ruleId})`)
124
- );
125
- if (warnings.length > warnLimit)
126
- lines.push(`... and ${warnings.length - warnLimit} more warnings`);
127
- }
128
- const diagnostics = messages.map((m) => ({
129
- severity: m.severity === ESLINT_ERROR ? import_constants.SEVERITY_ERROR : m.severity === ESLINT_WARN ? import_constants.SEVERITY_WARN : m.severity,
130
- file: m.filePath,
131
- range: {
132
- start: { line: (m.line || 1) - 1, character: (m.column || 1) - 1 },
133
- end: {
134
- line: (m.endLine || m.line || 1) - 1,
135
- character: (m.endColumn || m.column || 1) - 1
136
- }
137
- },
138
- message: `[ESLint] ${m.message} (${m.ruleId})`,
139
- source: "eslint"
140
- }));
141
- return { text: lines.length > 0 ? lines.join("\n") : void 0, diagnostics };
166
+ return formatLintMessages(messages, { label: "ESLint", source: "eslint" }, warnLimit);
142
167
  } catch (err) {
143
168
  log.warn("ESLint failed", { pattern, error: err.message });
144
169
  return {
145
170
  text: `[ESLint] \u8FD0\u884C\u5931\u8D25\uFF1A${err.message}\uFF08\u4EC5\u663E\u793A TypeScript \u8BCA\u65AD\uFF09`,
146
- diagnostics: []
171
+ diagnostics: [],
172
+ engines: ["ESLint"]
147
173
  };
148
174
  }
149
175
  }
176
+ let _oxlintBin;
177
+ function resolveOxlintBin(workspace) {
178
+ if (_oxlintBin !== void 0) return _oxlintBin;
179
+ try {
180
+ const req = (0, import_node_module.createRequire)(import_node_path.default.join(workspace, "package.json"));
181
+ const pkgJsonPath = req.resolve("oxlint/package.json");
182
+ const pkg = JSON.parse(import_node_fs.default.readFileSync(pkgJsonPath, "utf8"));
183
+ const binRel = typeof pkg.bin === "string" ? pkg.bin : pkg.bin?.oxlint;
184
+ _oxlintBin = binRel ? import_node_path.default.join(import_node_path.default.dirname(pkgJsonPath), binRel) : null;
185
+ } catch {
186
+ _oxlintBin = null;
187
+ }
188
+ return _oxlintBin;
189
+ }
190
+ function oxlintRuleName(code) {
191
+ if (!code) return null;
192
+ const match = /\(([^)]*)\)$/.exec(code);
193
+ return match ? match[1] : code;
194
+ }
195
+ function parseOxlintOutput(stdout, cwd) {
196
+ let parsed;
197
+ try {
198
+ parsed = JSON.parse(stdout);
199
+ } catch {
200
+ const start = stdout.indexOf("{");
201
+ const end = stdout.lastIndexOf("}");
202
+ if (start >= 0 && end > start) {
203
+ try {
204
+ parsed = JSON.parse(stdout.slice(start, end + 1));
205
+ } catch {
206
+ parsed = void 0;
207
+ }
208
+ }
209
+ }
210
+ if (!parsed) throw new Error("\u65E0\u6CD5\u89E3\u6790 oxlint JSON \u8F93\u51FA");
211
+ return (parsed.diagnostics ?? []).flatMap((d) => {
212
+ const filePath = d.filename ? import_node_path.default.isAbsolute(d.filename) ? d.filename : import_node_path.default.resolve(cwd, d.filename) : "";
213
+ if (!filePath) return [];
214
+ const span = d.labels?.[0]?.span;
215
+ const line = span?.line ?? 1;
216
+ const column = span?.column ?? 1;
217
+ return [
218
+ {
219
+ // oxlint 无 endLine/endColumn,同行按 span.length 延伸近似
220
+ severity: d.severity === "error" ? 2 : 1,
221
+ line,
222
+ column,
223
+ endLine: line,
224
+ endColumn: column + (span?.length ?? 0),
225
+ message: d.message ?? "\u672A\u77E5\u8BCA\u65AD",
226
+ ruleId: oxlintRuleName(d.code),
227
+ filePath
228
+ }
229
+ ];
230
+ });
231
+ }
232
+ async function runOxlintFiles(pattern, cwd, warnLimit) {
233
+ const bin = resolveOxlintBin(cwd);
234
+ if (!bin) return {};
235
+ return new Promise((resolve) => {
236
+ (0, import_node_child_process.exec)(
237
+ // 与 ESLint 默认行为对齐:忽略 node_modules(oxlint 默认不排除)
238
+ `node "${bin}" --format=json --ignore-pattern node_modules "${pattern}"`,
239
+ { cwd, timeout: 6e4, maxBuffer: 50 * 1024 * 1024 },
240
+ (error, stdout, stderr) => {
241
+ const killed = error?.killed;
242
+ if (killed) {
243
+ log.warn("oxlint timed out", { pattern });
244
+ resolve({
245
+ text: "[oxlint] \u8FD0\u884C\u5931\u8D25\uFF1A\u68C0\u67E5\u8D85\u65F6\uFF0C\u8BF7\u5C1D\u8BD5\u7F29\u5C0F\u68C0\u67E5\u8303\u56F4\u3002",
246
+ diagnostics: [],
247
+ engines: ["oxlint"]
248
+ });
249
+ return;
250
+ }
251
+ try {
252
+ const messages = parseOxlintOutput(stdout, cwd);
253
+ log.debug("oxlint lint", {
254
+ pattern,
255
+ messageCount: messages.length,
256
+ stderr: stderr || void 0
257
+ });
258
+ resolve(formatLintMessages(messages, { label: "oxlint", source: "oxlint" }, warnLimit));
259
+ } catch (e) {
260
+ log.warn("oxlint failed", { pattern, error: e.message });
261
+ resolve({
262
+ text: `[oxlint] \u8FD0\u884C\u5931\u8D25\uFF1A${e.message}`,
263
+ diagnostics: [],
264
+ engines: ["oxlint"]
265
+ });
266
+ }
267
+ }
268
+ );
269
+ });
270
+ }
150
271
  let _vueTscBin;
151
272
  function resolveVueTscBin() {
152
273
  if (_vueTscBin !== void 0) return _vueTscBin;
@@ -158,6 +279,46 @@ function resolveVueTscBin() {
158
279
  }
159
280
  return _vueTscBin;
160
281
  }
282
+ const _tscBinByPkgDir = /* @__PURE__ */ new Map();
283
+ function nearestPackageJsonDir(startDir) {
284
+ let dir = import_node_path.default.resolve(startDir);
285
+ while (true) {
286
+ if (import_node_fs.default.existsSync(import_node_path.default.join(dir, "package.json"))) return dir;
287
+ const parent = import_node_path.default.dirname(dir);
288
+ if (parent === dir) return null;
289
+ dir = parent;
290
+ }
291
+ }
292
+ function isVuePackage(pkgDir) {
293
+ try {
294
+ const pkg = JSON.parse(import_node_fs.default.readFileSync(import_node_path.default.join(pkgDir, "package.json"), "utf8"));
295
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies };
296
+ return "vue" in deps || "nuxt" in deps;
297
+ } catch {
298
+ return false;
299
+ }
300
+ }
301
+ function resolveTypeCheckBin(projectDir) {
302
+ const pkgDir = nearestPackageJsonDir(projectDir);
303
+ if (!pkgDir || isVuePackage(pkgDir)) {
304
+ const bin2 = resolveVueTscBin();
305
+ return bin2 ? { bin: bin2, source: "vue-tsc" } : null;
306
+ }
307
+ let bin = _tscBinByPkgDir.get(pkgDir);
308
+ if (bin === void 0) {
309
+ try {
310
+ const req = (0, import_node_module.createRequire)(import_node_path.default.join(pkgDir, "package.json"));
311
+ bin = req.resolve("typescript/bin/tsc");
312
+ } catch {
313
+ bin = null;
314
+ }
315
+ _tscBinByPkgDir.set(pkgDir, bin);
316
+ if (!bin) log.debug("workspace tsc not resolvable, fallback to vue-tsc", { pkgDir });
317
+ }
318
+ if (bin) return { bin, source: "tsc" };
319
+ const vueBin = resolveVueTscBin();
320
+ return vueBin ? { bin: vueBin, source: "vue-tsc" } : null;
321
+ }
161
322
  function findTsconfigDir(filePath) {
162
323
  const resolved = import_node_path.default.resolve(filePath);
163
324
  let dir = import_node_path.default.dirname(resolved);
@@ -203,7 +364,7 @@ function findAllTsconfigDirs(workspace) {
203
364
  });
204
365
  return dirs;
205
366
  }
206
- function parseTscDiags(rawOutput, filePath, projectDir) {
367
+ function parseTscDiags(rawOutput, filePath, projectDir, source = "tsc") {
207
368
  const errorLinePat = /^(.+?)\((\d+),(\d+)\):\s+(error|warning)\s+TS(\d+):\s+(.+)$/;
208
369
  const diags = [];
209
370
  const resolved = filePath ? import_node_path.default.resolve(filePath) : void 0;
@@ -224,40 +385,40 @@ function parseTscDiags(rawOutput, filePath, projectDir) {
224
385
  end: { line: Number(lineNum) - 1, character: Number(col) - 1 }
225
386
  },
226
387
  message: `[TS${code}] ${message}`,
227
- source: "vue-tsc"
388
+ source
228
389
  });
229
390
  }
230
391
  }
231
392
  return diags;
232
393
  }
233
- async function runVueTsc(filePath, cwd) {
394
+ async function runTypeCheck(filePath, cwd) {
234
395
  const dir = cwd;
235
396
  const projectDir = filePath ? findTsconfigDir(filePath) ?? dir : dir;
236
- log.debug("runVueTsc", {
397
+ log.debug("runTypeCheck", {
237
398
  filePath: filePath || "(all)",
238
399
  cwd: dir,
239
400
  projectDir,
240
401
  processCwd: process.cwd()
241
402
  });
242
- const bin = resolveVueTscBin();
243
- if (!bin) {
244
- log.warn("vue-tsc bin not found", { projectDir });
403
+ const engine = resolveTypeCheckBin(projectDir);
404
+ if (!engine) {
405
+ log.warn("type-check bin not found", { projectDir });
245
406
  return { rawOutput: "", exitCode: 0 };
246
407
  }
247
408
  const timeout = filePath ? 6e4 : 12e4;
248
409
  const maxBuffer = filePath ? 10 * 1024 * 1024 : 50 * 1024 * 1024;
249
410
  return new Promise((resolve) => {
250
411
  (0, import_node_child_process.exec)(
251
- `node "${bin}" --build --noEmit --pretty false`,
412
+ `node "${engine.bin}" --build --noEmit --pretty false`,
252
413
  { cwd: projectDir, timeout, maxBuffer },
253
414
  (error, stdout, stderr) => {
254
415
  let rawOutput = stdout + stderr;
255
416
  const killed = error?.killed;
256
417
  const exitCode = typeof error?.code === "number" ? error.code : killed ? 1 : 0;
257
418
  if (killed && !rawOutput) {
258
- 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";
419
+ 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`;
259
420
  }
260
- const diagnostics = parseTscDiags(rawOutput, filePath, projectDir);
421
+ const diagnostics = parseTscDiags(rawOutput, filePath, projectDir, engine.source);
261
422
  if (filePath) {
262
423
  const resolved = import_node_path.default.resolve(filePath);
263
424
  const errorLinePat = /^(.+?)\((\d+),(\d+)\):\s+(error|warning)\s+TS\d+:/;
@@ -275,12 +436,13 @@ async function runVueTsc(filePath, cwd) {
275
436
  }
276
437
  rawOutput = filtered.join("\n");
277
438
  }
278
- log.debug("vue-tsc finished", {
439
+ log.debug("type-check finished", {
440
+ engine: engine.source,
279
441
  filePath: filePath || "(all)",
280
442
  exitCode,
281
443
  outputLength: rawOutput.length
282
444
  });
283
- resolve({ rawOutput, exitCode, diagnostics });
445
+ resolve({ rawOutput, exitCode, diagnostics, source: engine.source });
284
446
  }
285
447
  );
286
448
  });
@@ -289,7 +451,7 @@ async function runAllChecks(pattern, cwd) {
289
451
  log.debug("runAllChecks", { pattern, cwd });
290
452
  const [eslintOutput, tscOutput] = await Promise.all([
291
453
  lintFiles(pattern, cwd),
292
- runVueTsc(pattern, cwd)
454
+ runTypeCheck(pattern, cwd)
293
455
  ]);
294
456
  return { eslintOutput, tscOutput };
295
457
  }
@@ -298,20 +460,31 @@ async function runProjectDiagnostics(workspace) {
298
460
  log.debug("Tsc dirs to check", { count: tscDirs.length, dirs: tscDirs });
299
461
  const [eslintOutput, ...tscOutputs] = await Promise.all([
300
462
  lintFiles(".", workspace, 10),
301
- ...tscDirs.map((dir) => runVueTsc(void 0, dir))
463
+ ...tscDirs.map((dir) => runTypeCheck(void 0, dir))
302
464
  ]);
303
465
  const mergedTsc = {
304
466
  rawOutput: tscOutputs.flatMap((o) => o.rawOutput).filter(Boolean).join("\n"),
305
467
  exitCode: tscOutputs.reduce((max, o) => Math.max(max, o.exitCode), 0),
306
- diagnostics: tscOutputs.flatMap((o) => o.diagnostics ?? [])
468
+ diagnostics: tscOutputs.flatMap((o) => o.diagnostics ?? []),
469
+ source: tscOutputs.find((o) => o.source)?.source
307
470
  };
308
471
  return { eslintOutput, tscOutput: mergedTsc };
309
472
  }
473
+ function tscSectionTitle(tscOutput) {
474
+ return tscOutput.source ?? "tsc";
475
+ }
476
+ function lintSectionTitle(lintOutput) {
477
+ return lintOutput.engines?.length ? lintOutput.engines.join(" + ") : "ESLint";
478
+ }
310
479
  function formatDiagnosticsSections(title, eslintOutput, tscOutput) {
311
480
  const parts = [];
312
- parts.push("## ESLint\n\n" + (eslintOutput.text || "\u6CA1\u6709\u53D1\u73B0\u95EE\u9898"));
481
+ parts.push(`## ${lintSectionTitle(eslintOutput)}
482
+
483
+ ` + (eslintOutput.text || "\u6CA1\u6709\u53D1\u73B0\u95EE\u9898"));
313
484
  const tscLines = tscOutput.rawOutput.trim();
314
- parts.push("## vue-tsc\n\n" + (tscLines || "\u6CA1\u6709\u53D1\u73B0\u7C7B\u578B\u9519\u8BEF"));
485
+ parts.push(`## ${tscSectionTitle(tscOutput)}
486
+
487
+ ` + (tscLines || "\u6CA1\u6709\u53D1\u73B0\u7C7B\u578B\u9519\u8BEF"));
315
488
  return `${title}
316
489
 
317
490
  ` + parts.join("\n\n");
@@ -324,7 +497,9 @@ function formatDiagnosticsSections(title, eslintOutput, tscOutput) {
324
497
  formatDiagnosticsSections,
325
498
  isJsFile,
326
499
  lintFiles,
500
+ lintSectionTitle,
327
501
  runAllChecks,
328
502
  runProjectDiagnostics,
329
- runVueTsc
503
+ runTypeCheck,
504
+ tscSectionTitle
330
505
  });
@@ -27,10 +27,14 @@ export interface TscResult {
27
27
  rawOutput: string;
28
28
  exitCode: number;
29
29
  diagnostics?: DiagnosticItem[];
30
+ /** 实际使用的类型检查引擎名("tsc" / "vue-tsc"),用于分区标题;解析失败等极端场景缺省 */
31
+ source?: string;
30
32
  }
31
33
  export interface EslintOutput {
32
34
  text?: string;
33
35
  diagnostics?: DiagnosticItem[];
36
+ /** 实际运行的 lint 引擎("ESLint" / "oxlint");缺省视为 ESLint(兼容旧调用方) */
37
+ engines?: string[];
34
38
  }
35
39
  export interface DiagnosticsResult {
36
40
  eslintOutput: EslintOutput;
@@ -45,14 +49,18 @@ export declare function lintFiles(pattern: string, cwd: string, warnLimit?: numb
45
49
  export declare function findTsconfigDir(filePath: string): string | null;
46
50
  /** 在工作区子目录中查找 tsconfig.json(不包括根目录;调用方已处理根目录场景) */
47
51
  export declare function findAllTsconfigDirs(workspace: string): string[];
48
- /** 运行 vue-tsc --build --noEmit,返回原始输出 */
49
- export declare function runVueTsc(filePath: string | undefined, cwd: string): Promise<TscResult>;
50
- /** 并行运行 ESLint + vue-tsc 检查(单文件或 glob) */
52
+ /** 运行 TypeScript 类型检查(tsc / vue-tsc 按项目自动选择)--build --noEmit,返回原始输出 */
53
+ export declare function runTypeCheck(filePath: string | undefined, cwd: string): Promise<TscResult>;
54
+ /** 并行运行 ESLint + 类型检查(单文件或 glob) */
51
55
  export declare function runAllChecks(pattern: string, cwd: string): Promise<DiagnosticsResult>;
52
56
  /**
53
- * 全量项目诊断:优先从根 tsconfig 运行一次 vue-tsc --build,
57
+ * 全量项目诊断:优先从根 tsconfig 运行一次类型检查 --build,
54
58
  * 根无 tsconfig 时回退到逐个子目录 build;ESLint 以 "." 全量扫描。
55
59
  */
56
60
  export declare function runProjectDiagnostics(workspace: string): Promise<DiagnosticsResult>;
57
- /** 组装统一的分区诊断文本(ESLint / vue-tsc,空结果显示占位文案) */
61
+ /** 类型检查分区标题(单一来源:跟随实际引擎 tsc / vue-tsc */
62
+ export declare function tscSectionTitle(tscOutput: TscResult): string;
63
+ /** Lint 分区标题(单一来源:跟随实际运行的引擎组合,如 "ESLint + oxlint") */
64
+ export declare function lintSectionTitle(lintOutput: EslintOutput): string;
65
+ /** 组装统一的分区诊断文本(Lint / 类型检查,空结果显示占位文案) */
58
66
  export declare function formatDiagnosticsSections(title: string, eslintOutput: EslintOutput, tscOutput: TscResult): string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aipanel/core",
3
- "version": "1.2.21",
3
+ "version": "1.2.23",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "main": "lib/index.cjs",