@coze-arch/cli 0.0.1-alpha.de5a13 → 0.0.1-alpha.deaedf

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.
Files changed (143) hide show
  1. package/README.md +1 -0
  2. package/lib/__templates__/expo/.cozeproj/scripts/server_dev_run.sh +1 -1
  3. package/lib/__templates__/expo/client/components/Screen.tsx +2 -2
  4. package/lib/__templates__/expo/client/eslint.config.mjs +7 -0
  5. package/lib/__templates__/expo/client/metro.config.js +3 -0
  6. package/lib/__templates__/expo/client/scripts/install-missing-deps.js +10 -10
  7. package/lib/__templates__/expo/eslint-plugins/forbid-emoji/index.js +9 -0
  8. package/lib/__templates__/expo/eslint-plugins/forbid-emoji/rule.js +112 -0
  9. package/lib/__templates__/expo/eslint-plugins/forbid-emoji/tech.md +94 -0
  10. package/lib/__templates__/expo/eslint-plugins/restrict-linear-gradient/index.js +9 -0
  11. package/lib/__templates__/expo/eslint-plugins/restrict-linear-gradient/rule.js +120 -0
  12. package/lib/__templates__/expo/eslint-plugins/restrict-linear-gradient/tech.md +58 -0
  13. package/lib/__templates__/expo/pnpm-lock.yaml +8 -5
  14. package/lib/__templates__/expo/server/package.json +1 -1
  15. package/lib/__templates__/native-static/.coze +11 -0
  16. package/lib/__templates__/native-static/index.html +33 -0
  17. package/lib/__templates__/native-static/styles/main.css +136 -0
  18. package/lib/__templates__/native-static/template.config.js +22 -0
  19. package/lib/__templates__/nextjs/.babelrc +3 -0
  20. package/lib/__templates__/nextjs/README.md +5 -0
  21. package/lib/__templates__/nextjs/eslint.config.mjs +5 -0
  22. package/lib/__templates__/nextjs/next.config.ts +1 -2
  23. package/lib/__templates__/nextjs/package.json +3 -6
  24. package/lib/__templates__/nextjs/pnpm-lock.yaml +1036 -10
  25. package/lib/__templates__/nextjs/scripts/build.sh +4 -1
  26. package/lib/__templates__/nextjs/scripts/dev.sh +8 -2
  27. package/lib/__templates__/nextjs/scripts/start.sh +7 -1
  28. package/lib/__templates__/nextjs/src/app/layout.tsx +1 -1
  29. package/lib/__templates__/nextjs/src/app/page.tsx +1 -2
  30. package/lib/__templates__/nextjs/src/server.ts +35 -0
  31. package/lib/__templates__/nextjs/tsconfig.json +1 -1
  32. package/lib/__templates__/nuxt-vue/.coze +12 -0
  33. package/lib/__templates__/nuxt-vue/README.md +73 -0
  34. package/lib/__templates__/nuxt-vue/_gitignore +24 -0
  35. package/lib/__templates__/nuxt-vue/_npmrc +23 -0
  36. package/lib/__templates__/nuxt-vue/app/app.vue +6 -0
  37. package/lib/__templates__/nuxt-vue/app/pages/index.vue +23 -0
  38. package/lib/__templates__/nuxt-vue/assets/css/main.css +24 -0
  39. package/lib/__templates__/nuxt-vue/nuxt.config.ts +116 -0
  40. package/lib/__templates__/nuxt-vue/package.json +35 -0
  41. package/lib/__templates__/nuxt-vue/pnpm-lock.yaml +8759 -0
  42. package/lib/__templates__/nuxt-vue/postcss.config.mjs +8 -0
  43. package/lib/__templates__/nuxt-vue/public/favicon.ico +0 -0
  44. package/lib/__templates__/nuxt-vue/public/robots.txt +2 -0
  45. package/lib/__templates__/nuxt-vue/scripts/build.sh +14 -0
  46. package/lib/__templates__/nuxt-vue/scripts/dev.sh +39 -0
  47. package/lib/__templates__/nuxt-vue/scripts/prepare.sh +14 -0
  48. package/lib/__templates__/nuxt-vue/scripts/start.sh +21 -0
  49. package/lib/__templates__/nuxt-vue/server/api/hello.ts +10 -0
  50. package/lib/__templates__/nuxt-vue/server/middleware/logger.ts +10 -0
  51. package/lib/__templates__/nuxt-vue/server/routes/health.ts +10 -0
  52. package/lib/__templates__/nuxt-vue/tailwind.config.js +13 -0
  53. package/lib/__templates__/nuxt-vue/template.config.js +87 -0
  54. package/lib/__templates__/nuxt-vue/tsconfig.json +18 -0
  55. package/lib/__templates__/taro/.cozeproj/scripts/dev_run.sh +107 -37
  56. package/lib/__templates__/taro/.cozeproj/scripts/pack.sh +24 -1
  57. package/lib/__templates__/taro/README.md +138 -62
  58. package/lib/__templates__/taro/config/index.ts +105 -41
  59. package/lib/__templates__/taro/config/prod.ts +4 -5
  60. package/lib/__templates__/taro/eslint.config.mjs +82 -4
  61. package/lib/__templates__/taro/package.json +23 -7
  62. package/lib/__templates__/taro/patches/@tarojs__plugin-mini-ci@4.1.9.patch +30 -0
  63. package/lib/__templates__/taro/pnpm-lock.yaml +1198 -214
  64. package/lib/__templates__/taro/server/package.json +3 -1
  65. package/lib/__templates__/taro/src/app.css +140 -47
  66. package/lib/__templates__/taro/src/app.tsx +9 -0
  67. package/lib/__templates__/taro/src/components/ui/accordion.tsx +159 -0
  68. package/lib/__templates__/taro/src/components/ui/alert-dialog.tsx +260 -0
  69. package/lib/__templates__/taro/src/components/ui/alert.tsx +60 -0
  70. package/lib/__templates__/taro/src/components/ui/aspect-ratio.tsx +36 -0
  71. package/lib/__templates__/taro/src/components/ui/avatar.tsx +84 -0
  72. package/lib/__templates__/taro/src/components/ui/badge.tsx +37 -0
  73. package/lib/__templates__/taro/src/components/ui/breadcrumb.tsx +117 -0
  74. package/lib/__templates__/taro/src/components/ui/button-group.tsx +83 -0
  75. package/lib/__templates__/taro/src/components/ui/button.tsx +67 -0
  76. package/lib/__templates__/taro/src/components/ui/calendar.tsx +394 -0
  77. package/lib/__templates__/taro/src/components/ui/card.tsx +108 -0
  78. package/lib/__templates__/taro/src/components/ui/carousel.tsx +228 -0
  79. package/lib/__templates__/taro/src/components/ui/checkbox.tsx +58 -0
  80. package/lib/__templates__/taro/src/components/ui/code-block.tsx +169 -0
  81. package/lib/__templates__/taro/src/components/ui/collapsible.tsx +71 -0
  82. package/lib/__templates__/taro/src/components/ui/command.tsx +385 -0
  83. package/lib/__templates__/taro/src/components/ui/context-menu.tsx +614 -0
  84. package/lib/__templates__/taro/src/components/ui/dialog.tsx +256 -0
  85. package/lib/__templates__/taro/src/components/ui/drawer.tsx +192 -0
  86. package/lib/__templates__/taro/src/components/ui/dropdown-menu.tsx +561 -0
  87. package/lib/__templates__/taro/src/components/ui/field.tsx +228 -0
  88. package/lib/__templates__/taro/src/components/ui/hover-card.tsx +282 -0
  89. package/lib/__templates__/taro/src/components/ui/input-group.tsx +197 -0
  90. package/lib/__templates__/taro/src/components/ui/input-otp.tsx +136 -0
  91. package/lib/__templates__/taro/src/components/ui/input.tsx +56 -0
  92. package/lib/__templates__/taro/src/components/ui/label.tsx +24 -0
  93. package/lib/__templates__/taro/src/components/ui/menubar.tsx +595 -0
  94. package/lib/__templates__/taro/src/components/ui/navigation-menu.tsx +264 -0
  95. package/lib/__templates__/taro/src/components/ui/pagination.tsx +118 -0
  96. package/lib/__templates__/taro/src/components/ui/popover.tsx +291 -0
  97. package/lib/__templates__/taro/src/components/ui/portal.tsx +19 -0
  98. package/lib/__templates__/taro/src/components/ui/progress.tsx +28 -0
  99. package/lib/__templates__/taro/src/components/ui/radio-group.tsx +64 -0
  100. package/lib/__templates__/taro/src/components/ui/resizable.tsx +346 -0
  101. package/lib/__templates__/taro/src/components/ui/scroll-area.tsx +34 -0
  102. package/lib/__templates__/taro/src/components/ui/select.tsx +438 -0
  103. package/lib/__templates__/taro/src/components/ui/separator.tsx +30 -0
  104. package/lib/__templates__/taro/src/components/ui/sheet.tsx +262 -0
  105. package/lib/__templates__/taro/src/components/ui/skeleton.tsx +17 -0
  106. package/lib/__templates__/taro/src/components/ui/slider.tsx +203 -0
  107. package/lib/__templates__/taro/src/components/ui/sonner.tsx +1 -0
  108. package/lib/__templates__/taro/src/components/ui/switch.tsx +55 -0
  109. package/lib/__templates__/taro/src/components/ui/table.tsx +142 -0
  110. package/lib/__templates__/taro/src/components/ui/tabs.tsx +114 -0
  111. package/lib/__templates__/taro/src/components/ui/textarea.tsx +54 -0
  112. package/lib/__templates__/taro/src/components/ui/toast.tsx +517 -0
  113. package/lib/__templates__/taro/src/components/ui/toggle-group.tsx +120 -0
  114. package/lib/__templates__/taro/src/components/ui/toggle.tsx +77 -0
  115. package/lib/__templates__/taro/src/components/ui/tooltip.tsx +455 -0
  116. package/lib/__templates__/taro/src/lib/hooks/use-keyboard-offset.ts +37 -0
  117. package/lib/__templates__/taro/src/lib/measure.ts +115 -0
  118. package/lib/__templates__/taro/src/lib/platform.ts +12 -0
  119. package/lib/__templates__/taro/src/lib/utils.ts +6 -0
  120. package/lib/__templates__/taro/src/presets/dev-debug.ts +23 -0
  121. package/lib/__templates__/taro/src/presets/h5-container.tsx +15 -0
  122. package/lib/__templates__/taro/src/presets/h5-navbar.tsx +238 -0
  123. package/lib/__templates__/taro/src/presets/h5-styles.ts +220 -0
  124. package/lib/__templates__/taro/src/presets/index.tsx +18 -0
  125. package/lib/__templates__/templates.json +43 -0
  126. package/lib/__templates__/vite/README.md +190 -11
  127. package/lib/__templates__/vite/_gitignore +1 -0
  128. package/lib/__templates__/vite/eslint.config.mjs +6 -1
  129. package/lib/__templates__/vite/package.json +14 -5
  130. package/lib/__templates__/vite/pnpm-lock.yaml +768 -24
  131. package/lib/__templates__/vite/scripts/build.sh +4 -1
  132. package/lib/__templates__/vite/scripts/dev.sh +9 -2
  133. package/lib/__templates__/vite/scripts/start.sh +9 -3
  134. package/lib/__templates__/vite/server/routes/index.ts +31 -0
  135. package/lib/__templates__/vite/server/server.ts +65 -0
  136. package/lib/__templates__/vite/server/vite.ts +67 -0
  137. package/lib/__templates__/vite/tsconfig.json +4 -3
  138. package/lib/__templates__/vite/vite.config.ts +5 -0
  139. package/lib/cli.js +124 -103
  140. package/package.json +7 -3
  141. package/lib/__templates__/taro/src/app.ts +0 -14
  142. package/lib/__templates__/taro/src/utils/h5-styles.ts +0 -22
  143. package/lib/__templates__/taro/src/utils/wx-debug.ts +0 -23
@@ -8,7 +8,10 @@ cd "${COZE_WORKSPACE_PATH}"
8
8
  echo "Installing dependencies..."
9
9
  pnpm install --prefer-frozen-lockfile --prefer-offline --loglevel debug --reporter=append-only
10
10
 
11
- echo "Building the project..."
11
+ echo "Building frontend with Vite..."
12
12
  npx vite build
13
13
 
14
+ echo "Bundling server with tsup..."
15
+ npx tsup server/server.ts --format cjs --platform node --target node20 --outDir dist-server --no-splitting --no-minify --external vite
16
+
14
17
  echo "Build completed successfully!"
@@ -1,9 +1,16 @@
1
1
  #!/bin/bash
2
2
  set -Eeuo pipefail
3
3
 
4
+ <% if (process.env.NODE_ENV === 'test') { %>
5
+ # 测试环境:支持环境变量覆盖端口
6
+ PORT="${PORT:-<%= port %>}"
7
+ COZE_WORKSPACE_PATH="${COZE_WORKSPACE_PATH:-$(pwd)}"
8
+ DEPLOY_RUN_PORT="${DEPLOY_RUN_PORT:-${PORT}}"
9
+ <% } else { %>
4
10
  PORT=<%= port %>
5
11
  COZE_WORKSPACE_PATH="${COZE_WORKSPACE_PATH:-$(pwd)}"
6
12
  DEPLOY_RUN_PORT=<%= port %>
13
+ <% } %>
7
14
 
8
15
  cd "${COZE_WORKSPACE_PATH}"
9
16
 
@@ -27,6 +34,6 @@ kill_port_if_listening() {
27
34
 
28
35
  echo "Clearing port ${PORT} before start."
29
36
  kill_port_if_listening
30
- echo "Starting HTTP service on port ${PORT} for dev..."
37
+ echo "Starting express + Vite dev server on port ${PORT}..."
31
38
 
32
- npx vite --port $PORT
39
+ PORT=$PORT npx tsx watch server/server.ts
@@ -2,14 +2,20 @@
2
2
  set -Eeuo pipefail
3
3
 
4
4
  COZE_WORKSPACE_PATH="${COZE_WORKSPACE_PATH:-$(pwd)}"
5
+ <% if (process.env.NODE_ENV === 'test') { %>
6
+ # 测试环境:支持环境变量覆盖端口
7
+ PORT="${PORT:-<%= port %>}"
8
+ DEPLOY_RUN_PORT="${DEPLOY_RUN_PORT:-${PORT}}"
9
+ <% } else { %>
5
10
  PORT=<%= port %>
6
11
  DEPLOY_RUN_PORT="${DEPLOY_RUN_PORT:-$PORT}"
12
+ <% } %>
7
13
 
8
14
  start_service() {
9
15
  cd "${COZE_WORKSPACE_PATH}"
10
- echo "Starting HTTP service on port ${DEPLOY_RUN_PORT} for deploy..."
11
- npx vite preview --port $DEPLOY_RUN_PORT
16
+ echo "Starting express production server on port ${DEPLOY_RUN_PORT}..."
17
+ PORT=$DEPLOY_RUN_PORT node dist-server/server.js
12
18
  }
13
19
 
14
- echo "Starting HTTP service on port ${DEPLOY_RUN_PORT} for deploy..."
20
+ echo "Starting express production server on port ${DEPLOY_RUN_PORT}..."
15
21
  start_service
@@ -0,0 +1,31 @@
1
+ import { Router } from 'express';
2
+
3
+ const router = Router();
4
+
5
+ // API 路由示例
6
+ router.get('/api/hello', (req, res) => {
7
+ res.json({
8
+ message: 'Hello from Express + Vite!',
9
+ timestamp: new Date().toISOString(),
10
+ });
11
+ });
12
+
13
+ router.post('/api/data', (req, res) => {
14
+ const requestData = req.body;
15
+ res.json({
16
+ success: true,
17
+ data: requestData,
18
+ receivedAt: new Date().toISOString(),
19
+ });
20
+ });
21
+
22
+ // 健康检查接口
23
+ router.get('/api/health', (req, res) => {
24
+ res.json({
25
+ status: 'ok',
26
+ env: process.env.COZE_PROJECT_ENV,
27
+ timestamp: new Date().toISOString(),
28
+ });
29
+ });
30
+
31
+ export default router;
@@ -0,0 +1,65 @@
1
+ // ABOUTME: Express server with Vite integration
2
+ // ABOUTME: Handles API routes and serves frontend in dev/prod modes
3
+
4
+ import { createServer, type Server } from 'http';
5
+ import express from 'express';
6
+ import router from './routes/index';
7
+ import { setupVite } from './vite';
8
+
9
+ const isDev = process.env.COZE_PROJECT_ENV !== 'PROD';
10
+ const port = parseInt(process.env.PORT || '<%= port %>', 10);
11
+ const hostname = process.env.HOSTNAME || 'localhost';
12
+ const app = express();
13
+ // 使用 http.createServer 包装 Express app,以便支持 WebSocket 等协议升级
14
+ const server = createServer(app);
15
+
16
+ async function startServer(): Promise<Server> {
17
+ // 请求日志(仅开发环境)
18
+ if (isDev) {
19
+ app.use((req, res, next) => {
20
+ const start = Date.now();
21
+ res.on('finish', () => {
22
+ const ms = Date.now() - start;
23
+ console.log(`${req.method} ${req.url} - ${ms}ms`);
24
+ });
25
+ next();
26
+ });
27
+ }
28
+
29
+ // 添加请求体解析
30
+ app.use(express.json());
31
+ app.use(express.urlencoded({ extended: true }));
32
+
33
+ // 注册 API 路由
34
+ app.use(router);
35
+
36
+ // 集成 Vite(开发模式)或静态文件服务(生产模式)
37
+ await setupVite(app);
38
+
39
+ // 全局错误处理
40
+ app.use((err: Error, req: express.Request, res: express.Response) => {
41
+ console.error('Server error:', err);
42
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
43
+ const status = 'status' in err ? (err as any).status || 500 : 500;
44
+ res.status(status).json({
45
+ error: err.message || 'Internal server error',
46
+ });
47
+ });
48
+
49
+ server.once('error', err => {
50
+ console.error('Server error:', err);
51
+ process.exit(1);
52
+ });
53
+
54
+ server.listen(port, () => {
55
+ console.log(`\n✨ Server running at http://${hostname}:${port}`);
56
+ console.log(`📝 Environment: ${isDev ? 'development' : 'production'}\n`);
57
+ });
58
+
59
+ return server;
60
+ }
61
+
62
+ startServer().catch(err => {
63
+ console.error('Failed to start server:', err);
64
+ process.exit(1);
65
+ });
@@ -0,0 +1,67 @@
1
+ // ABOUTME: Vite integration for Express server
2
+ // ABOUTME: Handles dev middleware and production static file serving
3
+
4
+ import type { Application, Request, Response } from 'express';
5
+ import express from 'express';
6
+ import path from 'path';
7
+ import fs from 'fs';
8
+ import { createServer as createViteServer } from 'vite';
9
+ import viteConfig from '../vite.config';
10
+
11
+ const isDev = process.env.COZE_PROJECT_ENV !== 'PROD';
12
+
13
+ /**
14
+ * 集成 Vite 开发服务器(中间件模式)
15
+ */
16
+ export async function setupViteMiddleware(app: Application) {
17
+ const vite = await createViteServer({
18
+ ...viteConfig,
19
+ server: {
20
+ ...viteConfig.server,
21
+ middlewareMode: true,
22
+ },
23
+ appType: 'spa',
24
+ });
25
+
26
+ // 使用 Vite middleware
27
+ app.use(vite.middlewares);
28
+
29
+ console.log('🚀 Vite dev server initialized');
30
+ }
31
+
32
+ /**
33
+ * 设置生产环境静态文件服务
34
+ */
35
+ export function setupStaticServer(app: Application) {
36
+ const distPath = path.resolve(process.cwd(), 'dist');
37
+
38
+ if (!fs.existsSync(distPath)) {
39
+ console.error('❌ dist folder not found. Please run "pnpm build" first.');
40
+ process.exit(1);
41
+ }
42
+
43
+ // 1. 服务静态文件(如果存在对应文件则直接返回)
44
+ app.use(express.static(distPath));
45
+
46
+ // 2. SPA fallback - 所有未处理的请求返回 index.html
47
+ // 到达这里的请求说明:
48
+ // - 不是 API 请求(已被前面注册的路由处理)
49
+ // - 不是静态文件(express.static 未找到对应文件)
50
+ // - 需要返回 index.html 让前端路由处理
51
+ app.use((_req: Request, res: Response) => {
52
+ res.sendFile(path.join(distPath, 'index.html'));
53
+ });
54
+
55
+ console.log('📦 Serving static files from dist/');
56
+ }
57
+
58
+ /**
59
+ * 根据环境设置 Vite
60
+ */
61
+ export async function setupVite(app: Application) {
62
+ if (isDev) {
63
+ await setupViteMiddleware(app);
64
+ } else {
65
+ setupStaticServer(app);
66
+ }
67
+ }
@@ -3,14 +3,15 @@
3
3
  "target": "ES2020",
4
4
  "lib": ["ES2020", "DOM", "DOM.Iterable"],
5
5
  "module": "ESNext",
6
- "moduleResolution": "bundler",
6
+ "moduleResolution": "node",
7
7
  "strict": true,
8
8
  "esModuleInterop": true,
9
9
  "skipLibCheck": true,
10
10
  "forceConsistentCasingInFileNames": true,
11
11
  "resolveJsonModule": true,
12
12
  "isolatedModules": true,
13
- "noEmit": true
13
+ "noEmit": true,
14
+ "types": ["node"]
14
15
  },
15
- "include": ["src"]
16
+ "include": ["src", "server"]
16
17
  }
@@ -4,6 +4,7 @@ export default defineConfig({
4
4
  server: {
5
5
  port: <%= port %>,
6
6
  host: '0.0.0.0',
7
+ allowedHosts: true,
7
8
  hmr: {
8
9
  overlay: true,
9
10
  path: '/hot/vite-hmr',
@@ -11,5 +12,9 @@ export default defineConfig({
11
12
  clientPort: 443,
12
13
  timeout: 30000,
13
14
  },
15
+ watch: {
16
+ usePolling: true,
17
+ interval: 100,
18
+ }
14
19
  },
15
20
  });
package/lib/cli.js CHANGED
@@ -4,6 +4,8 @@
4
4
  var commander = require('commander');
5
5
  var path = require('path');
6
6
  var fs = require('fs');
7
+ var node_path = require('node:path');
8
+ var node_fs = require('node:fs');
7
9
  var shelljs = require('shelljs');
8
10
  var perf_hooks = require('perf_hooks');
9
11
  var fs$1 = require('fs/promises');
@@ -481,6 +483,14 @@ const warmupTemplate = (templatePath, templateName) => {
481
483
  logger.info(`\nWarming up template: ${templateName}`);
482
484
  logger.info(` Path: ${templatePath}`);
483
485
 
486
+ // 检查是否存在 package.json
487
+ const packageJsonPath = node_path.join(templatePath, 'package.json');
488
+ // eslint-disable-next-line security/detect-non-literal-fs-filename
489
+ if (!node_fs.existsSync(packageJsonPath)) {
490
+ logger.info(` ⊘ Skipping ${templateName} (no package.json found)`);
491
+ return;
492
+ }
493
+
484
494
  const result = shelljs.exec('pnpm install', {
485
495
  cwd: templatePath,
486
496
  silent: true,
@@ -514,13 +524,7 @@ const warmupTemplate = (templatePath, templateName) => {
514
524
  /**
515
525
  * 执行 warmup 命令的内部实现
516
526
  */
517
- const executeWarmup = async (
518
- options
519
-
520
- ,
521
-
522
- command,
523
- ) => {
527
+ const executeWarmup = async (options) => {
524
528
  const timer = new TimeTracker();
525
529
 
526
530
  try {
@@ -590,7 +594,7 @@ const registerCommand$4 = program => {
590
594
  .command('warmup')
591
595
  .description('Pre-install dependencies for templates to speed up init')
592
596
  .option('-t, --template <name>', 'Warmup a specific template only')
593
- .action(async (options, command) => {
597
+ .action(async options => {
594
598
  await executeWarmup(options);
595
599
  });
596
600
  };
@@ -1718,38 +1722,6 @@ const collectFilesToRender = async (options
1718
1722
 
1719
1723
  return filesToWrite;
1720
1724
  };
1721
-
1722
- /**
1723
- * 检测文件冲突
1724
- *
1725
- * @param outputPath - 输出目录路径
1726
- * @param filesToWrite - 将要写入的文件路径列表
1727
- * @returns 冲突的文件路径列表
1728
- */
1729
- const detectFileConflicts = (
1730
- outputPath,
1731
- filesToWrite,
1732
- ) => {
1733
- logger.verbose('\nChecking for file conflicts...');
1734
-
1735
- const conflicts = [];
1736
-
1737
- for (const file of filesToWrite) {
1738
- const fullPath = path.join(outputPath, file);
1739
- if (fs.existsSync(fullPath)) {
1740
- conflicts.push(file);
1741
- logger.verbose(` ⚠ Conflict detected: ${file}`);
1742
- }
1743
- }
1744
-
1745
- if (conflicts.length === 0) {
1746
- logger.verbose(' ✓ No conflicts detected');
1747
- } else {
1748
- logger.verbose(` ⚠ ${conflicts.length} conflicts detected`);
1749
- }
1750
-
1751
- return conflicts;
1752
- };
1753
1725
  // end_aigc
1754
1726
 
1755
1727
  // ABOUTME: Main file processing orchestration for template rendering
@@ -1805,7 +1777,7 @@ const processSingleFile = async (options
1805
1777
  * 1. 验证模板目录
1806
1778
  * 2. 扫描所有模板文件
1807
1779
  * 3. Dry-run:收集将要写入的文件列表(考虑 hooks 影响)
1808
- * 4. 冲突检测:检查是否有文件会被覆盖
1780
+ * 4. 冲突检测:检查是否有文件会被覆盖(可通过 force 跳过)
1809
1781
  * 5. 实际写入:渲染并写入所有文件
1810
1782
  * 6. 复制 node_modules(如果存在)
1811
1783
  *
@@ -1816,8 +1788,9 @@ const processTemplateFiles = async (options
1816
1788
 
1817
1789
 
1818
1790
 
1791
+
1819
1792
  ) => {
1820
- const { templatePath, outputPath, context, templateConfig } = options;
1793
+ const { templatePath, outputPath, context, templateConfig} = options;
1821
1794
  logger.verbose('Processing template files:');
1822
1795
  logger.verbose(` - Template path: ${templatePath}`);
1823
1796
  logger.verbose(` - Output path: ${outputPath}`);
@@ -1849,23 +1822,17 @@ const processTemplateFiles = async (options
1849
1822
  }
1850
1823
 
1851
1824
  // 阶段 2: Dry-run - 收集所有将要写入的文件
1852
- const filesToWrite = await collectFilesToRender({
1825
+ await collectFilesToRender({
1853
1826
  files,
1854
1827
  templatePath,
1855
1828
  context,
1856
1829
  templateConfig,
1857
1830
  });
1858
1831
 
1859
- // 阶段 3: 冲突检测
1860
- const conflicts = detectFileConflicts(outputPath, filesToWrite);
1861
-
1862
- if (conflicts.length > 0) {
1863
- // 有冲突,抛出详细的错误信息
1864
- const conflictList = conflicts.map(f => ` - ${f}`).join('\n');
1865
- throw new Error(
1866
- `File conflicts detected in output directory: ${outputPath}\n\n` +
1867
- `The following files already exist and would be overwritten:\n${conflictList}\n\n` +
1868
- 'Please remove these files or use a different output directory.',
1832
+ // 阶段 3: 冲突检测(force 为 true 时跳过)
1833
+ {
1834
+ logger.verbose(
1835
+ ' - Force mode enabled, skipping conflict detection. Existing files will be overwritten.',
1869
1836
  );
1870
1837
  }
1871
1838
 
@@ -1898,6 +1865,7 @@ const processTemplateFiles = async (options
1898
1865
 
1899
1866
 
1900
1867
 
1868
+
1901
1869
  /**
1902
1870
  * 加载模板元数据和路径
1903
1871
  */
@@ -2007,7 +1975,7 @@ const prepareOutputDirectory = (outputPath) => {
2007
1975
  const execute = async (
2008
1976
  options,
2009
1977
  ) => {
2010
- const { templateName, outputPath, command } = options;
1978
+ const { templateName, outputPath, command} = options;
2011
1979
 
2012
1980
  // 1. 加载模板
2013
1981
  const { templatePath } = await loadTemplateMetadata(templateName);
@@ -2031,8 +1999,7 @@ const execute = async (
2031
1999
  templatePath,
2032
2000
  outputPath: absoluteOutputPath,
2033
2001
  context,
2034
- templateConfig,
2035
- });
2002
+ templateConfig});
2036
2003
 
2037
2004
  // 7. 执行 onAfterRender 钩子
2038
2005
  await executeAfterRenderHook(templateConfig, context, absoluteOutputPath);
@@ -2083,7 +2050,40 @@ const runPnpmInstall = (projectPath) => {
2083
2050
  };
2084
2051
 
2085
2052
  /**
2086
- * 初始化 git 仓库并创建初始提交
2053
+ * 运行 git 命令的辅助函数
2054
+ */
2055
+ const runGitCommand = (command, projectPath) => {
2056
+ logger.info(`Executing: ${command}`);
2057
+
2058
+ const result = shelljs.exec(command, {
2059
+ cwd: projectPath,
2060
+ silent: true,
2061
+ });
2062
+
2063
+ // 输出命令的结果
2064
+ if (result.stdout) {
2065
+ process.stdout.write(result.stdout);
2066
+ }
2067
+
2068
+ if (result.stderr) {
2069
+ process.stderr.write(result.stderr);
2070
+ }
2071
+
2072
+ if (result.code !== 0) {
2073
+ const errorMessage = [
2074
+ `${command} failed with exit code ${result.code}`,
2075
+ result.stderr ? `\nStderr:\n${result.stderr}` : '',
2076
+ result.stdout ? `\nStdout:\n${result.stdout}` : '',
2077
+ ]
2078
+ .filter(Boolean)
2079
+ .join('');
2080
+
2081
+ throw new Error(errorMessage);
2082
+ }
2083
+ };
2084
+
2085
+ /**
2086
+ * 初始化 git 仓库
2087
2087
  * 如果目录中已存在 .git,则跳过初始化
2088
2088
  */
2089
2089
  const runGitInit = (projectPath) => {
@@ -2096,46 +2096,9 @@ const runGitInit = (projectPath) => {
2096
2096
  return;
2097
2097
  }
2098
2098
 
2099
- const runGitCommand = (command) => {
2100
- logger.info(`Executing: ${command}`);
2101
-
2102
- const result = shelljs.exec(command, {
2103
- cwd: projectPath,
2104
- silent: true,
2105
- });
2106
-
2107
- // 输出命令的结果
2108
- if (result.stdout) {
2109
- process.stdout.write(result.stdout);
2110
- }
2111
-
2112
- if (result.stderr) {
2113
- process.stderr.write(result.stderr);
2114
- }
2115
-
2116
- if (result.code !== 0) {
2117
- const errorMessage = [
2118
- `${command} failed with exit code ${result.code}`,
2119
- result.stderr ? `\nStderr:\n${result.stderr}` : '',
2120
- result.stdout ? `\nStdout:\n${result.stdout}` : '',
2121
- ]
2122
- .filter(Boolean)
2123
- .join('');
2124
-
2125
- throw new Error(errorMessage);
2126
- }
2127
- };
2128
-
2129
2099
  try {
2130
2100
  logger.info('\nInitializing git repository...');
2131
- runGitCommand('git init');
2132
-
2133
- logger.info('Adding files to git...');
2134
- runGitCommand('git add .');
2135
-
2136
- logger.info('Creating initial commit...');
2137
- runGitCommand('git commit -m "chore: initial commit"');
2138
-
2101
+ runGitCommand('git init', projectPath);
2139
2102
  logger.success('Git repository initialized successfully!');
2140
2103
  } catch (error) {
2141
2104
  // Git 初始化失败不应该导致整个流程失败
@@ -2146,6 +2109,35 @@ const runGitInit = (projectPath) => {
2146
2109
  }
2147
2110
  };
2148
2111
 
2112
+ /**
2113
+ * 提交初始化生成的所有文件
2114
+ */
2115
+ const commitChanges = (projectPath) => {
2116
+ // 检查是否存在 .git 目录
2117
+ const gitDir = path.join(projectPath, '.git');
2118
+ if (!fs.existsSync(gitDir)) {
2119
+ logger.warn(
2120
+ '\n⚠️ Git repository does not exist, skipping commit. Run git init first.',
2121
+ );
2122
+ return;
2123
+ }
2124
+
2125
+ try {
2126
+ logger.info('\nCommitting initialized files...');
2127
+ runGitCommand('git add --all', projectPath);
2128
+ runGitCommand('git commit -m "chore: init env"', projectPath);
2129
+ logger.success('Changes committed successfully!');
2130
+ } catch (error) {
2131
+ // Commit 失败不应该导致整个流程失败
2132
+ logger.warn(
2133
+ `Git commit failed: ${error instanceof Error ? error.message : String(error)}`,
2134
+ );
2135
+ logger.info(
2136
+ 'You can manually commit later with: git add --all && git commit -m "chore: init env"',
2137
+ );
2138
+ }
2139
+ };
2140
+
2149
2141
  /**
2150
2142
  * 运行开发服务器(后台模式)
2151
2143
  * 启动后台子进程运行开发服务器,父进程可以直接退出
@@ -2187,6 +2179,8 @@ const executeInit = async (
2187
2179
 
2188
2180
 
2189
2181
 
2182
+
2183
+
2190
2184
  ,
2191
2185
  command,
2192
2186
  ) => {
@@ -2198,7 +2192,9 @@ const executeInit = async (
2198
2192
  output: outputPath,
2199
2193
  skipInstall,
2200
2194
  skipGit,
2195
+ skipCommit,
2201
2196
  skipDev,
2197
+ force,
2202
2198
  } = options;
2203
2199
 
2204
2200
  logger.info(`Initializing project with template: ${templateName}`);
@@ -2209,16 +2205,27 @@ const executeInit = async (
2209
2205
  templateName,
2210
2206
  outputPath,
2211
2207
  command,
2208
+ force,
2212
2209
  });
2213
2210
  const { outputPath: absoluteOutputPath, templateConfig, context } = result;
2214
2211
 
2215
2212
  timer.logPhase('Template engine execution');
2216
2213
  logger.success('Project created successfully!');
2217
2214
 
2215
+ // 检查是否存在 package.json
2216
+ const packageJsonPath = path.join(absoluteOutputPath, 'package.json');
2217
+ const hasPackageJson = fs.existsSync(packageJsonPath);
2218
+
2218
2219
  // 安装依赖(始终使用 pnpm install,利用缓存机制)
2219
2220
  if (!skipInstall) {
2220
- runPnpmInstall(absoluteOutputPath);
2221
- timer.logPhase('Dependencies installation');
2221
+ if (hasPackageJson) {
2222
+ runPnpmInstall(absoluteOutputPath);
2223
+ timer.logPhase('Dependencies installation');
2224
+ } else {
2225
+ logger.info(
2226
+ '\n💡 No package.json found, skipping dependency installation',
2227
+ );
2228
+ }
2222
2229
  }
2223
2230
 
2224
2231
  // 执行 onComplete 钩子(在 pnpm install 之后)
@@ -2231,6 +2238,12 @@ const executeInit = async (
2231
2238
  timer.logPhase('Git initialization');
2232
2239
  }
2233
2240
 
2241
+ // 如果没有跳过 commit,则提交初始化生成的文件
2242
+ if (!skipCommit) {
2243
+ commitChanges(absoluteOutputPath);
2244
+ timer.logPhase('Git commit');
2245
+ }
2246
+
2234
2247
  // 如果没有跳过 dev,则启动开发服务器
2235
2248
  if (!skipDev) {
2236
2249
  runDev(absoluteOutputPath);
@@ -2239,13 +2252,14 @@ const executeInit = async (
2239
2252
  // 只有跳过 dev 时才显示 Next steps
2240
2253
  logger.info('\nNext steps:');
2241
2254
  logger.info(` cd ${outputPath}`);
2242
- if (skipInstall) {
2255
+ if (skipInstall && hasPackageJson) {
2243
2256
  logger.info(' pnpm install');
2244
2257
  }
2245
2258
  if (skipGit) {
2246
- logger.info(
2247
- ' git init && git add . && git commit -m "initial commit"',
2248
- );
2259
+ logger.info(' git init');
2260
+ }
2261
+ if (skipCommit) {
2262
+ logger.info(' git add --all && git commit -m "chore: init env"');
2249
2263
  }
2250
2264
  logger.info(' coze dev');
2251
2265
  }
@@ -2272,12 +2286,19 @@ const registerCommand$1 = program => {
2272
2286
  .option('-o, --output <path>', 'Output directory', process.cwd())
2273
2287
  .option('--skip-install', 'Skip automatic pnpm install', false)
2274
2288
  .option('--skip-git', 'Skip automatic git initialization', false)
2289
+ .option(
2290
+ '--skip-commit',
2291
+ 'Skip automatic git commit after initialization',
2292
+ false,
2293
+ )
2275
2294
  .option('--skip-dev', 'Skip automatic dev server start', false)
2276
2295
  .allowUnknownOption() // 允许透传参数
2277
2296
  .action(async (directory, options, command) => {
2278
2297
  // 位置参数优先级高于 --output 选项
2279
2298
  const outputPath = _nullishCoalesce(directory, () => ( options.output));
2280
- await executeInit({ ...options, output: outputPath }, command);
2299
+ // Always use force mode - overwrite existing files without conflict check
2300
+ const force = true;
2301
+ await executeInit({ ...options, output: outputPath, force }, command);
2281
2302
  });
2282
2303
  };
2283
2304
 
@@ -2577,7 +2598,7 @@ const registerCommand = program => {
2577
2598
  });
2578
2599
  };
2579
2600
 
2580
- var version = "0.0.1-alpha.de5a13";
2601
+ var version = "0.0.1-alpha.deaedf";
2581
2602
  var packageJson = {
2582
2603
  version: version};
2583
2604
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coze-arch/cli",
3
- "version": "0.0.1-alpha.de5a13",
3
+ "version": "0.0.1-alpha.deaedf",
4
4
  "private": false,
5
5
  "description": "coze coding devtools cli",
6
6
  "license": "MIT",
@@ -50,6 +50,7 @@
50
50
  "@coze-arch/vitest-config": "workspace:*",
51
51
  "@coze-coding/lambda": "workspace:*",
52
52
  "@inquirer/prompts": "^3.2.0",
53
+ "@playwright/test": "~1.55.0",
53
54
  "@types/ejs": "^3.1.5",
54
55
  "@types/iarna__toml": "^2.0.5",
55
56
  "@types/js-yaml": "^4.0.9",
@@ -57,13 +58,16 @@
57
58
  "@types/minimist": "^1.2.5",
58
59
  "@types/node": "^24",
59
60
  "@types/shelljs": "^0.10.0",
60
- "@vitest/coverage-v8": "~4.0.16",
61
+ "@vitest/coverage-v8": "~4.0.18",
61
62
  "json-schema-to-typescript": "^15.0.3",
62
63
  "minimatch": "^10.0.1",
64
+ "playwright": "~1.55.0",
63
65
  "rollup": "^4.41.1",
64
66
  "sucrase": "^3.35.0",
67
+ "tree-kill": "^1.2.2",
65
68
  "tsx": "^4.20.6",
66
- "vitest": "~4.0.16"
69
+ "vite-tsconfig-paths": "^4.2.1",
70
+ "vitest": "~4.0.18"
67
71
  },
68
72
  "publishConfig": {
69
73
  "access": "public",