@coze-arch/cli 0.0.36-alpha.1dcb49 → 0.0.36-alpha.3ab612
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 +68 -104
- package/docs/deploy.md +179 -0
- package/lib/__templates__/expo/.cozeproj/scripts/dev_run.sh +80 -19
- package/lib/__templates__/expo/.cozeproj/scripts/prod_run.sh +1 -1
- package/lib/__templates__/expo/.cozeproj/scripts/server_dev_run.sh +1 -1
- package/lib/__templates__/expo/client/metro.config.js +3 -1
- package/lib/__templates__/expo/pnpm-lock.yaml +5 -5
- package/lib/__templates__/expo/server/package.json +2 -2
- package/lib/__templates__/expo/server/src/index.ts +1 -1
- package/lib/__templates__/expo/template.config.js +11 -2
- 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/package.json +1 -1
- package/lib/__templates__/nextjs/pnpm-lock.yaml +5 -5
- 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 +205 -7
- 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__/nextjs/template.config.js +4 -2
- package/lib/__templates__/nuxt-vue/.coze +5 -0
- package/lib/__templates__/nuxt-vue/package.json +1 -1
- package/lib/__templates__/nuxt-vue/pnpm-lock.yaml +5 -5
- 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/_gitignore +1 -0
- package/lib/__templates__/phaser/package.json +1 -1
- package/lib/__templates__/phaser/scripts/build.ps1 +12 -0
- package/lib/__templates__/phaser/scripts/dev.ps1 +49 -0
- package/lib/__templates__/phaser/scripts/dev.sh +74 -3
- package/lib/__templates__/phaser/scripts/prepare.ps1 +8 -0
- package/lib/__templates__/phaser/scripts/spawn-detached.cjs +29 -0
- package/lib/__templates__/phaser/scripts/start.ps1 +49 -0
- package/lib/__templates__/phaser/scripts/start.sh +74 -3
- 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/vite.config.ts +1 -25
- 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__/pi-agent/package.json +1 -1
- package/lib/__templates__/pi-agent/pnpm-lock.yaml +5 -5
- package/lib/__templates__/taro/.cozeproj/scripts/deploy_run.sh +1 -1
- package/lib/__templates__/taro/.cozeproj/scripts/dev_run.sh +150 -68
- package/lib/__templates__/taro/AGENTS.md +11 -7
- package/lib/__templates__/taro/README.md +4 -4
- package/lib/__templates__/taro/config/index.ts +10 -2
- package/lib/__templates__/taro/pnpm-lock.yaml +5 -5
- package/lib/__templates__/taro/server/package.json +1 -1
- package/lib/__templates__/taro/server/src/main.ts +8 -2
- package/lib/__templates__/templates.json +26 -1
- package/lib/__templates__/vite/.coze +5 -0
- package/lib/__templates__/vite/package.json +1 -1
- package/lib/__templates__/vite/pnpm-lock.yaml +5 -5
- 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/__templates__/vite/template.config.js +4 -2
- package/lib/cli.js +3631 -214
- package/lib/deploy/package-project.js +244 -0
- package/lib/deploy/package-project.py +183 -0
- package/package.json +5 -4
|
@@ -32,8 +32,89 @@ kill_port_if_listening() {
|
|
|
32
32
|
fi
|
|
33
33
|
}
|
|
34
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 Nuxt dev server on port ${DEPLOY_RUN_PORT}..."
|
|
39
|
+
|
|
40
|
+
# 测试环境保持服务为前台进程,便于 e2e 收集输出并停止进程。
|
|
41
|
+
exec env PORT="${DEPLOY_RUN_PORT}" pnpm nuxt dev
|
|
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 -> nuxt -> node),只清端口会漏掉上层 pnpm/nuxt,
|
|
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
|
+
|
|
35
97
|
echo "Clearing port ${DEPLOY_RUN_PORT} before start."
|
|
36
98
|
kill_port_if_listening
|
|
37
99
|
echo "Starting Nuxt dev server on port ${DEPLOY_RUN_PORT}..."
|
|
38
100
|
|
|
39
|
-
|
|
101
|
+
mkdir -p "${LOG_DIR}"
|
|
102
|
+
: > "${LOG_FILE}"
|
|
103
|
+
|
|
104
|
+
export PORT="${DEPLOY_RUN_PORT}"
|
|
105
|
+
server_pid="$(spawn_detached "${COZE_WORKSPACE_PATH}" "${LOG_FILE}" \
|
|
106
|
+
"$(command -v pnpm)" nuxt dev)"
|
|
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,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
|
|
8
|
+
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
|
|
9
|
+
|
|
10
|
+
Write-Host "Preparing Nuxt..."
|
|
11
|
+
& pnpm exec nuxt prepare
|
|
12
|
+
exit $LASTEXITCODE
|
|
@@ -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 Nuxt.js service on port $port for production..."
|
|
9
|
+
$env:PORT = "$port"
|
|
10
|
+
& node .output/server/index.mjs
|
|
11
|
+
exit $LASTEXITCODE
|
|
@@ -5,9 +5,14 @@ game_type = "phaser"
|
|
|
5
5
|
|
|
6
6
|
[dev]
|
|
7
7
|
build = ["bash", "./scripts/prepare.sh"]
|
|
8
|
+
build_win = ["powershell.exe", "-NoProfile", "-ExecutionPolicy", "Bypass", "-File", "./scripts/prepare.ps1"]
|
|
8
9
|
run = ["bash", "./scripts/dev.sh"]
|
|
10
|
+
run_win = ["powershell.exe", "-NoProfile", "-ExecutionPolicy", "Bypass", "-File", "./scripts/dev.ps1"]
|
|
9
11
|
validate = ["bash", "./scripts/validate.sh"]
|
|
12
|
+
validate_win = ["powershell.exe", "-NoProfile", "-ExecutionPolicy", "Bypass", "-File", "./scripts/validate.ps1"]
|
|
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"]
|
|
@@ -35,3 +35,11 @@ coze-dev start # 预览生产构建
|
|
|
35
35
|
- 开发和生产都使用稳定的 `assets/...` 路径,生产构建原样复制素材目录。
|
|
36
36
|
|
|
37
37
|
`IMAGES`、`IMAGE_SEQUENCES`、`VIDEOS` 和 `AUDIOS` 是四个素材分类表。
|
|
38
|
+
|
|
39
|
+
## 可视化编辑标识
|
|
40
|
+
|
|
41
|
+
用 `markEditable` 标记可在编辑器中调整的对象;第三个参数可选,仅用于编辑器展示名称:
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
markEditable('ui.start-button', button, { label: '开始按钮' });
|
|
45
|
+
```
|
|
@@ -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 --reporter=append-only
|
|
8
|
+
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
|
|
9
|
+
|
|
10
|
+
$env:COZE_PHASER_GAME_ENV = "PROD"
|
|
11
|
+
& pnpm build
|
|
12
|
+
exit $LASTEXITCODE
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
$ErrorActionPreference = "Stop"
|
|
2
|
+
|
|
3
|
+
function Stop-ProcessTree([int] $processId) {
|
|
4
|
+
if ($processId -gt 0 -and (Get-Process -Id $processId -ErrorAction SilentlyContinue)) {
|
|
5
|
+
& taskkill.exe /PID $processId /T /F *> $null
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function Stop-ListeningProcess([int] $port) {
|
|
10
|
+
$connections = Get-NetTCPConnection -LocalPort $port -State Listen -ErrorAction SilentlyContinue
|
|
11
|
+
$connections | Select-Object -ExpandProperty OwningProcess -Unique | ForEach-Object {
|
|
12
|
+
Stop-ProcessTree $_
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
$workspace = if ($env:COZE_WORKSPACE_PATH) { $env:COZE_WORKSPACE_PATH } else { (Get-Location).Path }
|
|
17
|
+
$defaultPort = <%= port %>
|
|
18
|
+
$port = if ($env:DEPLOY_RUN_PORT) { [int] $env:DEPLOY_RUN_PORT } elseif ($env:PORT) { [int] $env:PORT } else { $defaultPort }
|
|
19
|
+
Set-Location $workspace
|
|
20
|
+
Stop-ListeningProcess $port
|
|
21
|
+
$env:COZE_PHASER_GAME_ENV = "DEV"
|
|
22
|
+
|
|
23
|
+
<% if (process.env.NODE_ENV === 'test') { %>
|
|
24
|
+
& pnpm vite --port $port --host 127.0.0.1 --strictPort
|
|
25
|
+
exit $LASTEXITCODE
|
|
26
|
+
<% } else { %>
|
|
27
|
+
$logDirectory = if ($env:COZE_LOG_DIR) { $env:COZE_LOG_DIR } else { Join-Path $workspace "logs" }
|
|
28
|
+
$logFile = Join-Path $logDirectory "phaser-dev.log"
|
|
29
|
+
$errorLogFile = Join-Path $logDirectory "phaser-dev-error.log"
|
|
30
|
+
$pidFile = Join-Path $logDirectory "phaser-dev.pid"
|
|
31
|
+
New-Item -ItemType Directory -Force -Path $logDirectory | Out-Null
|
|
32
|
+
|
|
33
|
+
if (Test-Path $pidFile) {
|
|
34
|
+
Stop-ProcessTree ([int] (Get-Content $pidFile -Raw))
|
|
35
|
+
Remove-Item $pidFile -Force
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
$process = Start-Process -FilePath $env:ComSpec -ArgumentList @("/d", "/s", "/c", "pnpm vite --port $port --host 127.0.0.1 --strictPort") -WorkingDirectory $workspace -RedirectStandardOutput $logFile -RedirectStandardError $errorLogFile -PassThru
|
|
39
|
+
$process.Id | Set-Content $pidFile
|
|
40
|
+
Start-Sleep -Seconds 1
|
|
41
|
+
if ($process.HasExited) {
|
|
42
|
+
Get-Content $errorLogFile -Tail 20 -ErrorAction SilentlyContinue
|
|
43
|
+
Remove-Item $pidFile -Force -ErrorAction SilentlyContinue
|
|
44
|
+
exit 1
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
Write-Host "Phaser dev server started (PID: $($process.Id))."
|
|
48
|
+
Write-Host "Log file: $logFile"
|
|
49
|
+
<% } %>
|
|
@@ -2,10 +2,81 @@
|
|
|
2
2
|
set -Eeuo pipefail
|
|
3
3
|
|
|
4
4
|
COZE_WORKSPACE_PATH="${COZE_WORKSPACE_PATH:-$(pwd)}"
|
|
5
|
-
PORT="${
|
|
5
|
+
PORT="${PORT:-<%= port %>}"
|
|
6
|
+
DEPLOY_RUN_PORT="${DEPLOY_RUN_PORT:-${PORT}}"
|
|
6
7
|
cd "${COZE_WORKSPACE_PATH}"
|
|
7
8
|
|
|
8
|
-
|
|
9
|
-
|
|
9
|
+
get_listening_pids() {
|
|
10
|
+
local port="$1"
|
|
11
|
+
|
|
12
|
+
if command -v lsof >/dev/null 2>&1; then
|
|
13
|
+
lsof -tiTCP:"${port}" -sTCP:LISTEN 2>/dev/null || true
|
|
14
|
+
elif command -v ss >/dev/null 2>&1; then
|
|
15
|
+
ss -H -lntp 2>/dev/null \
|
|
16
|
+
| awk -v port="${port}" '$4 ~ ":"port"$"' \
|
|
17
|
+
| grep -o 'pid=[0-9]*' \
|
|
18
|
+
| cut -d= -f2 \
|
|
19
|
+
| sort -u || true
|
|
20
|
+
else
|
|
21
|
+
echo "Warning: neither lsof nor ss found, cannot check port ${port}." >&2
|
|
22
|
+
fi
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
kill_port_if_listening() {
|
|
26
|
+
local port="$1"
|
|
27
|
+
local pids
|
|
28
|
+
|
|
29
|
+
pids="$(get_listening_pids "${port}")"
|
|
30
|
+
if [[ -z "${pids}" ]]; then
|
|
31
|
+
echo "Port ${port} is free."
|
|
32
|
+
return
|
|
33
|
+
fi
|
|
34
|
+
|
|
35
|
+
echo "Port ${port} is in use by PIDs: ${pids//$'\n'/ } (SIGKILL)"
|
|
36
|
+
echo "${pids}" | xargs kill -9 2>/dev/null || true
|
|
37
|
+
sleep 1
|
|
38
|
+
|
|
39
|
+
pids="$(get_listening_pids "${port}")"
|
|
40
|
+
if [[ -n "${pids}" ]]; then
|
|
41
|
+
echo "Failed to clear port ${port}; remaining PIDs: ${pids//$'\n'/ }." >&2
|
|
42
|
+
return 1
|
|
43
|
+
fi
|
|
44
|
+
|
|
45
|
+
echo "Port ${port} cleared."
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
echo "Clearing port ${DEPLOY_RUN_PORT} before start."
|
|
49
|
+
kill_port_if_listening "${DEPLOY_RUN_PORT}"
|
|
50
|
+
|
|
51
|
+
<% if (process.env.NODE_ENV === 'test') { %>
|
|
52
|
+
# Keep the process attached in tests so the test runner can collect logs and stop it.
|
|
53
|
+
exec env COZE_PHASER_GAME_ENV=DEV pnpm vite \
|
|
54
|
+
--port "${DEPLOY_RUN_PORT}" \
|
|
10
55
|
--host 127.0.0.1 \
|
|
11
56
|
--strictPort
|
|
57
|
+
<% } else { %>
|
|
58
|
+
LOG_DIR="${COZE_WORKSPACE_PATH}/logs"
|
|
59
|
+
LOG_FILE="${LOG_DIR}/phaser-dev.log"
|
|
60
|
+
PID_FILE="${LOG_DIR}/phaser-dev.pid"
|
|
61
|
+
mkdir -p "${LOG_DIR}"
|
|
62
|
+
|
|
63
|
+
echo "Starting Phaser dev server on port ${DEPLOY_RUN_PORT}..."
|
|
64
|
+
server_pid="$(COZE_PHASER_GAME_ENV=DEV node scripts/spawn-detached.cjs \
|
|
65
|
+
"${LOG_FILE}" pnpm vite \
|
|
66
|
+
--port "${DEPLOY_RUN_PORT}" \
|
|
67
|
+
--host 127.0.0.1 \
|
|
68
|
+
--strictPort)"
|
|
69
|
+
echo "${server_pid}" > "${PID_FILE}"
|
|
70
|
+
|
|
71
|
+
sleep 1
|
|
72
|
+
if ! kill -0 "${server_pid}" 2>/dev/null; then
|
|
73
|
+
echo "Phaser dev server failed to start. See ${LOG_FILE}." >&2
|
|
74
|
+
tail -n 20 "${LOG_FILE}" >&2 || true
|
|
75
|
+
rm -f "${PID_FILE}"
|
|
76
|
+
exit 1
|
|
77
|
+
fi
|
|
78
|
+
|
|
79
|
+
echo "Phaser dev server started (PID: ${server_pid})."
|
|
80
|
+
echo "Log file: ${LOG_FILE}"
|
|
81
|
+
echo "PID file: ${PID_FILE}"
|
|
82
|
+
<% } %>
|
|
@@ -0,0 +1,8 @@
|
|
|
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 --reporter=append-only
|
|
8
|
+
exit $LASTEXITCODE
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
const fs = require('node:fs');
|
|
2
|
+
const { spawn } = require('node:child_process');
|
|
3
|
+
|
|
4
|
+
const [logFile, command, ...args] = process.argv.slice(2);
|
|
5
|
+
|
|
6
|
+
if (!logFile || !command) {
|
|
7
|
+
process.stderr.write(
|
|
8
|
+
'Usage: node scripts/spawn-detached.cjs <log-file> <command> [...args]\n',
|
|
9
|
+
);
|
|
10
|
+
process.exit(1);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const logFd = fs.openSync(logFile, 'a');
|
|
14
|
+
const child = spawn(command, args, {
|
|
15
|
+
cwd: process.cwd(),
|
|
16
|
+
detached: process.platform !== 'win32',
|
|
17
|
+
env: process.env,
|
|
18
|
+
stdio: ['ignore', logFd, logFd],
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
fs.closeSync(logFd);
|
|
22
|
+
child.unref();
|
|
23
|
+
|
|
24
|
+
if (!child.pid) {
|
|
25
|
+
process.stderr.write('Failed to start detached process.\n');
|
|
26
|
+
process.exit(1);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
process.stdout.write(String(child.pid));
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
$ErrorActionPreference = "Stop"
|
|
2
|
+
|
|
3
|
+
function Stop-ProcessTree([int] $processId) {
|
|
4
|
+
if ($processId -gt 0 -and (Get-Process -Id $processId -ErrorAction SilentlyContinue)) {
|
|
5
|
+
& taskkill.exe /PID $processId /T /F *> $null
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function Stop-ListeningProcess([int] $port) {
|
|
10
|
+
$connections = Get-NetTCPConnection -LocalPort $port -State Listen -ErrorAction SilentlyContinue
|
|
11
|
+
$connections | Select-Object -ExpandProperty OwningProcess -Unique | ForEach-Object {
|
|
12
|
+
Stop-ProcessTree $_
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
$workspace = if ($env:COZE_WORKSPACE_PATH) { $env:COZE_WORKSPACE_PATH } else { (Get-Location).Path }
|
|
17
|
+
$defaultPort = <%= port %>
|
|
18
|
+
$port = if ($env:DEPLOY_RUN_PORT) { [int] $env:DEPLOY_RUN_PORT } elseif ($env:PORT) { [int] $env:PORT } else { $defaultPort }
|
|
19
|
+
Set-Location $workspace
|
|
20
|
+
Stop-ListeningProcess $port
|
|
21
|
+
$env:COZE_PHASER_GAME_ENV = "PROD"
|
|
22
|
+
|
|
23
|
+
<% if (process.env.NODE_ENV === 'test') { %>
|
|
24
|
+
& pnpm vite preview --port $port --host 127.0.0.1 --strictPort
|
|
25
|
+
exit $LASTEXITCODE
|
|
26
|
+
<% } else { %>
|
|
27
|
+
$logDirectory = if ($env:COZE_LOG_DIR) { $env:COZE_LOG_DIR } else { Join-Path $workspace "logs" }
|
|
28
|
+
$logFile = Join-Path $logDirectory "phaser-start.log"
|
|
29
|
+
$errorLogFile = Join-Path $logDirectory "phaser-start-error.log"
|
|
30
|
+
$pidFile = Join-Path $logDirectory "phaser-start.pid"
|
|
31
|
+
New-Item -ItemType Directory -Force -Path $logDirectory | Out-Null
|
|
32
|
+
|
|
33
|
+
if (Test-Path $pidFile) {
|
|
34
|
+
Stop-ProcessTree ([int] (Get-Content $pidFile -Raw))
|
|
35
|
+
Remove-Item $pidFile -Force
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
$process = Start-Process -FilePath $env:ComSpec -ArgumentList @("/d", "/s", "/c", "pnpm vite preview --port $port --host 127.0.0.1 --strictPort") -WorkingDirectory $workspace -RedirectStandardOutput $logFile -RedirectStandardError $errorLogFile -PassThru
|
|
39
|
+
$process.Id | Set-Content $pidFile
|
|
40
|
+
Start-Sleep -Seconds 1
|
|
41
|
+
if ($process.HasExited) {
|
|
42
|
+
Get-Content $errorLogFile -Tail 20 -ErrorAction SilentlyContinue
|
|
43
|
+
Remove-Item $pidFile -Force -ErrorAction SilentlyContinue
|
|
44
|
+
exit 1
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
Write-Host "Phaser production server started (PID: $($process.Id))."
|
|
48
|
+
Write-Host "Log file: $logFile"
|
|
49
|
+
<% } %>
|
|
@@ -2,10 +2,81 @@
|
|
|
2
2
|
set -Eeuo pipefail
|
|
3
3
|
|
|
4
4
|
COZE_WORKSPACE_PATH="${COZE_WORKSPACE_PATH:-$(pwd)}"
|
|
5
|
-
PORT="${
|
|
5
|
+
PORT="${PORT:-<%= port %>}"
|
|
6
|
+
DEPLOY_RUN_PORT="${DEPLOY_RUN_PORT:-${PORT}}"
|
|
6
7
|
cd "${COZE_WORKSPACE_PATH}"
|
|
7
8
|
|
|
8
|
-
|
|
9
|
-
|
|
9
|
+
get_listening_pids() {
|
|
10
|
+
local port="$1"
|
|
11
|
+
|
|
12
|
+
if command -v lsof >/dev/null 2>&1; then
|
|
13
|
+
lsof -tiTCP:"${port}" -sTCP:LISTEN 2>/dev/null || true
|
|
14
|
+
elif command -v ss >/dev/null 2>&1; then
|
|
15
|
+
ss -H -lntp 2>/dev/null \
|
|
16
|
+
| awk -v port="${port}" '$4 ~ ":"port"$"' \
|
|
17
|
+
| grep -o 'pid=[0-9]*' \
|
|
18
|
+
| cut -d= -f2 \
|
|
19
|
+
| sort -u || true
|
|
20
|
+
else
|
|
21
|
+
echo "Warning: neither lsof nor ss found, cannot check port ${port}." >&2
|
|
22
|
+
fi
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
kill_port_if_listening() {
|
|
26
|
+
local port="$1"
|
|
27
|
+
local pids
|
|
28
|
+
|
|
29
|
+
pids="$(get_listening_pids "${port}")"
|
|
30
|
+
if [[ -z "${pids}" ]]; then
|
|
31
|
+
echo "Port ${port} is free."
|
|
32
|
+
return
|
|
33
|
+
fi
|
|
34
|
+
|
|
35
|
+
echo "Port ${port} is in use by PIDs: ${pids//$'\n'/ } (SIGKILL)"
|
|
36
|
+
echo "${pids}" | xargs kill -9 2>/dev/null || true
|
|
37
|
+
sleep 1
|
|
38
|
+
|
|
39
|
+
pids="$(get_listening_pids "${port}")"
|
|
40
|
+
if [[ -n "${pids}" ]]; then
|
|
41
|
+
echo "Failed to clear port ${port}; remaining PIDs: ${pids//$'\n'/ }." >&2
|
|
42
|
+
return 1
|
|
43
|
+
fi
|
|
44
|
+
|
|
45
|
+
echo "Port ${port} cleared."
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
echo "Clearing port ${DEPLOY_RUN_PORT} before start."
|
|
49
|
+
kill_port_if_listening "${DEPLOY_RUN_PORT}"
|
|
50
|
+
|
|
51
|
+
<% if (process.env.NODE_ENV === 'test') { %>
|
|
52
|
+
# Keep the process attached in tests so the test runner can collect logs and stop it.
|
|
53
|
+
exec env COZE_PHASER_GAME_ENV=PROD pnpm vite preview \
|
|
54
|
+
--port "${DEPLOY_RUN_PORT}" \
|
|
10
55
|
--host 127.0.0.1 \
|
|
11
56
|
--strictPort
|
|
57
|
+
<% } else { %>
|
|
58
|
+
LOG_DIR="${COZE_WORKSPACE_PATH}/logs"
|
|
59
|
+
LOG_FILE="${LOG_DIR}/phaser-start.log"
|
|
60
|
+
PID_FILE="${LOG_DIR}/phaser-start.pid"
|
|
61
|
+
mkdir -p "${LOG_DIR}"
|
|
62
|
+
|
|
63
|
+
echo "Starting Phaser production server on port ${DEPLOY_RUN_PORT}..."
|
|
64
|
+
server_pid="$(COZE_PHASER_GAME_ENV=PROD node scripts/spawn-detached.cjs \
|
|
65
|
+
"${LOG_FILE}" pnpm vite preview \
|
|
66
|
+
--port "${DEPLOY_RUN_PORT}" \
|
|
67
|
+
--host 127.0.0.1 \
|
|
68
|
+
--strictPort)"
|
|
69
|
+
echo "${server_pid}" > "${PID_FILE}"
|
|
70
|
+
|
|
71
|
+
sleep 1
|
|
72
|
+
if ! kill -0 "${server_pid}" 2>/dev/null; then
|
|
73
|
+
echo "Phaser production server failed to start. See ${LOG_FILE}." >&2
|
|
74
|
+
tail -n 20 "${LOG_FILE}" >&2 || true
|
|
75
|
+
rm -f "${PID_FILE}"
|
|
76
|
+
exit 1
|
|
77
|
+
fi
|
|
78
|
+
|
|
79
|
+
echo "Phaser production server started (PID: ${server_pid})."
|
|
80
|
+
echo "Log file: ${LOG_FILE}"
|
|
81
|
+
echo "PID file: ${PID_FILE}"
|
|
82
|
+
<% } %>
|
|
@@ -19,6 +19,9 @@ declare global {
|
|
|
19
19
|
markEditable?: <T extends Phaser.GameObjects.GameObject>(
|
|
20
20
|
stableId: string,
|
|
21
21
|
gameObject: T,
|
|
22
|
+
options?: {
|
|
23
|
+
label?: string;
|
|
24
|
+
},
|
|
22
25
|
) => T;
|
|
23
26
|
markImageAssetMap?: (images: Record<string, string>) => void;
|
|
24
27
|
markImageSequenceAssetMap?: (
|
|
@@ -95,6 +95,7 @@ export class BootScene extends Phaser.Scene {
|
|
|
95
95
|
.sprite(centerX, centerY - 58, DEV_LOADING_RUNTIME_KEYS.texture)
|
|
96
96
|
.setScale(0.56)
|
|
97
97
|
.play(DEV_LOADING_RUNTIME_KEYS.animation),
|
|
98
|
+
{ label: '加载吉祥物' },
|
|
98
99
|
);
|
|
99
100
|
|
|
100
101
|
this.loadingText = markEditable(
|
|
@@ -107,11 +108,13 @@ export class BootScene extends Phaser.Scene {
|
|
|
107
108
|
LOADING_TEXT_STYLE,
|
|
108
109
|
)
|
|
109
110
|
.setOrigin(0.5),
|
|
111
|
+
{ label: '加载状态文案' },
|
|
110
112
|
);
|
|
111
113
|
|
|
112
114
|
this.progressBar = markEditable(
|
|
113
115
|
'boot.loading-progress-bar',
|
|
114
116
|
this.add.graphics(),
|
|
117
|
+
{ label: '加载进度条' },
|
|
115
118
|
);
|
|
116
119
|
this.renderProgressBar(0);
|
|
117
120
|
|
|
@@ -120,6 +123,7 @@ export class BootScene extends Phaser.Scene {
|
|
|
120
123
|
this.add
|
|
121
124
|
.text(centerX, centerY + 190, '0%', LOADING_TEXT_STYLE)
|
|
122
125
|
.setOrigin(0.5),
|
|
126
|
+
{ label: '加载进度文本' },
|
|
123
127
|
);
|
|
124
128
|
}
|
|
125
129
|
|
|
@@ -21,6 +21,7 @@ export class DevLoadingScene extends Phaser.Scene {
|
|
|
21
21
|
.sprite(centerX, centerY - 82, DEV_LOADING_RUNTIME_KEYS.texture)
|
|
22
22
|
.setScale(0.64)
|
|
23
23
|
.play(DEV_LOADING_RUNTIME_KEYS.animation),
|
|
24
|
+
{ label: '开发中吉祥物' },
|
|
24
25
|
);
|
|
25
26
|
|
|
26
27
|
markEditable(
|
|
@@ -33,6 +34,7 @@ export class DevLoadingScene extends Phaser.Scene {
|
|
|
33
34
|
fontStyle: 'bold',
|
|
34
35
|
})
|
|
35
36
|
.setOrigin(0.5),
|
|
37
|
+
{ label: '开发中标题' },
|
|
36
38
|
);
|
|
37
39
|
|
|
38
40
|
markEditable(
|
|
@@ -44,6 +46,7 @@ export class DevLoadingScene extends Phaser.Scene {
|
|
|
44
46
|
fontSize: '18px',
|
|
45
47
|
})
|
|
46
48
|
.setOrigin(0.5),
|
|
49
|
+
{ label: '开发中说明文案' },
|
|
47
50
|
);
|
|
48
51
|
|
|
49
52
|
const loadingDots = Array.from({ length: 3 }, (_value, index) =>
|
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import type Phaser from 'phaser';
|
|
2
2
|
|
|
3
|
+
export interface MarkEditableOptions {
|
|
4
|
+
label?: string;
|
|
5
|
+
}
|
|
6
|
+
|
|
3
7
|
export const markEditable = <T extends Phaser.GameObjects.GameObject>(
|
|
4
8
|
locator: string,
|
|
5
9
|
gameObject: T,
|
|
6
|
-
|
|
10
|
+
options?: MarkEditableOptions,
|
|
11
|
+
): T =>
|
|
12
|
+
window.PhaserBridge?.markEditable?.(locator, gameObject, options) ??
|
|
13
|
+
gameObject;
|
|
@@ -4,8 +4,7 @@ import { defineConfig, type Plugin } from "vite";
|
|
|
4
4
|
import serveStatic from "serve-static";
|
|
5
5
|
|
|
6
6
|
const DEV_PHASER_BRIDGE_URL =
|
|
7
|
-
"https://
|
|
8
|
-
const DEV_IMAGE_DELAY_MS = 200;
|
|
7
|
+
"https://lf-coze-web-cdn.coze.cn/obj/eden-cn/lm-lgvj/ljhwZthlaukjlkulzlp/coze-game/js/phaser-bridge.min.js";
|
|
9
8
|
|
|
10
9
|
function injectDevPhaserBridge(): Plugin {
|
|
11
10
|
return {
|
|
@@ -70,28 +69,6 @@ function copyGameAssets(directory: string): Plugin {
|
|
|
70
69
|
};
|
|
71
70
|
}
|
|
72
71
|
|
|
73
|
-
function delayDevImages(): Plugin {
|
|
74
|
-
return {
|
|
75
|
-
name: "phaser-dev-image-delay",
|
|
76
|
-
configureServer(server) {
|
|
77
|
-
server.middlewares.use((request, _response, next) => {
|
|
78
|
-
const pathname = request.url?.split("?", 1)[0] ?? "";
|
|
79
|
-
const isImageRequest =
|
|
80
|
-
(request.method === "GET" || request.method === "HEAD") &&
|
|
81
|
-
pathname.includes("/assets/image/") &&
|
|
82
|
-
/\.(?:avif|gif|jpe?g|png|webp)$/i.test(pathname);
|
|
83
|
-
|
|
84
|
-
if (!isImageRequest) {
|
|
85
|
-
next();
|
|
86
|
-
return;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
setTimeout(next, DEV_IMAGE_DELAY_MS);
|
|
90
|
-
});
|
|
91
|
-
},
|
|
92
|
-
};
|
|
93
|
-
}
|
|
94
|
-
|
|
95
72
|
export default defineConfig(() => {
|
|
96
73
|
const isDev = process.env.COZE_PHASER_GAME_ENV === "DEV";
|
|
97
74
|
const assetsDirectory = path.join(import.meta.dirname, "assets");
|
|
@@ -111,7 +88,6 @@ export default defineConfig(() => {
|
|
|
111
88
|
...(isDev
|
|
112
89
|
? [
|
|
113
90
|
injectDevPhaserBridge(),
|
|
114
|
-
delayDevImages(),
|
|
115
91
|
mountDevAssets(assetsDirectory),
|
|
116
92
|
]
|
|
117
93
|
: []),
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
entrypoint = "index.html"
|
|
3
|
+
requires = ["python-3.12"]
|
|
4
|
+
project_type = "game"
|
|
5
|
+
game_type = "phaser"
|
|
6
|
+
|
|
7
|
+
[dev]
|
|
8
|
+
build = []
|
|
9
|
+
run = ["sh", "-c", "python -m http.server ${DEPLOY_RUN_PORT} --bind 0.0.0.0"]
|
|
10
|
+
run_win = ["powershell.exe", "-NoProfile", "-ExecutionPolicy", "Bypass", "-File", "./scripts/serve.ps1"]
|
|
11
|
+
|
|
12
|
+
[deploy]
|
|
13
|
+
build = []
|
|
14
|
+
run = ["sh", "-c", "python -m http.server ${DEPLOY_RUN_PORT} --bind 0.0.0.0"]
|
|
15
|
+
run_win = ["powershell.exe", "-NoProfile", "-ExecutionPolicy", "Bypass", "-File", "./scripts/serve.ps1"]
|