@lark-apaas/miaoda-cli 0.1.46 → 0.1.47

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.
@@ -2,25 +2,32 @@
2
2
  /**
3
3
  * vite-react → nestjs-react-fullstack 的跨 stack 迁移规则。
4
4
  *
5
- * 设计原则:**最小改动**。只动 fullstack 形态必须的文件 / package.json key,user 已有
6
- * 的 vite.config / tsconfig / eslint / prettier / tailwind / postcss / components.json
7
- * 等业务配置一律**保留**,不被 template 整体覆盖。
5
+ * 设计原则:**明确托管清单 + 定向适配 + 冲突按调用方策略处理**。
6
+ * - 明确托管的平台文件(scripts 清单、.githooks/pre-commit)按兼容模板整文件更新;清单外的
7
+ * scripts/ 用户文件保留。
8
+ * - 业务代码、server/shared、插件不整目录覆盖:只补平台启动所需的缺失文件,已有 app.module.ts
9
+ * 定向注册平台模块。
10
+ * - package.json / tsconfig / vite.config / index.html 等混合配置只改本次运行要求的部分,
11
+ * 保留 alias、paths、用户编译选项、HTML 自定义 head、额外 scripts 等业务部分。
12
+ * - 无法确定性处理(同路径不同内容、同 ID 插件、自定义同名 script、不支持的配置形态)一律
13
+ * action=conflict。冲突策略 stop(平台调用)下:执行前对原目录预检可识别冲突(不写盘),执行中
14
+ * 出现的冲突即停止,不覆盖用户内容;overwrite(手动 / Agent 调用)下按各规则说明用模板替换,
15
+ * 替换不了的保留用户内容(见 config/migrate.ts 各规则类型)。
8
16
  *
9
17
  * 步骤:
10
- * 1. src/ public/ 搬到 client/ 下(fullstack 布局)
11
- * 2. 清掉 vite-react 时代的根 index.html / eslint.config.mjs / package-lock.json
12
- * 3. 删 user package.json 里 lite SDK 相关 key(保留 coding-preset-vite-react)
13
- * 4. 把 NestJS server runtime 拷进来(server/ + nest-cli.json + tsconfig.node.json
14
- * + client/index.html 等 fullstack 形态新增的资产)
15
- * 5. 把 fullstack 必需的 scripts 加到 package.json(dev / build / type:check 等)
16
- * 6. 从 fullstack template/package.json 取版本号,精确加 NestJS 强依赖白名单
17
- * (client-toolkit + 几个 @nestjs/* + SWC 工具链 + fullstack-nestjs-core + hbs 等;
18
- * 不全量 merge)
19
- * 7. codemod 业务代码:@lark-apaas/client-toolkit-lite → @lark-apaas/client-toolkit
20
- * 8. codemod vite.config:defineConfig(...) → defineConfig(..., { fullstack: true }),
21
- * 让 coding-preset-vite-react 启用 fullstack dev-proxy / html-output / basename /
22
- * server-log 4 件套,vite 8080 反代 HTML / API 到 nest 3000
23
- * 9. set-stack 切 .spark/meta.json
18
+ * 1. src/ public/ 搬到 client/ 下(同名不同内容 → 冲突)
19
+ * 2. 旧 stack 平台残留:补 eslint.config.js 并带上旧配置的 globalIgnores,eslint.config.mjs 仅在是
20
+ * 平台默认内容时删除;lockfile 删除(依赖集合变化)
21
+ * 3. 删 user package.json 里 lite SDK / type=module
22
+ * 4. server 平台启动文件按缺失补齐 + app.module.ts 定向注册 PlatformModule / ViewModule
23
+ * 5. nest-cli.json 合并、tsconfig 三件套定向适配(exclude 随布局改写)、stylelint 缺失补齐
24
+ * 6. 根 index.html → client/index.html(HBS 骨架 + 用户 head/body 自定义部分)
25
+ * 7. 托管脚本清单更新;shared / .env 缺失补齐
26
+ * 8. 插件 shared/capabilities → server/capabilities(重复 ID 检查)
27
+ * 9. scripts 定向适配(旧平台写法改写、自定义同名冲突)
28
+ * 10. 从 fullstack template/package.json 取版本号,精确加 NestJS 强依赖白名单(SWC 钉 lockfile 版本)
29
+ * 11. codemod:lite → client-toolkit;vite.config alias src → client/src
30
+ * 12. set-stack 切 .spark/meta.json
24
31
  *
25
32
  * 跟 SDK 的协作:client-toolkit@1.2.52+ 顶层 single-entry 完整 re-export 了
26
33
  * client-toolkit-lite 全部 48 项 API(fullstack-plugin#1124),所以 codemod 只换
@@ -28,24 +35,76 @@
28
35
  */
29
36
  Object.defineProperty(exports, "__esModule", { value: true });
30
37
  exports.MIGRATE_CONFIG = void 0;
38
+ const fullstack_cli_pin_1 = require("../../config/fullstack-cli-pin");
39
+ const fullstack_managed_files_1 = require("../../config/fullstack-managed-files");
40
+ /**
41
+ * vite-react 模板默认的 eslint.config.mjs(规范化后)结构:只引 eslint/config 与
42
+ * @lark-apaas/coding-presets-react,导出 [globalIgnores([...]), ...eslintPresets.client]。
43
+ * 命中即视为平台默认、可由 fullstack 的 eslint.config.js 取代;否则视为用户定制 → 冲突。
44
+ */
45
+ const VITE_REACT_DEFAULT_ESLINT = 'import\\{globalIgnores\\}from"eslint/config"' +
46
+ 'import\\{eslintPresets\\}from"@lark-apaas/coding-presets-react"' +
47
+ 'exportdefault\\[(globalIgnores\\(\\[("[^"]*",?)*\\]\\),?)?\\.\\.\\.eslintPresets\\.client,?\\]';
48
+ /**
49
+ * 早期 vite-react 模板(coding-template-vite-react 0.1.8~0.1.17,2026-05~06 初)默认的
50
+ * eslint.config.mjs(规范化后):自包含的 flat config,直接引 @eslint/js / typescript-eslint /
51
+ * react-hooks / react-refresh,没有平台 preset。忽略列表允许不同。
52
+ */
53
+ const VITE_REACT_EARLY_DEFAULT_ESLINT = 'importjsfrom"@eslint\\/js"' +
54
+ 'importglobalsfrom"globals"' +
55
+ 'importreactHooksfrom"eslint-plugin-react-hooks"' +
56
+ 'importreactRefreshfrom"eslint-plugin-react-refresh"' +
57
+ 'importtseslintfrom"typescript-eslint"' +
58
+ 'import\\{defineConfig,globalIgnores\\}from"eslint\\/config"' +
59
+ 'exportdefaultdefineConfig\\(\\[' +
60
+ 'globalIgnores\\(\\[("[^"]*",?)*\\]\\),' +
61
+ '\\{files:\\["\\*\\*\\/\\*\\.\\{ts,tsx\\}"\\],' +
62
+ 'extends:\\[js\\.configs\\.recommended,tseslint\\.configs\\.recommended,reactHooks\\.configs\\.flat\\.recommended,reactRefresh\\.configs\\.vite,\\],' +
63
+ 'languageOptions:\\{ecmaVersion:2020,globals:globals\\.browser,\\},' +
64
+ 'rules:\\{"react-refresh\\/only-export-components":"off","@typescript-eslint\\/no-unused-vars":"off","@typescript-eslint\\/no-explicit-any":"off","@typescript-eslint\\/no-empty-object-type":"off","@typescript-eslint\\/no-require-imports":"off","no-empty":"off","prefer-const":"off","no-unused-labels":"off",\\},\\},\\]\\)';
31
65
  exports.MIGRATE_CONFIG = {
32
66
  from: 'vite-react',
33
67
  to: 'nestjs-react-fullstack',
34
68
  rules: [
35
- // ===== 1. 用户领地搬迁 =====
36
- { type: 'move-directory', from: 'src', to: 'client/src' },
37
- { type: 'move-directory', from: 'public', to: 'client/public' },
69
+ // ===== 1. 用户领地搬迁(同名不同内容冲突,不覆盖) =====
70
+ { type: 'move-directory', from: 'src', to: 'client/src', onConflict: 'fail' },
71
+ { type: 'move-directory', from: 'public', to: 'client/public', onConflict: 'fail' },
38
72
  // shared/ 不动(两边布局相同);.env / .spark_project 同理。
39
- // ===== 2. 清理 vite-react 残留 =====
40
- // 根 index.html 被 client/index.html 取代(fullstack 用 HBS 渲染)
41
- { type: 'delete-file', to: 'index.html' },
42
- // ESLint 9 flat config 文件名变了(user eslint.config.mjs → eslint.config.js)
43
- { type: 'delete-file', to: 'eslint.config.mjs' },
44
- // 依赖集合变了,lockfile 重新生成
45
- { type: 'delete-file', to: 'package-lock.json' },
73
+ // ===== 2. 清理 vite-react 平台残留 =====
74
+ // ESLint 9 flat config 文件名变了(eslint.config.mjs → eslint.config.js):先补新配置(用户已有则
75
+ // 保留),把旧配置 globalIgnores 的条目带过去 —— vite-react 模板排除了 **/components/ui/**,
76
+ // 不带过去 shadcn 组件会被 lint,组件里引用新版 react-hooks 规则的 disable 注释报"规则不存在"。
77
+ { type: 'file', from: 'eslint.config.js', to: 'eslint.config.js', overwrite: false },
78
+ { type: 'carry-eslint-ignores', from: 'eslint.config.mjs', to: 'eslint.config.js' },
79
+ // 新 preset(fullstack-presets simple client)比旧 preset(coding-presets-react)新增 / 加严的 error 级规则,
80
+ // 旧代码按旧规则合规、迁移后才违规,降为 warn,不让平台规范的增量拦下整次转换
81
+ {
82
+ type: 'relax-eslint-rules',
83
+ to: 'eslint.config.js',
84
+ files: ['client/**/*.{ts,tsx}', 'shared/**/*.{ts,tsx}'],
85
+ rules: [
86
+ '@lark-apaas/require-app-container',
87
+ '@lark-apaas/no-direct-capability-api',
88
+ '@lark-apaas/no-multiline-styled-jsx-classname',
89
+ '@lark-apaas/no-nested-styled-jsx',
90
+ '@lark-apaas/no-styled-jsx-data-uri-url-ref',
91
+ 'import/no-unresolved',
92
+ 'no-restricted-syntax',
93
+ ],
94
+ },
95
+ // 旧配置用户改过则冲突
96
+ {
97
+ type: 'remove-known-default',
98
+ to: 'eslint.config.mjs',
99
+ knownDefaults: [VITE_REACT_DEFAULT_ESLINT, VITE_REACT_EARLY_DEFAULT_ESLINT],
100
+ reason: 'customized ESLint config (eslint.config.mjs) cannot be converted automatically; move custom rules into eslint.config.js extending @lark-apaas/fullstack-presets, then retry',
101
+ },
102
+ // 依赖集合变了,lockfile 由原目录里的 npm install 重新生成。
103
+ // repair(已是目标布局)不删:只补安装,不重解析用户已锁定的依赖树。
104
+ { type: 'delete-file', to: 'package-lock.json', migrateOnly: true },
46
105
  // ===== 3. 从 user package.json 删 vite-react 专属字段 =====
47
106
  // 注意保留 devDependencies.@lark-apaas/coding-preset-vite-react —— user 迁移后
48
- // vite.config 仍用它(开 fullstack 模式即可),不切到 fullstack-vite-preset。
107
+ // vite.config 仍用它(由 MIAODA_APP_TYPE 开启全栈模式),不切到 fullstack-vite-preset。
49
108
  {
50
109
  type: 'delete-json-keys',
51
110
  to: 'package.json',
@@ -56,187 +115,142 @@ exports.MIGRATE_CONFIG = {
56
115
  'dependencies.@lark-apaas/client-toolkit-lite',
57
116
  ],
58
117
  },
59
- // ===== 4. fullstack 形态必需资产(覆盖 user 已有同名文件) =====
60
- // server/ 整目录:main.ts / app.module.ts / common/ / modules/view/ 等(fullstack 必需)
61
- { type: 'directory', from: 'server', to: 'server', overwrite: true },
62
- // nest-cli.json:整文件采用当前 fullstack template,除 Nest build 入口外还必须带上
63
- // compilerOptions.builder.type=swc 及配套 typeCheck/options。若这里只保留旧的空配置
64
- // 或字段级残缺合并,即使 package.json 已补齐 SWC 依赖,Nest 仍会回退到 TSC 构建。
65
- { type: 'file', from: 'nest-cli.json', to: 'nest-cli.json', overwrite: true },
66
- // tsconfig.* —— vite-react 时代 tsconfig 配 include: ["src"],迁完代码搬到 client/src,
67
- // include 路径不对 + 老 tsconfig.app 还 extends @lark-apaas/coding-presets-react;
68
- // 整体覆盖到 fullstack 版本(include 改 client/** + shared/**、extends fullstack-presets)。
69
- // user 自己加的 paths / strict 等设置如有需要,按 git diff 手动加回。
70
- { type: 'file', from: 'tsconfig.json', to: 'tsconfig.json', overwrite: true },
71
- { type: 'file', from: 'tsconfig.app.json', to: 'tsconfig.app.json', overwrite: true },
72
- { type: 'file', from: 'tsconfig.node.json', to: 'tsconfig.node.json', overwrite: true },
73
- // ESLint 9 flat config —— vite-react 用 eslint.config.mjs 已删,fullstack 用
74
- // eslint.config.js (commonjs) + extends @lark-apaas/fullstack-presets;user 通常不改
75
- { type: 'file', from: 'eslint.config.js', to: 'eslint.config.js', overwrite: true },
76
- // stylelint 配置 —— package.json 加了 `stylelint` script(下面 add-script 那条)
77
- // + npm run precommit 会调它,缺配置文件时报 `No configuration provided for
78
- // client/src/index.css`。fullstack template 的 .stylelintrc.js extends
79
- // @lark-apaas/fullstack-presets 的 stylelintPresetsOfSimple。
80
- { type: 'file', from: '.stylelintrc.js', to: '.stylelintrc.js', overwrite: true },
81
- // client/index.html:HBS 模板(fullstack 用,vite-react 用根 index.html 已删)
82
- { type: 'file', from: 'client/index.html', to: 'client/index.html', overwrite: true },
83
- // scripts/ 整目录:fullstack 形态启动 / 构建 / lint 所需的 8 个平台脚本(dev.sh /
84
- // dev.js / dev-local.js / build.sh / lint.js / prune-smart.js / run.sh / hooks/)。
85
- // dev.sh exec node dev.js,dev.js 才是并发起 nest + vite 的核心 —— 漏一个 dev 跑不起来。
86
- // overwrite: true:这些脚本由平台 cli 维护,user 一般不改;按 fullstack 版本覆盖。
87
- { type: 'directory', from: 'scripts', to: 'scripts', overwrite: true },
88
- // .githooks(fallback,user 已有则保留)
89
- { type: 'directory', from: '.githooks', to: '.githooks', overwrite: false },
90
- // shared/ fallback(user 已有同名文件保留,template 新增文件加入)
91
- { type: 'directory', from: 'shared', to: 'shared', overwrite: false },
92
- // .env fallback(user 没有时用 template 默认)
93
- { type: 'file', from: '.env', to: '.env', overwrite: false },
94
- // ===== 4.5. plugin 实例从 shared/capabilities 搬到 server/capabilities =====
95
- // vite-react (jsPage) 时期 plugin 实例 json 放在 shared/capabilities/<id>.json,
96
- // fullstack 形态走 server 侧装载,路径约定改成 server/capabilities/<id>.json。
97
- // 顺序约束:必须在 server/ 覆盖之后 —— server/ 是 overwrite:true,放前面会被擦掉。
98
- { type: 'move-directory', from: 'shared/capabilities', to: 'server/capabilities' },
99
- // ===== 5. 加 fullstack 形态必需的 scripts =====
100
- // 这些 scripts 用 user 现有的可能性低(vite-react 没有 nest 相关 script),直接覆盖
101
- {
102
- type: 'add-script',
103
- name: 'dev',
104
- command: './scripts/dev.sh',
105
- overwrite: true,
106
- },
107
- {
108
- type: 'add-script',
109
- name: 'dev:server',
110
- command: 'NODE_ENV=development nest start --watch',
111
- overwrite: true,
112
- },
113
- {
114
- type: 'add-script',
115
- name: 'dev:client',
116
- command: 'NODE_ENV=development vite --config vite.config.ts',
117
- overwrite: true,
118
- },
119
- {
120
- type: 'add-script',
121
- name: 'build',
122
- command: './scripts/build.sh',
123
- overwrite: true,
124
- },
125
- {
126
- type: 'add-script',
127
- name: 'build:server',
128
- command: 'NODE_ENV=production nest build',
129
- overwrite: true,
130
- },
131
- {
132
- type: 'add-script',
133
- name: 'build:client',
134
- command: 'NODE_ENV=production vite build --config vite.config.ts',
135
- overwrite: true,
136
- },
137
- {
138
- type: 'add-script',
139
- name: 'build:prod',
140
- command: 'npm run build:server && npm run build:client',
141
- overwrite: true,
142
- },
143
- {
144
- type: 'add-script',
145
- name: 'start',
146
- command: 'NODE_ENV=production node main.js',
147
- overwrite: true,
148
- },
149
- {
150
- type: 'add-script',
151
- name: 'type:check:server',
152
- command: 'tsc --noEmit --project tsconfig.node.json',
153
- overwrite: true,
154
- },
155
- {
156
- type: 'add-script',
157
- name: 'type:check:client',
158
- command: 'tsc --noEmit --project tsconfig.app.json',
159
- overwrite: true,
160
- },
118
+ // ===== 4. server:只补平台启动所需的缺失文件,不覆盖业务 server =====
119
+ { type: 'file', from: 'server/main.ts', to: 'server/main.ts', overwrite: false },
120
+ { type: 'file', from: 'server/app.module.ts', to: 'server/app.module.ts', overwrite: false },
121
+ { type: 'directory', from: 'server/common', to: 'server/common', overwrite: false },
122
+ { type: 'directory', from: 'server/modules/view', to: 'server/modules/view', overwrite: false },
123
+ // 已有业务 app.module.ts:定向注册 PlatformModule / ViewModule;main.ts 必须走平台 bootstrap
124
+ { type: 'adapt-nest-app-module', to: 'server/app.module.ts', checkMain: 'server/main.ts' },
125
+ // ===== 5. 构建 / 类型 / lint 配置 =====
126
+ // nest-cli.json:缺失时取模板;已存在时字段级合并(builder.type=swc 等平台键取模板值,
127
+ // 用户 assets / plugins 按 key 保留)。漏掉 SWC builder 会让 Nest 回退 TSC 构建。
161
128
  {
162
- type: 'add-script',
163
- name: 'type:check',
164
- command: 'concurrently -n "server,client" -c "blue,green" "npm run type:check:server" "npm run type:check:client"',
165
- overwrite: true,
129
+ type: 'merge-json',
130
+ from: 'nest-cli.json',
131
+ to: 'nest-cli.json',
132
+ arrayMerge: {
133
+ 'compilerOptions.assets': { key: 'include' },
134
+ 'compilerOptions.plugins': { key: 'name' },
135
+ },
166
136
  },
167
- // ----- 平台脚本调用链 -----
168
- // build.sh 步骤 1 跑 `npm run gen:openapi`,缺这条 npm ERR missing script,build 直接挂。
169
- // scripts/lint.js 内部 spawn `npm run eslint` 和 `npm run stylelint`,缺这两条 lint 挂。
170
- // 这些都是 fullstack 平台脚本自洽必需的桥接 script,user 不会自定义,直接覆盖。
137
+ // tsconfig:定向适配 —— 保留用户 paths / 编译选项,只改布局(src → client/src)与平台 preset
138
+ { type: 'adapt-tsconfig', role: 'root', from: 'tsconfig.json', to: 'tsconfig.json' },
171
139
  {
172
- type: 'add-script',
173
- name: 'gen:openapi',
174
- command: "echo 'UNSUPPORTED, SKIP'",
175
- overwrite: true,
176
- },
177
- {
178
- type: 'add-script',
179
- name: 'gen:db-schema',
180
- command: 'npx -y @lark-apaas/db-schema-sync@latest --output server/database/schema.ts --export-custom-types',
181
- overwrite: true,
182
- },
183
- {
184
- type: 'add-script',
185
- name: 'eslint',
186
- command: 'eslint . --quiet',
187
- overwrite: true,
188
- },
189
- {
190
- type: 'add-script',
191
- name: 'stylelint',
192
- command: 'stylelint client/src/**/*.css --quiet',
193
- overwrite: true,
194
- },
195
- {
196
- type: 'add-script',
197
- name: 'lint',
198
- command: 'node ./scripts/lint.js',
199
- overwrite: true,
140
+ type: 'adapt-tsconfig',
141
+ role: 'app',
142
+ from: 'tsconfig.app.json',
143
+ to: 'tsconfig.app.json',
144
+ legacyExtends: [
145
+ '@lark-apaas/coding-presets-react/lib/tsconfig/tsconfig.app.json',
146
+ // 早期模板(0.1.8~0.1.17)的 preset 包名
147
+ '@lark-apaas/coding-presets/lib/tsconfig/tsconfig.app.json',
148
+ ],
200
149
  },
150
+ { type: 'adapt-tsconfig', role: 'node', from: 'tsconfig.node.json', to: 'tsconfig.node.json' },
151
+ // stylelint:缺失时补模板(用户已有则保留);eslint.config.js 已在第 2 步补齐
152
+ // package.json 的 `stylelint` script + precommit 会调它,缺配置时报 `No configuration provided`
153
+ { type: 'file', from: '.stylelintrc.js', to: '.stylelintrc.js', overwrite: false },
154
+ // ===== 6. HTML 入口:根 index.html → client/index.html(HBS) =====
201
155
  {
202
- type: 'add-script',
203
- name: 'precommit',
204
- command: 'node scripts/hooks/run-precommit.js',
205
- overwrite: true,
156
+ type: 'adapt-html-entry',
157
+ from: 'index.html',
158
+ to: 'client/index.html',
159
+ template: 'client/index.html',
160
+ legacyEntry: '/src/index.tsx',
206
161
  },
162
+ // ===== 7. 平台托管文件(明确清单);shared / .env 缺失补齐 =====
163
+ // dev.sh exec node dev.js,dev.js 才是并发起 nest + vite 的核心 —— 漏一个 dev 跑不起来。
164
+ // 只更新清单内文件;vite-react 时代的 scripts/dev.mjs 等清单外文件原样保留。
165
+ ...(0, fullstack_managed_files_1.managedFileRules)(),
166
+ { type: 'directory', from: 'shared', to: 'shared', overwrite: false },
167
+ { type: 'file', from: '.env', to: '.env', overwrite: false },
168
+ // ===== 8. 插件实例 shared/capabilities → server/capabilities(重复 ID 检查) =====
169
+ // vite-react (jsPage) 时期 plugin 实例 json 放在 shared/capabilities/<id>.json,
170
+ // fullstack 形态走 server 侧装载,路径约定改成 server/capabilities/<id>.json。
171
+ { type: 'move-capabilities', from: 'shared/capabilities', to: 'server/capabilities' },
172
+ // ===== 9. scripts 定向适配 =====
173
+ // 平台脚本调用链需要的 script:缺失补齐;命中已识别旧平台写法改写;用户自定义同名 → 冲突。
174
+ // build.sh 跑 `npm run gen:openapi` / build:client / build:server;
175
+ // scripts/lint.js spawn `npm run eslint` / `npm run stylelint`。
207
176
  {
208
- type: 'add-script',
209
- name: 'upgrade',
210
- command: 'npx -y @lark-apaas/fullstack-cli sync --disable-gen-openapi',
211
- overwrite: true,
177
+ type: 'ensure-scripts',
178
+ to: 'package.json',
179
+ scripts: [
180
+ {
181
+ name: 'dev',
182
+ command: './scripts/dev.sh',
183
+ legacy: ['node scripts/dev.mjs'],
184
+ legacyPrefixes: ['npm run upgrade && '],
185
+ },
186
+ { name: 'dev:server', command: 'NODE_ENV=development nest start --watch' },
187
+ { name: 'dev:client', command: 'NODE_ENV=development vite --config vite.config.ts' },
188
+ { name: 'build', command: './scripts/build.sh', legacy: ['bash scripts/build.sh'] },
189
+ { name: 'build:server', command: 'NODE_ENV=production nest build' },
190
+ {
191
+ name: 'build:client',
192
+ command: 'NODE_ENV=production vite build --config vite.config.ts',
193
+ legacy: ['NODE_ENV=production vite build'],
194
+ },
195
+ { name: 'build:prod', command: 'npm run build:server && npm run build:client' },
196
+ { name: 'start', command: 'NODE_ENV=production node main.js' },
197
+ { name: 'type:check:server', command: 'tsc --noEmit --project tsconfig.node.json' },
198
+ { name: 'type:check:client', command: 'tsc --noEmit --project tsconfig.app.json' },
199
+ {
200
+ name: 'type:check',
201
+ command: 'concurrently -n "server,client" -c "blue,green" "npm run type:check:server" "npm run type:check:client"',
202
+ },
203
+ { name: 'gen:openapi', command: "echo 'UNSUPPORTED, SKIP'" },
204
+ {
205
+ name: 'gen:db-schema',
206
+ command: 'npx -y @lark-apaas/db-schema-sync@latest --output server/database/schema.ts --export-custom-types',
207
+ legacyPrefixes: [
208
+ 'fullstack-cli gen-db-schema',
209
+ `npx -y ${fullstack_cli_pin_1.FULLSTACK_CLI_PIN_SPEC} gen-db-schema`,
210
+ ],
211
+ },
212
+ { name: 'eslint', command: 'eslint . --quiet' },
213
+ { name: 'stylelint', command: 'stylelint client/src/**/*.css --quiet' },
214
+ {
215
+ name: 'lint',
216
+ command: 'node ./scripts/lint.js',
217
+ legacy: ['concurrently npm:typecheck npm:lint:eslint'],
218
+ legacyPrefixes: ['concurrently '],
219
+ },
220
+ {
221
+ name: 'precommit',
222
+ command: 'node scripts/hooks/run-precommit.js',
223
+ legacy: ['npm run lint'],
224
+ },
225
+ {
226
+ name: 'prepare',
227
+ command: 'chmod +x .githooks/pre-commit 2>/dev/null; git config core.hooksPath .githooks 2>/dev/null || true',
228
+ legacy: ['node scripts/setup-git-hooks.mjs'],
229
+ keepCustom: true,
230
+ },
231
+ {
232
+ name: 'upgrade',
233
+ command: `npx -y ${fullstack_cli_pin_1.FULLSTACK_CLI_PIN_SPEC} sync --disable-gen-openapi`,
234
+ legacyPrefixes: ['fullstack-cli sync', 'npx -y @lark-apaas/fullstack-cli sync'],
235
+ },
236
+ ],
212
237
  },
213
- // ----- user 可能自定义的 scripts -----
214
- // format/test 多半 user 自己改过(prettier 配 / jest 配),保留 user 自有值。
238
+ // user 可能自定义的 scripts:只在缺失时补,不改用户已有值
215
239
  {
216
240
  type: 'add-script',
217
241
  name: 'format',
218
242
  command: 'prettier --write "{server,client,test}/**/*.{js,ts,tsx,json,md}"',
219
243
  overwrite: false,
220
244
  },
221
- {
222
- type: 'add-script',
223
- name: 'test',
224
- command: 'jest',
225
- overwrite: false,
226
- },
227
- {
228
- type: 'add-script',
229
- name: 'test:watch',
230
- command: 'jest --watch',
231
- overwrite: false,
232
- },
245
+ { type: 'add-script', name: 'test', command: 'jest', overwrite: false },
246
+ { type: 'add-script', name: 'test:watch', command: 'jest --watch', overwrite: false },
233
247
  {
234
248
  type: 'add-script',
235
249
  name: 'test:e2e',
236
250
  command: 'jest --config test/e2e/jest.config.js',
237
251
  overwrite: false,
238
252
  },
239
- // ===== 6. 从 fullstack template 取版本号加 NestJS 强依赖(精确白名单) =====
253
+ // ===== 10. 从 fullstack template 取版本号加 NestJS 强依赖(精确白名单) =====
240
254
  // 不走 merge-json(template 130+ devDeps 全 merge 会污染 user 业务依赖集合);
241
255
  // 白名单只列 fullstack 启动能跑起来必需的最小集。
242
256
  {
@@ -275,7 +289,7 @@ exports.MIGRATE_CONFIG = {
275
289
  // nest start / nest build 必需
276
290
  '@nestjs/cli',
277
291
  '@nestjs/testing',
278
- // nest-cli.json 会被上面的 file rule 覆盖成 builder.type=swc。Nest CLI 只负责
292
+ // nest-cli.json 会被上面的 merge-json 合并成 builder.type=swc。Nest CLI 只负责
279
293
  // 调度 builder,不会自带 SWC 可执行入口和 native compiler;两者必须一起从
280
294
  // 当前目标模板取版本写入迁移后 package.json。若漏掉,前端应用升级成全栈后
281
295
  // 配置已经选择 SWC,但全新的依赖安装树里找不到 @swc/cli/@swc/core,冷启动和
@@ -299,18 +313,32 @@ exports.MIGRATE_CONFIG = {
299
313
  // 配套的 .stylelintrc.js 由上面 file rule 从 template 搬过来。
300
314
  'stylelint',
301
315
  ],
316
+ // SWC 钉模板 lockfile 里的精确版本:迁移删了用户 lockfile,^range 会解析到模板发布之后的
317
+ // 新版本(@swc/core 1.16.18 在沙箱里加载 native binding 失败,nest 起不来)。钉 lockfile
318
+ // 版本后与同版本模板新建的应用一致,模板升级 SWC 时自动跟随。
319
+ exactFromLock: ['@swc/cli', '@swc/core'],
302
320
  },
303
- // ===== 7. 业务代码 codemod:lite → client-toolkit 包名替换 =====
321
+ // 10b. 托管构建脚本的配套依赖(@vercel/nft,build.sh → prune-smart.js):缺失才补固定版本,
322
+ // 已声明保持用户版本。迁移 / repair 的验证要跑完整 npm run build。
323
+ ...(0, fullstack_managed_files_1.managedBuildDependencyRules)(),
324
+ // ===== 11. 业务代码 codemod:lite → client-toolkit 包名替换 =====
304
325
  // client-toolkit@1.2.52+ 顶层完整 re-export lite 全部 48 项,specifier 列表不动。
305
326
  // 同时扫 shared/(client/server 共享代码也可能引 lite 类型 / utils)。
306
327
  { type: 'codemod-client-toolkit-lite', root: 'client/src' },
307
328
  { type: 'codemod-client-toolkit-lite', root: 'shared' },
308
- // ===== 8. vite.config codemod:加 { fullstack: true } 第二参 =====
309
- // user vite.config 现在是 defineConfig({...}) 单参;fullstack 形态需要 vite 8080
310
- // 反代 HTML / API 到 nest 3000,coding-preset-vite-react 用 fullstack option 启用
311
- // 这一行为(详见 fullstack-plugin coding-preset-vite-react#fullstack)。
312
- { type: 'codemod-vite-config-fullstack', to: 'vite.config.ts' },
313
- // ===== 9. 切 stack =====
329
+ // ===== 11b. vite.config:alias 路径 src → client/src =====
330
+ // 全栈模式由 coding-preset-vite-react 读 MIAODA_APP_TYPE 开启 dev-proxy(vite 8080 反代 HTML /
331
+ // API 到 nest 3000);用户 vite.config 不用该 preset 时无法确定性适配 → 冲突。缺失时补模板。
332
+ {
333
+ type: 'codemod-vite-config-fullstack',
334
+ to: 'vite.config.ts',
335
+ template: 'vite.config.ts',
336
+ requirePreset: '@lark-apaas/coding-preset-vite-react',
337
+ // 早期模板(0.1.8~0.1.10)的 preset 包名:配置里只有 defineConfig({ resolve.alias }),换包等价;
338
+ // 新包在 followLatestPackages 里,安装时补上
339
+ legacyPresets: ['@lark-apaas/coding-vite-preset'],
340
+ },
341
+ // ===== 12. 切 stack =====
314
342
  { type: 'set-stack', stack: 'nestjs-react-fullstack' },
315
343
  ],
316
344
  // install 收尾要钉 latest 的关键平台包 —— 见 MigrateConfig.followLatestPackages 注释。
@@ -318,5 +346,7 @@ exports.MIGRATE_CONFIG = {
318
346
  // 这些 API 当前只在 alpha 版本里。template caret range 不匹配 pre-release,必须显式 latest。
319
347
  // - coding-preset-vite-react:本次切到 MIAODA_APP_TYPE='3' env 检测,老版本 preset 不认 env。
320
348
  followLatestPackages: ['@lark-apaas/client-toolkit', '@lark-apaas/coding-preset-vite-react'],
349
+ // 不配置 verify(不做完整构建):发布时 DevOps 构建机会完整构建一次,转换问题在预览 / 发布时暴露;
350
+ // 沙箱里跑模板 build.sh 还会经裸名 `npx fullstack-cli` 解析到公网同名第三方包。
321
351
  };
322
352
  exports.default = exports.MIGRATE_CONFIG;
@@ -58,19 +58,18 @@ exports.SYNC_CONFIG = {
58
58
  to: '.gitignore',
59
59
  line: '.npm_cache',
60
60
  },
61
- // 3. 老 npm scripts 迁移(裸 fullstack-cli → 钉版 npx)。两条 ifStartsWith 分别覆盖
62
- // "裸 fullstack-cli"(最老形态)和 "npx 未钉版" 形态,统一升到 FULLSTACK_CLI_PIN_SPEC。
61
+ // 3. 完整旧平台 postinstall 迁移到 scoped npx,保留用户追加命令和自定义参数。
63
62
  {
64
63
  type: 'patch-script',
65
64
  name: 'postinstall',
66
65
  to: `npx -y ${fullstack_cli_pin_1.FULLSTACK_CLI_PIN_SPEC} action-plugin init`,
67
- ifStartsWith: 'fullstack-cli action-plugin init',
66
+ ifMatches: [/^fullstack-cli action-plugin init$/],
68
67
  },
69
68
  {
70
69
  type: 'patch-script',
71
70
  name: 'postinstall',
72
71
  to: `npx -y ${fullstack_cli_pin_1.FULLSTACK_CLI_PIN_SPEC} action-plugin init`,
73
- ifStartsWith: 'npx -y @lark-apaas/fullstack-cli action-plugin init',
72
+ ifMatches: [/^npx -y @lark-apaas\/fullstack-cli action-plugin init$/],
74
73
  },
75
74
  {
76
75
  type: 'patch-script',
@@ -10,24 +10,14 @@
10
10
  Object.defineProperty(exports, "__esModule", { value: true });
11
11
  exports.SYNC_CONFIG = void 0;
12
12
  const fullstack_cli_pin_1 = require("../../config/fullstack-cli-pin");
13
+ const fullstack_managed_files_1 = require("../../config/fullstack-managed-files");
13
14
  exports.SYNC_CONFIG = {
14
15
  sync: [
15
16
  // ===== fullstack-cli sync 同款规则(对齐沙箱行为) =====
16
- // 1. 派生 scripts 目录(包含 dev.sh / dev-local.js / dev.js / build.sh / run.sh /
17
- // lint.js / prune-smart.js / hooks/run-precommit.js;directory rule 自动给 .sh +x)
18
- {
19
- type: 'directory',
20
- from: 'scripts',
21
- to: 'scripts',
22
- overwrite: true,
23
- },
24
- // 1a. 同步 .githooks 目录(hook 入口,可执行 sh 脚本)
25
- {
26
- type: 'directory',
27
- from: '.githooks',
28
- to: '.githooks',
29
- overwrite: true,
30
- },
17
+ // 1. 平台托管文件(明确清单,见 config/fullstack-managed-files.ts):dev.sh / dev.js /
18
+ // dev-local.js / build.sh / run.sh / lint.js / prune-smart.js / hooks/run-precommit.js
19
+ // 与 .githooks/pre-commit。逐文件同名更新(.sh 自动 +x),清单外的 scripts/ 用户文件保留。
20
+ ...(0, fullstack_managed_files_1.managedFileRules)(),
31
21
  // 1b. scripts.prepare:npm install 后自动激活 git hooks(原生 git,无第三方依赖)
32
22
  // 直接写 core.hooksPath,并保底给 pre-commit 加执行位;非 git 仓库下静默退出
33
23
  {
@@ -67,28 +57,26 @@ exports.SYNC_CONFIG = {
67
57
  // 5. 注册 postinstall 脚本,自动恢复 action plugins。
68
58
  // 用 npx -y 形式而不是裸 fullstack-cli:用户项目的 deps 没有 fullstack-cli,
69
59
  // bare 形式在新机器(PATH 没全局 fullstack-cli)下 npm i 立即 ENOENT。
70
- // fullstack-cli 版本临时钉到 FULLSTACK_CLI_PIN_SPEC,避免 npx 走 latest 碰外部回归版本。
71
60
  {
72
61
  type: 'add-script',
73
62
  name: 'postinstall',
74
63
  command: `npx -y ${fullstack_cli_pin_1.FULLSTACK_CLI_PIN_SPEC} action-plugin init`,
75
64
  overwrite: false,
76
65
  },
77
- // 5a. 迁移已有应用的老形式 postinstall(裸 fullstack-cli → npx -y 钉版)。
78
- // patch-script 只在脚本以指定前缀开头时改写,用户真正手改过的脚本保持原样。
66
+ // 5a. 迁移完整旧平台 postinstall(裸 fullstack-cli → scoped npx)。
67
+ // 整值匹配,保留用户追加命令和自定义参数。
79
68
  {
80
69
  type: 'patch-script',
81
70
  name: 'postinstall',
82
71
  to: `npx -y ${fullstack_cli_pin_1.FULLSTACK_CLI_PIN_SPEC} action-plugin init`,
83
- ifStartsWith: 'fullstack-cli action-plugin init',
72
+ ifMatches: [/^fullstack-cli action-plugin init$/],
84
73
  },
85
- // 5b. 迁移已有应用 npx 未钉版的 postinstall —— sync 之前的版本生成的是
86
- // `npx -y @lark-apaas/fullstack-cli action-plugin init`(无版本号),现在统一钉版。
74
+ // 5b. 迁移完整旧 scoped npx postinstall,显式采用配置的渠道 spec(当前为 latest)。
87
75
  {
88
76
  type: 'patch-script',
89
77
  name: 'postinstall',
90
78
  to: `npx -y ${fullstack_cli_pin_1.FULLSTACK_CLI_PIN_SPEC} action-plugin init`,
91
- ifStartsWith: 'npx -y @lark-apaas/fullstack-cli action-plugin init',
79
+ ifMatches: [/^npx -y @lark-apaas\/fullstack-cli action-plugin init$/],
92
80
  },
93
81
  // 5c. gen:db-schema —— 把裸 `fullstack-cli gen-db-schema` 迁到钉版 npx。
94
82
  // 这条只在 user app 自己 package.json 已经有 gen:db-schema 时才动(patch-script
@@ -144,7 +132,7 @@ exports.SYNC_CONFIG = {
144
132
  to: './scripts/dev.sh',
145
133
  ifStartsWith: 'npm run upgrade && ',
146
134
  },
147
- // 11. 把 `upgrade` 脚本里裸 `fullstack-cli sync` 改成钉版 npx。
135
+ // 11. 把 `upgrade` 脚本里裸 `fullstack-cli sync` 改成 scoped npx。
148
136
  // 跟 postinstall 同款根因:fullstack-cli 不是用户应用的 dep,新机器无全局命令会 ENOENT。
149
137
  {
150
138
  type: 'patch-script',