@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.
- package/README.md +1 -0
- package/lib/__templates__/expo/.cozeproj/scripts/server_dev_run.sh +1 -1
- package/lib/__templates__/expo/client/components/Screen.tsx +2 -2
- package/lib/__templates__/expo/client/eslint.config.mjs +7 -0
- package/lib/__templates__/expo/client/metro.config.js +3 -0
- package/lib/__templates__/expo/client/scripts/install-missing-deps.js +10 -10
- package/lib/__templates__/expo/eslint-plugins/forbid-emoji/index.js +9 -0
- package/lib/__templates__/expo/eslint-plugins/forbid-emoji/rule.js +112 -0
- package/lib/__templates__/expo/eslint-plugins/forbid-emoji/tech.md +94 -0
- package/lib/__templates__/expo/eslint-plugins/restrict-linear-gradient/index.js +9 -0
- package/lib/__templates__/expo/eslint-plugins/restrict-linear-gradient/rule.js +120 -0
- package/lib/__templates__/expo/eslint-plugins/restrict-linear-gradient/tech.md +58 -0
- package/lib/__templates__/expo/pnpm-lock.yaml +8 -5
- package/lib/__templates__/expo/server/package.json +1 -1
- package/lib/__templates__/native-static/.coze +11 -0
- package/lib/__templates__/native-static/index.html +33 -0
- package/lib/__templates__/native-static/styles/main.css +136 -0
- package/lib/__templates__/native-static/template.config.js +22 -0
- package/lib/__templates__/nextjs/.babelrc +3 -0
- package/lib/__templates__/nextjs/README.md +5 -0
- package/lib/__templates__/nextjs/eslint.config.mjs +5 -0
- package/lib/__templates__/nextjs/next.config.ts +1 -2
- package/lib/__templates__/nextjs/package.json +3 -6
- package/lib/__templates__/nextjs/pnpm-lock.yaml +1036 -10
- package/lib/__templates__/nextjs/scripts/build.sh +4 -1
- package/lib/__templates__/nextjs/scripts/dev.sh +8 -2
- package/lib/__templates__/nextjs/scripts/start.sh +7 -1
- package/lib/__templates__/nextjs/src/app/layout.tsx +1 -1
- package/lib/__templates__/nextjs/src/app/page.tsx +1 -2
- package/lib/__templates__/nextjs/src/server.ts +35 -0
- package/lib/__templates__/nextjs/tsconfig.json +1 -1
- package/lib/__templates__/nuxt-vue/.coze +12 -0
- package/lib/__templates__/nuxt-vue/README.md +73 -0
- package/lib/__templates__/nuxt-vue/_gitignore +24 -0
- package/lib/__templates__/nuxt-vue/_npmrc +23 -0
- package/lib/__templates__/nuxt-vue/app/app.vue +6 -0
- package/lib/__templates__/nuxt-vue/app/pages/index.vue +23 -0
- package/lib/__templates__/nuxt-vue/assets/css/main.css +24 -0
- package/lib/__templates__/nuxt-vue/nuxt.config.ts +116 -0
- package/lib/__templates__/nuxt-vue/package.json +35 -0
- package/lib/__templates__/nuxt-vue/pnpm-lock.yaml +8759 -0
- package/lib/__templates__/nuxt-vue/postcss.config.mjs +8 -0
- package/lib/__templates__/nuxt-vue/public/favicon.ico +0 -0
- package/lib/__templates__/nuxt-vue/public/robots.txt +2 -0
- package/lib/__templates__/nuxt-vue/scripts/build.sh +14 -0
- package/lib/__templates__/nuxt-vue/scripts/dev.sh +39 -0
- package/lib/__templates__/nuxt-vue/scripts/prepare.sh +14 -0
- package/lib/__templates__/nuxt-vue/scripts/start.sh +21 -0
- package/lib/__templates__/nuxt-vue/server/api/hello.ts +10 -0
- package/lib/__templates__/nuxt-vue/server/middleware/logger.ts +10 -0
- package/lib/__templates__/nuxt-vue/server/routes/health.ts +10 -0
- package/lib/__templates__/nuxt-vue/tailwind.config.js +13 -0
- package/lib/__templates__/nuxt-vue/template.config.js +87 -0
- package/lib/__templates__/nuxt-vue/tsconfig.json +18 -0
- package/lib/__templates__/taro/.cozeproj/scripts/dev_run.sh +107 -37
- package/lib/__templates__/taro/.cozeproj/scripts/pack.sh +24 -1
- package/lib/__templates__/taro/README.md +138 -62
- package/lib/__templates__/taro/config/index.ts +105 -41
- package/lib/__templates__/taro/config/prod.ts +4 -5
- package/lib/__templates__/taro/eslint.config.mjs +82 -4
- package/lib/__templates__/taro/package.json +23 -7
- package/lib/__templates__/taro/patches/@tarojs__plugin-mini-ci@4.1.9.patch +30 -0
- package/lib/__templates__/taro/pnpm-lock.yaml +1198 -214
- package/lib/__templates__/taro/server/package.json +3 -1
- package/lib/__templates__/taro/src/app.css +140 -47
- package/lib/__templates__/taro/src/app.tsx +9 -0
- package/lib/__templates__/taro/src/components/ui/accordion.tsx +159 -0
- package/lib/__templates__/taro/src/components/ui/alert-dialog.tsx +260 -0
- package/lib/__templates__/taro/src/components/ui/alert.tsx +60 -0
- package/lib/__templates__/taro/src/components/ui/aspect-ratio.tsx +36 -0
- package/lib/__templates__/taro/src/components/ui/avatar.tsx +84 -0
- package/lib/__templates__/taro/src/components/ui/badge.tsx +37 -0
- package/lib/__templates__/taro/src/components/ui/breadcrumb.tsx +117 -0
- package/lib/__templates__/taro/src/components/ui/button-group.tsx +83 -0
- package/lib/__templates__/taro/src/components/ui/button.tsx +67 -0
- package/lib/__templates__/taro/src/components/ui/calendar.tsx +394 -0
- package/lib/__templates__/taro/src/components/ui/card.tsx +108 -0
- package/lib/__templates__/taro/src/components/ui/carousel.tsx +228 -0
- package/lib/__templates__/taro/src/components/ui/checkbox.tsx +58 -0
- package/lib/__templates__/taro/src/components/ui/code-block.tsx +169 -0
- package/lib/__templates__/taro/src/components/ui/collapsible.tsx +71 -0
- package/lib/__templates__/taro/src/components/ui/command.tsx +385 -0
- package/lib/__templates__/taro/src/components/ui/context-menu.tsx +614 -0
- package/lib/__templates__/taro/src/components/ui/dialog.tsx +256 -0
- package/lib/__templates__/taro/src/components/ui/drawer.tsx +192 -0
- package/lib/__templates__/taro/src/components/ui/dropdown-menu.tsx +561 -0
- package/lib/__templates__/taro/src/components/ui/field.tsx +228 -0
- package/lib/__templates__/taro/src/components/ui/hover-card.tsx +282 -0
- package/lib/__templates__/taro/src/components/ui/input-group.tsx +197 -0
- package/lib/__templates__/taro/src/components/ui/input-otp.tsx +136 -0
- package/lib/__templates__/taro/src/components/ui/input.tsx +56 -0
- package/lib/__templates__/taro/src/components/ui/label.tsx +24 -0
- package/lib/__templates__/taro/src/components/ui/menubar.tsx +595 -0
- package/lib/__templates__/taro/src/components/ui/navigation-menu.tsx +264 -0
- package/lib/__templates__/taro/src/components/ui/pagination.tsx +118 -0
- package/lib/__templates__/taro/src/components/ui/popover.tsx +291 -0
- package/lib/__templates__/taro/src/components/ui/portal.tsx +19 -0
- package/lib/__templates__/taro/src/components/ui/progress.tsx +28 -0
- package/lib/__templates__/taro/src/components/ui/radio-group.tsx +64 -0
- package/lib/__templates__/taro/src/components/ui/resizable.tsx +346 -0
- package/lib/__templates__/taro/src/components/ui/scroll-area.tsx +34 -0
- package/lib/__templates__/taro/src/components/ui/select.tsx +438 -0
- package/lib/__templates__/taro/src/components/ui/separator.tsx +30 -0
- package/lib/__templates__/taro/src/components/ui/sheet.tsx +262 -0
- package/lib/__templates__/taro/src/components/ui/skeleton.tsx +17 -0
- package/lib/__templates__/taro/src/components/ui/slider.tsx +203 -0
- package/lib/__templates__/taro/src/components/ui/sonner.tsx +1 -0
- package/lib/__templates__/taro/src/components/ui/switch.tsx +55 -0
- package/lib/__templates__/taro/src/components/ui/table.tsx +142 -0
- package/lib/__templates__/taro/src/components/ui/tabs.tsx +114 -0
- package/lib/__templates__/taro/src/components/ui/textarea.tsx +54 -0
- package/lib/__templates__/taro/src/components/ui/toast.tsx +517 -0
- package/lib/__templates__/taro/src/components/ui/toggle-group.tsx +120 -0
- package/lib/__templates__/taro/src/components/ui/toggle.tsx +77 -0
- package/lib/__templates__/taro/src/components/ui/tooltip.tsx +455 -0
- package/lib/__templates__/taro/src/lib/hooks/use-keyboard-offset.ts +37 -0
- package/lib/__templates__/taro/src/lib/measure.ts +115 -0
- package/lib/__templates__/taro/src/lib/platform.ts +12 -0
- package/lib/__templates__/taro/src/lib/utils.ts +6 -0
- package/lib/__templates__/taro/src/presets/dev-debug.ts +23 -0
- package/lib/__templates__/taro/src/presets/h5-container.tsx +15 -0
- package/lib/__templates__/taro/src/presets/h5-navbar.tsx +238 -0
- package/lib/__templates__/taro/src/presets/h5-styles.ts +220 -0
- package/lib/__templates__/taro/src/presets/index.tsx +18 -0
- package/lib/__templates__/templates.json +43 -0
- package/lib/__templates__/vite/README.md +190 -11
- package/lib/__templates__/vite/_gitignore +1 -0
- package/lib/__templates__/vite/eslint.config.mjs +6 -1
- package/lib/__templates__/vite/package.json +14 -5
- package/lib/__templates__/vite/pnpm-lock.yaml +768 -24
- package/lib/__templates__/vite/scripts/build.sh +4 -1
- package/lib/__templates__/vite/scripts/dev.sh +9 -2
- package/lib/__templates__/vite/scripts/start.sh +9 -3
- package/lib/__templates__/vite/server/routes/index.ts +31 -0
- package/lib/__templates__/vite/server/server.ts +65 -0
- package/lib/__templates__/vite/server/vite.ts +67 -0
- package/lib/__templates__/vite/tsconfig.json +4 -3
- package/lib/__templates__/vite/vite.config.ts +5 -0
- package/lib/cli.js +124 -103
- package/package.json +7 -3
- package/lib/__templates__/taro/src/app.ts +0 -14
- package/lib/__templates__/taro/src/utils/h5-styles.ts +0 -22
- 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
|
|
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
|
|
37
|
+
echo "Starting express + Vite dev server on port ${PORT}..."
|
|
31
38
|
|
|
32
|
-
npx
|
|
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
|
|
11
|
-
|
|
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
|
|
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": "
|
|
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
|
|
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
|
|
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
|
-
|
|
1825
|
+
await collectFilesToRender({
|
|
1853
1826
|
files,
|
|
1854
1827
|
templatePath,
|
|
1855
1828
|
context,
|
|
1856
1829
|
templateConfig,
|
|
1857
1830
|
});
|
|
1858
1831
|
|
|
1859
|
-
// 阶段 3:
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
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
|
|
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
|
-
*
|
|
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
|
-
|
|
2221
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
-
"
|
|
69
|
+
"vite-tsconfig-paths": "^4.2.1",
|
|
70
|
+
"vitest": "~4.0.18"
|
|
67
71
|
},
|
|
68
72
|
"publishConfig": {
|
|
69
73
|
"access": "public",
|