@aipanel/dsh-plugin 1.3.4 → 1.3.6
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/dist/index.js +731 -234
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -38,16 +38,219 @@ var VUE_DEVTOOLS_TIMELINE_INCLUDES = [
|
|
|
38
38
|
];
|
|
39
39
|
var DEFAULT_TIMELINE_INCLUDE = VUE_DEVTOOLS_TIMELINE_INCLUDE.SLOW;
|
|
40
40
|
var MUTATING_TOOLS = /* @__PURE__ */ new Set(["write", "edit", "apply_patch"]);
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
41
|
+
|
|
42
|
+
// ../../core/es/common/diagnostics.mjs
|
|
43
|
+
var COMMAND_CHECK_TIMEOUT_MS = 6e4;
|
|
44
|
+
var SOURCE_EXTENSIONS = [
|
|
45
|
+
".js",
|
|
46
|
+
".jsx",
|
|
47
|
+
".ts",
|
|
48
|
+
".tsx",
|
|
49
|
+
".mjs",
|
|
50
|
+
".cjs",
|
|
51
|
+
".mts",
|
|
52
|
+
".cts",
|
|
53
|
+
".vue"
|
|
54
|
+
];
|
|
55
|
+
function matchesExtensions(filePath, extensions) {
|
|
56
|
+
if (!extensions?.length) return true;
|
|
57
|
+
const base = filePath.replace(/\\/g, "/").split("/").pop() ?? "";
|
|
58
|
+
const dot = base.lastIndexOf(".");
|
|
59
|
+
if (dot <= 0) return false;
|
|
60
|
+
return extensions.includes(base.slice(dot).toLowerCase());
|
|
61
|
+
}
|
|
62
|
+
var BUILTIN_LINTERS = {
|
|
63
|
+
eslint: {
|
|
64
|
+
label: "ESLint",
|
|
65
|
+
package: "eslint",
|
|
66
|
+
args: ["--format", "json", "{files}"],
|
|
67
|
+
projectArgs: ["--format", "json", "."],
|
|
68
|
+
extensions: [...SOURCE_EXTENSIONS],
|
|
69
|
+
format: "eslint-json"
|
|
70
|
+
},
|
|
71
|
+
oxlint: {
|
|
72
|
+
label: "oxlint",
|
|
73
|
+
package: "oxlint",
|
|
74
|
+
args: ["--format=json", "--ignore-pattern", "node_modules", "{files}"],
|
|
75
|
+
projectArgs: ["--format=json", "--ignore-pattern", "node_modules", "."],
|
|
76
|
+
extensions: [...SOURCE_EXTENSIONS],
|
|
77
|
+
format: "oxlint-json"
|
|
78
|
+
},
|
|
79
|
+
stylelint: {
|
|
80
|
+
label: "Stylelint",
|
|
81
|
+
package: "stylelint",
|
|
82
|
+
args: ["--formatter", "json", "{files}"],
|
|
83
|
+
projectArgs: ["--formatter", "json", "**/*.{css,scss,less}"],
|
|
84
|
+
extensions: [".css", ".scss", ".less"],
|
|
85
|
+
format: "stylelint-json"
|
|
86
|
+
}
|
|
50
87
|
};
|
|
88
|
+
var DEFAULT_MAX_FINDINGS_PER_SECTION = 3;
|
|
89
|
+
var DEFAULT_MAX_MESSAGE_CHARS = 4e3;
|
|
90
|
+
var DEFAULT_BUILTIN_CHECKS = Object.freeze([
|
|
91
|
+
Object.freeze({ builtin: "eslint" }),
|
|
92
|
+
Object.freeze({ builtin: "oxlint" }),
|
|
93
|
+
Object.freeze({ builtin: "typecheck" })
|
|
94
|
+
]);
|
|
95
|
+
var DEFAULT_DIAGNOSTICS_POLICY = Object.freeze({
|
|
96
|
+
checks: DEFAULT_BUILTIN_CHECKS.map((check) => ({ ...check })),
|
|
97
|
+
auto: true,
|
|
98
|
+
exposeTool: true,
|
|
99
|
+
severity: "warning",
|
|
100
|
+
maxFindingsPerSection: DEFAULT_MAX_FINDINGS_PER_SECTION,
|
|
101
|
+
maxMessageChars: DEFAULT_MAX_MESSAGE_CHARS
|
|
102
|
+
});
|
|
103
|
+
function isCommandCheck(check) {
|
|
104
|
+
return !("builtin" in check);
|
|
105
|
+
}
|
|
106
|
+
function isLinterPreset(check) {
|
|
107
|
+
return "builtin" in check && check.builtin !== "typecheck";
|
|
108
|
+
}
|
|
109
|
+
function isTypecheckCheck(check) {
|
|
110
|
+
return "builtin" in check && check.builtin === "typecheck";
|
|
111
|
+
}
|
|
112
|
+
function checkRunsInPhase(check, phase) {
|
|
113
|
+
const run = check.run ?? "both";
|
|
114
|
+
return run === "both" || run === phase;
|
|
115
|
+
}
|
|
116
|
+
var FORMATS = [
|
|
117
|
+
"text",
|
|
118
|
+
"tsc",
|
|
119
|
+
"eslint-json",
|
|
120
|
+
"oxlint-json",
|
|
121
|
+
"stylelint-json",
|
|
122
|
+
"aipanel-json"
|
|
123
|
+
];
|
|
124
|
+
var RUNS = ["edit", "manual", "both"];
|
|
125
|
+
function normalizeExtensions(raw) {
|
|
126
|
+
if (!Array.isArray(raw)) return void 0;
|
|
127
|
+
const extensions = raw.filter((item) => typeof item === "string" && item.trim() !== "").map((item) => {
|
|
128
|
+
const trimmed = item.trim().toLowerCase();
|
|
129
|
+
return trimmed.startsWith(".") ? trimmed : `.${trimmed}`;
|
|
130
|
+
});
|
|
131
|
+
return extensions.length > 0 ? [...new Set(extensions)] : void 0;
|
|
132
|
+
}
|
|
133
|
+
function normalizeArgs(raw) {
|
|
134
|
+
if (!Array.isArray(raw)) return void 0;
|
|
135
|
+
const args = raw.filter((item) => typeof item === "string");
|
|
136
|
+
return args.length > 0 ? args : void 0;
|
|
137
|
+
}
|
|
138
|
+
function normalizeCheck(raw) {
|
|
139
|
+
if (!raw || typeof raw !== "object") return void 0;
|
|
140
|
+
const value = raw;
|
|
141
|
+
const run = RUNS.includes(value.run) ? value.run : void 0;
|
|
142
|
+
const extensions = normalizeExtensions(value.extensions);
|
|
143
|
+
const cwd = typeof value.cwd === "string" && value.cwd ? { cwd: value.cwd } : {};
|
|
144
|
+
const timeout = typeof value.timeoutMs === "number" && Number.isFinite(value.timeoutMs) && value.timeoutMs > 0 ? { timeoutMs: Math.floor(value.timeoutMs) } : {};
|
|
145
|
+
const format = FORMATS.includes(value.format) ? { format: value.format } : {};
|
|
146
|
+
if (value.builtin !== void 0) {
|
|
147
|
+
if (value.builtin === "typecheck") {
|
|
148
|
+
return {
|
|
149
|
+
builtin: "typecheck",
|
|
150
|
+
...run ? { run } : {},
|
|
151
|
+
...extensions ? { extensions } : {}
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
if (typeof value.builtin === "string" && value.builtin in BUILTIN_LINTERS) {
|
|
155
|
+
const presetArgs = normalizeArgs(value.args);
|
|
156
|
+
const presetProjectArgs = normalizeArgs(value.projectArgs);
|
|
157
|
+
return {
|
|
158
|
+
builtin: value.builtin,
|
|
159
|
+
...presetArgs ? { args: presetArgs } : {},
|
|
160
|
+
...presetProjectArgs ? { projectArgs: presetProjectArgs } : {},
|
|
161
|
+
...extensions ? { extensions } : {},
|
|
162
|
+
...run ? { run } : {},
|
|
163
|
+
...format,
|
|
164
|
+
...cwd,
|
|
165
|
+
...timeout
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
return void 0;
|
|
169
|
+
}
|
|
170
|
+
if (typeof value.name !== "string" || !value.name) return void 0;
|
|
171
|
+
const command = typeof value.command === "string" && value.command ? value.command : void 0;
|
|
172
|
+
const bin = typeof value.bin === "string" && value.bin ? value.bin : void 0;
|
|
173
|
+
if (!command && !bin) return void 0;
|
|
174
|
+
const args = normalizeArgs(value.args);
|
|
175
|
+
const projectArgs = normalizeArgs(value.projectArgs);
|
|
176
|
+
return {
|
|
177
|
+
name: value.name,
|
|
178
|
+
...command ? { command } : {},
|
|
179
|
+
...bin ? { bin } : {},
|
|
180
|
+
...args ? { args } : {},
|
|
181
|
+
...projectArgs ? { projectArgs } : {},
|
|
182
|
+
...extensions ? { extensions } : {},
|
|
183
|
+
...cwd,
|
|
184
|
+
...run ? { run } : {},
|
|
185
|
+
...format,
|
|
186
|
+
...typeof value.adapter === "string" && value.adapter ? { adapter: value.adapter } : {},
|
|
187
|
+
...timeout
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
function normalizeChecks(raw, onInvalid) {
|
|
191
|
+
if (raw === void 0) return void 0;
|
|
192
|
+
if (!Array.isArray(raw)) {
|
|
193
|
+
onInvalid("diagnostics.checks \u5FC5\u987B\u662F\u6570\u7EC4\uFF0C\u5DF2\u56DE\u9000\u4E3A\u5185\u7F6E\u68C0\u67E5");
|
|
194
|
+
return void 0;
|
|
195
|
+
}
|
|
196
|
+
const checks = [];
|
|
197
|
+
for (const item of raw) {
|
|
198
|
+
const check = normalizeCheck(item);
|
|
199
|
+
if (check) checks.push(check);
|
|
200
|
+
else onInvalid(`diagnostics.checks \u542B\u975E\u6CD5\u68C0\u67E5\u9879\uFF0C\u5DF2\u8DF3\u8FC7\uFF1A${JSON.stringify(item)}`);
|
|
201
|
+
}
|
|
202
|
+
if (checks.length === 0) {
|
|
203
|
+
onInvalid("diagnostics.checks \u5F52\u4E00\u5316\u540E\u4E3A\u7A7A\uFF0C\u5DF2\u56DE\u9000\u4E3A\u5185\u7F6E\u68C0\u67E5");
|
|
204
|
+
return void 0;
|
|
205
|
+
}
|
|
206
|
+
return checks;
|
|
207
|
+
}
|
|
208
|
+
function normalizeBoolean(raw, fallback) {
|
|
209
|
+
return typeof raw === "boolean" ? raw : fallback;
|
|
210
|
+
}
|
|
211
|
+
function isValidPositiveInt(raw) {
|
|
212
|
+
return typeof raw === "number" && Number.isFinite(raw) && raw >= 1;
|
|
213
|
+
}
|
|
214
|
+
function normalizePositiveInt(raw, fallback) {
|
|
215
|
+
return isValidPositiveInt(raw) ? Math.floor(raw) : fallback;
|
|
216
|
+
}
|
|
217
|
+
function resolveDiagnosticsPolicy(layers, onInvalid = () => {
|
|
218
|
+
}) {
|
|
219
|
+
let policy = {
|
|
220
|
+
...DEFAULT_DIAGNOSTICS_POLICY,
|
|
221
|
+
checks: DEFAULT_BUILTIN_CHECKS.map((check) => ({ ...check }))
|
|
222
|
+
};
|
|
223
|
+
for (const layer of layers) {
|
|
224
|
+
if (!layer || typeof layer !== "object") continue;
|
|
225
|
+
const checks = normalizeChecks(layer.checks, onInvalid);
|
|
226
|
+
if (layer.severity !== void 0 && layer.severity !== "error" && layer.severity !== "warning") {
|
|
227
|
+
onInvalid(`diagnostics.severity \u53D6\u503C\u975E\u6CD5\uFF08${String(layer.severity)}\uFF09\uFF0C\u5DF2\u56DE\u9000\u4E0A\u4E00\u5C42`);
|
|
228
|
+
}
|
|
229
|
+
if (layer.maxFindingsPerSection !== void 0 && !isValidPositiveInt(layer.maxFindingsPerSection)) {
|
|
230
|
+
onInvalid("diagnostics.maxFindingsPerSection \u5FC5\u987B\u662F \u2265 1 \u7684\u6574\u6570\uFF0C\u5DF2\u56DE\u9000\u4E0A\u4E00\u5C42");
|
|
231
|
+
}
|
|
232
|
+
if (layer.maxMessageChars !== void 0 && !isValidPositiveInt(layer.maxMessageChars)) {
|
|
233
|
+
onInvalid("diagnostics.maxMessageChars \u5FC5\u987B\u662F \u2265 1 \u7684\u6574\u6570\uFF0C\u5DF2\u56DE\u9000\u4E0A\u4E00\u5C42");
|
|
234
|
+
}
|
|
235
|
+
for (const key of ["auto", "exposeTool"]) {
|
|
236
|
+
if (layer[key] !== void 0 && typeof layer[key] !== "boolean") {
|
|
237
|
+
onInvalid(`diagnostics.${key} \u5FC5\u987B\u662F\u5E03\u5C14\u503C\uFF0C\u5DF2\u56DE\u9000\u4E0A\u4E00\u5C42`);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
policy = {
|
|
241
|
+
checks: checks ? checks.map((check) => ({ ...check })) : policy.checks,
|
|
242
|
+
auto: normalizeBoolean(layer.auto, policy.auto),
|
|
243
|
+
exposeTool: normalizeBoolean(layer.exposeTool, policy.exposeTool),
|
|
244
|
+
severity: layer.severity === "error" || layer.severity === "warning" ? layer.severity : policy.severity,
|
|
245
|
+
maxFindingsPerSection: normalizePositiveInt(
|
|
246
|
+
layer.maxFindingsPerSection,
|
|
247
|
+
policy.maxFindingsPerSection
|
|
248
|
+
),
|
|
249
|
+
maxMessageChars: normalizePositiveInt(layer.maxMessageChars, policy.maxMessageChars)
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
return policy;
|
|
253
|
+
}
|
|
51
254
|
|
|
52
255
|
// ../../core/es/common/logger-core.mjs
|
|
53
256
|
var LogLevel = /* @__PURE__ */ ((LogLevel2) => {
|
|
@@ -299,28 +502,16 @@ var PerformanceTimer = class {
|
|
|
299
502
|
// ../../core/es/node/diagnostics.mjs
|
|
300
503
|
import fs from "node:fs";
|
|
301
504
|
import path from "node:path";
|
|
505
|
+
import { pathToFileURL } from "node:url";
|
|
302
506
|
import { execa } from "execa";
|
|
303
507
|
import { createRequire } from "node:module";
|
|
304
508
|
var log2 = createNodeLogger("Diagnostics");
|
|
305
|
-
var JS_EXTENSIONS =
|
|
306
|
-
".js",
|
|
307
|
-
".jsx",
|
|
308
|
-
".ts",
|
|
309
|
-
".tsx",
|
|
310
|
-
".mjs",
|
|
311
|
-
".cjs",
|
|
312
|
-
".mts",
|
|
313
|
-
".cts",
|
|
314
|
-
".vue"
|
|
315
|
-
]);
|
|
316
|
-
function isJsFile(filePath) {
|
|
317
|
-
return JS_EXTENSIONS.has(path.extname(filePath));
|
|
318
|
-
}
|
|
509
|
+
var JS_EXTENSIONS = new Set(SOURCE_EXTENSIONS);
|
|
319
510
|
var DIAGNOSTICS_TOOL_DESCRIPTION = [
|
|
320
|
-
"\u8FD0\u884C Lint
|
|
511
|
+
"\u8FD0\u884C\u9879\u76EE\u914D\u7F6E\u7684\u4EE3\u7801\u68C0\u67E5\uFF08\u9ED8\u8BA4 Lint \u4E0E TypeScript \u7C7B\u578B\u8BCA\u65AD\uFF09\uFF0C\u8FD4\u56DE\u8BCA\u65AD\u7ED3\u679C\u3002",
|
|
321
512
|
"",
|
|
322
513
|
"**\u652F\u6301\u7684\u6587\u4EF6\u7C7B\u578B**\uFF1A",
|
|
323
|
-
`- Lint\uFF1AJavaScript / TypeScript / Vue \u6E90\u7801\uFF08${[...JS_EXTENSIONS].map((e) => `*${e}`).join(" ")}\uFF09\uFF1B\
|
|
514
|
+
`- Lint\uFF1AJavaScript / TypeScript / Vue \u6E90\u7801\uFF08${[...JS_EXTENSIONS].map((e) => `*${e}`).join(" ")}\uFF09\uFF1B\u9879\u76EE\u540C\u65F6\u88C5\u6709 ESLint \u4E0E oxlint \u65F6\u4E92\u8865\u8FD0\u884C\uFF08\u8BCA\u65AD\u6309\u6765\u6E90\u6807\u6CE8\uFF09`,
|
|
324
515
|
"- TypeScript \u7C7B\u578B\u68C0\u67E5\uFF1A*.ts *.tsx *.vue",
|
|
325
516
|
"",
|
|
326
517
|
"**\u4F55\u65F6\u4F7F\u7528\u6B64\u5DE5\u5177**\uFF1A",
|
|
@@ -350,53 +541,14 @@ function resolvePackageBin(basePkgJson, pkgName, binName) {
|
|
|
350
541
|
}
|
|
351
542
|
});
|
|
352
543
|
}
|
|
353
|
-
|
|
354
|
-
function loadESLint(workspace) {
|
|
355
|
-
const basePkgJson = path.join(workspace, "package.json");
|
|
356
|
-
return cachedResolve(_eslintClassByBase, basePkgJson, () => {
|
|
357
|
-
log2.debug("Loading eslint", { workspace });
|
|
358
|
-
try {
|
|
359
|
-
const req = createRequire(basePkgJson);
|
|
360
|
-
const eslintModule = req("eslint");
|
|
361
|
-
const eslintClass = eslintModule.ESLint ?? eslintModule.FlatESLint ?? null;
|
|
362
|
-
log2.debug("eslint loaded", { hasClass: !!eslintClass });
|
|
363
|
-
return eslintClass;
|
|
364
|
-
} catch (e) {
|
|
365
|
-
log2.warn("eslint not found", { error: e.message });
|
|
366
|
-
return null;
|
|
367
|
-
}
|
|
368
|
-
});
|
|
369
|
-
}
|
|
370
|
-
async function lintFiles(pattern, cwd, warnLimit = 5) {
|
|
371
|
-
const eslintClass = loadESLint(cwd);
|
|
372
|
-
const [eslintOutput, oxlintOutput] = await Promise.all([
|
|
373
|
-
eslintClass ? runEslintFiles(eslintClass, pattern, cwd, warnLimit) : Promise.resolve(null),
|
|
374
|
-
runOxlintFiles(pattern, cwd, warnLimit)
|
|
375
|
-
]);
|
|
376
|
-
const engines = [];
|
|
377
|
-
const texts = [];
|
|
378
|
-
const diagnostics = [];
|
|
379
|
-
for (const output of [eslintOutput, oxlintOutput]) {
|
|
380
|
-
if (!output) continue;
|
|
381
|
-
engines.push(...output.engines ?? []);
|
|
382
|
-
if (output.text) texts.push(output.text);
|
|
383
|
-
diagnostics.push(...output.diagnostics ?? []);
|
|
384
|
-
}
|
|
385
|
-
if (engines.length === 0) {
|
|
386
|
-
return {
|
|
387
|
-
text: `[Lint] \u672A\u8FD0\u884C\uFF1A\u65E0\u6CD5\u5728 workspace "${cwd}" \u89E3\u6790\u5230 eslint \u6216 oxlint`,
|
|
388
|
-
diagnostics: []
|
|
389
|
-
};
|
|
390
|
-
}
|
|
391
|
-
return { text: texts.join("\n\n") || void 0, diagnostics, engines };
|
|
392
|
-
}
|
|
393
|
-
function formatLintMessages(messages, engine, warnLimit) {
|
|
394
|
-
if (messages.length === 0) return { engines: [engine.label] };
|
|
544
|
+
function formatLintMessages(messages, engine, warnLimit, minSeverity = "warning") {
|
|
395
545
|
const ESLINT_ERROR = 2;
|
|
396
546
|
const ESLINT_WARN = 1;
|
|
547
|
+
const kept = minSeverity === "error" ? messages.filter((m) => m.severity === ESLINT_ERROR) : messages;
|
|
548
|
+
if (kept.length === 0) return {};
|
|
397
549
|
const lines = [];
|
|
398
|
-
const errors =
|
|
399
|
-
const warnings =
|
|
550
|
+
const errors = kept.filter((m) => m.severity === ESLINT_ERROR);
|
|
551
|
+
const warnings = kept.filter((m) => m.severity === ESLINT_WARN);
|
|
400
552
|
if (errors.length > 0) {
|
|
401
553
|
lines.push(
|
|
402
554
|
...errors.map(
|
|
@@ -426,35 +578,9 @@ function formatLintMessages(messages, engine, warnLimit) {
|
|
|
426
578
|
}));
|
|
427
579
|
return {
|
|
428
580
|
text: lines.length > 0 ? lines.join("\n") : void 0,
|
|
429
|
-
diagnostics
|
|
430
|
-
engines: [engine.label]
|
|
581
|
+
diagnostics
|
|
431
582
|
};
|
|
432
583
|
}
|
|
433
|
-
async function runEslintFiles(eslintClass, pattern, cwd, warnLimit) {
|
|
434
|
-
try {
|
|
435
|
-
const eslint = new eslintClass({ cwd });
|
|
436
|
-
const results = await eslint.lintFiles(pattern);
|
|
437
|
-
const messages = results.flatMap(
|
|
438
|
-
(r) => (r.messages ?? []).map((m) => ({ ...m, filePath: r.filePath }))
|
|
439
|
-
);
|
|
440
|
-
log2.debug("ESLint lint", {
|
|
441
|
-
pattern,
|
|
442
|
-
fileCount: results.length,
|
|
443
|
-
messageCount: messages.length
|
|
444
|
-
});
|
|
445
|
-
return formatLintMessages(messages, { label: "ESLint", source: "eslint" }, warnLimit);
|
|
446
|
-
} catch (err) {
|
|
447
|
-
log2.warn("ESLint failed", { pattern, error: err.message });
|
|
448
|
-
return {
|
|
449
|
-
text: `[ESLint] \u8FD0\u884C\u5931\u8D25\uFF1A${err.message}\uFF08\u4EC5\u663E\u793A TypeScript \u8BCA\u65AD\uFF09`,
|
|
450
|
-
diagnostics: [],
|
|
451
|
-
engines: ["ESLint"]
|
|
452
|
-
};
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
function resolveOxlintBin(workspace) {
|
|
456
|
-
return resolvePackageBin(path.join(workspace, "package.json"), "oxlint", "oxlint");
|
|
457
|
-
}
|
|
458
584
|
function oxlintRuleName(code) {
|
|
459
585
|
if (!code) return null;
|
|
460
586
|
const match = /\(([^)]*)\)$/.exec(code);
|
|
@@ -497,39 +623,6 @@ function parseOxlintOutput(stdout, cwd) {
|
|
|
497
623
|
];
|
|
498
624
|
});
|
|
499
625
|
}
|
|
500
|
-
async function runOxlintFiles(pattern, cwd, warnLimit) {
|
|
501
|
-
const bin = resolveOxlintBin(cwd);
|
|
502
|
-
if (!bin) return {};
|
|
503
|
-
const result = await execa(
|
|
504
|
-
"node",
|
|
505
|
-
[bin, "--format=json", "--ignore-pattern", "node_modules", pattern],
|
|
506
|
-
{ cwd, timeout: 6e4, maxBuffer: 50 * 1024 * 1024, reject: false }
|
|
507
|
-
);
|
|
508
|
-
if (result.timedOut || result.isTerminated || result.isMaxBuffer) {
|
|
509
|
-
log2.warn("oxlint timed out", { pattern });
|
|
510
|
-
return {
|
|
511
|
-
text: "[oxlint] \u8FD0\u884C\u5931\u8D25\uFF1A\u68C0\u67E5\u8D85\u65F6\uFF0C\u8BF7\u5C1D\u8BD5\u7F29\u5C0F\u68C0\u67E5\u8303\u56F4\u3002",
|
|
512
|
-
diagnostics: [],
|
|
513
|
-
engines: ["oxlint"]
|
|
514
|
-
};
|
|
515
|
-
}
|
|
516
|
-
try {
|
|
517
|
-
const messages = parseOxlintOutput(result.stdout, cwd);
|
|
518
|
-
log2.debug("oxlint lint", {
|
|
519
|
-
pattern,
|
|
520
|
-
messageCount: messages.length,
|
|
521
|
-
stderr: result.stderr || void 0
|
|
522
|
-
});
|
|
523
|
-
return formatLintMessages(messages, { label: "oxlint", source: "oxlint" }, warnLimit);
|
|
524
|
-
} catch (e) {
|
|
525
|
-
log2.warn("oxlint failed", { pattern, error: e.message });
|
|
526
|
-
return {
|
|
527
|
-
text: `[oxlint] \u8FD0\u884C\u5931\u8D25\uFF1A${e.message}`,
|
|
528
|
-
diagnostics: [],
|
|
529
|
-
engines: ["oxlint"]
|
|
530
|
-
};
|
|
531
|
-
}
|
|
532
|
-
}
|
|
533
626
|
var BUNDLED_ENGINE_KEY = "<bundled>";
|
|
534
627
|
var _engineCache = /* @__PURE__ */ new Map();
|
|
535
628
|
var _tsVersionCache = /* @__PURE__ */ new Map();
|
|
@@ -820,47 +913,9 @@ async function runTypeChecksForFiles(files, cwd) {
|
|
|
820
913
|
}
|
|
821
914
|
return results;
|
|
822
915
|
}
|
|
823
|
-
async function runAllChecks(pattern, cwd) {
|
|
824
|
-
log2.debug("runAllChecks", { pattern, cwd });
|
|
825
|
-
const [eslintOutput, tscOutput] = await Promise.all([
|
|
826
|
-
lintFiles(pattern, cwd),
|
|
827
|
-
runTypeCheck(pattern, cwd)
|
|
828
|
-
]);
|
|
829
|
-
return { eslintOutput, tscOutput };
|
|
830
|
-
}
|
|
831
|
-
async function runAllChecksForFiles(files, cwd) {
|
|
832
|
-
const targets = [...new Set(files.map((file) => path.resolve(file)))];
|
|
833
|
-
const tscByFile = await runTypeChecksForFiles(targets, cwd);
|
|
834
|
-
const results = /* @__PURE__ */ new Map();
|
|
835
|
-
for (const file of targets) {
|
|
836
|
-
results.set(file, {
|
|
837
|
-
eslintOutput: await lintFiles(file, cwd),
|
|
838
|
-
tscOutput: tscByFile.get(file) ?? { rawOutput: "", exitCode: 0 }
|
|
839
|
-
});
|
|
840
|
-
}
|
|
841
|
-
return results;
|
|
842
|
-
}
|
|
843
|
-
async function runProjectDiagnostics(workspace) {
|
|
844
|
-
const tscDirs = fs.existsSync(path.join(workspace, "tsconfig.json")) ? [workspace] : findAllTsconfigDirs(workspace);
|
|
845
|
-
log2.debug("Tsc dirs to check", { count: tscDirs.length, dirs: tscDirs });
|
|
846
|
-
const [eslintOutput, ...tscOutputs] = await Promise.all([
|
|
847
|
-
lintFiles(".", workspace, 10),
|
|
848
|
-
...tscDirs.map((dir) => runTypeCheck(void 0, dir))
|
|
849
|
-
]);
|
|
850
|
-
const mergedTsc = {
|
|
851
|
-
rawOutput: tscOutputs.flatMap((o) => o.rawOutput).filter(Boolean).join("\n"),
|
|
852
|
-
exitCode: tscOutputs.reduce((max, o) => Math.max(max, o.exitCode), 0),
|
|
853
|
-
diagnostics: tscOutputs.flatMap((o) => o.diagnostics ?? []),
|
|
854
|
-
source: tscOutputs.find((o) => o.source)?.source
|
|
855
|
-
};
|
|
856
|
-
return { eslintOutput, tscOutput: mergedTsc };
|
|
857
|
-
}
|
|
858
916
|
function tscSectionTitle(tscOutput) {
|
|
859
917
|
return tscOutput.source ?? "tsc";
|
|
860
918
|
}
|
|
861
|
-
function lintSectionTitle(lintOutput) {
|
|
862
|
-
return lintOutput.engines?.length ? lintOutput.engines.join(" + ") : "ESLint";
|
|
863
|
-
}
|
|
864
919
|
function omittedFindingsHint(omitted) {
|
|
865
920
|
return `\u2026\u8FD8\u6709 ${omitted} \u6761\uFF0C\u5B8C\u6574\u7ED3\u679C\u8BF7\u8C03\u7528 run_diagnostics`;
|
|
866
921
|
}
|
|
@@ -872,25 +927,482 @@ function boundFindings(text, maxFindings) {
|
|
|
872
927
|
"\n"
|
|
873
928
|
);
|
|
874
929
|
}
|
|
875
|
-
function
|
|
876
|
-
const
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
930
|
+
function displayPath(cwd, file) {
|
|
931
|
+
const rel = path.relative(cwd, file);
|
|
932
|
+
return rel.startsWith("..") || path.isAbsolute(rel) ? file : rel;
|
|
933
|
+
}
|
|
934
|
+
function targetFiles(target) {
|
|
935
|
+
if (target.kind === "file") return [path.resolve(target.file)];
|
|
936
|
+
if (target.kind === "edited") return [...new Set(target.files.map((file) => path.resolve(file)))];
|
|
937
|
+
return [];
|
|
938
|
+
}
|
|
939
|
+
function splitsByFile(target) {
|
|
940
|
+
return target.kind === "edited";
|
|
941
|
+
}
|
|
942
|
+
function filterBySeverity(items, severity) {
|
|
943
|
+
return severity === "error" ? items.filter((item) => item.severity === SEVERITY_ERROR) : [...items];
|
|
944
|
+
}
|
|
945
|
+
function renderDiagnosticLines(items) {
|
|
946
|
+
return items.map((item) => {
|
|
947
|
+
const level = item.severity === SEVERITY_ERROR ? "ERROR" : "WARN";
|
|
948
|
+
const file = item.file ?? "";
|
|
949
|
+
const { line, character } = item.range.start;
|
|
950
|
+
return `${level} [${file}:${line + 1}:${character + 1}] ${item.message}`;
|
|
951
|
+
}).join("\n");
|
|
952
|
+
}
|
|
953
|
+
function entryToDiagnosticItem(entry, source) {
|
|
954
|
+
return {
|
|
955
|
+
file: entry.file,
|
|
956
|
+
severity: entry.severity === "error" ? SEVERITY_ERROR : SEVERITY_WARN,
|
|
957
|
+
range: {
|
|
958
|
+
start: { line: entry.line - 1, character: entry.column - 1 },
|
|
959
|
+
end: { line: entry.line - 1, character: entry.column - 1 }
|
|
960
|
+
},
|
|
961
|
+
message: entry.message,
|
|
962
|
+
source
|
|
963
|
+
};
|
|
964
|
+
}
|
|
965
|
+
function normalizeEntries(value, source) {
|
|
966
|
+
if (value === void 0) return [];
|
|
967
|
+
if (!Array.isArray(value)) throw new Error("diagnostics \u5FC5\u987B\u662F\u6570\u7EC4");
|
|
968
|
+
return value.map((raw, index) => {
|
|
969
|
+
const at = `diagnostics[${index}]`;
|
|
970
|
+
if (!raw || typeof raw !== "object") throw new Error(`${at} \u5FC5\u987B\u662F\u5BF9\u8C61`);
|
|
971
|
+
const entry = raw;
|
|
972
|
+
if (typeof entry.file !== "string" || !entry.file)
|
|
973
|
+
throw new Error(`${at}.file \u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32`);
|
|
974
|
+
if (typeof entry.line !== "number" || entry.line < 1)
|
|
975
|
+
throw new Error(`${at}.line \u5FC5\u987B\u662F \u2265 1 \u7684\u6570\u5B57`);
|
|
976
|
+
if (typeof entry.column !== "number" || entry.column < 1)
|
|
977
|
+
throw new Error(`${at}.column \u5FC5\u987B\u662F \u2265 1 \u7684\u6570\u5B57`);
|
|
978
|
+
if (entry.severity !== "error" && entry.severity !== "warning")
|
|
979
|
+
throw new Error(`${at}.severity \u5FC5\u987B\u662F "error" \u6216 "warning"`);
|
|
980
|
+
if (typeof entry.message !== "string") throw new Error(`${at}.message \u5FC5\u987B\u662F\u5B57\u7B26\u4E32`);
|
|
981
|
+
return entryToDiagnosticItem(entry, source);
|
|
982
|
+
});
|
|
983
|
+
}
|
|
984
|
+
function extractJsonValue(raw) {
|
|
985
|
+
const trimmed = raw.trim();
|
|
986
|
+
try {
|
|
987
|
+
return JSON.parse(trimmed);
|
|
988
|
+
} catch {
|
|
989
|
+
const starts = [raw.indexOf("{"), raw.indexOf("[")].filter((index) => index >= 0);
|
|
990
|
+
if (starts.length === 0) throw new Error("\u672A\u627E\u5230 JSON \u8F93\u51FA");
|
|
991
|
+
const start = Math.min(...starts);
|
|
992
|
+
const close = raw[start] === "{" ? "}" : "]";
|
|
993
|
+
const end = raw.lastIndexOf(close);
|
|
994
|
+
if (end <= start) throw new Error("\u672A\u627E\u5230 JSON \u8F93\u51FA");
|
|
995
|
+
return JSON.parse(raw.slice(start, end + 1));
|
|
883
996
|
}
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
997
|
+
}
|
|
998
|
+
function parseEslintJson(raw, cwd) {
|
|
999
|
+
const parsed = extractJsonValue(raw);
|
|
1000
|
+
if (!Array.isArray(parsed)) throw new Error("\u9876\u5C42\u5FC5\u987B\u662F\u6570\u7EC4");
|
|
1001
|
+
const all = parsed.flatMap(
|
|
1002
|
+
(file) => (file.messages ?? []).map((message) => ({
|
|
1003
|
+
...message,
|
|
1004
|
+
filePath: file.filePath ? path.resolve(cwd, file.filePath) : ""
|
|
1005
|
+
}))
|
|
1006
|
+
);
|
|
1007
|
+
return {
|
|
1008
|
+
messages: all.filter((message) => message.filePath && !isEslintIgnoreNotice(message)),
|
|
1009
|
+
ignored: all.filter((message) => message.filePath && isEslintIgnoreNotice(message)).map((m) => m.filePath)
|
|
1010
|
+
};
|
|
1011
|
+
}
|
|
1012
|
+
function isEslintIgnoreNotice(message) {
|
|
1013
|
+
return (message.ruleId ?? null) === null && typeof message.message === "string" && message.message.startsWith("File ignored because");
|
|
1014
|
+
}
|
|
1015
|
+
function filterTscOutputBySeverity(rawOutput, minSeverity) {
|
|
1016
|
+
if (minSeverity === "warning" || !rawOutput) return rawOutput;
|
|
1017
|
+
const errorLinePat = /^(.+?)\((\d+),(\d+)\):\s+(error|warning)\s+TS\d+:/;
|
|
1018
|
+
const kept = [];
|
|
1019
|
+
let keep = false;
|
|
1020
|
+
for (const line of rawOutput.split("\n")) {
|
|
1021
|
+
const match = errorLinePat.exec(line);
|
|
1022
|
+
if (match) keep = match[4] === "error";
|
|
1023
|
+
else if (!/^\s/.test(line)) keep = false;
|
|
1024
|
+
if (keep) kept.push(line);
|
|
1025
|
+
}
|
|
1026
|
+
return kept.join("\n");
|
|
1027
|
+
}
|
|
1028
|
+
function applyTscSeverity(result, minSeverity) {
|
|
1029
|
+
if (minSeverity === "warning") return result;
|
|
1030
|
+
return {
|
|
1031
|
+
...result,
|
|
1032
|
+
rawOutput: filterTscOutputBySeverity(result.rawOutput, minSeverity),
|
|
1033
|
+
diagnostics: (result.diagnostics ?? []).filter((item) => item.severity === SEVERITY_ERROR)
|
|
1034
|
+
};
|
|
1035
|
+
}
|
|
1036
|
+
function emptySectionText(kind, phase, severity) {
|
|
1037
|
+
if (phase !== "manual") return void 0;
|
|
1038
|
+
if (kind === "typecheck") return "\u6CA1\u6709\u53D1\u73B0\u7C7B\u578B\u9519\u8BEF";
|
|
1039
|
+
return severity === "error" ? "\u6CA1\u6709\u53D1\u73B0\u9519\u8BEF" : "\u6CA1\u6709\u53D1\u73B0\u95EE\u9898";
|
|
1040
|
+
}
|
|
1041
|
+
function buildSection(name2, target, outcome, phase, severity, kind) {
|
|
1042
|
+
const diagnostics = filterBySeverity(outcome.diagnostics ?? [], severity);
|
|
1043
|
+
const explicit = (outcome.text ?? "").trim();
|
|
1044
|
+
const body = explicit || (diagnostics.length > 0 ? renderDiagnosticLines(diagnostics) : emptySectionText(kind, phase, severity) ?? "");
|
|
1045
|
+
const notes = phase === "manual" ? (outcome.notes ?? []).filter(Boolean) : [];
|
|
1046
|
+
const text = [body, ...notes].filter(Boolean).join("\n\n");
|
|
1047
|
+
return {
|
|
1048
|
+
name: name2,
|
|
1049
|
+
...target ? { target } : {},
|
|
1050
|
+
...text ? { text } : {},
|
|
1051
|
+
diagnostics
|
|
1052
|
+
};
|
|
1053
|
+
}
|
|
1054
|
+
function resolveCommandSource(check, cwd) {
|
|
1055
|
+
if (check.command) {
|
|
1056
|
+
return { command: check.command, prefix: [], label: check.command };
|
|
1057
|
+
}
|
|
1058
|
+
const binName = check.bin;
|
|
1059
|
+
const bin = resolvePackageBin(path.join(cwd, "package.json"), binName, binName);
|
|
1060
|
+
if (!bin) {
|
|
1061
|
+
return {
|
|
1062
|
+
command: "node",
|
|
1063
|
+
prefix: [],
|
|
1064
|
+
label: binName,
|
|
1065
|
+
error: `\u9879\u76EE\u91CC\u89E3\u6790\u4E0D\u5230 ${binName}\uFF08\u8BF7\u5148\u5B89\u88C5\u8BE5\u4F9D\u8D56\uFF0C\u6216\u6539\u7528 command \u6307\u5B9A\u53EF\u6267\u884C\u6587\u4EF6\uFF09`
|
|
1066
|
+
};
|
|
1067
|
+
}
|
|
1068
|
+
return { command: "node", prefix: [bin], label: binName };
|
|
1069
|
+
}
|
|
1070
|
+
async function runCommand(check, source, argv, cwd) {
|
|
1071
|
+
const result = await execa(source.command, [...source.prefix, ...argv], {
|
|
1072
|
+
cwd,
|
|
1073
|
+
timeout: check.timeoutMs ?? COMMAND_CHECK_TIMEOUT_MS,
|
|
1074
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
1075
|
+
reject: false,
|
|
1076
|
+
stdin: "ignore"
|
|
1077
|
+
});
|
|
1078
|
+
return {
|
|
1079
|
+
stdout: String(result.stdout ?? ""),
|
|
1080
|
+
stderr: String(result.stderr ?? ""),
|
|
1081
|
+
exitCode: typeof result.exitCode === "number" ? result.exitCode : void 0,
|
|
1082
|
+
failed: result.failed,
|
|
1083
|
+
timedOut: Boolean(result.timedOut || result.isTerminated),
|
|
1084
|
+
overflowed: Boolean(result.isMaxBuffer),
|
|
1085
|
+
message: result.originalMessage
|
|
1086
|
+
};
|
|
1087
|
+
}
|
|
1088
|
+
function commandFailureText(check, source, outcome) {
|
|
1089
|
+
if (outcome.timedOut) {
|
|
1090
|
+
return `[${check.name}] \u8FD0\u884C\u5931\u8D25\uFF1A\u68C0\u67E5\u8D85\u65F6\uFF08${check.timeoutMs ?? COMMAND_CHECK_TIMEOUT_MS}ms\uFF09\uFF0C\u53EF\u63D0\u9AD8 diagnostics.timeoutMs \u6216\u7F29\u5C0F\u68C0\u67E5\u8303\u56F4\u3002`;
|
|
1091
|
+
}
|
|
1092
|
+
if (outcome.overflowed) return `[${check.name}] \u8FD0\u884C\u5931\u8D25\uFF1A\u8F93\u51FA\u8D85\u8FC7\u4E0A\u9650\uFF0C\u8BF7\u7F29\u5C0F\u68C0\u67E5\u8303\u56F4\u3002`;
|
|
1093
|
+
if (outcome.failed && outcome.exitCode === void 0) {
|
|
1094
|
+
return `[${check.name}] \u8FD0\u884C\u5931\u8D25\uFF1A\u65E0\u6CD5\u6267\u884C ${source.label}\uFF08${outcome.message ?? "spawn failed"}\uFF09\u3002`;
|
|
1095
|
+
}
|
|
1096
|
+
return void 0;
|
|
1097
|
+
}
|
|
1098
|
+
function rawCommandOutput(outcome) {
|
|
1099
|
+
return [outcome.stdout, outcome.stderr].map((text) => text.trim()).filter(Boolean).join("\n");
|
|
1100
|
+
}
|
|
1101
|
+
function expandArgs(args, files) {
|
|
1102
|
+
return args.flatMap((arg) => {
|
|
1103
|
+
if (arg === "{file}") return files[0] ? [files[0]] : [];
|
|
1104
|
+
if (arg === "{files}") return [...files];
|
|
1105
|
+
return [
|
|
1106
|
+
arg.replace(
|
|
1107
|
+
/\{file\}|\{files\}/g,
|
|
1108
|
+
(match) => match === "{file}" ? files[0] ?? "" : files.join(" ")
|
|
1109
|
+
)
|
|
1110
|
+
];
|
|
1111
|
+
});
|
|
1112
|
+
}
|
|
1113
|
+
async function runAdapterModule(check, outcome, cwd, files) {
|
|
1114
|
+
const adapterPath = path.resolve(cwd, check.adapter);
|
|
1115
|
+
const fail = (reason) => ({
|
|
1116
|
+
text: `[${check.name}] \u9002\u914D\u5668\u4E0D\u53EF\u7528\uFF1A${check.adapter}\uFF08${reason}\uFF09`,
|
|
1117
|
+
diagnostics: []
|
|
1118
|
+
});
|
|
1119
|
+
let moduleExports;
|
|
1120
|
+
try {
|
|
1121
|
+
moduleExports = await import(pathToFileURL(adapterPath).href);
|
|
1122
|
+
} catch (error) {
|
|
1123
|
+
return fail(error instanceof Error ? error.message : String(error));
|
|
1124
|
+
}
|
|
1125
|
+
if (typeof moduleExports.default !== "function") {
|
|
1126
|
+
return fail("\u6A21\u5757\u5FC5\u987B default export \u4E00\u4E2A\u9002\u914D\u5668\u51FD\u6570");
|
|
1127
|
+
}
|
|
1128
|
+
const input = {
|
|
1129
|
+
name: check.name,
|
|
1130
|
+
stdout: outcome.stdout,
|
|
1131
|
+
stderr: outcome.stderr,
|
|
1132
|
+
exitCode: outcome.exitCode,
|
|
1133
|
+
files: [...files],
|
|
1134
|
+
cwd
|
|
1135
|
+
};
|
|
1136
|
+
let output;
|
|
1137
|
+
try {
|
|
1138
|
+
output = await moduleExports.default(
|
|
1139
|
+
input
|
|
1140
|
+
);
|
|
1141
|
+
} catch (error) {
|
|
1142
|
+
return fail(error instanceof Error ? error.message : String(error));
|
|
1143
|
+
}
|
|
1144
|
+
if (!output || typeof output !== "object") return fail("\u9002\u914D\u5668\u5FC5\u987B\u8FD4\u56DE\u5BF9\u8C61");
|
|
1145
|
+
try {
|
|
1146
|
+
const diagnostics = normalizeEntries(output.diagnostics, check.name);
|
|
1147
|
+
return { text: diagnostics.length > 0 ? void 0 : output.text, diagnostics };
|
|
1148
|
+
} catch (error) {
|
|
1149
|
+
return fail(error instanceof Error ? error.message : String(error));
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
function parseStylelintJson(raw, cwd) {
|
|
1153
|
+
const parsed = extractJsonValue(raw);
|
|
1154
|
+
if (!Array.isArray(parsed)) throw new Error("\u9876\u5C42\u5FC5\u987B\u662F\u6570\u7EC4");
|
|
1155
|
+
return parsed.flatMap((file) => {
|
|
1156
|
+
const filePath = file.source ? path.resolve(cwd, file.source) : "";
|
|
1157
|
+
if (!filePath) return [];
|
|
1158
|
+
return (file.warnings ?? []).map((warning) => ({
|
|
1159
|
+
severity: warning.severity === "error" ? 2 : 1,
|
|
1160
|
+
line: warning.line ?? 1,
|
|
1161
|
+
column: warning.column ?? 1,
|
|
1162
|
+
endLine: warning.endLine,
|
|
1163
|
+
endColumn: warning.endColumn,
|
|
1164
|
+
message: warning.text ?? "\u672A\u77E5\u8BCA\u65AD",
|
|
1165
|
+
ruleId: warning.rule ?? null,
|
|
1166
|
+
filePath
|
|
1167
|
+
}));
|
|
1168
|
+
});
|
|
1169
|
+
}
|
|
1170
|
+
function adaptBuiltinFormat(format, check, raw, cwd, severity) {
|
|
1171
|
+
const lintFromMessages = (messages) => {
|
|
1172
|
+
const output = formatLintMessages(
|
|
1173
|
+
messages,
|
|
1174
|
+
{ label: check.name, source: check.name },
|
|
1175
|
+
10,
|
|
1176
|
+
severity
|
|
1177
|
+
);
|
|
1178
|
+
return { text: output.text, diagnostics: output.diagnostics ?? [] };
|
|
1179
|
+
};
|
|
1180
|
+
switch (format) {
|
|
1181
|
+
case "tsc":
|
|
1182
|
+
return {
|
|
1183
|
+
text: filterTscOutputBySeverity(raw, severity),
|
|
1184
|
+
diagnostics: parseTscDiags(raw, void 0, cwd, check.name)
|
|
1185
|
+
};
|
|
1186
|
+
case "eslint-json": {
|
|
1187
|
+
const { messages, ignored } = parseEslintJson(raw, cwd);
|
|
1188
|
+
return {
|
|
1189
|
+
...lintFromMessages(messages),
|
|
1190
|
+
notes: ignored.map((file) => `${file} \u4E0D\u5728 ESLint \u914D\u7F6E\u8303\u56F4\u5185\uFF0C\u672A\u68C0\u67E5`)
|
|
1191
|
+
};
|
|
1192
|
+
}
|
|
1193
|
+
case "oxlint-json":
|
|
1194
|
+
return lintFromMessages(parseOxlintOutput(raw, cwd));
|
|
1195
|
+
case "stylelint-json":
|
|
1196
|
+
return lintFromMessages(parseStylelintJson(raw, cwd));
|
|
1197
|
+
case "aipanel-json": {
|
|
1198
|
+
const value = extractJsonValue(raw);
|
|
1199
|
+
const payload = Array.isArray(value) ? { diagnostics: value } : value;
|
|
1200
|
+
const diagnostics = normalizeEntries(payload?.diagnostics, check.name);
|
|
1201
|
+
return { text: diagnostics.length > 0 ? void 0 : payload?.text, diagnostics };
|
|
1202
|
+
}
|
|
1203
|
+
case "text":
|
|
1204
|
+
default:
|
|
1205
|
+
return { text: raw, diagnostics: [] };
|
|
1206
|
+
}
|
|
1207
|
+
}
|
|
1208
|
+
function expandLinterPreset(check) {
|
|
1209
|
+
const spec = BUILTIN_LINTERS[check.builtin];
|
|
1210
|
+
return {
|
|
1211
|
+
name: spec.label,
|
|
1212
|
+
bin: spec.bin ?? spec.package,
|
|
1213
|
+
args: check.args ?? [...spec.args],
|
|
1214
|
+
...check.projectArgs ?? spec.projectArgs ? { projectArgs: [...check.projectArgs ?? spec.projectArgs ?? []] } : {},
|
|
1215
|
+
extensions: check.extensions ?? [...spec.extensions],
|
|
1216
|
+
format: check.format ?? spec.format,
|
|
1217
|
+
...check.run ? { run: check.run } : {},
|
|
1218
|
+
...check.cwd ? { cwd: check.cwd } : {},
|
|
1219
|
+
...check.timeoutMs ? { timeoutMs: check.timeoutMs } : {}
|
|
1220
|
+
};
|
|
1221
|
+
}
|
|
1222
|
+
async function runCommandCheck(check, target, phase, severity, optional = false) {
|
|
1223
|
+
const cwd = check.cwd ? path.resolve(target.cwd, check.cwd) : target.cwd;
|
|
1224
|
+
const args = check.args ?? [];
|
|
1225
|
+
const hasPlaceholder = args.some((arg) => arg.includes("{file}") || arg.includes("{files}"));
|
|
1226
|
+
const perFile = args.some((arg) => arg.includes("{file}"));
|
|
1227
|
+
const split = splitsByFile(target);
|
|
1228
|
+
const targeted = target.kind !== "project";
|
|
1229
|
+
const files = targeted ? targetFiles(target).filter((file) => matchesExtensions(file, check.extensions)) : [];
|
|
1230
|
+
if (targeted && hasPlaceholder && files.length === 0) {
|
|
1231
|
+
log2.debug("skip command check: no matching file target", { name: check.name, phase });
|
|
1232
|
+
return [];
|
|
1233
|
+
}
|
|
1234
|
+
const source = resolveCommandSource(check, cwd);
|
|
1235
|
+
if (source.error) {
|
|
1236
|
+
if (optional && phase === "edit") {
|
|
1237
|
+
log2.debug("skip uninstalled builtin linter", { name: check.name });
|
|
1238
|
+
return [];
|
|
1239
|
+
}
|
|
1240
|
+
const text = optional ? `[${check.name}] \u672A\u8FD0\u884C\uFF1A${source.error}` : `[${check.name}] ${source.error}`;
|
|
1241
|
+
return [buildSection(check.name, void 0, { text }, phase, severity, "command")];
|
|
1242
|
+
}
|
|
1243
|
+
const execute = async (argvTemplate, fileSet) => {
|
|
1244
|
+
const outcome = await runCommand(check, source, expandArgs(argvTemplate, fileSet), cwd);
|
|
1245
|
+
const failure = commandFailureText(check, source, outcome);
|
|
1246
|
+
if (failure) return { text: failure, diagnostics: [] };
|
|
1247
|
+
const raw = rawCommandOutput(outcome);
|
|
1248
|
+
try {
|
|
1249
|
+
if (check.adapter) return await runAdapterModule(check, outcome, cwd, fileSet);
|
|
1250
|
+
return adaptBuiltinFormat(check.format ?? "text", check, raw, cwd, severity);
|
|
1251
|
+
} catch (error) {
|
|
1252
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
1253
|
+
const excerpt = raw.replace(/\s+/g, " ").trim().slice(0, 200);
|
|
1254
|
+
return {
|
|
1255
|
+
text: `[${check.name}] \u8FD0\u884C\u5931\u8D25\uFF1A\u8F93\u51FA\u89E3\u6790\u5931\u8D25\uFF08${reason}\uFF09${excerpt ? `\uFF1A${excerpt}` : ""}`,
|
|
1256
|
+
diagnostics: []
|
|
1257
|
+
};
|
|
1258
|
+
}
|
|
1259
|
+
};
|
|
1260
|
+
const targetLabel = (file) => split ? displayPath(target.cwd, file) : void 0;
|
|
1261
|
+
if (!hasPlaceholder) {
|
|
1262
|
+
return [
|
|
1263
|
+
buildSection(check.name, void 0, await execute(args, []), phase, severity, "command")
|
|
1264
|
+
];
|
|
1265
|
+
}
|
|
1266
|
+
if (target.kind === "project") {
|
|
1267
|
+
if (!check.projectArgs) {
|
|
1268
|
+
log2.debug("skip command check: no project args", { name: check.name });
|
|
1269
|
+
return [];
|
|
1270
|
+
}
|
|
1271
|
+
return [
|
|
1272
|
+
buildSection(
|
|
1273
|
+
check.name,
|
|
1274
|
+
void 0,
|
|
1275
|
+
await execute(check.projectArgs, []),
|
|
1276
|
+
phase,
|
|
1277
|
+
severity,
|
|
1278
|
+
"command"
|
|
1279
|
+
)
|
|
1280
|
+
];
|
|
1281
|
+
}
|
|
1282
|
+
if (perFile) {
|
|
1283
|
+
const sections = [];
|
|
1284
|
+
for (const file of files) {
|
|
1285
|
+
const produced2 = await execute(args, [file]);
|
|
1286
|
+
sections.push(
|
|
1287
|
+
buildSection(check.name, targetLabel(file), produced2, phase, severity, "command")
|
|
1288
|
+
);
|
|
1289
|
+
}
|
|
1290
|
+
return sections;
|
|
1291
|
+
}
|
|
1292
|
+
const produced = await execute(args, files);
|
|
1293
|
+
const label = files.length === 1 ? targetLabel(files[0]) : void 0;
|
|
1294
|
+
return [buildSection(check.name, label, produced, phase, severity, "command")];
|
|
1295
|
+
}
|
|
1296
|
+
async function runProjectTypeCheck(workspace, severity) {
|
|
1297
|
+
const dirs = fs.existsSync(path.join(workspace, "tsconfig.json")) ? [workspace] : findAllTsconfigDirs(workspace);
|
|
1298
|
+
log2.debug("Tsc dirs to check", { count: dirs.length, dirs });
|
|
1299
|
+
const results = await Promise.all(dirs.map((dir) => runTypeCheck(void 0, dir)));
|
|
1300
|
+
return applyTscSeverity(
|
|
1301
|
+
{
|
|
1302
|
+
rawOutput: results.flatMap((output) => output.rawOutput).filter(Boolean).join("\n"),
|
|
1303
|
+
exitCode: results.reduce((max, output) => Math.max(max, output.exitCode), 0),
|
|
1304
|
+
diagnostics: results.flatMap((output) => output.diagnostics ?? []),
|
|
1305
|
+
source: results.find((output) => output.source)?.source
|
|
1306
|
+
},
|
|
1307
|
+
severity
|
|
1308
|
+
);
|
|
1309
|
+
}
|
|
1310
|
+
async function runTypecheckCheck(check, target, phase, severity) {
|
|
1311
|
+
const cwd = target.cwd;
|
|
1312
|
+
const split = splitsByFile(target);
|
|
1313
|
+
const files = target.kind === "project" ? [] : targetFiles(target).filter(
|
|
1314
|
+
(file) => matchesExtensions(file, check.extensions ?? SOURCE_EXTENSIONS)
|
|
1315
|
+
);
|
|
1316
|
+
if (target.kind !== "project" && files.length === 0) {
|
|
1317
|
+
log2.debug("skip builtin check: no matching file target", { builtin: check.builtin, phase });
|
|
1318
|
+
return [];
|
|
888
1319
|
}
|
|
889
|
-
if (
|
|
890
|
-
|
|
891
|
-
|
|
1320
|
+
if (split) {
|
|
1321
|
+
const results = await runTypeChecksForFiles(files, cwd);
|
|
1322
|
+
return files.map((file) => {
|
|
1323
|
+
const result2 = applyTscSeverity(
|
|
1324
|
+
results.get(path.resolve(file)) ?? { rawOutput: "", exitCode: 0 },
|
|
1325
|
+
severity
|
|
1326
|
+
);
|
|
1327
|
+
return buildSection(
|
|
1328
|
+
tscSectionTitle(result2),
|
|
1329
|
+
displayPath(cwd, file),
|
|
1330
|
+
{ text: result2.rawOutput.trim(), diagnostics: result2.diagnostics },
|
|
1331
|
+
phase,
|
|
1332
|
+
severity,
|
|
1333
|
+
"typecheck"
|
|
1334
|
+
);
|
|
1335
|
+
});
|
|
1336
|
+
}
|
|
1337
|
+
const result = target.kind === "file" ? applyTscSeverity(await runTypeCheck(files[0], cwd), severity) : await runProjectTypeCheck(cwd, severity);
|
|
1338
|
+
return [
|
|
1339
|
+
buildSection(
|
|
1340
|
+
tscSectionTitle(result),
|
|
1341
|
+
void 0,
|
|
1342
|
+
{ text: result.rawOutput.trim(), diagnostics: result.diagnostics },
|
|
1343
|
+
phase,
|
|
1344
|
+
severity,
|
|
1345
|
+
"typecheck"
|
|
1346
|
+
)
|
|
1347
|
+
];
|
|
1348
|
+
}
|
|
1349
|
+
async function runDiagnostics(target, policy, phase) {
|
|
1350
|
+
const checks = policy.checks.filter((check) => checkRunsInPhase(check, phase));
|
|
1351
|
+
log2.debug("runDiagnostics", { phase, target: target.kind, checks: checks.length });
|
|
1352
|
+
const results = await Promise.all(
|
|
1353
|
+
checks.map((check) => {
|
|
1354
|
+
if (isTypecheckCheck(check)) {
|
|
1355
|
+
return runTypecheckCheck(check, target, phase, policy.severity);
|
|
1356
|
+
}
|
|
1357
|
+
if (isLinterPreset(check)) {
|
|
1358
|
+
return runCommandCheck(expandLinterPreset(check), target, phase, policy.severity, true);
|
|
1359
|
+
}
|
|
1360
|
+
if (isCommandCheck(check)) {
|
|
1361
|
+
return runCommandCheck(check, target, phase, policy.severity);
|
|
1362
|
+
}
|
|
1363
|
+
return Promise.resolve([]);
|
|
1364
|
+
})
|
|
1365
|
+
);
|
|
1366
|
+
const sections = results.flat().filter((section) => section.text !== void 0 || section.diagnostics.length > 0);
|
|
1367
|
+
if (sections.length === 0 && phase === "manual") {
|
|
1368
|
+
return {
|
|
1369
|
+
sections: [
|
|
1370
|
+
{
|
|
1371
|
+
name: "\u68C0\u67E5",
|
|
1372
|
+
text: "\u6CA1\u6709\u53EF\u8FD0\u884C\u7684\u68C0\u67E5\uFF1A\u5DF2\u914D\u7F6E\u7684\u68C0\u67E5\u90FD\u4E0D\u5339\u914D\u672C\u8F6E\u76EE\u6807\uFF08\u68C0\u67E5\u7684 extensions / run \u9636\u6BB5 / \u76EE\u6807\u7C7B\u578B\uFF09\u3002",
|
|
1373
|
+
diagnostics: []
|
|
1374
|
+
}
|
|
1375
|
+
]
|
|
1376
|
+
};
|
|
1377
|
+
}
|
|
1378
|
+
return { sections };
|
|
1379
|
+
}
|
|
1380
|
+
function collectDiagnostics(result) {
|
|
1381
|
+
return result.sections.flatMap((section) => section.diagnostics);
|
|
1382
|
+
}
|
|
1383
|
+
function renderDiagnostics(result, options = {}) {
|
|
1384
|
+
const sections = options.onlyFindings ? result.sections.filter((section) => (section.text ?? "").trim()) : result.sections;
|
|
1385
|
+
if (sections.length === 0) return "";
|
|
1386
|
+
const groups = /* @__PURE__ */ new Map();
|
|
1387
|
+
for (const section of sections) {
|
|
1388
|
+
const key = section.target ?? "";
|
|
1389
|
+
const group = groups.get(key);
|
|
1390
|
+
if (group) group.push(section);
|
|
1391
|
+
else groups.set(key, [section]);
|
|
1392
|
+
}
|
|
1393
|
+
const blocks = [];
|
|
1394
|
+
for (const [key, group] of groups) {
|
|
1395
|
+
const body = group.map((section) => {
|
|
1396
|
+
const text = boundFindings(section.text, options.maxFindingsPerSection);
|
|
1397
|
+
return `## ${section.name}
|
|
1398
|
+
|
|
1399
|
+
${text || "\u6CA1\u6709\u53D1\u73B0\u95EE\u9898"}`;
|
|
1400
|
+
}).join("\n\n");
|
|
1401
|
+
blocks.push(key ? `### ${key}
|
|
892
1402
|
|
|
893
|
-
${body}` : body;
|
|
1403
|
+
${body}` : body);
|
|
1404
|
+
}
|
|
1405
|
+
return blocks.join("\n\n");
|
|
894
1406
|
}
|
|
895
1407
|
|
|
896
1408
|
// ../../core/es/common/utils.mjs
|
|
@@ -1149,8 +1661,6 @@ function buildPluginMessage(text, notice) {
|
|
|
1149
1661
|
source
|
|
1150
1662
|
};
|
|
1151
1663
|
}
|
|
1152
|
-
var DIAGNOSTICS_MESSAGE_MAX_CHARS = 4e3;
|
|
1153
|
-
var MAX_FINDINGS_PER_SECTION = 3;
|
|
1154
1664
|
function editTarget(exec) {
|
|
1155
1665
|
const rawArgs = exec.arguments;
|
|
1156
1666
|
const filePath = typeof rawArgs?.file_path === "string" ? rawArgs.file_path : rawArgs?.filePath;
|
|
@@ -1161,7 +1671,7 @@ function registerPendingEdit(pending, exec, result, decision, cwd) {
|
|
|
1161
1671
|
if (result.isError) return;
|
|
1162
1672
|
if (decision.kind !== "accept") return;
|
|
1163
1673
|
const filePath = editTarget(exec);
|
|
1164
|
-
if (!filePath
|
|
1674
|
+
if (!filePath) return;
|
|
1165
1675
|
const { agent } = exec;
|
|
1166
1676
|
if (!agent) return;
|
|
1167
1677
|
let files = pending.get(agent);
|
|
@@ -1171,36 +1681,24 @@ function registerPendingEdit(pending, exec, result, decision, cwd) {
|
|
|
1171
1681
|
}
|
|
1172
1682
|
files.add(path2.resolve(cwd, filePath));
|
|
1173
1683
|
}
|
|
1174
|
-
function truncateDiagnostics(text) {
|
|
1175
|
-
if (text.length <=
|
|
1176
|
-
return `${text.slice(0,
|
|
1684
|
+
function truncateDiagnostics(text, maxChars) {
|
|
1685
|
+
if (text.length <= maxChars) return text;
|
|
1686
|
+
return `${text.slice(0, maxChars)}
|
|
1177
1687
|
|
|
1178
1688
|
\u2026\uFF08\u8BCA\u65AD\u8F93\u51FA\u8FC7\u957F\uFF0C\u5DF2\u622A\u65AD\uFF1B\u53EF\u8C03\u7528 run_diagnostics \u67E5\u770B\u5B8C\u6574\u7ED3\u679C\uFF09`;
|
|
1179
1689
|
}
|
|
1180
|
-
async function collectPendingDiagnostics(pending, cwd) {
|
|
1690
|
+
async function collectPendingDiagnostics(pending, cwd, policy) {
|
|
1181
1691
|
const files = [...pending];
|
|
1182
|
-
const
|
|
1183
|
-
() =>
|
|
1692
|
+
const result = await runDiagnostics({ kind: "edited", files, cwd }, policy, "edit").catch(
|
|
1693
|
+
() => ({ sections: [] })
|
|
1184
1694
|
);
|
|
1185
|
-
const
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
};
|
|
1189
|
-
|
|
1190
|
-
for (const file of files) {
|
|
1191
|
-
const { eslintOutput, tscOutput } = checks.get(file) ?? empty;
|
|
1192
|
-
const section = formatDiagnosticsSections(
|
|
1193
|
-
`### ${path2.relative(cwd, file)}`,
|
|
1194
|
-
eslintOutput,
|
|
1195
|
-
tscOutput,
|
|
1196
|
-
{ onlyFindings: true, maxFindingsPerSection: MAX_FINDINGS_PER_SECTION }
|
|
1197
|
-
);
|
|
1198
|
-
if (!section) continue;
|
|
1199
|
-
blocks.push(section);
|
|
1200
|
-
}
|
|
1201
|
-
return blocks.length > 0 ? truncateDiagnostics(`\u81EA\u52A8\u8BCA\u65AD\uFF08\u7F16\u8F91\u540E\uFF09\uFF1A
|
|
1695
|
+
const text = renderDiagnostics(result, {
|
|
1696
|
+
onlyFindings: true,
|
|
1697
|
+
maxFindingsPerSection: policy.maxFindingsPerSection
|
|
1698
|
+
});
|
|
1699
|
+
return text ? truncateDiagnostics(`\u81EA\u52A8\u8BCA\u65AD\uFF08\u7F16\u8F91\u540E\uFF09\uFF1A
|
|
1202
1700
|
|
|
1203
|
-
${
|
|
1701
|
+
${text}`, policy.maxMessageChars) : "";
|
|
1204
1702
|
}
|
|
1205
1703
|
function toDiagnosticEntries(items) {
|
|
1206
1704
|
return items.map((d) => ({
|
|
@@ -1211,17 +1709,14 @@ function toDiagnosticEntries(items) {
|
|
|
1211
1709
|
message: d.message
|
|
1212
1710
|
}));
|
|
1213
1711
|
}
|
|
1214
|
-
function buildDiagnosticsCanonical(title,
|
|
1712
|
+
function buildDiagnosticsCanonical(title, result) {
|
|
1215
1713
|
return {
|
|
1216
1714
|
title,
|
|
1217
|
-
sections:
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
diagnostics:
|
|
1222
|
-
...toDiagnosticEntries(eslintOutput.diagnostics ?? []),
|
|
1223
|
-
...toDiagnosticEntries(tscOutput.diagnostics ?? [])
|
|
1224
|
-
]
|
|
1715
|
+
sections: result.sections.map((section) => ({
|
|
1716
|
+
title: section.target ? `${section.target} \xB7 ${section.name}` : section.name,
|
|
1717
|
+
text: section.text ?? "\u6CA1\u6709\u53D1\u73B0\u95EE\u9898"
|
|
1718
|
+
})),
|
|
1719
|
+
diagnostics: toDiagnosticEntries(collectDiagnostics(result))
|
|
1225
1720
|
};
|
|
1226
1721
|
}
|
|
1227
1722
|
function renderDiagnosticsText(value) {
|
|
@@ -1296,13 +1791,15 @@ function applyProviderSettings(ctx, config) {
|
|
|
1296
1791
|
}
|
|
1297
1792
|
function apply(ctx, config = {}) {
|
|
1298
1793
|
const cwd = config.cwd ?? process.cwd();
|
|
1299
|
-
const
|
|
1300
|
-
|
|
1794
|
+
const policy = resolveDiagnosticsPolicy(
|
|
1795
|
+
[DEFAULT_DIAGNOSTICS_POLICY, config.diagnostics],
|
|
1796
|
+
(message) => log4.warn(message)
|
|
1797
|
+
);
|
|
1301
1798
|
const vitePort = config.vitePort ?? 0;
|
|
1302
1799
|
const viteHost = config.viteHost;
|
|
1303
1800
|
const contextApiPath = config.contextApiPath ?? CONTEXT_API_PATH;
|
|
1304
1801
|
const tools = ctx.tools;
|
|
1305
|
-
if (
|
|
1802
|
+
if (policy.exposeTool) {
|
|
1306
1803
|
const diagnosticsTool = {
|
|
1307
1804
|
name: "run_diagnostics",
|
|
1308
1805
|
description: DIAGNOSTICS_TOOL_DESCRIPTION,
|
|
@@ -1353,7 +1850,7 @@ function apply(ctx, config = {}) {
|
|
|
1353
1850
|
},
|
|
1354
1851
|
required: ["title", "sections", "diagnostics"]
|
|
1355
1852
|
},
|
|
1356
|
-
// canonical →
|
|
1853
|
+
// canonical → 模型可见文本(分区标题由配置的检查给出,与 renderDiagnostics 一致)
|
|
1357
1854
|
render: (_args, value) => [
|
|
1358
1855
|
{ type: "text", text: renderDiagnosticsText(value) }
|
|
1359
1856
|
],
|
|
@@ -1364,27 +1861,28 @@ function apply(ctx, config = {}) {
|
|
|
1364
1861
|
},
|
|
1365
1862
|
async execute(args) {
|
|
1366
1863
|
const filePath = args?.filePath;
|
|
1864
|
+
let target;
|
|
1865
|
+
let title;
|
|
1367
1866
|
if (typeof filePath === "string" && filePath) {
|
|
1368
1867
|
const resolved = path2.resolve(cwd, filePath);
|
|
1369
1868
|
if (!fs2.existsSync(resolved)) throw new Error(`\u6587\u4EF6\u4E0D\u5B58\u5728: ${resolved}`);
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
);
|
|
1869
|
+
target = { kind: "file", file: resolved, cwd };
|
|
1870
|
+
title = `\u8BCA\u65AD\u7ED3\u679C: ${path2.relative(cwd, resolved)}`;
|
|
1871
|
+
} else {
|
|
1872
|
+
target = { kind: "project", cwd };
|
|
1873
|
+
title = "\u5168\u91CF\u8BCA\u65AD\u7ED3\u679C";
|
|
1376
1874
|
}
|
|
1377
|
-
|
|
1378
|
-
return buildDiagnosticsCanonical("\u5168\u91CF\u8BCA\u65AD\u7ED3\u679C", eslintOutput, tscOutput);
|
|
1875
|
+
return buildDiagnosticsCanonical(title, await runDiagnostics(target, policy, "manual"));
|
|
1379
1876
|
}
|
|
1380
1877
|
};
|
|
1381
1878
|
tools.register(diagnosticsTool);
|
|
1879
|
+
}
|
|
1880
|
+
if (policy.auto) {
|
|
1382
1881
|
const pendingEdits = /* @__PURE__ */ new WeakMap();
|
|
1383
1882
|
ctx.on(
|
|
1384
1883
|
"tools/post-execute",
|
|
1385
1884
|
async (exec, result, next) => {
|
|
1386
1885
|
const decision = await next();
|
|
1387
|
-
if (!autoDiagnose) return decision;
|
|
1388
1886
|
registerPendingEdit(pendingEdits, exec, result, decision, cwd);
|
|
1389
1887
|
return decision;
|
|
1390
1888
|
}
|
|
@@ -1393,12 +1891,11 @@ function apply(ctx, config = {}) {
|
|
|
1393
1891
|
"agent/pre-step",
|
|
1394
1892
|
async ({ agent }, next) => {
|
|
1395
1893
|
const decision = await next();
|
|
1396
|
-
if (!autoDiagnose) return decision;
|
|
1397
1894
|
const files = pendingEdits.get(agent);
|
|
1398
1895
|
if (!files || files.size === 0) return decision;
|
|
1399
1896
|
pendingEdits.delete(agent);
|
|
1400
1897
|
if (decision.kind === "reject") return decision;
|
|
1401
|
-
const text = await collectPendingDiagnostics(files, cwd);
|
|
1898
|
+
const text = await collectPendingDiagnostics(files, cwd, policy);
|
|
1402
1899
|
if (!text) return decision;
|
|
1403
1900
|
return {
|
|
1404
1901
|
...decision,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aipanel/dsh-plugin",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.6",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "AIPanel for DeepSeek Harness (dsh):注入审查工具 run_diagnostics、编辑后自动诊断。",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"vue-tsc": "^3.3.9"
|
|
17
17
|
},
|
|
18
18
|
"devDependencies": {
|
|
19
|
-
"@aipanel/core": "1.3.
|
|
19
|
+
"@aipanel/core": "1.3.6",
|
|
20
20
|
"@deepseek-ai/cordis": "~4.0.4",
|
|
21
21
|
"@deepseek-ai/dsh-agent": "^0.1.7-alpha.2",
|
|
22
22
|
"@deepseek-ai/dsh-llm": "^0.1.7-alpha.2",
|