@lark-apaas/miaoda-cli 0.1.20-alpha.dd573f8 → 0.1.20-beta.4eeca5a

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.
@@ -164,8 +164,6 @@ function registerAppInit(parent) {
164
164
  .command('init')
165
165
  .description('初始化应用代码:抓 template 渲染、同步 upgrade/templates、装 .agent/steering/ skills、写 .spark/meta.json。.spark/meta.json 已存在则直接退出')
166
166
  .option('--template <stack>', `技术栈短名(${index_1.SUPPORTED_STACKS.join(' / ')})`)
167
- .option('--app-type <type>', 'aPaaS 业务类型(html / modern_html / jspage / full_stack);未传 --template 时用于解析技术栈')
168
- .option('--source-path <path>', '导入源目录:把该目录内容聚合进脚手架 src/(当前仅 --app-type modern_html 生效)')
169
167
  .option('--conf <json>', 'init 配置 JSON。支持 {"version": "<template 版本>"},默认 latest')
170
168
  .option('--skip-install', '跳过依赖安装', false)
171
169
  .option('--async-install', '派发后台进程装依赖并立即返回(与 --skip-install 互斥)', false)
@@ -182,17 +180,6 @@ function registerAppInit(parent) {
182
180
  未提供则不写。运行端命令(deploy / file / plugin 等)仍优先读 MIAODA_APP_ID env,
183
181
  env 未设置时回退到 meta.json.app_id。
184
182
 
185
- 技术栈解析(--template / --app-type)
186
- --template 传了 → 直接用(vite-react / html / nestjs-react-fullstack)
187
- 否则 --app-type 传了 → 查表:html→html, modern_html→html, jspage→vite-react, full_stack→nestjs-react-fullstack
188
- 两者都没传 → 报错 ARGS_INVALID
189
-
190
- 源码导入(--source-path)
191
- 仅 --app-type modern_html 生效:把 <source-path> 整个目录递归聚合进 src/(同名覆盖,叠加保留)。
192
- 过滤:跳过 node_modules/.git/dist/build 目录,跳过 .env/.env.*/.DS_Store/.npmrc/package.json/lockfiles。
193
- source-path 不存在 → 报错;非 modern_html 传了 source-path → 警告并忽略,继续正常 init。
194
- app_type 不写入 .spark/meta.json。
195
-
196
183
  平台同步(upgrade/templates)
197
184
  init 内嵌一次 upgrade/templates 同步(跟 app upgrade 共用同一份 util):
198
185
  从 miaoda-cli 自带的 upgrade/templates/<stack>/ 同步 files/(覆盖)+ patches/
@@ -221,8 +208,7 @@ function registerAppInit(parent) {
221
208
  JSON 输出
222
209
  已初始化:{"data": {"initialized": false, "reason": "already_initialized", "targetDir": "..."}}
223
210
  新初始化:{"data": {"initialized": true, "template": "...", "templateVersion": "...", "steeringVersion": "...",
224
- "appId": "...", "appType": "modern_html", "sourceImported": true, "importedFileCount": 7,
225
- "platformStackFound": true, "platformSyncedFiles": [...],
211
+ "appId": "...", "platformStackFound": true, "platformSyncedFiles": [...],
226
212
  "installed": true, "installSource": "cache|npm|skipped", "installHash": "...", ...}}
227
213
  async 模式:{"data": {"initialized": true, "asyncInstall": true, "installed": false,
228
214
  "installSource": "async", "installPid": 123, "installLogPath": "...",
@@ -234,16 +220,12 @@ JSON 输出
234
220
  $ miaoda app init --template vite-react --conf '{"version": "0.1.0"}'
235
221
  $ miaoda app init --template vite-react --skip-install
236
222
  $ miaoda app init --template vite-react --async-install
237
- $ miaoda app init --app-type full_stack --app-id app_demo_xxx
238
- $ miaoda app init --app-type modern_html --source-path ./my-assets
239
223
  $ MIAODA_DEP_CACHE_DIR=/tmp/dep-cache miaoda app init --template vite-react
240
224
  `);
241
225
  cmd.action((0, shared_1.withHelp)(cmd, async (rawOpts) => {
242
226
  const conf = parseInitConf(rawOpts.conf);
243
227
  await (0, index_1.handleAppInit)({
244
228
  template: rawOpts.template,
245
- appType: rawOpts.appType,
246
- sourcePath: rawOpts.sourcePath,
247
229
  conf,
248
230
  skipInstall: rawOpts.skipInstall,
249
231
  appId: rawOpts.appId,
@@ -51,15 +51,23 @@ async function handleAppInit(opts) {
51
51
  });
52
52
  return;
53
53
  }
54
- const stack = (0, index_1.resolveStack)({ template: opts.template, appType: opts.appType });
54
+ const stack = opts.template;
55
+ if (!stack) {
56
+ throw new error_1.AppError('ARGS_INVALID', '缺少 --template <stack>', {
57
+ next_actions: [`可用 stack:${index_1.SUPPORTED_STACKS.join(', ')}`],
58
+ });
59
+ }
60
+ if (!index_1.SUPPORTED_STACKS.includes(stack)) {
61
+ throw new error_1.AppError('ARGS_INVALID', `不支持的 template: ${stack}`, {
62
+ next_actions: [`可用 stack:${index_1.SUPPORTED_STACKS.join(', ')}`],
63
+ });
64
+ }
55
65
  if (opts.asyncInstall && opts.skipInstall) {
56
66
  throw new error_1.AppError('ARGS_INVALID', '--async-install 与 --skip-install 互斥');
57
67
  }
58
68
  const version = opts.conf?.version;
59
69
  const projectName = node_path_1.default.basename(targetDir);
60
70
  const tplResult = (0, index_1.renderTemplate)({ stack, version, targetDir, projectName });
61
- // source_path 导入:当前仅 app_type=modern_html 生效。渲染完模板后、装依赖前叠加进 src/。
62
- const sourceImport = applySourcePathImport(opts, targetDir);
63
71
  // 先建 logs/,防止 user 跑 dev 之前 AI/工具 redirect 到 logs/*.log 因为父目录不存在直接挂
64
72
  // (dev.js / dev-local.js 自己也建 logs/,但只在它启动后;启动前的 shell redirect 会先于此)
65
73
  (0, logs_dir_1.ensureLogsDir)(targetDir);
@@ -127,11 +135,6 @@ async function handleAppInit(opts) {
127
135
  steeringVersion: steeringResult.version,
128
136
  archType: tplResult.archType,
129
137
  appId: opts.appId,
130
- appType: opts.appType,
131
- sourcePath: opts.sourcePath,
132
- sourceImported: sourceImport.sourceImported,
133
- importedFileCount: sourceImport.importedFileCount,
134
- sourceIgnoredReason: sourceImport.sourceIgnoredReason,
135
138
  syncedSkills: steeringResult.syncedSkills,
136
139
  techSynced: steeringResult.techSynced,
137
140
  steeringError,
@@ -156,25 +159,3 @@ async function handleAppInit(opts) {
156
159
  },
157
160
  });
158
161
  }
159
- /**
160
- * 处理 --source-path 导入:当前仅 app_type=modern_html 生效。
161
- * - 未传 source_path → 什么都不做
162
- * - modern_html → 调 importSourceSrc 把源目录聚合进 targetDir/src/
163
- * - 传了 source_path 但非 modern_html → 警告并忽略,继续正常 init(退出码 0)
164
- * 终端提示留在 handler 层(service 不做终端输出)。
165
- */
166
- function applySourcePathImport(opts, targetDir) {
167
- // 真值判断:未传或空串都视为"无 source_path"。
168
- if (!opts.sourcePath) {
169
- return { sourceImported: false };
170
- }
171
- if (opts.appType === 'modern_html') {
172
- const { importedFileCount } = (0, index_1.importSourceSrc)({ sourcePath: opts.sourcePath, targetDir });
173
- return { sourceImported: true, importedFileCount };
174
- }
175
- (0, logger_1.log)('init', '⚠ source-path ignored: 仅 app_type=modern_html 支持 source_path 导入');
176
- if (!(0, output_1.isJsonMode)()) {
177
- process.stdout.write('⚠ 不支持 source_path(仅 app_type=modern_html 生效),已忽略\n');
178
- }
179
- return { sourceImported: false, sourceIgnoredReason: 'not_modern_html' };
180
- }
@@ -67,9 +67,26 @@ exports.MIGRATE_CONFIG = {
67
67
  { type: 'file', from: 'tsconfig.json', to: 'tsconfig.json', overwrite: true },
68
68
  { type: 'file', from: 'tsconfig.app.json', to: 'tsconfig.app.json', overwrite: true },
69
69
  { type: 'file', from: 'tsconfig.node.json', to: 'tsconfig.node.json', overwrite: true },
70
+ // vite-react template 的 tsconfig 里有 exclude: ["src/components/ui"],把 shadcn 组件目录
71
+ // 整个从 typecheck 排除 —— 因为 template 里 shadcn 组件是老写法(recharts 2.x / RP v3 API),
72
+ // 但 dep 已经装到 recharts 3.x / RP v4 新版,两侧错配靠 exclude 藏起来。
73
+ // fullstack template 的 tsconfig 没这条 exclude,migrate 覆盖后 user 老 shadcn 组件
74
+ // (client/src/components/ui/*.tsx) 立刻被 tsc 扫到,chart.tsx / resizable.tsx 类型 / 命名报错。
75
+ // 这里在覆盖 tsconfig.app.json 之后补一行 exclude,跟 vite-react 行为对齐。
76
+ {
77
+ type: 'add-json-array-items',
78
+ to: 'tsconfig.app.json',
79
+ path: ['exclude'],
80
+ items: ['client/src/components/ui'],
81
+ },
70
82
  // ESLint 9 flat config —— vite-react 用 eslint.config.mjs 已删,fullstack 用
71
83
  // eslint.config.js (commonjs) + extends @lark-apaas/fullstack-presets;user 通常不改
72
84
  { type: 'file', from: 'eslint.config.js', to: 'eslint.config.js', overwrite: true },
85
+ // stylelint 配置 —— package.json 加了 `stylelint` script(下面 add-script 那条)
86
+ // + npm run precommit 会调它,缺配置文件时报 `No configuration provided for
87
+ // client/src/index.css`。fullstack template 的 .stylelintrc.js extends
88
+ // @lark-apaas/fullstack-presets 的 stylelintPresetsOfSimple。
89
+ { type: 'file', from: '.stylelintrc.js', to: '.stylelintrc.js', overwrite: true },
73
90
  // client/index.html:HBS 模板(fullstack 用,vite-react 用根 index.html 已删)
74
91
  { type: 'file', from: 'client/index.html', to: 'client/index.html', overwrite: true },
75
92
  // scripts/ 整目录:fullstack 形态启动 / 构建 / lint 所需的 8 个平台脚本(dev.sh /
@@ -274,6 +291,10 @@ exports.MIGRATE_CONFIG = {
274
291
  // (@lark-apaas/fullstack-presets/lib/simple/tsconfig/tsconfig.node.json);
275
292
  // 不装会导致 nest build / type:check:server / vite dev 解析 tsconfig 时 ENOENT
276
293
  '@lark-apaas/fullstack-presets',
294
+ // stylelint —— scripts.stylelint + npm run precommit 会调它,
295
+ // 缺依赖时 CI / 本地 precommit 报 "stylelint: command not found"。
296
+ // 配套的 .stylelintrc.js 由上面 file rule 从 template 搬过来。
297
+ 'stylelint',
277
298
  ],
278
299
  },
279
300
  // ===== 7. 业务代码 codemod:lite → client-toolkit 包名替换 =====
@@ -1,17 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ASYNC_INSTALL_LOG = exports.runAsyncInstallWorker = exports.dispatchAsyncInstall = exports.resolveNpmInstallRegistry = exports.installDependencies = exports.writeSparkMeta = exports.readSparkMeta = exports.IMPORT_SKIP_FILES = exports.IMPORT_SKIP_DIRS = exports.importSourceSrc = exports.TEMPLATE_PACKAGE_BY_STACK = exports.STACK_BY_APP_TYPE = exports.APP_TYPES = exports.SUPPORTED_STACKS = exports.resolveStack = exports.renderTemplate = void 0;
3
+ exports.ASYNC_INSTALL_LOG = exports.runAsyncInstallWorker = exports.dispatchAsyncInstall = exports.resolveNpmInstallRegistry = exports.installDependencies = exports.writeSparkMeta = exports.readSparkMeta = exports.TEMPLATE_PACKAGE_BY_STACK = exports.SUPPORTED_STACKS = exports.renderTemplate = void 0;
4
4
  var template_1 = require("./template");
5
5
  Object.defineProperty(exports, "renderTemplate", { enumerable: true, get: function () { return template_1.renderTemplate; } });
6
- Object.defineProperty(exports, "resolveStack", { enumerable: true, get: function () { return template_1.resolveStack; } });
7
6
  Object.defineProperty(exports, "SUPPORTED_STACKS", { enumerable: true, get: function () { return template_1.SUPPORTED_STACKS; } });
8
- Object.defineProperty(exports, "APP_TYPES", { enumerable: true, get: function () { return template_1.APP_TYPES; } });
9
- Object.defineProperty(exports, "STACK_BY_APP_TYPE", { enumerable: true, get: function () { return template_1.STACK_BY_APP_TYPE; } });
10
7
  Object.defineProperty(exports, "TEMPLATE_PACKAGE_BY_STACK", { enumerable: true, get: function () { return template_1.TEMPLATE_PACKAGE_BY_STACK; } });
11
- var import_source_1 = require("./import-source");
12
- Object.defineProperty(exports, "importSourceSrc", { enumerable: true, get: function () { return import_source_1.importSourceSrc; } });
13
- Object.defineProperty(exports, "IMPORT_SKIP_DIRS", { enumerable: true, get: function () { return import_source_1.IMPORT_SKIP_DIRS; } });
14
- Object.defineProperty(exports, "IMPORT_SKIP_FILES", { enumerable: true, get: function () { return import_source_1.IMPORT_SKIP_FILES; } });
15
8
  var spark_meta_1 = require("../../../utils/spark-meta");
16
9
  Object.defineProperty(exports, "readSparkMeta", { enumerable: true, get: function () { return spark_meta_1.readSparkMeta; } });
17
10
  Object.defineProperty(exports, "writeSparkMeta", { enumerable: true, get: function () { return spark_meta_1.writeSparkMeta; } });
@@ -3,8 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.APP_TYPES = exports.STACK_BY_APP_TYPE = exports.SUPPORTED_STACKS = exports.TEMPLATE_PINNED_VERSION_BY_STACK = exports.TEMPLATE_PACKAGE_BY_STACK = void 0;
7
- exports.resolveStack = resolveStack;
6
+ exports.SUPPORTED_STACKS = exports.TEMPLATE_PINNED_VERSION_BY_STACK = exports.TEMPLATE_PACKAGE_BY_STACK = void 0;
8
7
  exports.renderTemplate = renderTemplate;
9
8
  const node_fs_1 = __importDefault(require("node:fs"));
10
9
  const node_path_1 = __importDefault(require("node:path"));
@@ -26,51 +25,6 @@ exports.TEMPLATE_PACKAGE_BY_STACK = {
26
25
  */
27
26
  exports.TEMPLATE_PINNED_VERSION_BY_STACK = {};
28
27
  exports.SUPPORTED_STACKS = Object.keys(exports.TEMPLATE_PACKAGE_BY_STACK);
29
- /**
30
- * app_type(业务类型)→ stack 短名映射。仅在调用方未显式传 --template 时用于解析 stack。
31
- * 与 src/api/app/types.ts 的 AppType 枚举无关,是独立的业务类型概念。
32
- */
33
- exports.STACK_BY_APP_TYPE = {
34
- html: 'html',
35
- modern_html: 'html',
36
- jspage: 'vite-react',
37
- full_stack: 'nestjs-react-fullstack',
38
- };
39
- exports.APP_TYPES = Object.keys(exports.STACK_BY_APP_TYPE);
40
- /**
41
- * 解析要用的 stack(template-first):
42
- * 1. template 传了 → 直接用(SUPPORTED_STACKS 校验)
43
- * 2. 否则 appType 传了 → 按 STACK_BY_APP_TYPE 查表
44
- * 3. 都没传 → ARGS_INVALID
45
- * 非法 template / 非法 appType 均抛 ARGS_INVALID。
46
- */
47
- function resolveStack(opts) {
48
- const { template, appType } = opts;
49
- // 用真值判断(非 undefined/null/空串):空串视为未传,回落到 appType。
50
- if (template) {
51
- if (!exports.SUPPORTED_STACKS.includes(template)) {
52
- throw new error_1.AppError('ARGS_INVALID', `不支持的 template: ${template}`, {
53
- next_actions: [`可用 stack:${exports.SUPPORTED_STACKS.join(', ')}`],
54
- });
55
- }
56
- return template;
57
- }
58
- if (appType) {
59
- const stack = exports.STACK_BY_APP_TYPE[appType];
60
- if (!stack) {
61
- throw new error_1.AppError('ARGS_INVALID', `不支持的 app_type: ${appType}`, {
62
- next_actions: [`可用 app_type:${exports.APP_TYPES.join(', ')}`],
63
- });
64
- }
65
- return stack;
66
- }
67
- throw new error_1.AppError('ARGS_INVALID', '缺少 --template 或 --app-type', {
68
- next_actions: [
69
- `可用 stack:${exports.SUPPORTED_STACKS.join(', ')}`,
70
- `可用 app_type:${exports.APP_TYPES.join(', ')}`,
71
- ],
72
- });
73
- }
74
28
  // template/ 内以下划线开头的占位文件名在渲染时改名。
75
29
  // 原因:
76
30
  // 1. npm pack 强制剥的:.npmrc(防 auth token 泄露)
@@ -109,6 +109,9 @@ function applyOne(rule, opts) {
109
109
  case 'merge-json': {
110
110
  return applyMergeJson(rule, sourceRoot, targetDir, logPrefix);
111
111
  }
112
+ case 'add-json-array-items': {
113
+ return applyAddJsonArrayItems(rule, targetDir, logPrefix);
114
+ }
112
115
  case 'directory': {
113
116
  const src = node_path_1.default.join(sourceRoot, rule.from);
114
117
  const dest = node_path_1.default.join(targetDir, rule.to);
@@ -257,6 +260,53 @@ function applyMergeJson(rule, sourceRoot, targetDir, logPrefix) {
257
260
  (0, logger_1.log)(logPrefix, ` ✓ ${rule.to} (merged: ${keys})`);
258
261
  return { rule, action: 'merged', path: rule.to, detail: keys };
259
262
  }
263
+ function applyAddJsonArrayItems(rule, targetDir, logPrefix) {
264
+ const dest = node_path_1.default.join(targetDir, rule.to);
265
+ if (!node_fs_1.default.existsSync(dest)) {
266
+ (0, logger_1.log)(logPrefix, ` ○ ${rule.to} (not found, skip add-json-array-items)`);
267
+ return { rule, action: 'skipped', path: rule.to };
268
+ }
269
+ const originalText = node_fs_1.default.readFileSync(dest, 'utf-8');
270
+ // 读一次拿数组当前值来判断幂等;jsonc 兼容 trailing comma / 注释。
271
+ const errors = [];
272
+ const root = jsonc.parse(originalText, errors, { allowTrailingComma: true });
273
+ if (errors.length > 0) {
274
+ const first = errors[0];
275
+ throw new Error(`${rule.to}: jsonc parse error ${jsonc.printParseErrorCode(first.error)} at offset ${String(first.offset)}`);
276
+ }
277
+ // 沿 rule.path 走到目标节点
278
+ let node = root;
279
+ for (const seg of rule.path) {
280
+ if (node && typeof node === 'object' && seg in node) {
281
+ node = node[seg];
282
+ }
283
+ else {
284
+ node = undefined;
285
+ break;
286
+ }
287
+ }
288
+ if (!Array.isArray(node)) {
289
+ (0, logger_1.log)(logPrefix, ` ○ ${rule.to} (path ${rule.path.join('.')} is not an array, skip)`);
290
+ return { rule, action: 'skipped', path: rule.to };
291
+ }
292
+ const existing = new Set(node.filter((v) => typeof v === 'string'));
293
+ const toAdd = rule.items.filter((it) => !existing.has(it));
294
+ if (toAdd.length === 0) {
295
+ (0, logger_1.log)(logPrefix, ` ○ ${rule.to} (${rule.path.join('.')} already has all items)`);
296
+ return { rule, action: 'noop', path: rule.to };
297
+ }
298
+ // jsonc.modify 逐项 append,保留缩进 / 注释 / trailing comma。
299
+ let text = originalText;
300
+ for (const item of toAdd) {
301
+ const edits = jsonc.modify(text, [...rule.path, -1], item, {
302
+ formattingOptions: { insertSpaces: true, tabSize: 2 },
303
+ });
304
+ text = jsonc.applyEdits(text, edits);
305
+ }
306
+ node_fs_1.default.writeFileSync(dest, text);
307
+ (0, logger_1.log)(logPrefix, ` ✓ ${rule.to} (${rule.path.join('.')} += ${toAdd.map((s) => JSON.stringify(s)).join(', ')})`);
308
+ return { rule, action: 'patched', path: rule.to, detail: toAdd.join(',') };
309
+ }
260
310
  /**
261
311
  * 用 jsonc-parser 读 user 端 JSON 文件,兼容 tsconfig/nest-cli.json 等带 trailing comma 或
262
312
  * 注释的配置。模板侧严格 JSON 走 JSON.parse 也能通,统一走 jsonc 简化代码。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lark-apaas/miaoda-cli",
3
- "version": "0.1.20-alpha.dd573f8",
3
+ "version": "0.1.20-beta.4eeca5a",
4
4
  "description": "Miaoda 平台命令行工具,面向 Agent 调用",
5
5
  "type": "commonjs",
6
6
  "bin": {
@@ -1,67 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.IMPORT_SKIP_FILES = exports.IMPORT_SKIP_DIRS = void 0;
7
- exports.importSourceSrc = importSourceSrc;
8
- const node_fs_1 = __importDefault(require("node:fs"));
9
- const node_path_1 = __importDefault(require("node:path"));
10
- const error_1 = require("../../../utils/error");
11
- const logger_1 = require("../../../utils/logger");
12
- /** 导入时跳过的目录名(任意层级命中即整目录跳过)。 */
13
- exports.IMPORT_SKIP_DIRS = new Set(['node_modules', '.git', 'dist', 'build']);
14
- /** 导入时跳过的精确文件名。`.env.*`(如 .env.local)另由前缀规则处理。 */
15
- exports.IMPORT_SKIP_FILES = new Set([
16
- '.env',
17
- '.DS_Store',
18
- '.npmrc',
19
- 'package.json',
20
- 'package-lock.json',
21
- 'yarn.lock',
22
- 'pnpm-lock.yaml',
23
- ]);
24
- function isSkippedFile(name) {
25
- if (exports.IMPORT_SKIP_FILES.has(name))
26
- return true;
27
- // .env.local / .env.production 等一律跳过
28
- if (name.startsWith('.env.'))
29
- return true;
30
- return false;
31
- }
32
- /**
33
- * 把整个 sourcePath 递归拷进 targetDir/src/(叠加,同名覆盖,不删目标已有文件),
34
- * 按 IMPORT_SKIP_DIRS / IMPORT_SKIP_FILES 过滤。
35
- * sourcePath 不存在或非目录 → 抛 ARGS_INVALID。
36
- */
37
- function importSourceSrc(opts) {
38
- const sourcePath = node_path_1.default.resolve(opts.sourcePath);
39
- if (!node_fs_1.default.existsSync(sourcePath) || !node_fs_1.default.statSync(sourcePath).isDirectory()) {
40
- throw new error_1.AppError('ARGS_INVALID', `--source-path 不存在或不是目录: ${opts.sourcePath}`);
41
- }
42
- const destSrc = node_path_1.default.join(opts.targetDir, 'src');
43
- node_fs_1.default.mkdirSync(destSrc, { recursive: true });
44
- let count = 0;
45
- const walk = (relDir) => {
46
- const absDir = node_path_1.default.join(sourcePath, relDir);
47
- for (const entry of node_fs_1.default.readdirSync(absDir, { withFileTypes: true })) {
48
- if (entry.isDirectory()) {
49
- if (exports.IMPORT_SKIP_DIRS.has(entry.name))
50
- continue;
51
- walk(node_path_1.default.join(relDir, entry.name));
52
- }
53
- else if (entry.isFile()) {
54
- if (isSkippedFile(entry.name))
55
- continue;
56
- const rel = node_path_1.default.join(relDir, entry.name);
57
- const dest = node_path_1.default.join(destSrc, rel);
58
- node_fs_1.default.mkdirSync(node_path_1.default.dirname(dest), { recursive: true });
59
- node_fs_1.default.copyFileSync(node_path_1.default.join(sourcePath, rel), dest);
60
- count += 1;
61
- }
62
- }
63
- };
64
- walk('.');
65
- (0, logger_1.log)('init', `Imported ${String(count)} file(s) from ${sourcePath} → src/`);
66
- return { importedFileCount: count };
67
- }