@coze-arch/cli 0.0.36-alpha.b293fc → 0.0.36-alpha.fd6b86
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 +11 -0
- package/docs/deploy.md +171 -0
- package/lib/__templates__/expo/.cozeproj/scripts/dev_run.sh +73 -18
- package/lib/__templates__/expo/pnpm-lock.yaml +5 -5
- package/lib/__templates__/expo/server/package.json +1 -1
- package/lib/__templates__/nextjs/scripts/dev.sh +82 -1
- package/lib/__templates__/nextjs/template.config.js +3 -1
- package/lib/__templates__/nuxt-vue/scripts/dev.sh +82 -1
- package/lib/__templates__/phaser/_gitignore +1 -0
- package/lib/__templates__/phaser/package.json +1 -1
- package/lib/__templates__/phaser/scripts/dev.sh +74 -3
- package/lib/__templates__/phaser/scripts/spawn-detached.cjs +29 -0
- package/lib/__templates__/phaser/scripts/start.sh +74 -3
- package/lib/__templates__/phaser/vite.config.ts +1 -1
- package/lib/__templates__/taro/.cozeproj/scripts/dev_run.sh +63 -26
- package/lib/__templates__/taro/pnpm-lock.yaml +5 -5
- package/lib/__templates__/taro/server/package.json +1 -1
- package/lib/__templates__/vite/scripts/dev.sh +82 -1
- package/lib/__templates__/vite/template.config.js +3 -1
- package/lib/cli.js +3447 -201
- package/lib/deploy/package-project.js +226 -0
- package/lib/deploy/package-project.py +168 -0
- package/package.json +5 -4
|
@@ -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,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));
|
|
@@ -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
|
+
<% } %>
|
|
@@ -4,7 +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://
|
|
7
|
+
"https://lf-coze-web-cdn.coze.cn/obj/eden-cn/lm-lgvj/ljhwZthlaukjlkulzlp/coze-game/js/phaser-bridge.min.js";
|
|
8
8
|
|
|
9
9
|
function injectDevPhaserBridge(): Plugin {
|
|
10
10
|
return {
|
|
@@ -8,6 +8,9 @@ cd "${COZE_WORKSPACE_PATH}"
|
|
|
8
8
|
# PID 文件,用于追踪上一次启动的进程树
|
|
9
9
|
# ---------------------------------------------------------
|
|
10
10
|
PID_FILE="/tmp/coze-dev-run.pid"
|
|
11
|
+
LOG_DIR="/tmp/coze-logs"
|
|
12
|
+
LOG_FILE="${LOG_DIR}/dev.log"
|
|
13
|
+
DEV_PID=""
|
|
11
14
|
|
|
12
15
|
# ---------------------------------------------------------
|
|
13
16
|
# 工具函数
|
|
@@ -25,6 +28,49 @@ kill_process_tree() {
|
|
|
25
28
|
fi
|
|
26
29
|
}
|
|
27
30
|
|
|
31
|
+
# coze-daemon 会在 runtime shell 退出时清理原进程组。
|
|
32
|
+
# 通过 Node detached spawn 创建独立 session/进程组,并将 stdio 直接写入日志。
|
|
33
|
+
spawn_detached() {
|
|
34
|
+
local cwd="$1"
|
|
35
|
+
local log_file="$2"
|
|
36
|
+
shift 2
|
|
37
|
+
|
|
38
|
+
node - "$cwd" "$log_file" "$@" <<'NODE'
|
|
39
|
+
const fs = require('node:fs');
|
|
40
|
+
const { spawn } = require('node:child_process');
|
|
41
|
+
|
|
42
|
+
const [cwd, logFile, command, ...args] = process.argv.slice(2);
|
|
43
|
+
if (!cwd || !logFile || !command) {
|
|
44
|
+
throw new Error('spawn_detached 缺少 cwd、log_file 或 command');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const logFd = fs.openSync(logFile, 'a');
|
|
48
|
+
try {
|
|
49
|
+
const child = spawn(command, args, {
|
|
50
|
+
cwd,
|
|
51
|
+
detached: true,
|
|
52
|
+
env: process.env,
|
|
53
|
+
stdio: ['ignore', logFd, logFd],
|
|
54
|
+
});
|
|
55
|
+
child.unref();
|
|
56
|
+
process.stdout.write(String(child.pid));
|
|
57
|
+
} finally {
|
|
58
|
+
fs.closeSync(logFd);
|
|
59
|
+
}
|
|
60
|
+
NODE
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
stop_detached() {
|
|
64
|
+
local pid="${1:-}"
|
|
65
|
+
if [[ -z "${pid}" ]]; then
|
|
66
|
+
return
|
|
67
|
+
fi
|
|
68
|
+
|
|
69
|
+
kill -TERM -- "-${pid}" 2>/dev/null || kill -TERM "${pid}" 2>/dev/null || true
|
|
70
|
+
sleep 1
|
|
71
|
+
kill -KILL -- "-${pid}" 2>/dev/null || true
|
|
72
|
+
}
|
|
73
|
+
|
|
28
74
|
kill_port_if_listening() {
|
|
29
75
|
local port=$1
|
|
30
76
|
local pids
|
|
@@ -56,7 +102,7 @@ cleanup_previous_run() {
|
|
|
56
102
|
old_pid=$(cat "${PID_FILE}" 2>/dev/null || true)
|
|
57
103
|
if [[ -n "${old_pid}" ]] && kill -0 "${old_pid}" 2>/dev/null; then
|
|
58
104
|
echo "🧹 Killing previous dev process tree (root PID: ${old_pid})..."
|
|
59
|
-
|
|
105
|
+
stop_detached "${old_pid}"
|
|
60
106
|
fi
|
|
61
107
|
rm -f "${PID_FILE}"
|
|
62
108
|
fi
|
|
@@ -89,7 +135,8 @@ cleanup_previous_run() {
|
|
|
89
135
|
# 2. 安装依赖
|
|
90
136
|
# ---------------------------------------------------------
|
|
91
137
|
echo "📦 Installing dependencies..."
|
|
92
|
-
pnpm
|
|
138
|
+
PNPM_BIN="$(command -v pnpm)"
|
|
139
|
+
"${PNPM_BIN}" install
|
|
93
140
|
echo "✅ Dependencies installed successfully!"
|
|
94
141
|
|
|
95
142
|
# ---------------------------------------------------------
|
|
@@ -105,19 +152,7 @@ echo "Clearing port ${SERVER_PORT} (server) before start."
|
|
|
105
152
|
kill_port_if_listening "${SERVER_PORT}"
|
|
106
153
|
|
|
107
154
|
# ---------------------------------------------------------
|
|
108
|
-
# 4.
|
|
109
|
-
# ---------------------------------------------------------
|
|
110
|
-
cleanup_on_exit() {
|
|
111
|
-
echo "🛑 dev_run.sh exiting, cleaning up child processes..."
|
|
112
|
-
# 杀掉当前脚本的所有子进程
|
|
113
|
-
kill -- -$$ 2>/dev/null || true
|
|
114
|
-
rm -f "${PID_FILE}"
|
|
115
|
-
exit 0
|
|
116
|
-
}
|
|
117
|
-
trap cleanup_on_exit EXIT INT TERM HUP
|
|
118
|
-
|
|
119
|
-
# ---------------------------------------------------------
|
|
120
|
-
# 5. 启动服务
|
|
155
|
+
# 4. 启动服务
|
|
121
156
|
# ---------------------------------------------------------
|
|
122
157
|
start_service() {
|
|
123
158
|
cd "${COZE_WORKSPACE_PATH}"
|
|
@@ -134,17 +169,19 @@ start_service() {
|
|
|
134
169
|
echo "Starting Taro H5 Dev Server and NestJS Server..."
|
|
135
170
|
|
|
136
171
|
export PORT=${DEPLOY_RUN_PORT}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
172
|
+
mkdir -p "${LOG_DIR}"
|
|
173
|
+
: > "${LOG_FILE}"
|
|
174
|
+
|
|
175
|
+
DEV_PID="$(spawn_detached \
|
|
176
|
+
"${COZE_WORKSPACE_PATH}" \
|
|
177
|
+
"${LOG_FILE}" \
|
|
178
|
+
"${PNPM_BIN}" dev)"
|
|
179
|
+
if [[ -z "${DEV_PID}" ]]; then
|
|
180
|
+
echo "❌ 无法获取 dev 后台进程 PID"
|
|
181
|
+
return 1
|
|
182
|
+
fi
|
|
183
|
+
echo "${DEV_PID}" > "${PID_FILE}"
|
|
184
|
+
echo "📝 Dev process started with PID: ${DEV_PID} (saved to ${PID_FILE})"
|
|
148
185
|
}
|
|
149
186
|
|
|
150
187
|
echo "Starting HTTP services on port ${DEPLOY_RUN_PORT} (web) and ${SERVER_PORT} (server)..."
|
|
@@ -204,8 +204,8 @@ importers:
|
|
|
204
204
|
specifier: 2.95.3
|
|
205
205
|
version: 2.95.3
|
|
206
206
|
coze-coding-dev-sdk:
|
|
207
|
-
specifier: ^0.7.
|
|
208
|
-
version: 0.7.
|
|
207
|
+
specifier: ^0.7.25-beta.4
|
|
208
|
+
version: 0.7.25-beta.4(openai@6.16.0(ws@8.19.0)(zod@4.3.5))(ws@8.19.0)
|
|
209
209
|
dotenv:
|
|
210
210
|
specifier: ^17.2.3
|
|
211
211
|
version: 17.2.3
|
|
@@ -5416,8 +5416,8 @@ packages:
|
|
|
5416
5416
|
typescript:
|
|
5417
5417
|
optional: true
|
|
5418
5418
|
|
|
5419
|
-
coze-coding-dev-sdk@0.7.
|
|
5420
|
-
resolution: {integrity: sha512
|
|
5419
|
+
coze-coding-dev-sdk@0.7.25-beta.4:
|
|
5420
|
+
resolution: {integrity: sha512-+PCoJ8yhsAIlx3YT898bCkB2gx5EMBunJMP7/kI/Jq/8dj7SDU9EUBZ2Z8ZJocSaPBT9T6dVvFHBsDLZh4FN/Q==}
|
|
5421
5421
|
engines: {node: '>=18.0.0'}
|
|
5422
5422
|
hasBin: true
|
|
5423
5423
|
|
|
@@ -17159,7 +17159,7 @@ snapshots:
|
|
|
17159
17159
|
optionalDependencies:
|
|
17160
17160
|
typescript: 5.9.3
|
|
17161
17161
|
|
|
17162
|
-
coze-coding-dev-sdk@0.7.
|
|
17162
|
+
coze-coding-dev-sdk@0.7.25-beta.4(openai@6.16.0(ws@8.19.0)(zod@4.3.5))(ws@8.19.0):
|
|
17163
17163
|
dependencies:
|
|
17164
17164
|
'@langchain/core': 1.1.16(openai@6.16.0(ws@8.19.0)(zod@4.3.5))
|
|
17165
17165
|
'@langchain/openai': 1.2.3(@langchain/core@1.1.16(openai@6.16.0(ws@8.19.0)(zod@4.3.5)))(ws@8.19.0)
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"@nestjs/core": "^10.4.15",
|
|
18
18
|
"@nestjs/platform-express": "^10.4.15",
|
|
19
19
|
"@supabase/supabase-js": "2.95.3",
|
|
20
|
-
"coze-coding-dev-sdk": "^0.7.
|
|
20
|
+
"coze-coding-dev-sdk": "^0.7.25-beta.4",
|
|
21
21
|
"dotenv": "^17.2.3",
|
|
22
22
|
"drizzle-kit": "^0.31.8",
|
|
23
23
|
"drizzle-orm": "^0.45.1",
|
|
@@ -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 express + Vite dev server on port ${DEPLOY_RUN_PORT}..."
|
|
39
|
+
|
|
40
|
+
# 测试环境保持服务为前台进程,便于 e2e 收集输出并停止进程。
|
|
41
|
+
exec env PORT="${DEPLOY_RUN_PORT}" pnpm tsx watch server/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
|
+
|
|
35
97
|
echo "Clearing port ${DEPLOY_RUN_PORT} before start."
|
|
36
98
|
kill_port_if_listening
|
|
37
99
|
echo "Starting express + Vite 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)" tsx watch server/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
|
+
<% } %>
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { spawn } from 'child_process';
|
|
3
3
|
import { resolve, join, basename } from 'path';
|
|
4
4
|
import { appendFileSync, openSync, closeSync, mkdirSync } from 'fs';
|
|
5
|
+
import { homedir } from 'os';
|
|
5
6
|
|
|
6
7
|
|
|
7
8
|
|
|
@@ -81,7 +82,8 @@ const config = {
|
|
|
81
82
|
const projectRoot = resolve(outputPath);
|
|
82
83
|
|
|
83
84
|
// Determine log directory
|
|
84
|
-
const
|
|
85
|
+
const cozeHome = process.env.COZE_HOME || join(homedir(), '.coze');
|
|
86
|
+
const logDir = process.env.COZE_LOG_DIR || join(cozeHome, 'logs');
|
|
85
87
|
mkdirSync(logDir, { recursive: true });
|
|
86
88
|
|
|
87
89
|
// Use project name in log file to avoid conflicts
|