@aipanel/core 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/es/common/constants.d.ts +3 -2
- package/es/common/constants.mjs +2 -1
- package/es/common/diagnostics.d.ts +199 -0
- package/es/common/diagnostics.mjs +226 -0
- package/es/common/options.d.ts +0 -2
- package/es/index.d.ts +1 -0
- package/es/index.mjs +1 -0
- package/es/node/diagnostics.d.ts +52 -34
- package/es/node/diagnostics.mjs +496 -177
- package/es/node.d.ts +1 -0
- package/es/node.mjs +1 -0
- package/lib/common/constants.cjs +2 -1
- package/lib/common/constants.d.ts +3 -2
- package/lib/common/diagnostics.cjs +261 -0
- package/lib/common/diagnostics.d.ts +199 -0
- package/lib/common/options.d.ts +0 -2
- package/lib/index.cjs +2 -0
- package/lib/index.d.ts +1 -0
- package/lib/node/diagnostics.cjs +490 -183
- package/lib/node/diagnostics.d.ts +52 -34
- package/lib/node.cjs +2 -0
- package/lib/node.d.ts +1 -0
- package/package.json +1 -1
package/es/node.d.ts
CHANGED
package/es/node.mjs
CHANGED
package/lib/common/constants.cjs
CHANGED
|
@@ -203,7 +203,8 @@ const OPENCODE_ENV = {
|
|
|
203
203
|
VITE_LOGS_API_URL: "OPENCODE_VITE_LOGS_API_URL",
|
|
204
204
|
LOG_FILES_JSON: "OPENCODE_LOG_FILES_JSON",
|
|
205
205
|
VERBOSE: "OPENCODE_VERBOSE",
|
|
206
|
-
|
|
206
|
+
/** 诊断策略 JSON(DiagnosticsPolicy):provider 写,opencode 插件读 */
|
|
207
|
+
DIAGNOSTICS: "OPENCODE_DIAGNOSTICS",
|
|
207
208
|
VUE_DEVTOOLS_API_URL: "OPENCODE_VUE_DEVTOOLS_API_URL",
|
|
208
209
|
WORKSPACE: "OPENCODE_WORKSPACE"
|
|
209
210
|
};
|
|
@@ -196,14 +196,15 @@ export declare const MUTATING_TOOLS: ReadonlySet<string>;
|
|
|
196
196
|
/** 挂件主题可选值(对应 AIPanelWidgetTheme) */
|
|
197
197
|
export declare const WIDGET_THEME_MODES: readonly ["auto", "light", "dark"];
|
|
198
198
|
/** ==================== OpenCode 环境变量名 ==================== */
|
|
199
|
-
/** OpenCode 相关环境变量名(opencode provider 写、es/plugins
|
|
199
|
+
/** OpenCode 相关环境变量名(opencode provider 写、es/plugins 读,统一引用防止字面量漂移) */
|
|
200
200
|
export declare const OPENCODE_ENV: {
|
|
201
201
|
readonly CONFIG_DIR: "OPENCODE_CONFIG_DIR";
|
|
202
202
|
readonly CONTEXT_API_URL: "OPENCODE_CONTEXT_API_URL";
|
|
203
203
|
readonly VITE_LOGS_API_URL: "OPENCODE_VITE_LOGS_API_URL";
|
|
204
204
|
readonly LOG_FILES_JSON: "OPENCODE_LOG_FILES_JSON";
|
|
205
205
|
readonly VERBOSE: "OPENCODE_VERBOSE";
|
|
206
|
-
|
|
206
|
+
/** 诊断策略 JSON(DiagnosticsPolicy):provider 写,opencode 插件读 */
|
|
207
|
+
readonly DIAGNOSTICS: "OPENCODE_DIAGNOSTICS";
|
|
207
208
|
readonly VUE_DEVTOOLS_API_URL: "OPENCODE_VUE_DEVTOOLS_API_URL";
|
|
208
209
|
readonly WORKSPACE: "OPENCODE_WORKSPACE";
|
|
209
210
|
};
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __export = (target, all) => {
|
|
6
|
+
for (var name in all)
|
|
7
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
8
|
+
};
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
|
+
var diagnostics_exports = {};
|
|
19
|
+
__export(diagnostics_exports, {
|
|
20
|
+
BUILTIN_LINTERS: () => BUILTIN_LINTERS,
|
|
21
|
+
COMMAND_CHECK_TIMEOUT_MS: () => COMMAND_CHECK_TIMEOUT_MS,
|
|
22
|
+
DEFAULT_BUILTIN_CHECKS: () => DEFAULT_BUILTIN_CHECKS,
|
|
23
|
+
DEFAULT_DIAGNOSTICS_POLICY: () => DEFAULT_DIAGNOSTICS_POLICY,
|
|
24
|
+
DEFAULT_MAX_FINDINGS_PER_SECTION: () => DEFAULT_MAX_FINDINGS_PER_SECTION,
|
|
25
|
+
DEFAULT_MAX_MESSAGE_CHARS: () => DEFAULT_MAX_MESSAGE_CHARS,
|
|
26
|
+
SOURCE_EXTENSIONS: () => SOURCE_EXTENSIONS,
|
|
27
|
+
checkRunsInPhase: () => checkRunsInPhase,
|
|
28
|
+
isCommandCheck: () => isCommandCheck,
|
|
29
|
+
isLinterPreset: () => isLinterPreset,
|
|
30
|
+
isTypecheckCheck: () => isTypecheckCheck,
|
|
31
|
+
matchesExtensions: () => matchesExtensions,
|
|
32
|
+
resolveDiagnosticsPolicy: () => resolveDiagnosticsPolicy
|
|
33
|
+
});
|
|
34
|
+
module.exports = __toCommonJS(diagnostics_exports);
|
|
35
|
+
const COMMAND_CHECK_TIMEOUT_MS = 6e4;
|
|
36
|
+
const SOURCE_EXTENSIONS = [
|
|
37
|
+
".js",
|
|
38
|
+
".jsx",
|
|
39
|
+
".ts",
|
|
40
|
+
".tsx",
|
|
41
|
+
".mjs",
|
|
42
|
+
".cjs",
|
|
43
|
+
".mts",
|
|
44
|
+
".cts",
|
|
45
|
+
".vue"
|
|
46
|
+
];
|
|
47
|
+
function matchesExtensions(filePath, extensions) {
|
|
48
|
+
if (!extensions?.length) return true;
|
|
49
|
+
const base = filePath.replace(/\\/g, "/").split("/").pop() ?? "";
|
|
50
|
+
const dot = base.lastIndexOf(".");
|
|
51
|
+
if (dot <= 0) return false;
|
|
52
|
+
return extensions.includes(base.slice(dot).toLowerCase());
|
|
53
|
+
}
|
|
54
|
+
const BUILTIN_LINTERS = {
|
|
55
|
+
eslint: {
|
|
56
|
+
label: "ESLint",
|
|
57
|
+
package: "eslint",
|
|
58
|
+
args: ["--format", "json", "{files}"],
|
|
59
|
+
projectArgs: ["--format", "json", "."],
|
|
60
|
+
extensions: [...SOURCE_EXTENSIONS],
|
|
61
|
+
format: "eslint-json"
|
|
62
|
+
},
|
|
63
|
+
oxlint: {
|
|
64
|
+
label: "oxlint",
|
|
65
|
+
package: "oxlint",
|
|
66
|
+
args: ["--format=json", "--ignore-pattern", "node_modules", "{files}"],
|
|
67
|
+
projectArgs: ["--format=json", "--ignore-pattern", "node_modules", "."],
|
|
68
|
+
extensions: [...SOURCE_EXTENSIONS],
|
|
69
|
+
format: "oxlint-json"
|
|
70
|
+
},
|
|
71
|
+
stylelint: {
|
|
72
|
+
label: "Stylelint",
|
|
73
|
+
package: "stylelint",
|
|
74
|
+
args: ["--formatter", "json", "{files}"],
|
|
75
|
+
projectArgs: ["--formatter", "json", "**/*.{css,scss,less}"],
|
|
76
|
+
extensions: [".css", ".scss", ".less"],
|
|
77
|
+
format: "stylelint-json"
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
const DEFAULT_MAX_FINDINGS_PER_SECTION = 3;
|
|
81
|
+
const DEFAULT_MAX_MESSAGE_CHARS = 4e3;
|
|
82
|
+
const DEFAULT_BUILTIN_CHECKS = Object.freeze([
|
|
83
|
+
Object.freeze({ builtin: "eslint" }),
|
|
84
|
+
Object.freeze({ builtin: "oxlint" }),
|
|
85
|
+
Object.freeze({ builtin: "typecheck" })
|
|
86
|
+
]);
|
|
87
|
+
const DEFAULT_DIAGNOSTICS_POLICY = Object.freeze({
|
|
88
|
+
checks: DEFAULT_BUILTIN_CHECKS.map((check) => ({ ...check })),
|
|
89
|
+
auto: true,
|
|
90
|
+
exposeTool: true,
|
|
91
|
+
severity: "warning",
|
|
92
|
+
maxFindingsPerSection: DEFAULT_MAX_FINDINGS_PER_SECTION,
|
|
93
|
+
maxMessageChars: DEFAULT_MAX_MESSAGE_CHARS
|
|
94
|
+
});
|
|
95
|
+
function isCommandCheck(check) {
|
|
96
|
+
return !("builtin" in check);
|
|
97
|
+
}
|
|
98
|
+
function isLinterPreset(check) {
|
|
99
|
+
return "builtin" in check && check.builtin !== "typecheck";
|
|
100
|
+
}
|
|
101
|
+
function isTypecheckCheck(check) {
|
|
102
|
+
return "builtin" in check && check.builtin === "typecheck";
|
|
103
|
+
}
|
|
104
|
+
function checkRunsInPhase(check, phase) {
|
|
105
|
+
const run = check.run ?? "both";
|
|
106
|
+
return run === "both" || run === phase;
|
|
107
|
+
}
|
|
108
|
+
const FORMATS = [
|
|
109
|
+
"text",
|
|
110
|
+
"tsc",
|
|
111
|
+
"eslint-json",
|
|
112
|
+
"oxlint-json",
|
|
113
|
+
"stylelint-json",
|
|
114
|
+
"aipanel-json"
|
|
115
|
+
];
|
|
116
|
+
const RUNS = ["edit", "manual", "both"];
|
|
117
|
+
function normalizeExtensions(raw) {
|
|
118
|
+
if (!Array.isArray(raw)) return void 0;
|
|
119
|
+
const extensions = raw.filter((item) => typeof item === "string" && item.trim() !== "").map((item) => {
|
|
120
|
+
const trimmed = item.trim().toLowerCase();
|
|
121
|
+
return trimmed.startsWith(".") ? trimmed : `.${trimmed}`;
|
|
122
|
+
});
|
|
123
|
+
return extensions.length > 0 ? [...new Set(extensions)] : void 0;
|
|
124
|
+
}
|
|
125
|
+
function normalizeArgs(raw) {
|
|
126
|
+
if (!Array.isArray(raw)) return void 0;
|
|
127
|
+
const args = raw.filter((item) => typeof item === "string");
|
|
128
|
+
return args.length > 0 ? args : void 0;
|
|
129
|
+
}
|
|
130
|
+
function normalizeCheck(raw) {
|
|
131
|
+
if (!raw || typeof raw !== "object") return void 0;
|
|
132
|
+
const value = raw;
|
|
133
|
+
const run = RUNS.includes(value.run) ? value.run : void 0;
|
|
134
|
+
const extensions = normalizeExtensions(value.extensions);
|
|
135
|
+
const cwd = typeof value.cwd === "string" && value.cwd ? { cwd: value.cwd } : {};
|
|
136
|
+
const timeout = typeof value.timeoutMs === "number" && Number.isFinite(value.timeoutMs) && value.timeoutMs > 0 ? { timeoutMs: Math.floor(value.timeoutMs) } : {};
|
|
137
|
+
const format = FORMATS.includes(value.format) ? { format: value.format } : {};
|
|
138
|
+
if (value.builtin !== void 0) {
|
|
139
|
+
if (value.builtin === "typecheck") {
|
|
140
|
+
return {
|
|
141
|
+
builtin: "typecheck",
|
|
142
|
+
...run ? { run } : {},
|
|
143
|
+
...extensions ? { extensions } : {}
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
if (typeof value.builtin === "string" && value.builtin in BUILTIN_LINTERS) {
|
|
147
|
+
const presetArgs = normalizeArgs(value.args);
|
|
148
|
+
const presetProjectArgs = normalizeArgs(value.projectArgs);
|
|
149
|
+
return {
|
|
150
|
+
builtin: value.builtin,
|
|
151
|
+
...presetArgs ? { args: presetArgs } : {},
|
|
152
|
+
...presetProjectArgs ? { projectArgs: presetProjectArgs } : {},
|
|
153
|
+
...extensions ? { extensions } : {},
|
|
154
|
+
...run ? { run } : {},
|
|
155
|
+
...format,
|
|
156
|
+
...cwd,
|
|
157
|
+
...timeout
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
return void 0;
|
|
161
|
+
}
|
|
162
|
+
if (typeof value.name !== "string" || !value.name) return void 0;
|
|
163
|
+
const command = typeof value.command === "string" && value.command ? value.command : void 0;
|
|
164
|
+
const bin = typeof value.bin === "string" && value.bin ? value.bin : void 0;
|
|
165
|
+
if (!command && !bin) return void 0;
|
|
166
|
+
const args = normalizeArgs(value.args);
|
|
167
|
+
const projectArgs = normalizeArgs(value.projectArgs);
|
|
168
|
+
return {
|
|
169
|
+
name: value.name,
|
|
170
|
+
...command ? { command } : {},
|
|
171
|
+
...bin ? { bin } : {},
|
|
172
|
+
...args ? { args } : {},
|
|
173
|
+
...projectArgs ? { projectArgs } : {},
|
|
174
|
+
...extensions ? { extensions } : {},
|
|
175
|
+
...cwd,
|
|
176
|
+
...run ? { run } : {},
|
|
177
|
+
...format,
|
|
178
|
+
...typeof value.adapter === "string" && value.adapter ? { adapter: value.adapter } : {},
|
|
179
|
+
...timeout
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
function normalizeChecks(raw, onInvalid) {
|
|
183
|
+
if (raw === void 0) return void 0;
|
|
184
|
+
if (!Array.isArray(raw)) {
|
|
185
|
+
onInvalid("diagnostics.checks \u5FC5\u987B\u662F\u6570\u7EC4\uFF0C\u5DF2\u56DE\u9000\u4E3A\u5185\u7F6E\u68C0\u67E5");
|
|
186
|
+
return void 0;
|
|
187
|
+
}
|
|
188
|
+
const checks = [];
|
|
189
|
+
for (const item of raw) {
|
|
190
|
+
const check = normalizeCheck(item);
|
|
191
|
+
if (check) checks.push(check);
|
|
192
|
+
else onInvalid(`diagnostics.checks \u542B\u975E\u6CD5\u68C0\u67E5\u9879\uFF0C\u5DF2\u8DF3\u8FC7\uFF1A${JSON.stringify(item)}`);
|
|
193
|
+
}
|
|
194
|
+
if (checks.length === 0) {
|
|
195
|
+
onInvalid("diagnostics.checks \u5F52\u4E00\u5316\u540E\u4E3A\u7A7A\uFF0C\u5DF2\u56DE\u9000\u4E3A\u5185\u7F6E\u68C0\u67E5");
|
|
196
|
+
return void 0;
|
|
197
|
+
}
|
|
198
|
+
return checks;
|
|
199
|
+
}
|
|
200
|
+
function normalizeBoolean(raw, fallback) {
|
|
201
|
+
return typeof raw === "boolean" ? raw : fallback;
|
|
202
|
+
}
|
|
203
|
+
function isValidPositiveInt(raw) {
|
|
204
|
+
return typeof raw === "number" && Number.isFinite(raw) && raw >= 1;
|
|
205
|
+
}
|
|
206
|
+
function normalizePositiveInt(raw, fallback) {
|
|
207
|
+
return isValidPositiveInt(raw) ? Math.floor(raw) : fallback;
|
|
208
|
+
}
|
|
209
|
+
function resolveDiagnosticsPolicy(layers, onInvalid = () => {
|
|
210
|
+
}) {
|
|
211
|
+
let policy = {
|
|
212
|
+
...DEFAULT_DIAGNOSTICS_POLICY,
|
|
213
|
+
checks: DEFAULT_BUILTIN_CHECKS.map((check) => ({ ...check }))
|
|
214
|
+
};
|
|
215
|
+
for (const layer of layers) {
|
|
216
|
+
if (!layer || typeof layer !== "object") continue;
|
|
217
|
+
const checks = normalizeChecks(layer.checks, onInvalid);
|
|
218
|
+
if (layer.severity !== void 0 && layer.severity !== "error" && layer.severity !== "warning") {
|
|
219
|
+
onInvalid(`diagnostics.severity \u53D6\u503C\u975E\u6CD5\uFF08${String(layer.severity)}\uFF09\uFF0C\u5DF2\u56DE\u9000\u4E0A\u4E00\u5C42`);
|
|
220
|
+
}
|
|
221
|
+
if (layer.maxFindingsPerSection !== void 0 && !isValidPositiveInt(layer.maxFindingsPerSection)) {
|
|
222
|
+
onInvalid("diagnostics.maxFindingsPerSection \u5FC5\u987B\u662F \u2265 1 \u7684\u6574\u6570\uFF0C\u5DF2\u56DE\u9000\u4E0A\u4E00\u5C42");
|
|
223
|
+
}
|
|
224
|
+
if (layer.maxMessageChars !== void 0 && !isValidPositiveInt(layer.maxMessageChars)) {
|
|
225
|
+
onInvalid("diagnostics.maxMessageChars \u5FC5\u987B\u662F \u2265 1 \u7684\u6574\u6570\uFF0C\u5DF2\u56DE\u9000\u4E0A\u4E00\u5C42");
|
|
226
|
+
}
|
|
227
|
+
for (const key of ["auto", "exposeTool"]) {
|
|
228
|
+
if (layer[key] !== void 0 && typeof layer[key] !== "boolean") {
|
|
229
|
+
onInvalid(`diagnostics.${key} \u5FC5\u987B\u662F\u5E03\u5C14\u503C\uFF0C\u5DF2\u56DE\u9000\u4E0A\u4E00\u5C42`);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
policy = {
|
|
233
|
+
checks: checks ? checks.map((check) => ({ ...check })) : policy.checks,
|
|
234
|
+
auto: normalizeBoolean(layer.auto, policy.auto),
|
|
235
|
+
exposeTool: normalizeBoolean(layer.exposeTool, policy.exposeTool),
|
|
236
|
+
severity: layer.severity === "error" || layer.severity === "warning" ? layer.severity : policy.severity,
|
|
237
|
+
maxFindingsPerSection: normalizePositiveInt(
|
|
238
|
+
layer.maxFindingsPerSection,
|
|
239
|
+
policy.maxFindingsPerSection
|
|
240
|
+
),
|
|
241
|
+
maxMessageChars: normalizePositiveInt(layer.maxMessageChars, policy.maxMessageChars)
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
return policy;
|
|
245
|
+
}
|
|
246
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
247
|
+
0 && (module.exports = {
|
|
248
|
+
BUILTIN_LINTERS,
|
|
249
|
+
COMMAND_CHECK_TIMEOUT_MS,
|
|
250
|
+
DEFAULT_BUILTIN_CHECKS,
|
|
251
|
+
DEFAULT_DIAGNOSTICS_POLICY,
|
|
252
|
+
DEFAULT_MAX_FINDINGS_PER_SECTION,
|
|
253
|
+
DEFAULT_MAX_MESSAGE_CHARS,
|
|
254
|
+
SOURCE_EXTENSIONS,
|
|
255
|
+
checkRunsInPhase,
|
|
256
|
+
isCommandCheck,
|
|
257
|
+
isLinterPreset,
|
|
258
|
+
isTypecheckCheck,
|
|
259
|
+
matchesExtensions,
|
|
260
|
+
resolveDiagnosticsPolicy
|
|
261
|
+
});
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 诊断的用户配置契约(provider 无关)。
|
|
3
|
+
*
|
|
4
|
+
* 用户配置面只有一处:vite 插件的 `providerOptions.diagnostics`。核心层在这里定义策略形状、
|
|
5
|
+
* 检查来源(内置引擎 / 项目命令)、输出适配器协议与默认值;两个 provider(deepseek / opencode)
|
|
6
|
+
* 与两侧宿主插件共用同一份语义,因此"用户配置了什么"在每个宿主上含义一致。
|
|
7
|
+
*
|
|
8
|
+
* 不在这里定义的东西:排除规则(ignore)—— 那是底层工具的事(ESLint 自身 ignore、tsconfig
|
|
9
|
+
* `exclude`、命令自己的 glob),我们不复制一套 glob 语义。
|
|
10
|
+
*/
|
|
11
|
+
import type { AIPanelDiagnosticEntry } from "./types";
|
|
12
|
+
/** 诊断阶段:编辑后自动诊断 / agent 手动调用工具 */
|
|
13
|
+
export type DiagnosticsPhase = "edit" | "manual";
|
|
14
|
+
/** 检查在哪些阶段执行(缺省 both) */
|
|
15
|
+
export type DiagnosticsRun = DiagnosticsPhase | "both";
|
|
16
|
+
/**
|
|
17
|
+
* 类型检查检查:唯一的"引擎级"内置(要 tsconfig 感知的批量归并、项目本地 tsc/vue-tsc 探测
|
|
18
|
+
* 与自带 vue-tsc 兜底,不是一条命令能表达的)。其余一切检查都走同一条命令执行路径。
|
|
19
|
+
*/
|
|
20
|
+
export interface TypecheckCheck {
|
|
21
|
+
builtin: "typecheck";
|
|
22
|
+
run?: DiagnosticsRun;
|
|
23
|
+
/** 只吃这些扩展名(如 [".ts", ".vue"]);缺省 = 可诊断源码扩展名(与历史行为一致) */
|
|
24
|
+
extensions?: string[];
|
|
25
|
+
}
|
|
26
|
+
/** 命令输出的内置适配器名(内置适配器由我们开发维护) */
|
|
27
|
+
export type DiagnosticsFormat = "text" | "tsc" | "eslint-json" | "oxlint-json" | "stylelint-json" | "aipanel-json";
|
|
28
|
+
/**
|
|
29
|
+
* 命令检查:跑用户项目里的一条命令(或项目本地某个包的 bin),输出经适配器归一成分区。
|
|
30
|
+
*
|
|
31
|
+
* 命令按 argv 直传、不经 shell(见 ADR-0002);需要 shell 语义时由用户显式选择解释器。
|
|
32
|
+
* `command` 与 `bin` 二选一:`bin` 走"项目本地包解析"(与内置预设同一策略),
|
|
33
|
+
* 因此 stylelint / biome / 自研工具包都是同一条路,不需要为每个工具内置特判。
|
|
34
|
+
*/
|
|
35
|
+
export interface CommandCheck {
|
|
36
|
+
/** 分区标题(模型与诊断卡片都看到它) */
|
|
37
|
+
name: string;
|
|
38
|
+
/** argv[0]:命令名(PATH 解析)或路径;与 `bin` 二选一 */
|
|
39
|
+
command?: string;
|
|
40
|
+
/** 项目本地包的 bin 名(同时也是包名):解析不到时给明确文案;与 `command` 二选一 */
|
|
41
|
+
bin?: string;
|
|
42
|
+
/** argv[1..];可含 `{file}`(逐文件)与 `{files}`(一次传全部)占位符 */
|
|
43
|
+
args?: string[];
|
|
44
|
+
/**
|
|
45
|
+
* 无目标文件(全量诊断)时的 argv。
|
|
46
|
+
* 含占位符的检查没写它 → 全量诊断跳过该检查;不带占位符的检查三种目标都跑同一个 argv。
|
|
47
|
+
*/
|
|
48
|
+
projectArgs?: string[];
|
|
49
|
+
/** 只吃这些扩展名(如 [".css", ".scss"]);缺省 = 不限 */
|
|
50
|
+
extensions?: string[];
|
|
51
|
+
/** 相对项目根,默认项目根 */
|
|
52
|
+
cwd?: string;
|
|
53
|
+
run?: DiagnosticsRun;
|
|
54
|
+
/** 内置适配器名;与 `adapter` 同时给出时 `adapter` 优先 */
|
|
55
|
+
format?: DiagnosticsFormat;
|
|
56
|
+
/** 用户适配器模块路径(相对项目根);default export 一个 {@link DiagnosticsAdapter} */
|
|
57
|
+
adapter?: string;
|
|
58
|
+
/** 命令超时(ms),默认 {@link COMMAND_CHECK_TIMEOUT_MS} */
|
|
59
|
+
timeoutMs?: number;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* 内置 linter 预设:只写 `builtin: "eslint"` 就能用——包名 / bin / 默认 argv / 输出格式 /
|
|
63
|
+
* 扩展名都取 {@link BUILTIN_LINTERS} 的目录项,展开后与用户自定义的 {@link CommandCheck}
|
|
64
|
+
* **完全同形**,走同一条执行与适配逻辑。可局部覆盖(args / extensions / format / run …)。
|
|
65
|
+
*/
|
|
66
|
+
export type LinterPresetCheck = {
|
|
67
|
+
builtin: BuiltinLinterId;
|
|
68
|
+
args?: string[];
|
|
69
|
+
projectArgs?: string[];
|
|
70
|
+
extensions?: string[];
|
|
71
|
+
format?: DiagnosticsFormat;
|
|
72
|
+
cwd?: string;
|
|
73
|
+
run?: DiagnosticsRun;
|
|
74
|
+
timeoutMs?: number;
|
|
75
|
+
};
|
|
76
|
+
export type DiagnosticsCheck = TypecheckCheck | LinterPresetCheck | CommandCheck;
|
|
77
|
+
/** 诊断策略:用户可自定义的全部行为 */
|
|
78
|
+
export interface DiagnosticsPolicy {
|
|
79
|
+
/** 检查来源;缺省(或归一化后为空)= 内置 lint + typecheck */
|
|
80
|
+
checks: DiagnosticsCheck[];
|
|
81
|
+
/** 编辑后自动诊断(tools/post-execute 登记 → agent/pre-step 收尾注入) */
|
|
82
|
+
auto: boolean;
|
|
83
|
+
/** 是否把 run_diagnostics 暴露给模型 */
|
|
84
|
+
exposeTool: boolean;
|
|
85
|
+
/** 投递门槛:`error` 只报错误,`warning` 错误与警告都报 */
|
|
86
|
+
severity: "error" | "warning";
|
|
87
|
+
/** 自动诊断每个分区最多列出的发现条数 */
|
|
88
|
+
maxFindingsPerSection: number;
|
|
89
|
+
/** 自动诊断注入消息的字符上限 */
|
|
90
|
+
maxMessageChars: number;
|
|
91
|
+
}
|
|
92
|
+
/** 用户适配器入参:命令的原始产物 + 本次目标 */
|
|
93
|
+
export interface DiagnosticsAdapterInput {
|
|
94
|
+
/** 分区名(check.name) */
|
|
95
|
+
name: string;
|
|
96
|
+
stdout: string;
|
|
97
|
+
stderr: string;
|
|
98
|
+
/** 超时 / 被信号杀死时为 undefined */
|
|
99
|
+
exitCode: number | undefined;
|
|
100
|
+
/** 本次目标文件(绝对路径);项目级检查为空数组 */
|
|
101
|
+
files: string[];
|
|
102
|
+
/** 项目根 */
|
|
103
|
+
cwd: string;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* 用户适配器出参。
|
|
107
|
+
* 提供 `diagnostics` 时文本由 AIPanel 统一渲染(保证 severity 门槛与诊断卡片一致);
|
|
108
|
+
* 只有需要自定义叙述时才只给 `text`(此时无结构化条目、也不参与 severity 过滤)。
|
|
109
|
+
*/
|
|
110
|
+
export interface DiagnosticsAdapterOutput {
|
|
111
|
+
text?: string;
|
|
112
|
+
diagnostics?: AIPanelDiagnosticEntry[];
|
|
113
|
+
}
|
|
114
|
+
export type DiagnosticsAdapter = (input: DiagnosticsAdapterInput) => DiagnosticsAdapterOutput | Promise<DiagnosticsAdapterOutput>;
|
|
115
|
+
/** 命令检查默认超时 */
|
|
116
|
+
export declare const COMMAND_CHECK_TIMEOUT_MS = 60000;
|
|
117
|
+
/**
|
|
118
|
+
* 可诊断源码扩展名(内置 lint / typecheck 的默认匹配集)。
|
|
119
|
+
* node 侧的 `JS_EXTENSIONS` 引它,保持单一来源。
|
|
120
|
+
*/
|
|
121
|
+
export declare const SOURCE_EXTENSIONS: readonly string[];
|
|
122
|
+
/**
|
|
123
|
+
* 目标文件是否命中检查声明的扩展名。
|
|
124
|
+
* 未声明(undefined / 空)表示不限;实现保持 client-safe(不引 node:path)。
|
|
125
|
+
*/
|
|
126
|
+
export declare function matchesExtensions(filePath: string, extensions: readonly string[] | undefined): boolean;
|
|
127
|
+
/** 内置 linter 目录项:一个预设 = 一条命令检查的全部默认值(纯数据) */
|
|
128
|
+
export interface BuiltinLinterSpec {
|
|
129
|
+
/** 分区标题 */
|
|
130
|
+
label: string;
|
|
131
|
+
/** 项目本地包名(bin 从项目 package.json 解析,解析不到即视为未安装) */
|
|
132
|
+
package: string;
|
|
133
|
+
/** bin 名;缺省与包名相同 */
|
|
134
|
+
bin?: string;
|
|
135
|
+
/** 默认 argv(可含 `{file}` / `{files}` 占位符) */
|
|
136
|
+
args: string[];
|
|
137
|
+
/** 全量诊断时的 argv(含占位符的预设必须给,否则全量时跳过) */
|
|
138
|
+
projectArgs?: string[];
|
|
139
|
+
/** 默认匹配的扩展名 */
|
|
140
|
+
extensions: string[];
|
|
141
|
+
/** 默认输出适配器(内置工具一律能出结构化诊断,因此卡片/severity 都生效) */
|
|
142
|
+
format: DiagnosticsFormat;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* 内置 linter 目录(数据表)。加一个常见 lint = 加一行;预设展开后与用户自定义检查同形,
|
|
146
|
+
* 走同一条执行 + 适配逻辑,所以"内置"与"自定义"没有第二套底层实现。
|
|
147
|
+
*/
|
|
148
|
+
export declare const BUILTIN_LINTERS: {
|
|
149
|
+
readonly eslint: {
|
|
150
|
+
readonly label: "ESLint";
|
|
151
|
+
readonly package: "eslint";
|
|
152
|
+
readonly args: ["--format", "json", "{files}"];
|
|
153
|
+
readonly projectArgs: ["--format", "json", "."];
|
|
154
|
+
readonly extensions: string[];
|
|
155
|
+
readonly format: "eslint-json";
|
|
156
|
+
};
|
|
157
|
+
readonly oxlint: {
|
|
158
|
+
readonly label: "oxlint";
|
|
159
|
+
readonly package: "oxlint";
|
|
160
|
+
readonly args: ["--format=json", "--ignore-pattern", "node_modules", "{files}"];
|
|
161
|
+
readonly projectArgs: ["--format=json", "--ignore-pattern", "node_modules", "."];
|
|
162
|
+
readonly extensions: string[];
|
|
163
|
+
readonly format: "oxlint-json";
|
|
164
|
+
};
|
|
165
|
+
readonly stylelint: {
|
|
166
|
+
readonly label: "Stylelint";
|
|
167
|
+
readonly package: "stylelint";
|
|
168
|
+
readonly args: ["--formatter", "json", "{files}"];
|
|
169
|
+
readonly projectArgs: ["--formatter", "json", "**/*.{css,scss,less}"];
|
|
170
|
+
readonly extensions: [".css", ".scss", ".less"];
|
|
171
|
+
readonly format: "stylelint-json";
|
|
172
|
+
};
|
|
173
|
+
};
|
|
174
|
+
/** 内置 linter 预设 id */
|
|
175
|
+
export type BuiltinLinterId = keyof typeof BUILTIN_LINTERS;
|
|
176
|
+
/** 自动诊断默认分区条数上限(与历史行为一致) */
|
|
177
|
+
export declare const DEFAULT_MAX_FINDINGS_PER_SECTION = 3;
|
|
178
|
+
/** 自动诊断默认注入字符上限(与历史行为一致) */
|
|
179
|
+
export declare const DEFAULT_MAX_MESSAGE_CHARS = 4000;
|
|
180
|
+
/**
|
|
181
|
+
* 缺省检查来源(= 未配置 diagnostics 时的行为):
|
|
182
|
+
* 项目装了哪个内置 linter 就跑哪个(没装的自动跳过),类型检查始终在。
|
|
183
|
+
*/
|
|
184
|
+
export declare const DEFAULT_BUILTIN_CHECKS: readonly DiagnosticsCheck[];
|
|
185
|
+
/** 策略默认值(单一来源:provider 的默认值、插件的兜底都引它) */
|
|
186
|
+
export declare const DEFAULT_DIAGNOSTICS_POLICY: DiagnosticsPolicy;
|
|
187
|
+
/** 是否为命令检查(用户自定义:既无内置 linter 预设也无内置引擎) */
|
|
188
|
+
export declare function isCommandCheck(check: DiagnosticsCheck): check is CommandCheck;
|
|
189
|
+
/** 是否为内置 linter 预设 */
|
|
190
|
+
export declare function isLinterPreset(check: DiagnosticsCheck): check is LinterPresetCheck;
|
|
191
|
+
/** 是否为内置类型检查(引擎级) */
|
|
192
|
+
export declare function isTypecheckCheck(check: DiagnosticsCheck): check is TypecheckCheck;
|
|
193
|
+
/** 该检查是否在指定阶段执行 */
|
|
194
|
+
export declare function checkRunsInPhase(check: DiagnosticsCheck, phase: DiagnosticsPhase): boolean;
|
|
195
|
+
/**
|
|
196
|
+
* 逐层覆盖 + 逐字段归一化:后面的层覆盖前面的层,非法值回退默认并通过 `onInvalid` 告警。
|
|
197
|
+
* 调用方(provider)负责把告警写进日志,核心层保持无副作用、可单测。
|
|
198
|
+
*/
|
|
199
|
+
export declare function resolveDiagnosticsPolicy(layers: readonly (Partial<DiagnosticsPolicy> | undefined)[], onInvalid?: (message: string) => void): DiagnosticsPolicy;
|
package/lib/common/options.d.ts
CHANGED
|
@@ -86,8 +86,6 @@ export interface PluginOptions<P extends Record<string, unknown> = Record<string
|
|
|
86
86
|
language?: string;
|
|
87
87
|
/** @deprecated 使用 providerOptions.settings */
|
|
88
88
|
settings?: unknown;
|
|
89
|
-
/** @deprecated 使用 providerOptions.enableLsp */
|
|
90
|
-
enableLsp?: boolean;
|
|
91
89
|
/** @deprecated 使用 providerOptions.enablePrettier */
|
|
92
90
|
enablePrettier?: boolean;
|
|
93
91
|
}
|
package/lib/index.cjs
CHANGED
|
@@ -15,6 +15,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
15
15
|
var lib_exports = {};
|
|
16
16
|
module.exports = __toCommonJS(lib_exports);
|
|
17
17
|
__reExport(lib_exports, require("./common/constants.cjs"), module.exports);
|
|
18
|
+
__reExport(lib_exports, require("./common/diagnostics.cjs"), module.exports);
|
|
18
19
|
__reExport(lib_exports, require("./common/inspector/index.cjs"), module.exports);
|
|
19
20
|
__reExport(lib_exports, require("./common/logger-core.cjs"), module.exports);
|
|
20
21
|
__reExport(lib_exports, require("./common/options.cjs"), module.exports);
|
|
@@ -24,6 +25,7 @@ __reExport(lib_exports, require("./common/utils.cjs"), module.exports);
|
|
|
24
25
|
// Annotate the CommonJS export names for ESM import in node:
|
|
25
26
|
0 && (module.exports = {
|
|
26
27
|
...require("./common/constants.cjs"),
|
|
28
|
+
...require("./common/diagnostics.cjs"),
|
|
27
29
|
...require("./common/inspector/index.cjs"),
|
|
28
30
|
...require("./common/logger-core.cjs"),
|
|
29
31
|
...require("./common/options.cjs"),
|