@aipanel/core 1.3.6 → 1.3.8
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.
|
@@ -13,6 +13,13 @@ import type { AIPanelDiagnosticEntry } from "./types";
|
|
|
13
13
|
export type DiagnosticsPhase = "edit" | "manual";
|
|
14
14
|
/** 检查在哪些阶段执行(缺省 both) */
|
|
15
15
|
export type DiagnosticsRun = DiagnosticsPhase | "both";
|
|
16
|
+
/**
|
|
17
|
+
* 诊断目标形态(与 `run` 正交:`run` 管阶段,这里管"跑什么样的目标"):
|
|
18
|
+
* - `edited`:编辑后自动诊断(本步编辑过的文件)
|
|
19
|
+
* - `file`:`run_diagnostics({ filePath })` 单文件
|
|
20
|
+
* - `project`:`run_diagnostics()` 全量
|
|
21
|
+
*/
|
|
22
|
+
export type DiagnosticsTargetKind = "edited" | "file" | "project";
|
|
16
23
|
/**
|
|
17
24
|
* 类型检查检查:唯一的"引擎级"内置(要 tsconfig 感知的批量归并、项目本地 tsc/vue-tsc 探测
|
|
18
25
|
* 与自带 vue-tsc 兜底,不是一条命令能表达的)。其余一切检查都走同一条命令执行路径。
|
|
@@ -20,6 +27,8 @@ export type DiagnosticsRun = DiagnosticsPhase | "both";
|
|
|
20
27
|
export interface TypecheckCheck {
|
|
21
28
|
builtin: "typecheck";
|
|
22
29
|
run?: DiagnosticsRun;
|
|
30
|
+
/** 只在这些目标形态下跑(如 ["project"] = 仅全量诊断);缺省 = 不限 */
|
|
31
|
+
targets?: DiagnosticsTargetKind[];
|
|
23
32
|
/** 只吃这些扩展名(如 [".ts", ".vue"]);缺省 = 可诊断源码扩展名(与历史行为一致) */
|
|
24
33
|
extensions?: string[];
|
|
25
34
|
}
|
|
@@ -48,6 +57,8 @@ export interface CommandCheck {
|
|
|
48
57
|
projectArgs?: string[];
|
|
49
58
|
/** 只吃这些扩展名(如 [".css", ".scss"]);缺省 = 不限 */
|
|
50
59
|
extensions?: string[];
|
|
60
|
+
/** 只在这些目标形态下跑(如 ["project"] = 仅全量诊断)——想知道"这次是不是全量"就用它;缺省 = 不限 */
|
|
61
|
+
targets?: DiagnosticsTargetKind[];
|
|
51
62
|
/** 相对项目根,默认项目根 */
|
|
52
63
|
cwd?: string;
|
|
53
64
|
run?: DiagnosticsRun;
|
|
@@ -68,6 +79,7 @@ export type LinterPresetCheck = {
|
|
|
68
79
|
args?: string[];
|
|
69
80
|
projectArgs?: string[];
|
|
70
81
|
extensions?: string[];
|
|
82
|
+
targets?: DiagnosticsTargetKind[];
|
|
71
83
|
format?: DiagnosticsFormat;
|
|
72
84
|
cwd?: string;
|
|
73
85
|
run?: DiagnosticsRun;
|
|
@@ -192,6 +204,8 @@ export declare function isLinterPreset(check: DiagnosticsCheck): check is Linter
|
|
|
192
204
|
export declare function isTypecheckCheck(check: DiagnosticsCheck): check is TypecheckCheck;
|
|
193
205
|
/** 该检查是否在指定阶段执行 */
|
|
194
206
|
export declare function checkRunsInPhase(check: DiagnosticsCheck, phase: DiagnosticsPhase): boolean;
|
|
207
|
+
/** 该检查是否在指定目标形态下执行(未声明 targets = 不限) */
|
|
208
|
+
export declare function checkRunsOnTarget(check: DiagnosticsCheck, kind: DiagnosticsTargetKind): boolean;
|
|
195
209
|
/**
|
|
196
210
|
* 逐层覆盖 + 逐字段归一化:后面的层覆盖前面的层,非法值回退默认并通过 `onInvalid` 告警。
|
|
197
211
|
* 调用方(provider)负责把告警写进日志,核心层保持无副作用、可单测。
|
|
@@ -71,6 +71,9 @@ function checkRunsInPhase(check, phase) {
|
|
|
71
71
|
const run = check.run ?? "both";
|
|
72
72
|
return run === "both" || run === phase;
|
|
73
73
|
}
|
|
74
|
+
function checkRunsOnTarget(check, kind) {
|
|
75
|
+
return check.targets === void 0 || check.targets.includes(kind);
|
|
76
|
+
}
|
|
74
77
|
const FORMATS = [
|
|
75
78
|
"text",
|
|
76
79
|
"tsc",
|
|
@@ -80,6 +83,7 @@ const FORMATS = [
|
|
|
80
83
|
"aipanel-json"
|
|
81
84
|
];
|
|
82
85
|
const RUNS = ["edit", "manual", "both"];
|
|
86
|
+
const TARGET_KINDS = ["edited", "file", "project"];
|
|
83
87
|
function normalizeExtensions(raw) {
|
|
84
88
|
if (!Array.isArray(raw)) return void 0;
|
|
85
89
|
const extensions = raw.filter((item) => typeof item === "string" && item.trim() !== "").map((item) => {
|
|
@@ -88,6 +92,13 @@ function normalizeExtensions(raw) {
|
|
|
88
92
|
});
|
|
89
93
|
return extensions.length > 0 ? [...new Set(extensions)] : void 0;
|
|
90
94
|
}
|
|
95
|
+
function normalizeTargets(raw) {
|
|
96
|
+
if (!Array.isArray(raw)) return void 0;
|
|
97
|
+
const targets = raw.filter(
|
|
98
|
+
(item) => TARGET_KINDS.includes(item)
|
|
99
|
+
);
|
|
100
|
+
return targets.length > 0 ? [...new Set(targets)] : void 0;
|
|
101
|
+
}
|
|
91
102
|
function normalizeArgs(raw) {
|
|
92
103
|
if (!Array.isArray(raw)) return void 0;
|
|
93
104
|
const args = raw.filter((item) => typeof item === "string");
|
|
@@ -98,6 +109,7 @@ function normalizeCheck(raw) {
|
|
|
98
109
|
const value = raw;
|
|
99
110
|
const run = RUNS.includes(value.run) ? value.run : void 0;
|
|
100
111
|
const extensions = normalizeExtensions(value.extensions);
|
|
112
|
+
const targets = normalizeTargets(value.targets);
|
|
101
113
|
const cwd = typeof value.cwd === "string" && value.cwd ? { cwd: value.cwd } : {};
|
|
102
114
|
const timeout = typeof value.timeoutMs === "number" && Number.isFinite(value.timeoutMs) && value.timeoutMs > 0 ? { timeoutMs: Math.floor(value.timeoutMs) } : {};
|
|
103
115
|
const format = FORMATS.includes(value.format) ? { format: value.format } : {};
|
|
@@ -106,6 +118,7 @@ function normalizeCheck(raw) {
|
|
|
106
118
|
return {
|
|
107
119
|
builtin: "typecheck",
|
|
108
120
|
...run ? { run } : {},
|
|
121
|
+
...targets ? { targets } : {},
|
|
109
122
|
...extensions ? { extensions } : {}
|
|
110
123
|
};
|
|
111
124
|
}
|
|
@@ -117,6 +130,7 @@ function normalizeCheck(raw) {
|
|
|
117
130
|
...presetArgs ? { args: presetArgs } : {},
|
|
118
131
|
...presetProjectArgs ? { projectArgs: presetProjectArgs } : {},
|
|
119
132
|
...extensions ? { extensions } : {},
|
|
133
|
+
...targets ? { targets } : {},
|
|
120
134
|
...run ? { run } : {},
|
|
121
135
|
...format,
|
|
122
136
|
...cwd,
|
|
@@ -138,6 +152,7 @@ function normalizeCheck(raw) {
|
|
|
138
152
|
...args ? { args } : {},
|
|
139
153
|
...projectArgs ? { projectArgs } : {},
|
|
140
154
|
...extensions ? { extensions } : {},
|
|
155
|
+
...targets ? { targets } : {},
|
|
141
156
|
...cwd,
|
|
142
157
|
...run ? { run } : {},
|
|
143
158
|
...format,
|
|
@@ -218,6 +233,7 @@ export {
|
|
|
218
233
|
DEFAULT_MAX_MESSAGE_CHARS,
|
|
219
234
|
SOURCE_EXTENSIONS,
|
|
220
235
|
checkRunsInPhase,
|
|
236
|
+
checkRunsOnTarget,
|
|
221
237
|
isCommandCheck,
|
|
222
238
|
isLinterPreset,
|
|
223
239
|
isTypecheckCheck,
|
package/es/node/diagnostics.mjs
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
COMMAND_CHECK_TIMEOUT_MS,
|
|
10
10
|
SOURCE_EXTENSIONS,
|
|
11
11
|
checkRunsInPhase,
|
|
12
|
+
checkRunsOnTarget,
|
|
12
13
|
isCommandCheck,
|
|
13
14
|
isLinterPreset,
|
|
14
15
|
isTypecheckCheck,
|
|
@@ -759,8 +760,11 @@ async function runCommandCheck(check, target, phase, severity, optional = false)
|
|
|
759
760
|
if (failure) return { text: failure, diagnostics: [] };
|
|
760
761
|
const raw = rawCommandOutput(outcome);
|
|
761
762
|
try {
|
|
762
|
-
|
|
763
|
-
|
|
763
|
+
const produced2 = check.adapter ? await runAdapterModule(check, outcome, cwd, fileSet) : adaptBuiltinFormat(check.format ?? "text", check, raw, cwd, severity);
|
|
764
|
+
if (phase === "edit" && outcome.exitCode === 0 && produced2.diagnostics.length === 0) {
|
|
765
|
+
return { ...produced2, text: void 0, notes: void 0 };
|
|
766
|
+
}
|
|
767
|
+
return produced2;
|
|
764
768
|
} catch (error) {
|
|
765
769
|
const reason = error instanceof Error ? error.message : String(error);
|
|
766
770
|
const excerpt = raw.replace(/\s+/g, " ").trim().slice(0, 200);
|
|
@@ -860,7 +864,9 @@ async function runTypecheckCheck(check, target, phase, severity) {
|
|
|
860
864
|
];
|
|
861
865
|
}
|
|
862
866
|
async function runDiagnostics(target, policy, phase) {
|
|
863
|
-
const checks = policy.checks.filter(
|
|
867
|
+
const checks = policy.checks.filter(
|
|
868
|
+
(check) => checkRunsInPhase(check, phase) && checkRunsOnTarget(check, target.kind)
|
|
869
|
+
);
|
|
864
870
|
log.debug("runDiagnostics", { phase, target: target.kind, checks: checks.length });
|
|
865
871
|
const results = await Promise.all(
|
|
866
872
|
checks.map((check) => {
|
|
@@ -25,6 +25,7 @@ __export(diagnostics_exports, {
|
|
|
25
25
|
DEFAULT_MAX_MESSAGE_CHARS: () => DEFAULT_MAX_MESSAGE_CHARS,
|
|
26
26
|
SOURCE_EXTENSIONS: () => SOURCE_EXTENSIONS,
|
|
27
27
|
checkRunsInPhase: () => checkRunsInPhase,
|
|
28
|
+
checkRunsOnTarget: () => checkRunsOnTarget,
|
|
28
29
|
isCommandCheck: () => isCommandCheck,
|
|
29
30
|
isLinterPreset: () => isLinterPreset,
|
|
30
31
|
isTypecheckCheck: () => isTypecheckCheck,
|
|
@@ -105,6 +106,9 @@ function checkRunsInPhase(check, phase) {
|
|
|
105
106
|
const run = check.run ?? "both";
|
|
106
107
|
return run === "both" || run === phase;
|
|
107
108
|
}
|
|
109
|
+
function checkRunsOnTarget(check, kind) {
|
|
110
|
+
return check.targets === void 0 || check.targets.includes(kind);
|
|
111
|
+
}
|
|
108
112
|
const FORMATS = [
|
|
109
113
|
"text",
|
|
110
114
|
"tsc",
|
|
@@ -114,6 +118,7 @@ const FORMATS = [
|
|
|
114
118
|
"aipanel-json"
|
|
115
119
|
];
|
|
116
120
|
const RUNS = ["edit", "manual", "both"];
|
|
121
|
+
const TARGET_KINDS = ["edited", "file", "project"];
|
|
117
122
|
function normalizeExtensions(raw) {
|
|
118
123
|
if (!Array.isArray(raw)) return void 0;
|
|
119
124
|
const extensions = raw.filter((item) => typeof item === "string" && item.trim() !== "").map((item) => {
|
|
@@ -122,6 +127,13 @@ function normalizeExtensions(raw) {
|
|
|
122
127
|
});
|
|
123
128
|
return extensions.length > 0 ? [...new Set(extensions)] : void 0;
|
|
124
129
|
}
|
|
130
|
+
function normalizeTargets(raw) {
|
|
131
|
+
if (!Array.isArray(raw)) return void 0;
|
|
132
|
+
const targets = raw.filter(
|
|
133
|
+
(item) => TARGET_KINDS.includes(item)
|
|
134
|
+
);
|
|
135
|
+
return targets.length > 0 ? [...new Set(targets)] : void 0;
|
|
136
|
+
}
|
|
125
137
|
function normalizeArgs(raw) {
|
|
126
138
|
if (!Array.isArray(raw)) return void 0;
|
|
127
139
|
const args = raw.filter((item) => typeof item === "string");
|
|
@@ -132,6 +144,7 @@ function normalizeCheck(raw) {
|
|
|
132
144
|
const value = raw;
|
|
133
145
|
const run = RUNS.includes(value.run) ? value.run : void 0;
|
|
134
146
|
const extensions = normalizeExtensions(value.extensions);
|
|
147
|
+
const targets = normalizeTargets(value.targets);
|
|
135
148
|
const cwd = typeof value.cwd === "string" && value.cwd ? { cwd: value.cwd } : {};
|
|
136
149
|
const timeout = typeof value.timeoutMs === "number" && Number.isFinite(value.timeoutMs) && value.timeoutMs > 0 ? { timeoutMs: Math.floor(value.timeoutMs) } : {};
|
|
137
150
|
const format = FORMATS.includes(value.format) ? { format: value.format } : {};
|
|
@@ -140,6 +153,7 @@ function normalizeCheck(raw) {
|
|
|
140
153
|
return {
|
|
141
154
|
builtin: "typecheck",
|
|
142
155
|
...run ? { run } : {},
|
|
156
|
+
...targets ? { targets } : {},
|
|
143
157
|
...extensions ? { extensions } : {}
|
|
144
158
|
};
|
|
145
159
|
}
|
|
@@ -151,6 +165,7 @@ function normalizeCheck(raw) {
|
|
|
151
165
|
...presetArgs ? { args: presetArgs } : {},
|
|
152
166
|
...presetProjectArgs ? { projectArgs: presetProjectArgs } : {},
|
|
153
167
|
...extensions ? { extensions } : {},
|
|
168
|
+
...targets ? { targets } : {},
|
|
154
169
|
...run ? { run } : {},
|
|
155
170
|
...format,
|
|
156
171
|
...cwd,
|
|
@@ -172,6 +187,7 @@ function normalizeCheck(raw) {
|
|
|
172
187
|
...args ? { args } : {},
|
|
173
188
|
...projectArgs ? { projectArgs } : {},
|
|
174
189
|
...extensions ? { extensions } : {},
|
|
190
|
+
...targets ? { targets } : {},
|
|
175
191
|
...cwd,
|
|
176
192
|
...run ? { run } : {},
|
|
177
193
|
...format,
|
|
@@ -253,6 +269,7 @@ function resolveDiagnosticsPolicy(layers, onInvalid = () => {
|
|
|
253
269
|
DEFAULT_MAX_MESSAGE_CHARS,
|
|
254
270
|
SOURCE_EXTENSIONS,
|
|
255
271
|
checkRunsInPhase,
|
|
272
|
+
checkRunsOnTarget,
|
|
256
273
|
isCommandCheck,
|
|
257
274
|
isLinterPreset,
|
|
258
275
|
isTypecheckCheck,
|
|
@@ -13,6 +13,13 @@ import type { AIPanelDiagnosticEntry } from "./types";
|
|
|
13
13
|
export type DiagnosticsPhase = "edit" | "manual";
|
|
14
14
|
/** 检查在哪些阶段执行(缺省 both) */
|
|
15
15
|
export type DiagnosticsRun = DiagnosticsPhase | "both";
|
|
16
|
+
/**
|
|
17
|
+
* 诊断目标形态(与 `run` 正交:`run` 管阶段,这里管"跑什么样的目标"):
|
|
18
|
+
* - `edited`:编辑后自动诊断(本步编辑过的文件)
|
|
19
|
+
* - `file`:`run_diagnostics({ filePath })` 单文件
|
|
20
|
+
* - `project`:`run_diagnostics()` 全量
|
|
21
|
+
*/
|
|
22
|
+
export type DiagnosticsTargetKind = "edited" | "file" | "project";
|
|
16
23
|
/**
|
|
17
24
|
* 类型检查检查:唯一的"引擎级"内置(要 tsconfig 感知的批量归并、项目本地 tsc/vue-tsc 探测
|
|
18
25
|
* 与自带 vue-tsc 兜底,不是一条命令能表达的)。其余一切检查都走同一条命令执行路径。
|
|
@@ -20,6 +27,8 @@ export type DiagnosticsRun = DiagnosticsPhase | "both";
|
|
|
20
27
|
export interface TypecheckCheck {
|
|
21
28
|
builtin: "typecheck";
|
|
22
29
|
run?: DiagnosticsRun;
|
|
30
|
+
/** 只在这些目标形态下跑(如 ["project"] = 仅全量诊断);缺省 = 不限 */
|
|
31
|
+
targets?: DiagnosticsTargetKind[];
|
|
23
32
|
/** 只吃这些扩展名(如 [".ts", ".vue"]);缺省 = 可诊断源码扩展名(与历史行为一致) */
|
|
24
33
|
extensions?: string[];
|
|
25
34
|
}
|
|
@@ -48,6 +57,8 @@ export interface CommandCheck {
|
|
|
48
57
|
projectArgs?: string[];
|
|
49
58
|
/** 只吃这些扩展名(如 [".css", ".scss"]);缺省 = 不限 */
|
|
50
59
|
extensions?: string[];
|
|
60
|
+
/** 只在这些目标形态下跑(如 ["project"] = 仅全量诊断)——想知道"这次是不是全量"就用它;缺省 = 不限 */
|
|
61
|
+
targets?: DiagnosticsTargetKind[];
|
|
51
62
|
/** 相对项目根,默认项目根 */
|
|
52
63
|
cwd?: string;
|
|
53
64
|
run?: DiagnosticsRun;
|
|
@@ -68,6 +79,7 @@ export type LinterPresetCheck = {
|
|
|
68
79
|
args?: string[];
|
|
69
80
|
projectArgs?: string[];
|
|
70
81
|
extensions?: string[];
|
|
82
|
+
targets?: DiagnosticsTargetKind[];
|
|
71
83
|
format?: DiagnosticsFormat;
|
|
72
84
|
cwd?: string;
|
|
73
85
|
run?: DiagnosticsRun;
|
|
@@ -192,6 +204,8 @@ export declare function isLinterPreset(check: DiagnosticsCheck): check is Linter
|
|
|
192
204
|
export declare function isTypecheckCheck(check: DiagnosticsCheck): check is TypecheckCheck;
|
|
193
205
|
/** 该检查是否在指定阶段执行 */
|
|
194
206
|
export declare function checkRunsInPhase(check: DiagnosticsCheck, phase: DiagnosticsPhase): boolean;
|
|
207
|
+
/** 该检查是否在指定目标形态下执行(未声明 targets = 不限) */
|
|
208
|
+
export declare function checkRunsOnTarget(check: DiagnosticsCheck, kind: DiagnosticsTargetKind): boolean;
|
|
195
209
|
/**
|
|
196
210
|
* 逐层覆盖 + 逐字段归一化:后面的层覆盖前面的层,非法值回退默认并通过 `onInvalid` 告警。
|
|
197
211
|
* 调用方(provider)负责把告警写进日志,核心层保持无副作用、可单测。
|
package/lib/node/diagnostics.cjs
CHANGED
|
@@ -793,8 +793,11 @@ async function runCommandCheck(check, target, phase, severity, optional = false)
|
|
|
793
793
|
if (failure) return { text: failure, diagnostics: [] };
|
|
794
794
|
const raw = rawCommandOutput(outcome);
|
|
795
795
|
try {
|
|
796
|
-
|
|
797
|
-
|
|
796
|
+
const produced2 = check.adapter ? await runAdapterModule(check, outcome, cwd, fileSet) : adaptBuiltinFormat(check.format ?? "text", check, raw, cwd, severity);
|
|
797
|
+
if (phase === "edit" && outcome.exitCode === 0 && produced2.diagnostics.length === 0) {
|
|
798
|
+
return { ...produced2, text: void 0, notes: void 0 };
|
|
799
|
+
}
|
|
800
|
+
return produced2;
|
|
798
801
|
} catch (error) {
|
|
799
802
|
const reason = error instanceof Error ? error.message : String(error);
|
|
800
803
|
const excerpt = raw.replace(/\s+/g, " ").trim().slice(0, 200);
|
|
@@ -894,7 +897,9 @@ async function runTypecheckCheck(check, target, phase, severity) {
|
|
|
894
897
|
];
|
|
895
898
|
}
|
|
896
899
|
async function runDiagnostics(target, policy, phase) {
|
|
897
|
-
const checks = policy.checks.filter(
|
|
900
|
+
const checks = policy.checks.filter(
|
|
901
|
+
(check) => (0, import_diagnostics.checkRunsInPhase)(check, phase) && (0, import_diagnostics.checkRunsOnTarget)(check, target.kind)
|
|
902
|
+
);
|
|
898
903
|
log.debug("runDiagnostics", { phase, target: target.kind, checks: checks.length });
|
|
899
904
|
const results = await Promise.all(
|
|
900
905
|
checks.map((check) => {
|