@lark-apaas/fullstack-cli 1.1.67-alpha.20260917134435 → 1.1.67-alpha.20260917183015
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/README.md +3 -3
- package/dist/index.js +4 -33
- package/package.json +1 -1
- package/templates/scripts/build.sh +0 -25
- package/templates/scripts/lint.js +43 -176
- package/templates/scripts/typecheck-mcp-ui.js +0 -32
- package/templates/tsconfig.mcp-ui.json +0 -33
package/README.md
CHANGED
|
@@ -399,10 +399,10 @@ MIT
|
|
|
399
399
|
|
|
400
400
|
## MCP UI 检查与存量配置同步
|
|
401
401
|
|
|
402
|
-
MCP UI
|
|
402
|
+
创建 MCP UI 时,Agent 在 `server/mcp/ui` 中同时生成 `tsconfig.json` 和 `eslint.config.cjs`,修改 UI 或其 shared 依赖后主动运行独立检查。模板和 CLI 不生成 UI 配置,也不将 UI 检查接入主工程 lint/type:check。
|
|
403
403
|
|
|
404
|
-
|
|
404
|
+
主工程保留原 client/server 检查。Agent 从工程根执行 `npx --no-install tsc --noEmit --project server/mcp/ui/tsconfig.json`,再执行 `npx --no-install eslint --config server/mcp/ui/eslint.config.cjs "server/mcp/ui/**/*.{ts,tsx,js,jsx}" --max-warnings 0`;必须检查退出码并修复错误。无需辅助脚本或新增 npm 命令。
|
|
405
405
|
|
|
406
|
-
|
|
406
|
+
CLI 不注入 MCP UI 检查命令;主工程保留原有 client/server 检查,UI 由 Agent 按独立配置执行标准 tsc/eslint。
|
|
407
407
|
|
|
408
408
|
存量 sync 不改写 ESLint 源码;UI 全局排除项由平台 ESLint 预设提供。TS 仅向已有显式 `exclude` 数组追加目录,保留注释和原项;依赖继承且未显式声明 `exclude` 的自定义配置保持不变并提示人工调整。自定义检查命令保留。lint.js 和 build.sh 仍由平台脚本模板维护,不依赖预设包中的脚本执行入口。
|
package/dist/index.js
CHANGED
|
@@ -2581,38 +2581,9 @@ function buildDefaultRules(opts) {
|
|
|
2581
2581
|
type: "file",
|
|
2582
2582
|
overwrite: true
|
|
2583
2583
|
},
|
|
2584
|
-
// UI
|
|
2584
|
+
// UI 位于 server/mcp/ui,检查配置由 Agent 随 UI 代码创建。
|
|
2585
2585
|
// 不生成 UI 目录;仅给已有 Nest 工程增量补服务端排除项。
|
|
2586
2586
|
{ onlyNestjs: true, type: "typescript-exclude", to: "tsconfig.node.json", path: "server/mcp/ui" },
|
|
2587
|
-
{ onlyNestjs: true, type: "file", from: "templates/tsconfig.mcp-ui.json", to: "tsconfig.mcp-ui.json", overwrite: false },
|
|
2588
|
-
{ onlyNestjs: true, type: "add-script", name: "type:check:mcp-ui", command: "node ./scripts/typecheck-mcp-ui.js", overwrite: false },
|
|
2589
|
-
{
|
|
2590
|
-
onlyNestjs: true,
|
|
2591
|
-
type: "patch-script",
|
|
2592
|
-
name: "type:check:mcp-ui",
|
|
2593
|
-
to: "node ./scripts/typecheck-mcp-ui.js",
|
|
2594
|
-
ifEquals: ["node ./scripts/check.cjs --typecheck-mcp-ui", "node ./scripts/lint.js --typecheck-mcp-ui"]
|
|
2595
|
-
},
|
|
2596
|
-
{
|
|
2597
|
-
onlyNestjs: true,
|
|
2598
|
-
type: "patch-script",
|
|
2599
|
-
name: "type:check",
|
|
2600
|
-
to: 'concurrently -n "server,client,mcp-ui" -c "blue,green,magenta" "npm run type:check:server" "npm run type:check:client" "npm run type:check:mcp-ui"',
|
|
2601
|
-
ifEquals: [
|
|
2602
|
-
"node ./scripts/check.cjs --typecheck",
|
|
2603
|
-
"node ./scripts/lint.js --typecheck",
|
|
2604
|
-
'concurrently -n "server,client" -c "blue,green" "npm run type:check:server" "npm run type:check:client"',
|
|
2605
|
-
'concurrently "npm run type:check:server" "npm run type:check:client"',
|
|
2606
|
-
'concurrently "npm run type:check:client" "npm run type:check:server"'
|
|
2607
|
-
]
|
|
2608
|
-
},
|
|
2609
|
-
{
|
|
2610
|
-
onlyNestjs: true,
|
|
2611
|
-
type: "patch-script",
|
|
2612
|
-
name: "eslint",
|
|
2613
|
-
to: "eslint . --quiet",
|
|
2614
|
-
ifEquals: ['eslint . --quiet --ignore-pattern "server/mcp/ui/**"']
|
|
2615
|
-
},
|
|
2616
2587
|
// 9. 把模板版本的 lint 脚本替换为支持 --files 的 runner
|
|
2617
2588
|
// 只识别平台模板生成的 `concurrently ...` 形态,用户真正改写过的脚本保持原样
|
|
2618
2589
|
{
|
|
@@ -2906,7 +2877,7 @@ async function syncRule(rule, pluginRoot, userProjectRoot) {
|
|
|
2906
2877
|
}
|
|
2907
2878
|
if (rule.type === "patch-script") {
|
|
2908
2879
|
const packageJsonPath = path6.join(userProjectRoot, "package.json");
|
|
2909
|
-
patchScript(packageJsonPath, rule.name, rule.to, rule.ifStartsWith
|
|
2880
|
+
patchScript(packageJsonPath, rule.name, rule.to, rule.ifStartsWith);
|
|
2910
2881
|
return;
|
|
2911
2882
|
}
|
|
2912
2883
|
if (rule.type === "add-line") {
|
|
@@ -3046,7 +3017,7 @@ function addScript(packageJsonPath, name, command, overwrite) {
|
|
|
3046
3017
|
fs9.writeFileSync(packageJsonPath, JSON.stringify(pkg2, null, 2) + "\n");
|
|
3047
3018
|
console.log(`[fullstack-cli] \u2713 scripts.${name}`);
|
|
3048
3019
|
}
|
|
3049
|
-
function patchScript(packageJsonPath, name, to, ifStartsWith
|
|
3020
|
+
function patchScript(packageJsonPath, name, to, ifStartsWith) {
|
|
3050
3021
|
if (!fs9.existsSync(packageJsonPath)) {
|
|
3051
3022
|
console.log(`[fullstack-cli] \u25CB package.json (not found)`);
|
|
3052
3023
|
return;
|
|
@@ -3063,7 +3034,7 @@ function patchScript(packageJsonPath, name, to, ifStartsWith, ifEquals) {
|
|
|
3063
3034
|
console.log(`[fullstack-cli] \u25CB scripts.${name} (already patched)`);
|
|
3064
3035
|
return;
|
|
3065
3036
|
}
|
|
3066
|
-
if (!
|
|
3037
|
+
if (!current.startsWith(ifStartsWith)) {
|
|
3067
3038
|
console.warn(
|
|
3068
3039
|
`[fullstack-cli] \u26A0 Skipped patching scripts.${name} because it has been customized`
|
|
3069
3040
|
);
|
package/package.json
CHANGED
|
@@ -210,28 +210,3 @@ else
|
|
|
210
210
|
echo " node_modules: $NODE_MODULES_SIZE"
|
|
211
211
|
echo ""
|
|
212
212
|
fi
|
|
213
|
-
|
|
214
|
-
# 仅成功的全构建生成 backendBuildID;必须在构建、产物准备和依赖裁剪之后。
|
|
215
|
-
# UI/Skill 内容由 SDK 独立计入总 hash;纯前端发布不替换已部署的 backendBuildID。
|
|
216
|
-
if [[ "${only_frontend_change:-false}" != "true" ]]; then
|
|
217
|
-
node - "$ROOT_DIR/dist" <<'NODE'
|
|
218
|
-
const fs = require('node:fs');
|
|
219
|
-
const path = require('node:path');
|
|
220
|
-
const { randomUUID } = require('node:crypto');
|
|
221
|
-
const dist = process.argv[2];
|
|
222
|
-
// 防止 build:server 空跑成功、却没有可交付的服务端入口。
|
|
223
|
-
if (!fs.statSync(path.join(dist, 'server/main.js')).isFile()) {
|
|
224
|
-
throw new Error('Missing server build output: dist/server/main.js');
|
|
225
|
-
}
|
|
226
|
-
// runtime cwd 分别为工程根、dist/(或整包解压到 dist-server/)、旧版 dist/server/。
|
|
227
|
-
// 与 MCP UI/Skill 的交付布局一致:复制产物时保留同一个 UUID,不在启动时生成。
|
|
228
|
-
const files = [
|
|
229
|
-
path.join(dist, 'mcp-build-id'),
|
|
230
|
-
path.join(dist, 'dist/mcp-build-id'),
|
|
231
|
-
path.join(dist, 'server/dist/mcp-build-id'),
|
|
232
|
-
];
|
|
233
|
-
for (const file of files) fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
234
|
-
const buildID = randomUUID();
|
|
235
|
-
for (const file of files) fs.writeFileSync(file, buildID, 'utf8');
|
|
236
|
-
NODE
|
|
237
|
-
fi
|
|
@@ -1,26 +1,53 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
const path = require('node:path');
|
|
4
|
-
const fs = require('node:fs');
|
|
5
4
|
const { spawn } = require('node:child_process');
|
|
5
|
+
const fs = require('node:fs');
|
|
6
6
|
|
|
7
7
|
const cwd = process.cwd();
|
|
8
8
|
|
|
9
|
+
function getBinName(name) {
|
|
10
|
+
return process.platform === 'win32' ? `${name}.cmd` : name;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function runCommand(command, args) {
|
|
14
|
+
return new Promise((resolve) => {
|
|
15
|
+
const child = spawn(command, args, {
|
|
16
|
+
cwd,
|
|
17
|
+
stdio: 'inherit',
|
|
18
|
+
shell: false,
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
child.on('close', (code) => resolve(code || 0));
|
|
22
|
+
child.on('error', () => resolve(1));
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// 串行依次执行每个任务,全部跑完后再聚合退出码:
|
|
27
|
+
// 降低并发资源占用、让各任务输出按顺序清晰可读,同时保留“一次暴露所有 lint 问题”的行为。
|
|
28
|
+
async function runTasksSerially(taskSpecs) {
|
|
29
|
+
let exitCode = 0;
|
|
30
|
+
for (const [command, args] of taskSpecs) {
|
|
31
|
+
const code = await runCommand(command, args);
|
|
32
|
+
if (code !== 0) {
|
|
33
|
+
exitCode = 1;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return exitCode;
|
|
37
|
+
}
|
|
38
|
+
|
|
9
39
|
function normalizeProjectFile(filePath) {
|
|
10
40
|
const absolutePath = path.isAbsolute(filePath)
|
|
11
41
|
? filePath
|
|
12
42
|
: path.resolve(cwd, filePath);
|
|
13
43
|
|
|
14
44
|
if (!fs.existsSync(absolutePath)) {
|
|
15
|
-
console.
|
|
45
|
+
console.warn(`[lint] Skip missing file: ${filePath}`);
|
|
46
|
+
return null;
|
|
16
47
|
}
|
|
17
48
|
|
|
18
49
|
const relativePath = path.relative(cwd, absolutePath);
|
|
19
|
-
if (
|
|
20
|
-
relativePath === '..' ||
|
|
21
|
-
relativePath.startsWith(`..${path.sep}`) ||
|
|
22
|
-
path.isAbsolute(relativePath)
|
|
23
|
-
) {
|
|
50
|
+
if (relativePath.startsWith('..')) {
|
|
24
51
|
console.warn(`[lint] Skip file outside project: ${filePath}`);
|
|
25
52
|
return null;
|
|
26
53
|
}
|
|
@@ -77,113 +104,7 @@ function canRunStylelint() {
|
|
|
77
104
|
|
|
78
105
|
if (!pkg.scripts || !pkg.scripts.stylelint) return false;
|
|
79
106
|
|
|
80
|
-
return STYLELINT_CONFIG_FILES.some(file =>
|
|
81
|
-
fs.existsSync(path.join(cwd, file))
|
|
82
|
-
);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
function getBinName(name) {
|
|
86
|
-
return process.platform === 'win32' ? `${name}.cmd` : name;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
function runCommand(command, args) {
|
|
90
|
-
return new Promise(resolve => {
|
|
91
|
-
const child = spawn(command, args, {
|
|
92
|
-
cwd,
|
|
93
|
-
stdio: 'inherit',
|
|
94
|
-
shell: false,
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
child.on('close', code => resolve(code ?? 1));
|
|
98
|
-
child.on('error', () => resolve(1));
|
|
99
|
-
});
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// 串行依次执行每个任务,全部跑完后再聚合退出码:
|
|
103
|
-
// 降低并发资源占用、让各任务输出按顺序清晰可读,同时保留“一次暴露所有 lint 问题”的行为。
|
|
104
|
-
async function runTasksSerially(taskSpecs) {
|
|
105
|
-
let exitCode = 0;
|
|
106
|
-
for (const [command, args] of taskSpecs) {
|
|
107
|
-
const code = await runCommand(command, args);
|
|
108
|
-
if (code !== 0) {
|
|
109
|
-
exitCode = 1;
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
return exitCode;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
const UI_DIR = 'server/mcp/ui';
|
|
116
|
-
|
|
117
|
-
function uiSourceFiles() {
|
|
118
|
-
const files = [];
|
|
119
|
-
function visit(relative) {
|
|
120
|
-
const absolute = path.join(cwd, relative);
|
|
121
|
-
if (!fs.existsSync(absolute)) return;
|
|
122
|
-
if (fs.lstatSync(absolute).isSymbolicLink()) {
|
|
123
|
-
throw new Error(`MCP UI 检查不支持符号链接: ${relative}`);
|
|
124
|
-
}
|
|
125
|
-
for (const entry of fs.readdirSync(absolute, { withFileTypes: true })) {
|
|
126
|
-
if (['node_modules', 'dist', '.git'].includes(entry.name)) continue;
|
|
127
|
-
const file = `${relative}/${entry.name}`;
|
|
128
|
-
if (entry.isSymbolicLink())
|
|
129
|
-
throw new Error(`MCP UI 检查不支持符号链接: ${file}`);
|
|
130
|
-
if (entry.isDirectory()) visit(file);
|
|
131
|
-
else if (isEslintTarget(file) && !/\.d\.(?:ts|mts|cts)$/.test(file))
|
|
132
|
-
files.push(file);
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
visit(UI_DIR);
|
|
136
|
-
return files.sort();
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
function uiTasks({ types = true, eslint = true } = {}) {
|
|
140
|
-
const sources = uiSourceFiles();
|
|
141
|
-
if (!sources.length) return [];
|
|
142
|
-
const tasks = [];
|
|
143
|
-
if (types) tasks.push([getBinName('npm'), ['run', 'type:check:mcp-ui']]);
|
|
144
|
-
if (eslint) {
|
|
145
|
-
const config = [
|
|
146
|
-
'eslint.mcp-ui.config.js',
|
|
147
|
-
'eslint.mcp-ui.config.cjs',
|
|
148
|
-
'eslint.mcp-ui.config.mjs',
|
|
149
|
-
].find(file => fs.existsSync(path.join(cwd, file)));
|
|
150
|
-
let resolvedConfig = config;
|
|
151
|
-
if (!resolvedConfig) {
|
|
152
|
-
try {
|
|
153
|
-
resolvedConfig =
|
|
154
|
-
require.resolve('@lark-apaas/fullstack-presets/lib/mcp/eslint-ui.js');
|
|
155
|
-
} catch {
|
|
156
|
-
throw new Error(
|
|
157
|
-
'请升级 @lark-apaas/fullstack-presets 以使用 MCP UI 默认 ESLint 配置,或提供 eslint.mcp-ui.config.cjs'
|
|
158
|
-
);
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
tasks.push([
|
|
162
|
-
getBinName('npx'),
|
|
163
|
-
[
|
|
164
|
-
'--no-install',
|
|
165
|
-
'eslint',
|
|
166
|
-
'--config',
|
|
167
|
-
resolvedConfig,
|
|
168
|
-
'--quiet',
|
|
169
|
-
'--max-warnings',
|
|
170
|
-
'0',
|
|
171
|
-
...sources,
|
|
172
|
-
],
|
|
173
|
-
]);
|
|
174
|
-
}
|
|
175
|
-
return tasks;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
function packageScripts() {
|
|
179
|
-
return (
|
|
180
|
-
JSON.parse(fs.readFileSync(path.join(cwd, 'package.json'), 'utf8'))
|
|
181
|
-
.scripts || {}
|
|
182
|
-
);
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
function isUiFile(file) {
|
|
186
|
-
return file.startsWith('server/mcp/ui/');
|
|
107
|
+
return STYLELINT_CONFIG_FILES.some(file => fs.existsSync(path.join(cwd, file)));
|
|
187
108
|
}
|
|
188
109
|
|
|
189
110
|
async function runDefaultLint() {
|
|
@@ -192,21 +113,10 @@ async function runDefaultLint() {
|
|
|
192
113
|
[getBinName('npm'), ['run', 'type:check']],
|
|
193
114
|
];
|
|
194
115
|
|
|
195
|
-
// 保留用户的 type:check;未聚合 UI 时由 lint 补查。
|
|
196
|
-
taskSpecs.push(
|
|
197
|
-
...uiTasks({
|
|
198
|
-
types: !/\bnpm\s+run\s+type:check:mcp-ui(?=[\s"';&|)]|$)/.test(
|
|
199
|
-
packageScripts()['type:check'] || ''
|
|
200
|
-
),
|
|
201
|
-
})
|
|
202
|
-
);
|
|
203
|
-
|
|
204
116
|
if (canRunStylelint()) {
|
|
205
117
|
taskSpecs.push([getBinName('npm'), ['run', 'stylelint']]);
|
|
206
118
|
} else {
|
|
207
|
-
console.warn(
|
|
208
|
-
'[lint] Skip stylelint: missing scripts.stylelint or stylelint config'
|
|
209
|
-
);
|
|
119
|
+
console.warn('[lint] Skip stylelint: missing scripts.stylelint or stylelint config');
|
|
210
120
|
}
|
|
211
121
|
|
|
212
122
|
process.exit(await runTasksSerially(taskSpecs));
|
|
@@ -214,7 +124,7 @@ async function runDefaultLint() {
|
|
|
214
124
|
|
|
215
125
|
async function runSelectiveLint(inputFiles) {
|
|
216
126
|
const normalizedFiles = Array.from(
|
|
217
|
-
new Set(inputFiles.map(normalizeProjectFile).filter(Boolean))
|
|
127
|
+
new Set(inputFiles.map(normalizeProjectFile).filter(Boolean)),
|
|
218
128
|
);
|
|
219
129
|
|
|
220
130
|
if (normalizedFiles.length === 0) {
|
|
@@ -222,41 +132,15 @@ async function runSelectiveLint(inputFiles) {
|
|
|
222
132
|
process.exit(0);
|
|
223
133
|
}
|
|
224
134
|
|
|
225
|
-
const eslintFiles = normalizedFiles.filter(
|
|
226
|
-
|
|
227
|
-
fs.existsSync(path.join(cwd, file)) &&
|
|
228
|
-
isEslintTarget(file) &&
|
|
229
|
-
!isUiFile(file) &&
|
|
230
|
-
!file.startsWith('eslint.mcp-ui.config.')
|
|
231
|
-
);
|
|
232
|
-
const stylelintFiles = normalizedFiles.filter(
|
|
233
|
-
file => fs.existsSync(path.join(cwd, file)) && isStylelintTarget(file)
|
|
234
|
-
);
|
|
135
|
+
const eslintFiles = normalizedFiles.filter(isEslintTarget);
|
|
136
|
+
const stylelintFiles = normalizedFiles.filter(isStylelintTarget);
|
|
235
137
|
const typeCheckFiles = normalizedFiles.filter(isTypeCheckTarget);
|
|
236
138
|
|
|
237
139
|
const clientTypeFiles = [];
|
|
238
140
|
const serverTypeFiles = [];
|
|
239
|
-
const rootConfigChanged = normalizedFiles.some(file =>
|
|
240
|
-
/^tsconfig(?:\.[^/]*)?\.json$/.test(file)
|
|
241
|
-
);
|
|
242
|
-
if (rootConfigChanged) {
|
|
243
|
-
clientTypeFiles.push('config');
|
|
244
|
-
serverTypeFiles.push('config');
|
|
245
|
-
}
|
|
246
|
-
let checkUi =
|
|
247
|
-
rootConfigChanged ||
|
|
248
|
-
normalizedFiles.some(
|
|
249
|
-
file =>
|
|
250
|
-
isUiFile(file) ||
|
|
251
|
-
file.startsWith('shared/') ||
|
|
252
|
-
file.startsWith('eslint.mcp-ui.config.') ||
|
|
253
|
-
file === 'package.json'
|
|
254
|
-
);
|
|
255
141
|
|
|
256
142
|
for (const filePath of typeCheckFiles) {
|
|
257
|
-
if (
|
|
258
|
-
checkUi = true;
|
|
259
|
-
} else if (filePath.startsWith('client/')) {
|
|
143
|
+
if (filePath.startsWith('client/')) {
|
|
260
144
|
clientTypeFiles.push(filePath);
|
|
261
145
|
} else if (filePath.startsWith('server/')) {
|
|
262
146
|
serverTypeFiles.push(filePath);
|
|
@@ -273,14 +157,9 @@ async function runSelectiveLint(inputFiles) {
|
|
|
273
157
|
}
|
|
274
158
|
|
|
275
159
|
if (stylelintFiles.length > 0 && !canRunStylelint()) {
|
|
276
|
-
console.warn(
|
|
277
|
-
'[lint] Skip stylelint: missing scripts.stylelint or stylelint config'
|
|
278
|
-
);
|
|
160
|
+
console.warn('[lint] Skip stylelint: missing scripts.stylelint or stylelint config');
|
|
279
161
|
} else if (stylelintFiles.length > 0) {
|
|
280
|
-
taskSpecs.push([
|
|
281
|
-
getBinName('npx'),
|
|
282
|
-
['stylelint', '--quiet', ...stylelintFiles],
|
|
283
|
-
]);
|
|
162
|
+
taskSpecs.push([getBinName('npx'), ['stylelint', '--quiet', ...stylelintFiles]]);
|
|
284
163
|
}
|
|
285
164
|
|
|
286
165
|
if (clientTypeFiles.length > 0) {
|
|
@@ -291,8 +170,6 @@ async function runSelectiveLint(inputFiles) {
|
|
|
291
170
|
taskSpecs.push([getBinName('npm'), ['run', 'type:check:server']]);
|
|
292
171
|
}
|
|
293
172
|
|
|
294
|
-
if (checkUi) taskSpecs.push(...uiTasks());
|
|
295
|
-
|
|
296
173
|
if (taskSpecs.length === 0) {
|
|
297
174
|
console.log('[lint] No supported files matched for lint');
|
|
298
175
|
process.exit(0);
|
|
@@ -302,16 +179,6 @@ async function runSelectiveLint(inputFiles) {
|
|
|
302
179
|
}
|
|
303
180
|
|
|
304
181
|
async function main() {
|
|
305
|
-
const args = process.argv.slice(2);
|
|
306
|
-
if (args.length === 1 && args[0] === '--eslint-mcp-ui') {
|
|
307
|
-
process.exit(await runTasksSerially(uiTasks({ types: false })));
|
|
308
|
-
return;
|
|
309
|
-
}
|
|
310
|
-
if (args.length && !(args[0] === '--files' && args.length > 1)) {
|
|
311
|
-
throw new Error('用法: lint.js [--files <paths...>]');
|
|
312
|
-
}
|
|
313
|
-
if (args[0] === '--files' && args.slice(1).some(arg => arg.startsWith('--')))
|
|
314
|
-
throw new Error('--files 不可与其他检查模式混用');
|
|
315
182
|
const files = parseFilesArg(process.argv.slice(2));
|
|
316
183
|
if (files === null) {
|
|
317
184
|
await runDefaultLint();
|
|
@@ -326,7 +193,7 @@ async function main() {
|
|
|
326
193
|
await runSelectiveLint(files);
|
|
327
194
|
}
|
|
328
195
|
|
|
329
|
-
main().catch(error => {
|
|
196
|
+
main().catch((error) => {
|
|
330
197
|
const message = error instanceof Error ? error.message : String(error);
|
|
331
198
|
console.error(`[lint] Failed to run lint: ${message}`);
|
|
332
199
|
process.exit(1);
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
// MCP UI 是可选浏览器工程;没有源码时跳过,否则直接交给 tsc。
|
|
2
|
-
const fs = require('node:fs');
|
|
3
|
-
const path = require('node:path');
|
|
4
|
-
const { spawnSync } = require('node:child_process');
|
|
5
|
-
|
|
6
|
-
function hasSource(dir) {
|
|
7
|
-
if (!fs.existsSync(dir)) return false;
|
|
8
|
-
return fs.readdirSync(dir, { withFileTypes: true }).some(entry => {
|
|
9
|
-
if (['node_modules', 'dist'].includes(entry.name)) return false;
|
|
10
|
-
if (entry.isDirectory()) return hasSource(path.join(dir, entry.name));
|
|
11
|
-
return entry.isFile() && /\.(?:[cm]?[jt]sx?)$/.test(entry.name);
|
|
12
|
-
});
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
if (hasSource('server/mcp/ui')) {
|
|
16
|
-
// 已有应用的独立 UI 配置继续生效,避免升级覆盖自定义 paths/types。
|
|
17
|
-
const config = fs.existsSync('server/mcp/ui/tsconfig.json')
|
|
18
|
-
? 'server/mcp/ui/tsconfig.json'
|
|
19
|
-
: 'tsconfig.mcp-ui.json';
|
|
20
|
-
const result = spawnSync(
|
|
21
|
-
process.execPath,
|
|
22
|
-
[
|
|
23
|
-
require.resolve('typescript/bin/tsc'),
|
|
24
|
-
'--noEmit',
|
|
25
|
-
'--project',
|
|
26
|
-
config,
|
|
27
|
-
],
|
|
28
|
-
{ stdio: 'inherit' }
|
|
29
|
-
);
|
|
30
|
-
if (result.error) console.error(result.error.message);
|
|
31
|
-
process.exitCode = result.status ?? 1;
|
|
32
|
-
}
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ES2020",
|
|
4
|
-
"module": "ESNext",
|
|
5
|
-
"moduleResolution": "Bundler",
|
|
6
|
-
"jsx": "react-jsx",
|
|
7
|
-
"types": [],
|
|
8
|
-
"strict": true,
|
|
9
|
-
"checkJs": true,
|
|
10
|
-
"lib": [
|
|
11
|
-
"ES2020",
|
|
12
|
-
"DOM",
|
|
13
|
-
"DOM.Iterable"
|
|
14
|
-
],
|
|
15
|
-
"allowJs": true,
|
|
16
|
-
"skipLibCheck": true,
|
|
17
|
-
"esModuleInterop": true,
|
|
18
|
-
"noEmit": true,
|
|
19
|
-
"baseUrl": ".",
|
|
20
|
-
"paths": {
|
|
21
|
-
"@shared/*": [
|
|
22
|
-
"shared/*"
|
|
23
|
-
]
|
|
24
|
-
}
|
|
25
|
-
},
|
|
26
|
-
"include": [
|
|
27
|
-
"server/mcp/ui/**/*"
|
|
28
|
-
],
|
|
29
|
-
"exclude": [
|
|
30
|
-
"node_modules",
|
|
31
|
-
"dist"
|
|
32
|
-
]
|
|
33
|
-
}
|