@lark-apaas/coding-template-nestjs-react-fullstack 0.1.40-alpha.20260915110512 → 0.1.40-alpha.20260915170225

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 CHANGED
@@ -27,6 +27,25 @@ MIAODA_APP_TYPE=3 npx @lark-apaas/miaoda-cli@<latest> app init \
27
27
  - `SANDBOX_PUBLIC_URL` —— 沙箱公网域
28
28
  - `CLIENT_BASE_PATH=/app/<app_id>/` —— React Router basename + Vite base
29
29
 
30
+ ## MCP UI 的类型与代码检查
31
+
32
+ `server/mcp/ui` 是独立浏览器工程,主应用的 TypeScript 和 ESLint 配置排除该目录。
33
+ `npm run lint` 通过现有 `scripts/lint.js` 统一调度检查:
34
+
35
+ | 命令 | 检查范围 |
36
+ | --- | --- |
37
+ | `npm run type:check` | 服务端、客户端、MCP UI 类型检查 |
38
+ | `npm run type:check:mcp-ui` | 仅 MCP UI 类型检查 |
39
+ | `npm run eslint:mcp-ui` | 仅 MCP UI ESLint 检查 |
40
+ | `npm run lint -- --files <files...>` | 根据改动文件选择检查范围 |
41
+
42
+ 模板不预建 UI 目录。Agent 开发 MCP UI 时,按照 MCP 指南生成
43
+ `server/mcp/ui/tsconfig.json` 和根目录 `eslint.mcp-ui.config.cjs`。
44
+ 没有 UI 源码时跳过独立检查;存在源码但配置缺失或未覆盖源码时明确报错。
45
+
46
+ 存量应用通过本地 `miaoda app sync` 或沙箱 `fullstack-cli sync` 更新脚本、迁移已知模板命令,
47
+ 并保留现有 TS 排除项。自定义检查命令会保留,开发者需自行接入独立 UI 检查。
48
+
30
49
  ## 包结构
31
50
 
32
51
  ```
@@ -39,3 +58,30 @@ MIAODA_APP_TYPE=3 npx @lark-apaas/miaoda-cli@<latest> app init \
39
58
  `template/` 内以下划线开头的占位文件(`_gitignore` / `_npmrc` / `_env.local`)在 `miaoda app init`
40
59
  渲染时会按 RENAME 映射改回正常名(npm pack 会特殊处理 `.gitignore`、且 `.npmrc` 直接放
41
60
  在包里会污染用户 `npm install` 行为,所以都要 underscore 前缀)。
61
+
62
+ ## MCP 后端构建标识
63
+
64
+ `npm run build` 的 `scripts/build.sh` 在服务端、客户端构建、产物准备和依赖裁剪全部成功后,
65
+ 用 Node 内置 `crypto.randomUUID()` 生成一次纯文本 UUID(36 字符,无需发布环境变量)。
66
+ 同次构建写入下列文件,内容完全相同:
67
+
68
+ | 构建文件(相对工程根) | 对应运行目录 |
69
+ | --- | --- |
70
+ | `dist/mcp-build-id` | 工程根 |
71
+ | `dist/dist/mcp-build-id` | `dist/`,或整个 `dist/` 复制/解压到的 `dist-server/` |
72
+ | `dist/server/dist/mcp-build-id` | 旧布局 `dist/server/`,或该目录复制/解压到的 `dist-server/` |
73
+
74
+ SDK 统一读取 `cwd/dist/mcp-build-id`;production 首次读取后缓存。
75
+ 复制/部署同一产物必须保留文件,不在启动时重新生成 UUID;再次成功全构建会得到新的 UUID。
76
+ 直接运行 `build:server` 不完成交付流程,不能替代 `npm run build`。
77
+ SDK 在文件缺失时不返回 `appRevision`,标准 MCP 仍可用;开发态使用进程单例 UUID,不读构建文件。
78
+ UI/Skill 内容仍由 SDK 计入总 hash,独立修改这些产物不会重写 `backendBuildID`。
79
+
80
+ `only_frontend_change=true` 跳过服务端构建、依赖裁剪和 UUID 生成。
81
+ 构建目录仍按原逻辑清空;平台跳过服务端包上传,所以已部署服务的旧 ID 保持不变。
82
+ `server/mcp/ui`、`server/mcp/skills` 的源码变更应由平台判为全构建;它们不属于 `client/`。
83
+ 平台实际根据配置的前端路径前缀匹配变更前后路径,不能把 `server/mcp` 列为前端前缀。
84
+ 即使 client build 在本地写出了 `mcp-ui`,纯前端发布也不携带服务端 MCP 产物,**不承诺热更 MCP UI**。
85
+
86
+ 存量应用通过既有 `fullstack-cli sync` 或 `miaoda app sync` 的 `scripts/` 目录覆盖同步获得此脚本,
87
+ 同步本身不生成 UUID、不修改已有构建标识,无新增用户 CLI 命令。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lark-apaas/coding-template-nestjs-react-fullstack",
3
- "version": "0.1.40-alpha.20260915110512",
3
+ "version": "0.1.40-alpha.20260915170225",
4
4
  "description": "NestJS + React fullstack template for miaoda coding",
5
5
  "type": "module",
6
6
  "files": [
@@ -9,7 +9,7 @@ module.exports = tseslint.config(
9
9
  'node_modules',
10
10
  'source_package',
11
11
  'client/src/api/gen',
12
- // MCP UI 是独立浏览器工程,暂不参与主应用的 ESLint 检查。
12
+ // MCP UI 使用独立浏览器配置,由 lint.js 使用 eslint.mcp-ui.config.cjs 独立检查。
13
13
  'server/mcp/ui/**',
14
14
  '**/*.d.ts',
15
15
  '**/*.js.map',
@@ -8,7 +8,7 @@
8
8
  "name": "fullstack-nestjs-template",
9
9
  "version": "2.3.0",
10
10
  "dependencies": {
11
- "@lark-apaas/fullstack-nestjs-core": "1.1.62-alpha.20260915105802",
11
+ "@lark-apaas/fullstack-nestjs-core": "1.1.62-alpha.20260915164949",
12
12
  "@nestjs/axios": "^4.0.1",
13
13
  "@nestjs/cache-manager": "^3.1.3",
14
14
  "@nestjs/common": "^10.4.20",
@@ -33,7 +33,7 @@
33
33
  "devDependencies": {
34
34
  "@hookform/resolvers": "^5.2.2",
35
35
  "@lark-apaas/client-toolkit": "^1.2.70",
36
- "@lark-apaas/coding-preset-vite-react": "1.0.23-alpha.20260915105803",
36
+ "@lark-apaas/coding-preset-vite-react": "1.0.23-alpha.20260915164951",
37
37
  "@lark-apaas/fullstack-presets": "^1.1.0",
38
38
  "@nestjs/cli": "^10.4.9",
39
39
  "@radix-ui/react-accordion": "^1.2.12",
@@ -1634,9 +1634,9 @@
1634
1634
  "license": "MIT"
1635
1635
  },
1636
1636
  "node_modules/@lark-apaas/coding-preset-vite-react": {
1637
- "version": "1.0.23-alpha.20260915105803",
1638
- "resolved": "https://registry.npmmirror.com/@lark-apaas/coding-preset-vite-react/-/coding-preset-vite-react-1.0.23-alpha.20260915105803.tgz",
1639
- "integrity": "sha512-GwUV/4DHWibTx0GrhflevI2kWC+4UqjtHucAwHWJpvD7rd8Q+AdQEIAvYVj5nKZ6QuCc8yQEAMKSwvREDTwcEg==",
1637
+ "version": "1.0.23-alpha.20260915164951",
1638
+ "resolved": "https://registry.npmmirror.com/@lark-apaas/coding-preset-vite-react/-/coding-preset-vite-react-1.0.23-alpha.20260915164951.tgz",
1639
+ "integrity": "sha512-5QRc/9rXGp9GYP7ISD9nN99Jt8/NHzro3BnSj3QezaAzBBzH5OMFQOySK3BKFVqvWvnXTNpTiAzt9EioGiVNWQ==",
1640
1640
  "dev": true,
1641
1641
  "license": "MIT",
1642
1642
  "dependencies": {
@@ -1697,9 +1697,9 @@
1697
1697
  }
1698
1698
  },
1699
1699
  "node_modules/@lark-apaas/fullstack-nestjs-core": {
1700
- "version": "1.1.62-alpha.20260915105802",
1701
- "resolved": "https://registry.npmmirror.com/@lark-apaas/fullstack-nestjs-core/-/fullstack-nestjs-core-1.1.62-alpha.20260915105802.tgz",
1702
- "integrity": "sha512-7eJM0cJ0jqjhKCslzyl5SX6l7RE0CRCWXWW4I6u5SZN0NDogNcYU11uWjXbscZnqIsLwNiQj+tOnk5iKeSkSYA==",
1700
+ "version": "1.1.62-alpha.20260915164949",
1701
+ "resolved": "https://registry.npmmirror.com/@lark-apaas/fullstack-nestjs-core/-/fullstack-nestjs-core-1.1.62-alpha.20260915164949.tgz",
1702
+ "integrity": "sha512-l5OUcUnbRFWcP8FArwFXkn0kwPDiM4Mu7jSEROGJuHMoOA7DRBZlEfTL9HB6sXXsX92Jo5YJophb2sFCC14KGw==",
1703
1703
  "license": "MIT",
1704
1704
  "dependencies": {
1705
1705
  "@lark-apaas/cache-service": "^0.1.1",
@@ -1712,7 +1712,7 @@
1712
1712
  "@lark-apaas/nestjs-datapaas": "^1.0.21",
1713
1713
  "@lark-apaas/nestjs-http-forwarder": "^0.1.3",
1714
1714
  "@lark-apaas/nestjs-logger": "^1.0.17",
1715
- "@lark-apaas/nestjs-mcp": "0.1.1-alpha.20260915105801",
1715
+ "@lark-apaas/nestjs-mcp": "0.1.1-alpha.20260915164952",
1716
1716
  "@lark-apaas/nestjs-observable": "^0.0.12",
1717
1717
  "@lark-apaas/nestjs-openapi-devtools": "^1.0.10",
1718
1718
  "@lark-apaas/nestjs-trigger": "^0.0.3",
@@ -1945,9 +1945,9 @@
1945
1945
  }
1946
1946
  },
1947
1947
  "node_modules/@lark-apaas/nestjs-mcp": {
1948
- "version": "0.1.1-alpha.20260915105801",
1949
- "resolved": "https://registry.npmmirror.com/@lark-apaas/nestjs-mcp/-/nestjs-mcp-0.1.1-alpha.20260915105801.tgz",
1950
- "integrity": "sha512-VjW7VlIb24fFktFtzVxySetClX0yD0l5Eixx80LtnsdyKaOKWRW3GCZaVLb0Kn6k5cAao8kF/bImPp55u47Olg==",
1948
+ "version": "0.1.1-alpha.20260915164952",
1949
+ "resolved": "https://registry.npmmirror.com/@lark-apaas/nestjs-mcp/-/nestjs-mcp-0.1.1-alpha.20260915164952.tgz",
1950
+ "integrity": "sha512-TxZ0BAISQKmjLLLjQ2vFsM41J98qSqgg82/MjB950uxm1UgalYbhLe2ok/CdE1SXziO+gvQb3yfZG6avI8muJA==",
1951
1951
  "license": "MIT",
1952
1952
  "dependencies": {
1953
1953
  "@modelcontextprotocol/ext-apps": "^1.7.5",
@@ -18,7 +18,7 @@
18
18
  "build:server": "NODE_ENV=production nest build",
19
19
  "build:client": "NODE_ENV=production vite build --config vite.config.ts",
20
20
  "start": "NODE_ENV=production node main.js",
21
- "eslint": "eslint . --quiet",
21
+ "eslint": "eslint . --quiet --ignore-pattern \"server/mcp/ui/**\"",
22
22
  "stylelint": "stylelint client/src/**/*.css --quiet",
23
23
  "type:check": "node ./scripts/lint.js --typecheck",
24
24
  "type:check:client": "tsc --noEmit --project tsconfig.app.json",
@@ -30,7 +30,7 @@
30
30
  "eslint:mcp-ui": "node ./scripts/lint.js --eslint-mcp-ui"
31
31
  },
32
32
  "dependencies": {
33
- "@lark-apaas/fullstack-nestjs-core": "1.1.62-alpha.20260915105802",
33
+ "@lark-apaas/fullstack-nestjs-core": "1.1.62-alpha.20260915164949",
34
34
  "@nestjs/axios": "^4.0.1",
35
35
  "@nestjs/cache-manager": "^3.1.3",
36
36
  "@nestjs/common": "^10.4.20",
@@ -55,7 +55,7 @@
55
55
  "devDependencies": {
56
56
  "@hookform/resolvers": "^5.2.2",
57
57
  "@lark-apaas/client-toolkit": "^1.2.70",
58
- "@lark-apaas/coding-preset-vite-react": "1.0.23-alpha.20260915105803",
58
+ "@lark-apaas/coding-preset-vite-react": "1.0.23-alpha.20260915164951",
59
59
  "@lark-apaas/fullstack-presets": "^1.1.0",
60
60
  "@nestjs/cli": "^10.4.9",
61
61
  "@radix-ui/react-accordion": "^1.2.12",
@@ -43,37 +43,43 @@ echo ""
43
43
  echo "🔨 [3/5] 并行构建 server 和 client"
44
44
  STEP_START=$(node -e "console.log(Date.now())")
45
45
 
46
- # 并行构建
47
- echo " ├─ 启动 server 构建..."
48
- npm run build:server > /tmp/build-server.log 2>&1 &
49
- SERVER_PID=$!
50
-
51
- echo " ├─ 启动 client 构建..."
52
- npm run build:client > /tmp/build-client.log 2>&1 &
53
- CLIENT_PID=$!
54
-
55
- # 等待两个构建完成
56
- SERVER_EXIT=0
57
- CLIENT_EXIT=0
58
-
59
- wait $SERVER_PID || SERVER_EXIT=$?
60
- wait $CLIENT_PID || CLIENT_EXIT=$?
61
-
62
- # 检查构建结果
63
- if [ $SERVER_EXIT -ne 0 ]; then
64
- echo " ❌ Server 构建失败"
65
- cat /tmp/build-server.log
66
- exit 1
46
+ # server/mcp(含 UI/Skill)变更必须由平台判定为全构建。
47
+ if [[ "${only_frontend_change:-false}" == "true" ]]; then
48
+ echo " ├─ 仅构建 client (only_frontend_change=true)"
49
+ npm run build:client > /tmp/build-client.log 2>&1
50
+ else
51
+ # 并行构建
52
+ echo " ├─ 启动 server 构建..."
53
+ npm run build:server > /tmp/build-server.log 2>&1 &
54
+ SERVER_PID=$!
55
+
56
+ echo " ├─ 启动 client 构建..."
57
+ npm run build:client > /tmp/build-client.log 2>&1 &
58
+ CLIENT_PID=$!
59
+
60
+ # 等待两个构建完成
61
+ SERVER_EXIT=0
62
+ CLIENT_EXIT=0
63
+
64
+ wait $SERVER_PID || SERVER_EXIT=$?
65
+ wait $CLIENT_PID || CLIENT_EXIT=$?
66
+
67
+ # 检查构建结果
68
+ if [ $SERVER_EXIT -ne 0 ]; then
69
+ echo " ❌ Server 构建失败"
70
+ cat /tmp/build-server.log
71
+ exit 1
72
+ fi
73
+
74
+ if [ $CLIENT_EXIT -ne 0 ]; then
75
+ echo " ❌ Client 构建失败"
76
+ cat /tmp/build-client.log
77
+ exit 1
78
+ fi
79
+
80
+ echo " ✅ Server 构建完成"
81
+ echo " ✅ Client 构建完成"
67
82
  fi
68
-
69
- if [ $CLIENT_EXIT -ne 0 ]; then
70
- echo " ❌ Client 构建失败"
71
- cat /tmp/build-client.log
72
- exit 1
73
- fi
74
-
75
- echo " ✅ Server 构建完成"
76
- echo " ✅ Client 构建完成"
77
83
  print_time $STEP_START
78
84
  echo ""
79
85
 
@@ -81,18 +87,21 @@ echo ""
81
87
  echo "📦 [4/5] 准备 server 依赖产物"
82
88
  STEP_START=$(node -e "console.log(Date.now())")
83
89
 
84
- mkdir -p "$OUT_DIR/dist/client"
90
+ if [[ "${only_frontend_change:-false}" != "true" ]]; then
91
+ mkdir -p "$OUT_DIR/dist/client"
85
92
 
86
- # public 先进(server setBaseViewsDir + nestjs-core 中间件同源 serve)
87
- if [ -d "$ROOT_DIR/client/public" ]; then
88
- cp -R "$ROOT_DIR/client/public/." "$OUT_DIR/dist/client/"
89
- fi
93
+ # public 先进(server setBaseViewsDir + nestjs-core 中间件同源 serve)
94
+ if [ -d "$ROOT_DIR/client/public" ]; then
95
+ cp -R "$ROOT_DIR/client/public/." "$OUT_DIR/dist/client/"
96
+ fi
97
+
98
+ # 构建产物 HTML 随后拷,覆盖 public 里的同名文件(保证入口页是构建版,不被 public 静默覆盖)
99
+ cp "$ROOT_DIR/dist/client/"*.html "$OUT_DIR/dist/client/" || true
90
100
 
91
- # 构建产物 HTML 随后拷,覆盖 public 里的同名文件(保证入口页是构建版,不被 public 静默覆盖)
92
- cp "$ROOT_DIR/dist/client/"*.html "$OUT_DIR/dist/client/" || true
101
+ # 拷贝 run.sh 文件
102
+ cp "$ROOT_DIR/scripts/run.sh" "$OUT_DIR/"
93
103
 
94
- # 拷贝 run.sh 文件
95
- cp "$ROOT_DIR/scripts/run.sh" "$OUT_DIR/"
104
+ fi
96
105
 
97
106
  # 清理无用文件
98
107
  rm -rf "$ROOT_DIR/dist/scripts"
@@ -106,7 +115,9 @@ echo "✂️ [5/5] 智能依赖裁剪"
106
115
  STEP_START=$(node -e "console.log(Date.now())")
107
116
 
108
117
  # 分析实际依赖、复制并裁剪 node_modules、生成精简的 package.json
109
- node "$ROOT_DIR/scripts/prune-smart.js"
118
+ if [[ "${only_frontend_change:-false}" != "true" ]]; then
119
+ node "$ROOT_DIR/scripts/prune-smart.js"
120
+ fi
110
121
 
111
122
  print_time $STEP_START
112
123
  echo ""
@@ -116,10 +127,37 @@ echo "构建完成"
116
127
  print_time $TOTAL_START
117
128
 
118
129
  # 输出产物信息
119
- DIST_SIZE=$(du -sh "$OUT_DIR" | cut -f1)
120
- NODE_MODULES_SIZE=$(du -sh "$OUT_DIR/node_modules" | cut -f1)
130
+ DIST_SIZE=$(du -sh "$ROOT_DIR/dist" | cut -f1)
121
131
  echo ""
122
132
  echo "📊 构建产物统计:"
123
133
  echo " 总大小: $DIST_SIZE"
124
- echo " node_modules: $NODE_MODULES_SIZE"
134
+ if [[ "${only_frontend_change:-false}" != "true" ]]; then
135
+ NODE_MODULES_SIZE=$(du -sh "$OUT_DIR/node_modules" | cut -f1)
136
+ echo " node_modules: $NODE_MODULES_SIZE"
137
+ fi
125
138
  echo ""
139
+
140
+ # 仅成功的全构建生成 backendBuildID;必须在构建、产物准备和依赖裁剪之后。
141
+ # UI/Skill 内容由 SDK 独立计入总 hash;纯前端发布不替换已部署的 backendBuildID。
142
+ if [[ "${only_frontend_change:-false}" != "true" ]]; then
143
+ node - "$ROOT_DIR/dist" <<'NODE'
144
+ const fs = require('node:fs');
145
+ const path = require('node:path');
146
+ const { randomUUID } = require('node:crypto');
147
+ const dist = process.argv[2];
148
+ // 防止 build:server 空跑成功、却没有可交付的服务端入口。
149
+ if (!fs.statSync(path.join(dist, 'server/main.js')).isFile()) {
150
+ throw new Error('Missing server build output: dist/server/main.js');
151
+ }
152
+ // runtime cwd 分别为工程根、dist/(或整包解压到 dist-server/)、旧版 dist/server/。
153
+ // 与 MCP UI/Skill 的交付布局一致:复制产物时保留同一个 UUID,不在启动时生成。
154
+ const files = [
155
+ path.join(dist, 'mcp-build-id'),
156
+ path.join(dist, 'dist/mcp-build-id'),
157
+ path.join(dist, 'server/dist/mcp-build-id'),
158
+ ];
159
+ for (const file of files) fs.mkdirSync(path.dirname(file), { recursive: true });
160
+ const buildID = randomUUID();
161
+ for (const file of files) fs.writeFileSync(file, buildID, 'utf8');
162
+ NODE
163
+ fi