@coze-arch/cli 0.0.36-alpha.dd2af3 → 0.0.36-alpha.e6ca88
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 +65 -114
- package/docs/deploy.md +2 -1
- package/lib/__templates__/native-static/.coze +2 -0
- package/lib/__templates__/native-static/scripts/serve.ps1 +7 -0
- package/lib/__templates__/nextjs/.coze +5 -0
- package/lib/__templates__/nextjs/scripts/build.ps1 +16 -0
- package/lib/__templates__/nextjs/scripts/dev.ps1 +63 -0
- package/lib/__templates__/nextjs/scripts/dev.sh +80 -8
- package/lib/__templates__/nextjs/scripts/prepare.ps1 +18 -0
- package/lib/__templates__/nextjs/scripts/start.ps1 +11 -0
- package/lib/__templates__/nextjs/scripts/validate.ps1 +8 -0
- package/lib/__templates__/nuxt-vue/.coze +5 -0
- package/lib/__templates__/nuxt-vue/scripts/build.ps1 +12 -0
- package/lib/__templates__/nuxt-vue/scripts/dev.ps1 +63 -0
- package/lib/__templates__/nuxt-vue/scripts/dev.sh +82 -1
- package/lib/__templates__/nuxt-vue/scripts/prepare.ps1 +12 -0
- package/lib/__templates__/nuxt-vue/scripts/start.ps1 +11 -0
- package/lib/__templates__/nuxt-vue/scripts/validate.ps1 +8 -0
- package/lib/__templates__/phaser/.coze +5 -0
- package/lib/__templates__/phaser/README.md +8 -0
- package/lib/__templates__/phaser/scripts/build.ps1 +12 -0
- package/lib/__templates__/phaser/scripts/dev.ps1 +49 -0
- package/lib/__templates__/phaser/scripts/prepare.ps1 +8 -0
- package/lib/__templates__/phaser/scripts/start.ps1 +49 -0
- package/lib/__templates__/phaser/scripts/validate.ps1 +7 -0
- package/lib/__templates__/phaser/src/global.d.ts +3 -0
- package/lib/__templates__/phaser/src/scene/BootScene.ts +4 -0
- package/lib/__templates__/phaser/src/scene/DevLoadingScene.ts +3 -0
- package/lib/__templates__/phaser/src/utils/mark-editable.ts +8 -1
- package/lib/__templates__/phaser-static/.coze +15 -0
- package/lib/__templates__/phaser-static/README.md +40 -0
- package/lib/__templates__/phaser-static/_gitignore +6 -0
- package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0001.png +0 -0
- package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0002.png +0 -0
- package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0003.png +0 -0
- package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0004.png +0 -0
- package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0005.png +0 -0
- package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0006.png +0 -0
- package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0007.png +0 -0
- package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0008.png +0 -0
- package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0009.png +0 -0
- package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0010.png +0 -0
- package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0011.png +0 -0
- package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0012.png +0 -0
- package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0013.png +0 -0
- package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0014.png +0 -0
- package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0015.png +0 -0
- package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0016.png +0 -0
- package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0017.png +0 -0
- package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0018.png +0 -0
- package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0019.png +0 -0
- package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0020.png +0 -0
- package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0021.png +0 -0
- package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0022.png +0 -0
- package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0023.png +0 -0
- package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0024.png +0 -0
- package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/manifest.json +11 -0
- package/lib/__templates__/phaser-static/debug-runtime/flow-graph.json +20 -0
- package/lib/__templates__/phaser-static/index.html +17 -0
- package/lib/__templates__/phaser-static/scripts/serve.ps1 +7 -0
- package/lib/__templates__/phaser-static/src/assets.js +15 -0
- package/lib/__templates__/phaser-static/src/main.js +26 -0
- package/lib/__templates__/phaser-static/src/phaser.js +7 -0
- package/lib/__templates__/phaser-static/src/scene/BootScene.js +205 -0
- package/lib/__templates__/phaser-static/src/scene/DevLoadingScene.js +67 -0
- package/lib/__templates__/phaser-static/src/style.css +28 -0
- package/lib/__templates__/phaser-static/src/utils/asset-loader.js +267 -0
- package/lib/__templates__/phaser-static/src/utils/index.js +2 -0
- package/lib/__templates__/phaser-static/src/utils/mark-editable.js +3 -0
- package/lib/__templates__/phaser-static/template.config.js +35 -0
- package/lib/__templates__/taro/.cozeproj/scripts/dev_run.sh +53 -22
- package/lib/__templates__/templates.json +18 -0
- package/lib/__templates__/vite/.coze +5 -0
- package/lib/__templates__/vite/scripts/build.ps1 +16 -0
- package/lib/__templates__/vite/scripts/dev.ps1 +63 -0
- package/lib/__templates__/vite/scripts/dev.sh +82 -1
- package/lib/__templates__/vite/scripts/prepare.ps1 +18 -0
- package/lib/__templates__/vite/scripts/start.ps1 +11 -0
- package/lib/__templates__/vite/scripts/validate.ps1 +8 -0
- package/lib/cli.js +186 -155
- package/lib/deploy/package-project.js +22 -4
- package/lib/deploy/package-project.py +18 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,154 +1,105 @@
|
|
|
1
|
-
# @coze-
|
|
1
|
+
# @coze-arch/cli
|
|
2
2
|
|
|
3
|
-
Coze Coding
|
|
4
|
-
|
|
5
|
-
## 特性
|
|
6
|
-
|
|
7
|
-
- 🚀 **快速初始化**: 一键创建预配置的项目模板
|
|
8
|
-
- 🤖 **AI 优先设计**: 专为 AI Agent 消费设计,提供清晰的错误信息和自描述能力
|
|
9
|
-
- 📦 **多模板支持**: 支持 React、Next.js、HTML 等多种技术栈
|
|
10
|
-
- 🔧 **类型安全**: 基于 JSON Schema 的参数校验和 TypeScript 类型生成
|
|
11
|
-
- ⚡ **命令代理**: 统一的 dev/build/start 命令,抹平不同技术栈差异
|
|
3
|
+
Coze Coding 的项目模板与本地运行 CLI。发布包名为 `@coze-arch/cli`,命令为
|
|
4
|
+
`coze-dev`。
|
|
12
5
|
|
|
13
6
|
## 安装
|
|
14
7
|
|
|
15
8
|
```bash
|
|
16
|
-
|
|
17
|
-
|
|
9
|
+
npm install -g @coze-arch/cli
|
|
10
|
+
coze-dev --help
|
|
18
11
|
```
|
|
19
12
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
### 部署应用
|
|
13
|
+
也可以不全局安装:
|
|
23
14
|
|
|
24
15
|
```bash
|
|
25
|
-
coze-
|
|
26
|
-
coze-dev deploy code deploy --source-root . --yes --wait
|
|
16
|
+
npx @coze-arch/cli --help
|
|
27
17
|
```
|
|
28
18
|
|
|
29
|
-
|
|
30
|
-
`coze-dev` 能力共享 `~/.coze/cli/config.json` 登录态,也支持通过
|
|
31
|
-
`COZE_API_TOKEN` 提供固定运行时凭证。
|
|
32
|
-
|
|
33
|
-
### 初始化项目
|
|
19
|
+
## 初始化项目
|
|
34
20
|
|
|
35
21
|
```bash
|
|
36
|
-
coze-
|
|
22
|
+
coze-dev init my-app --template <template> --app-name my-app
|
|
23
|
+
coze-dev init --help
|
|
37
24
|
```
|
|
38
25
|
|
|
39
|
-
|
|
26
|
+
`init` 默认会渲染模板、安装依赖、初始化 Git、创建初始提交并启动开发服务。按需使用
|
|
27
|
+
`--skip-install`、`--skip-git`、`--skip-commit`、`--skip-dev` 跳过这些步骤。模板名称和
|
|
28
|
+
参数以 `coze-dev init --help` 的实时输出为准;未声明的参数会以 kebab-case 转为
|
|
29
|
+
camelCase 后传给模板。
|
|
40
30
|
|
|
41
|
-
|
|
42
|
-
coze-coding init --help
|
|
43
|
-
```
|
|
31
|
+
## 在项目中运行
|
|
44
32
|
|
|
45
|
-
|
|
33
|
+
初始化产物根目录的 `.coze` 是统一命令契约:
|
|
46
34
|
|
|
47
35
|
```bash
|
|
48
|
-
#
|
|
49
|
-
coze-
|
|
50
|
-
|
|
51
|
-
#
|
|
52
|
-
coze-coding build
|
|
53
|
-
|
|
54
|
-
# 启动生产服务器
|
|
55
|
-
coze-coding start
|
|
36
|
+
coze-dev dev # 读取 dev.run
|
|
37
|
+
coze-dev build # 读取 deploy.build
|
|
38
|
+
coze-dev start # 读取 deploy.run
|
|
39
|
+
coze-dev validate # 读取 dev.validate
|
|
56
40
|
```
|
|
57
41
|
|
|
58
|
-
|
|
42
|
+
`dev` 和 `build` 在执行前会尝试应用模板补丁;补丁失败会记录调试信息,但不会阻止主命令。
|
|
43
|
+
子进程日志默认写入 `~/.coze-logs/dev.log`,可用 `--log-file <path>` 覆盖。
|
|
59
44
|
|
|
60
|
-
|
|
45
|
+
## Windows 与 WSL
|
|
61
46
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
- `--use-typescript` → `useTypeScript`
|
|
65
|
-
- `--port` → `port`
|
|
47
|
+
原生 Windows(`process.platform === "win32"`)优先使用 `.coze` 中非空的 Windows
|
|
48
|
+
覆盖命令;未配置时回退默认命令。WSL 被识别为 Linux,始终执行默认命令。
|
|
66
49
|
|
|
67
|
-
|
|
50
|
+
| CLI 命令或场景 | 默认字段 | Windows 覆盖字段 |
|
|
51
|
+
| --- | --- | --- |
|
|
52
|
+
| `coze-dev dev` | `dev.run` | `dev.run_win` |
|
|
53
|
+
| `coze-dev build` | `deploy.build` | `deploy.build_win` |
|
|
54
|
+
| `coze-dev start` | `deploy.run` | `deploy.run_win` |
|
|
55
|
+
| `coze-dev validate` | `dev.validate` | `dev.validate_win` |
|
|
56
|
+
| `coze-dev deploy` 的本地打包 | `dev.pack` | `dev.pack_win` |
|
|
68
57
|
|
|
69
|
-
|
|
58
|
+
已支持 Windows 的内置 Web 与 Phaser 模板将覆盖命令映射到 PowerShell 脚本,例如:
|
|
70
59
|
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
├── .coze # 项目配置文件
|
|
76
|
-
└── src/ # 源代码(支持 EJS 模板)
|
|
77
|
-
```
|
|
60
|
+
```toml
|
|
61
|
+
[dev]
|
|
62
|
+
run = ["bash", "./scripts/dev.sh"]
|
|
63
|
+
run_win = ["powershell.exe", "-NoProfile", "-ExecutionPolicy", "Bypass", "-File", "./scripts/dev.ps1"]
|
|
78
64
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
```typescript
|
|
84
|
-
import type { JSONSchemaType } from 'ajv';
|
|
85
|
-
|
|
86
|
-
export interface TemplateParams {
|
|
87
|
-
appName: string;
|
|
88
|
-
useTypeScript: boolean;
|
|
89
|
-
port: number;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
export const paramsSchema: JSONSchemaType<TemplateParams> = {
|
|
93
|
-
type: 'object',
|
|
94
|
-
properties: {
|
|
95
|
-
appName: {
|
|
96
|
-
type: 'string',
|
|
97
|
-
minLength: 1,
|
|
98
|
-
pattern: '^[a-z0-9-]+$',
|
|
99
|
-
cliParam: '--app-name',
|
|
100
|
-
description: 'Application name'
|
|
101
|
-
},
|
|
102
|
-
useTypeScript: {
|
|
103
|
-
type: 'boolean',
|
|
104
|
-
default: true,
|
|
105
|
-
cliParam: '--use-typescript',
|
|
106
|
-
description: 'Enable TypeScript'
|
|
107
|
-
},
|
|
108
|
-
port: {
|
|
109
|
-
type: 'number',
|
|
110
|
-
default: 3000,
|
|
111
|
-
minimum: 1024,
|
|
112
|
-
maximum: 65535,
|
|
113
|
-
cliParam: '--port',
|
|
114
|
-
description: 'Development server port'
|
|
115
|
-
}
|
|
116
|
-
},
|
|
117
|
-
required: ['appName'],
|
|
118
|
-
additionalProperties: false
|
|
119
|
-
};
|
|
65
|
+
[deploy]
|
|
66
|
+
build = ["bash", "./scripts/build.sh"]
|
|
67
|
+
build_win = ["powershell.exe", "-NoProfile", "-ExecutionPolicy", "Bypass", "-File", "./scripts/build.ps1"]
|
|
120
68
|
```
|
|
121
69
|
|
|
122
|
-
|
|
70
|
+
## 部署
|
|
123
71
|
|
|
124
|
-
|
|
125
|
-
export const onBeforeRender = (context) => {
|
|
126
|
-
// 渲染前处理
|
|
127
|
-
return context;
|
|
128
|
-
};
|
|
72
|
+
`coze-dev deploy` 内置于同一 CLI,登录态默认保存在 `~/.coze/cli/config.json`:
|
|
129
73
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
74
|
+
```bash
|
|
75
|
+
coze-dev deploy auth login
|
|
76
|
+
coze-dev deploy doctor
|
|
77
|
+
coze-dev deploy code deploy --source-root . --yes --wait
|
|
133
78
|
```
|
|
134
79
|
|
|
135
|
-
|
|
80
|
+
完整的应用、环境变量、Pages 和小程序命令说明见 [部署文档](./docs/deploy.md)。
|
|
81
|
+
`dev.pack_win` 是自定义模板可选的 Windows 打包覆盖;当前 Expo、Taro 和 Pi Agent 模板
|
|
82
|
+
不承诺 Windows 支持。
|
|
136
83
|
|
|
137
|
-
|
|
84
|
+
## 模板开发
|
|
138
85
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
- ✅ 使用工厂函数和闭包
|
|
142
|
-
- ❌ 禁止使用 class
|
|
143
|
-
- ❌ 避免副作用和可变状态
|
|
86
|
+
模板位于 `src/__templates__/`,每个模板通过 `template.config.ts` 定义参数和渲染钩子,
|
|
87
|
+
`.coze` 定义生成项目的运行命令。新增模板或修改模板目录后执行:
|
|
144
88
|
|
|
145
|
-
|
|
89
|
+
```bash
|
|
90
|
+
npm run prebuild
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
模板开发细节见 [模板开发指南](./docs/how-to-dev.md)。仓库开发依赖由 Rush 管理,不要在本包目录单独执行 `npm install` 或 `pnpm install`。
|
|
146
94
|
|
|
147
|
-
##
|
|
95
|
+
## 本地开发与验证
|
|
148
96
|
|
|
149
|
-
|
|
150
|
-
- [技术设计](./docs/technical-design.md)
|
|
97
|
+
源码入口支持直接运行,无需先构建:
|
|
151
98
|
|
|
152
|
-
|
|
99
|
+
```bash
|
|
100
|
+
node src/cli.js --help
|
|
101
|
+
npm run test
|
|
102
|
+
npm run build
|
|
103
|
+
```
|
|
153
104
|
|
|
154
|
-
|
|
105
|
+
端到端模板验证使用 `npm run test:e2e`,会真实安装模板依赖并启动服务。发布前需完成该验证。
|
package/docs/deploy.md
CHANGED
|
@@ -93,7 +93,8 @@ coze-dev deploy code deploy --source-root . --application-type pages --yes --wai
|
|
|
93
93
|
`--application-type pages` 自动复用,或显式传 `--app-id`。
|
|
94
94
|
|
|
95
95
|
V2 接口的所有参数均通过 POST JSON body 发送,不会放入 URL。确认非 Pages 部署后,CLI
|
|
96
|
-
会执行 `.coze` 中可选的 `dev.pack`
|
|
96
|
+
会执行 `.coze` 中可选的 `dev.pack` 命令;原生 Windows 优先执行非空的
|
|
97
|
+
`dev.pack_win`,未配置时回退 `dev.pack`。该步骤将
|
|
97
98
|
本地部署内容打成无根目录的 `tar.gz`,再通过 `source_package_base64` 上传。Pages 部署
|
|
98
99
|
统一上传源码根目录:已有 `index.html` 时服务端跳过构建,没有时由服务端按 Snapshot 中的
|
|
99
100
|
`.coze deploy.build` 构建。打包由 CLI 自带的 Node.js 脚本执行,并排除 `.coze`、`.env`、
|
|
@@ -6,7 +6,9 @@ project_type = "web"
|
|
|
6
6
|
[dev]
|
|
7
7
|
build = []
|
|
8
8
|
run = [ "sh", "-c", "python -m http.server ${DEPLOY_RUN_PORT} --bind 0.0.0.0" ]
|
|
9
|
+
run_win = ["powershell.exe", "-NoProfile", "-ExecutionPolicy", "Bypass", "-File", "./scripts/serve.ps1"]
|
|
9
10
|
|
|
10
11
|
[deploy]
|
|
11
12
|
build = []
|
|
12
13
|
run = [ "sh", "-c", "python -m http.server ${DEPLOY_RUN_PORT} --bind 0.0.0.0" ]
|
|
14
|
+
run_win = ["powershell.exe", "-NoProfile", "-ExecutionPolicy", "Bypass", "-File", "./scripts/serve.ps1"]
|
|
@@ -4,11 +4,16 @@ project_type = "web"
|
|
|
4
4
|
|
|
5
5
|
[dev]
|
|
6
6
|
build = ["bash", "./scripts/prepare.sh"]
|
|
7
|
+
build_win = ["powershell.exe", "-NoProfile", "-ExecutionPolicy", "Bypass", "-File", "./scripts/prepare.ps1"]
|
|
7
8
|
run = ["bash", "./scripts/dev.sh"]
|
|
9
|
+
run_win = ["powershell.exe", "-NoProfile", "-ExecutionPolicy", "Bypass", "-File", "./scripts/dev.ps1"]
|
|
8
10
|
validate = ["bash", "./scripts/validate.sh"]
|
|
11
|
+
validate_win = ["powershell.exe", "-NoProfile", "-ExecutionPolicy", "Bypass", "-File", "./scripts/validate.ps1"]
|
|
9
12
|
deps = ["git"] # -> apt install git
|
|
10
13
|
|
|
11
14
|
[deploy]
|
|
12
15
|
build = ["bash","./scripts/build.sh"]
|
|
16
|
+
build_win = ["powershell.exe", "-NoProfile", "-ExecutionPolicy", "Bypass", "-File", "./scripts/build.ps1"]
|
|
13
17
|
run = ["bash","./scripts/start.sh"]
|
|
18
|
+
run_win = ["powershell.exe", "-NoProfile", "-ExecutionPolicy", "Bypass", "-File", "./scripts/start.ps1"]
|
|
14
19
|
deps = ["git"] # -> apt install git
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
$ErrorActionPreference = "Stop"
|
|
2
|
+
|
|
3
|
+
$workspace = if ($env:COZE_WORKSPACE_PATH) { $env:COZE_WORKSPACE_PATH } else { (Get-Location).Path }
|
|
4
|
+
Set-Location $workspace
|
|
5
|
+
|
|
6
|
+
Write-Host "Installing dependencies..."
|
|
7
|
+
& pnpm install --prefer-frozen-lockfile --prefer-offline --loglevel debug --reporter=append-only
|
|
8
|
+
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
|
|
9
|
+
|
|
10
|
+
Write-Host "Building the Next.js project..."
|
|
11
|
+
& pnpm next build
|
|
12
|
+
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
|
|
13
|
+
|
|
14
|
+
Write-Host "Bundling server with tsup..."
|
|
15
|
+
& pnpm tsup src/server.ts --format cjs --platform node --target node20 --outDir dist --no-splitting --no-minify
|
|
16
|
+
exit $LASTEXITCODE
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
$ErrorActionPreference = "Stop"
|
|
2
|
+
|
|
3
|
+
function Get-WorkspacePath {
|
|
4
|
+
if ($env:COZE_WORKSPACE_PATH) {
|
|
5
|
+
return $env:COZE_WORKSPACE_PATH
|
|
6
|
+
}
|
|
7
|
+
return (Get-Location).Path
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function Stop-ProcessTree([int] $processId) {
|
|
11
|
+
if ($processId -gt 0 -and (Get-Process -Id $processId -ErrorAction SilentlyContinue)) {
|
|
12
|
+
& taskkill.exe /PID $processId /T /F *> $null
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function Stop-ListeningProcess([int] $port) {
|
|
17
|
+
$connections = Get-NetTCPConnection -LocalPort $port -State Listen -ErrorAction SilentlyContinue
|
|
18
|
+
$connections | Select-Object -ExpandProperty OwningProcess -Unique | ForEach-Object {
|
|
19
|
+
Stop-ProcessTree $_
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
$workspace = Get-WorkspacePath
|
|
24
|
+
$defaultPort = <%= port %>
|
|
25
|
+
$port = if ($env:DEPLOY_RUN_PORT) { [int] $env:DEPLOY_RUN_PORT } elseif ($env:PORT) { [int] $env:PORT } else { $defaultPort }
|
|
26
|
+
Set-Location $workspace
|
|
27
|
+
Stop-ListeningProcess $port
|
|
28
|
+
|
|
29
|
+
<% if (process.env.NODE_ENV === 'test') { %>
|
|
30
|
+
$env:PORT = "$port"
|
|
31
|
+
& pnpm tsx watch src/server.ts
|
|
32
|
+
exit $LASTEXITCODE
|
|
33
|
+
<% } else { %>
|
|
34
|
+
$logDirectory = if ($env:COZE_LOG_DIR) { $env:COZE_LOG_DIR } else { Join-Path $workspace "logs" }
|
|
35
|
+
$logFile = Join-Path $logDirectory "server.log"
|
|
36
|
+
$errorLogFile = Join-Path $logDirectory "server-error.log"
|
|
37
|
+
$pidFile = Join-Path $logDirectory "server.pid"
|
|
38
|
+
New-Item -ItemType Directory -Force -Path $logDirectory | Out-Null
|
|
39
|
+
|
|
40
|
+
if (Test-Path $pidFile) {
|
|
41
|
+
Stop-ProcessTree ([int] (Get-Content $pidFile -Raw))
|
|
42
|
+
Remove-Item $pidFile -Force
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
$previousPort = $env:PORT
|
|
46
|
+
$env:PORT = "$port"
|
|
47
|
+
try {
|
|
48
|
+
$process = Start-Process -FilePath $env:ComSpec -ArgumentList @("/d", "/s", "/c", "pnpm tsx watch src/server.ts") -WorkingDirectory $workspace -RedirectStandardOutput $logFile -RedirectStandardError $errorLogFile -PassThru
|
|
49
|
+
} finally {
|
|
50
|
+
if ($null -eq $previousPort) { Remove-Item Env:PORT -ErrorAction SilentlyContinue } else { $env:PORT = $previousPort }
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
$process.Id | Set-Content $pidFile
|
|
54
|
+
Start-Sleep -Seconds 1
|
|
55
|
+
if ($process.HasExited) {
|
|
56
|
+
Get-Content $errorLogFile -Tail 20 -ErrorAction SilentlyContinue
|
|
57
|
+
Remove-Item $pidFile -Force -ErrorAction SilentlyContinue
|
|
58
|
+
exit 1
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
Write-Host "Dev server started (PID: $($process.Id))."
|
|
62
|
+
Write-Host "Log file: $logFile"
|
|
63
|
+
<% } %>
|
|
@@ -14,9 +14,6 @@ DEPLOY_RUN_PORT="${DEPLOY_RUN_PORT:-${PORT}}"
|
|
|
14
14
|
|
|
15
15
|
cd "${COZE_WORKSPACE_PATH}"
|
|
16
16
|
|
|
17
|
-
LOG_DIR="${COZE_LOG_DIR:-${COZE_WORKSPACE_PATH}/logs}"
|
|
18
|
-
LOG_SERVER_FILE="${LOG_DIR}/server.log"
|
|
19
|
-
|
|
20
17
|
kill_port_if_listening() {
|
|
21
18
|
local pids
|
|
22
19
|
pids=$(ss -H -lntp 2>/dev/null | awk -v port="${DEPLOY_RUN_PORT}" '$4 ~ ":"port"$"' | grep -o 'pid=[0-9]*' | cut -d= -f2 | paste -sd' ' - || true)
|
|
@@ -35,14 +32,89 @@ kill_port_if_listening() {
|
|
|
35
32
|
fi
|
|
36
33
|
}
|
|
37
34
|
|
|
35
|
+
<% if (process.env.NODE_ENV === 'test') { %>
|
|
36
|
+
echo "Clearing port ${DEPLOY_RUN_PORT} before start."
|
|
37
|
+
kill_port_if_listening
|
|
38
|
+
echo "Starting HTTP service on port ${DEPLOY_RUN_PORT} for dev..."
|
|
39
|
+
|
|
40
|
+
# 测试环境保持服务为前台进程,便于 e2e 收集输出并停止进程。
|
|
41
|
+
exec env PORT="${DEPLOY_RUN_PORT}" pnpm tsx watch src/server.ts
|
|
42
|
+
<% } else { %>
|
|
43
|
+
LOG_DIR="${COZE_LOG_DIR:-${COZE_WORKSPACE_PATH}/logs}"
|
|
44
|
+
LOG_FILE="${LOG_DIR}/server.log"
|
|
45
|
+
PID_FILE="${LOG_DIR}/server.pid"
|
|
46
|
+
|
|
47
|
+
# coze-daemon 会在 runtime shell 退出时清理原进程组。
|
|
48
|
+
# 通过 Node detached spawn 创建独立 session/进程组,并将 stdio 直接写入日志。
|
|
49
|
+
spawn_detached() {
|
|
50
|
+
local cwd="$1"
|
|
51
|
+
local log_file="$2"
|
|
52
|
+
shift 2
|
|
53
|
+
|
|
54
|
+
node - "$cwd" "$log_file" "$@" <<'NODE'
|
|
55
|
+
const fs = require('node:fs');
|
|
56
|
+
const { spawn } = require('node:child_process');
|
|
57
|
+
|
|
58
|
+
const [cwd, logFile, command, ...args] = process.argv.slice(2);
|
|
59
|
+
if (!cwd || !logFile || !command) {
|
|
60
|
+
throw new Error('spawn_detached 缺少 cwd、log_file 或 command');
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const logFd = fs.openSync(logFile, 'a');
|
|
64
|
+
try {
|
|
65
|
+
const child = spawn(command, args, {
|
|
66
|
+
cwd,
|
|
67
|
+
detached: true,
|
|
68
|
+
env: process.env,
|
|
69
|
+
stdio: ['ignore', logFd, logFd],
|
|
70
|
+
});
|
|
71
|
+
child.unref();
|
|
72
|
+
process.stdout.write(String(child.pid));
|
|
73
|
+
} finally {
|
|
74
|
+
fs.closeSync(logFd);
|
|
75
|
+
}
|
|
76
|
+
NODE
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
stop_detached() {
|
|
80
|
+
local pid="${1:-}"
|
|
81
|
+
if [[ -z "${pid}" ]]; then
|
|
82
|
+
return
|
|
83
|
+
fi
|
|
84
|
+
|
|
85
|
+
kill -TERM -- "-${pid}" 2>/dev/null || kill -TERM "${pid}" 2>/dev/null || true
|
|
86
|
+
sleep 1
|
|
87
|
+
kill -KILL -- "-${pid}" 2>/dev/null || true
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
# 监听端口的是孙进程(pnpm -> tsx -> node),只清端口会漏掉上层 pnpm/tsx,
|
|
91
|
+
# 所以先按上次记录的 PID 把整个进程组回收掉。
|
|
92
|
+
if [[ -f "${PID_FILE}" ]]; then
|
|
93
|
+
stop_detached "$(cat "${PID_FILE}" 2>/dev/null || true)"
|
|
94
|
+
rm -f "${PID_FILE}"
|
|
95
|
+
fi
|
|
96
|
+
|
|
38
97
|
echo "Clearing port ${DEPLOY_RUN_PORT} before start."
|
|
39
98
|
kill_port_if_listening
|
|
40
99
|
echo "Starting HTTP service on port ${DEPLOY_RUN_PORT} for dev..."
|
|
41
100
|
|
|
42
101
|
mkdir -p "${LOG_DIR}"
|
|
43
|
-
: > "${
|
|
102
|
+
: > "${LOG_FILE}"
|
|
44
103
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
104
|
+
export PORT="${DEPLOY_RUN_PORT}"
|
|
105
|
+
server_pid="$(spawn_detached "${COZE_WORKSPACE_PATH}" "${LOG_FILE}" \
|
|
106
|
+
"$(command -v pnpm)" tsx watch src/server.ts)"
|
|
107
|
+
echo "${server_pid}" > "${PID_FILE}"
|
|
108
|
+
|
|
109
|
+
sleep 1
|
|
110
|
+
if [[ -z "${server_pid}" ]] || ! kill -0 "${server_pid}" 2>/dev/null; then
|
|
111
|
+
echo "Dev server failed to start. See ${LOG_FILE}." >&2
|
|
112
|
+
tail -n 20 "${LOG_FILE}" >&2 || true
|
|
113
|
+
rm -f "${PID_FILE}"
|
|
114
|
+
exit 1
|
|
115
|
+
fi
|
|
116
|
+
|
|
117
|
+
echo "Dev server started (PID: ${server_pid})."
|
|
118
|
+
echo "Log file: ${LOG_FILE}"
|
|
119
|
+
echo "PID file: ${PID_FILE}"
|
|
120
|
+
<% } %>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
$ErrorActionPreference = "Stop"
|
|
2
|
+
|
|
3
|
+
$workspace = if ($env:COZE_WORKSPACE_PATH) { $env:COZE_WORKSPACE_PATH } else { (Get-Location).Path }
|
|
4
|
+
Set-Location $workspace
|
|
5
|
+
|
|
6
|
+
Write-Host "Installing dependencies..."
|
|
7
|
+
& pnpm install --prefer-frozen-lockfile --prefer-offline --loglevel debug --reporter=append-only
|
|
8
|
+
if ($LASTEXITCODE -ne 0) {
|
|
9
|
+
exit $LASTEXITCODE
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
if (Get-Command coze-dev -ErrorAction SilentlyContinue) {
|
|
13
|
+
& coze-dev check-bins --help *> $null
|
|
14
|
+
if ($LASTEXITCODE -eq 0) {
|
|
15
|
+
& coze-dev check-bins --fix
|
|
16
|
+
exit $LASTEXITCODE
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
$ErrorActionPreference = "Stop"
|
|
2
|
+
|
|
3
|
+
$workspace = if ($env:COZE_WORKSPACE_PATH) { $env:COZE_WORKSPACE_PATH } else { (Get-Location).Path }
|
|
4
|
+
$defaultPort = <%= port %>
|
|
5
|
+
$port = if ($env:DEPLOY_RUN_PORT) { $env:DEPLOY_RUN_PORT } elseif ($env:PORT) { $env:PORT } else { $defaultPort }
|
|
6
|
+
Set-Location $workspace
|
|
7
|
+
|
|
8
|
+
Write-Host "Starting HTTP service on port $port for deploy..."
|
|
9
|
+
$env:PORT = "$port"
|
|
10
|
+
& node dist/server.js
|
|
11
|
+
exit $LASTEXITCODE
|
|
@@ -4,11 +4,16 @@ project_type = "web"
|
|
|
4
4
|
|
|
5
5
|
[dev]
|
|
6
6
|
build = ["bash", "./scripts/prepare.sh"]
|
|
7
|
+
build_win = ["powershell.exe", "-NoProfile", "-ExecutionPolicy", "Bypass", "-File", "./scripts/prepare.ps1"]
|
|
7
8
|
run = ["bash", "./scripts/dev.sh"]
|
|
9
|
+
run_win = ["powershell.exe", "-NoProfile", "-ExecutionPolicy", "Bypass", "-File", "./scripts/dev.ps1"]
|
|
8
10
|
validate = ["bash", "./scripts/validate.sh"]
|
|
11
|
+
validate_win = ["powershell.exe", "-NoProfile", "-ExecutionPolicy", "Bypass", "-File", "./scripts/validate.ps1"]
|
|
9
12
|
deps = ["git"] # -> apt install git
|
|
10
13
|
|
|
11
14
|
[deploy]
|
|
12
15
|
build = ["bash","./scripts/build.sh"]
|
|
16
|
+
build_win = ["powershell.exe", "-NoProfile", "-ExecutionPolicy", "Bypass", "-File", "./scripts/build.ps1"]
|
|
13
17
|
run = ["bash","./scripts/start.sh"]
|
|
18
|
+
run_win = ["powershell.exe", "-NoProfile", "-ExecutionPolicy", "Bypass", "-File", "./scripts/start.ps1"]
|
|
14
19
|
deps = ["git"] # -> apt install git
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
$ErrorActionPreference = "Stop"
|
|
2
|
+
|
|
3
|
+
$workspace = if ($env:COZE_WORKSPACE_PATH) { $env:COZE_WORKSPACE_PATH } else { (Get-Location).Path }
|
|
4
|
+
Set-Location $workspace
|
|
5
|
+
|
|
6
|
+
Write-Host "Installing dependencies..."
|
|
7
|
+
& pnpm install --prefer-frozen-lockfile --prefer-offline --loglevel debug --reporter=append-only
|
|
8
|
+
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
|
|
9
|
+
|
|
10
|
+
Write-Host "Building the Nuxt.js project..."
|
|
11
|
+
& pnpm nuxt build
|
|
12
|
+
exit $LASTEXITCODE
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
$ErrorActionPreference = "Stop"
|
|
2
|
+
|
|
3
|
+
function Get-WorkspacePath {
|
|
4
|
+
if ($env:COZE_WORKSPACE_PATH) {
|
|
5
|
+
return $env:COZE_WORKSPACE_PATH
|
|
6
|
+
}
|
|
7
|
+
return (Get-Location).Path
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function Stop-ProcessTree([int] $processId) {
|
|
11
|
+
if ($processId -gt 0 -and (Get-Process -Id $processId -ErrorAction SilentlyContinue)) {
|
|
12
|
+
& taskkill.exe /PID $processId /T /F *> $null
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function Stop-ListeningProcess([int] $port) {
|
|
17
|
+
$connections = Get-NetTCPConnection -LocalPort $port -State Listen -ErrorAction SilentlyContinue
|
|
18
|
+
$connections | Select-Object -ExpandProperty OwningProcess -Unique | ForEach-Object {
|
|
19
|
+
Stop-ProcessTree $_
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
$workspace = Get-WorkspacePath
|
|
24
|
+
$defaultPort = <%= port %>
|
|
25
|
+
$port = if ($env:DEPLOY_RUN_PORT) { [int] $env:DEPLOY_RUN_PORT } elseif ($env:PORT) { [int] $env:PORT } else { $defaultPort }
|
|
26
|
+
Set-Location $workspace
|
|
27
|
+
Stop-ListeningProcess $port
|
|
28
|
+
|
|
29
|
+
<% if (process.env.NODE_ENV === 'test') { %>
|
|
30
|
+
$env:PORT = "$port"
|
|
31
|
+
& pnpm nuxt dev
|
|
32
|
+
exit $LASTEXITCODE
|
|
33
|
+
<% } else { %>
|
|
34
|
+
$logDirectory = if ($env:COZE_LOG_DIR) { $env:COZE_LOG_DIR } else { Join-Path $workspace "logs" }
|
|
35
|
+
$logFile = Join-Path $logDirectory "server.log"
|
|
36
|
+
$errorLogFile = Join-Path $logDirectory "server-error.log"
|
|
37
|
+
$pidFile = Join-Path $logDirectory "server.pid"
|
|
38
|
+
New-Item -ItemType Directory -Force -Path $logDirectory | Out-Null
|
|
39
|
+
|
|
40
|
+
if (Test-Path $pidFile) {
|
|
41
|
+
Stop-ProcessTree ([int] (Get-Content $pidFile -Raw))
|
|
42
|
+
Remove-Item $pidFile -Force
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
$previousPort = $env:PORT
|
|
46
|
+
$env:PORT = "$port"
|
|
47
|
+
try {
|
|
48
|
+
$process = Start-Process -FilePath $env:ComSpec -ArgumentList @("/d", "/s", "/c", "pnpm nuxt dev") -WorkingDirectory $workspace -RedirectStandardOutput $logFile -RedirectStandardError $errorLogFile -PassThru
|
|
49
|
+
} finally {
|
|
50
|
+
if ($null -eq $previousPort) { Remove-Item Env:PORT -ErrorAction SilentlyContinue } else { $env:PORT = $previousPort }
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
$process.Id | Set-Content $pidFile
|
|
54
|
+
Start-Sleep -Seconds 1
|
|
55
|
+
if ($process.HasExited) {
|
|
56
|
+
Get-Content $errorLogFile -Tail 20 -ErrorAction SilentlyContinue
|
|
57
|
+
Remove-Item $pidFile -Force -ErrorAction SilentlyContinue
|
|
58
|
+
exit 1
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
Write-Host "Nuxt dev server started (PID: $($process.Id))."
|
|
62
|
+
Write-Host "Log file: $logFile"
|
|
63
|
+
<% } %>
|