@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.
Files changed (114) hide show
  1. package/README.md +68 -104
  2. package/docs/deploy.md +179 -0
  3. package/lib/__templates__/expo/.cozeproj/scripts/dev_run.sh +80 -19
  4. package/lib/__templates__/expo/.cozeproj/scripts/prod_run.sh +1 -1
  5. package/lib/__templates__/expo/.cozeproj/scripts/server_dev_run.sh +1 -1
  6. package/lib/__templates__/expo/client/metro.config.js +3 -1
  7. package/lib/__templates__/expo/pnpm-lock.yaml +5 -5
  8. package/lib/__templates__/expo/server/package.json +2 -2
  9. package/lib/__templates__/expo/server/src/index.ts +1 -1
  10. package/lib/__templates__/expo/template.config.js +11 -2
  11. package/lib/__templates__/native-static/.coze +2 -0
  12. package/lib/__templates__/native-static/scripts/serve.ps1 +7 -0
  13. package/lib/__templates__/nextjs/.coze +5 -0
  14. package/lib/__templates__/nextjs/package.json +1 -1
  15. package/lib/__templates__/nextjs/pnpm-lock.yaml +5 -5
  16. package/lib/__templates__/nextjs/scripts/build.ps1 +16 -0
  17. package/lib/__templates__/nextjs/scripts/dev.ps1 +63 -0
  18. package/lib/__templates__/nextjs/scripts/dev.sh +205 -7
  19. package/lib/__templates__/nextjs/scripts/prepare.ps1 +18 -0
  20. package/lib/__templates__/nextjs/scripts/start.ps1 +11 -0
  21. package/lib/__templates__/nextjs/scripts/validate.ps1 +8 -0
  22. package/lib/__templates__/nextjs/template.config.js +4 -2
  23. package/lib/__templates__/nuxt-vue/.coze +5 -0
  24. package/lib/__templates__/nuxt-vue/package.json +1 -1
  25. package/lib/__templates__/nuxt-vue/pnpm-lock.yaml +5 -5
  26. package/lib/__templates__/nuxt-vue/scripts/build.ps1 +12 -0
  27. package/lib/__templates__/nuxt-vue/scripts/dev.ps1 +63 -0
  28. package/lib/__templates__/nuxt-vue/scripts/dev.sh +82 -1
  29. package/lib/__templates__/nuxt-vue/scripts/prepare.ps1 +12 -0
  30. package/lib/__templates__/nuxt-vue/scripts/start.ps1 +11 -0
  31. package/lib/__templates__/nuxt-vue/scripts/validate.ps1 +8 -0
  32. package/lib/__templates__/phaser/.coze +5 -0
  33. package/lib/__templates__/phaser/README.md +8 -0
  34. package/lib/__templates__/phaser/_gitignore +1 -0
  35. package/lib/__templates__/phaser/package.json +1 -1
  36. package/lib/__templates__/phaser/scripts/build.ps1 +12 -0
  37. package/lib/__templates__/phaser/scripts/dev.ps1 +49 -0
  38. package/lib/__templates__/phaser/scripts/dev.sh +74 -3
  39. package/lib/__templates__/phaser/scripts/prepare.ps1 +8 -0
  40. package/lib/__templates__/phaser/scripts/spawn-detached.cjs +29 -0
  41. package/lib/__templates__/phaser/scripts/start.ps1 +49 -0
  42. package/lib/__templates__/phaser/scripts/start.sh +74 -3
  43. package/lib/__templates__/phaser/scripts/validate.ps1 +7 -0
  44. package/lib/__templates__/phaser/src/global.d.ts +3 -0
  45. package/lib/__templates__/phaser/src/scene/BootScene.ts +4 -0
  46. package/lib/__templates__/phaser/src/scene/DevLoadingScene.ts +3 -0
  47. package/lib/__templates__/phaser/src/utils/mark-editable.ts +8 -1
  48. package/lib/__templates__/phaser/vite.config.ts +1 -25
  49. package/lib/__templates__/phaser-static/.coze +15 -0
  50. package/lib/__templates__/phaser-static/README.md +40 -0
  51. package/lib/__templates__/phaser-static/_gitignore +6 -0
  52. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0001.png +0 -0
  53. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0002.png +0 -0
  54. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0003.png +0 -0
  55. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0004.png +0 -0
  56. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0005.png +0 -0
  57. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0006.png +0 -0
  58. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0007.png +0 -0
  59. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0008.png +0 -0
  60. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0009.png +0 -0
  61. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0010.png +0 -0
  62. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0011.png +0 -0
  63. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0012.png +0 -0
  64. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0013.png +0 -0
  65. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0014.png +0 -0
  66. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0015.png +0 -0
  67. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0016.png +0 -0
  68. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0017.png +0 -0
  69. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0018.png +0 -0
  70. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0019.png +0 -0
  71. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0020.png +0 -0
  72. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0021.png +0 -0
  73. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0022.png +0 -0
  74. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0023.png +0 -0
  75. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0024.png +0 -0
  76. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/manifest.json +11 -0
  77. package/lib/__templates__/phaser-static/debug-runtime/flow-graph.json +20 -0
  78. package/lib/__templates__/phaser-static/index.html +17 -0
  79. package/lib/__templates__/phaser-static/scripts/serve.ps1 +7 -0
  80. package/lib/__templates__/phaser-static/src/assets.js +15 -0
  81. package/lib/__templates__/phaser-static/src/main.js +26 -0
  82. package/lib/__templates__/phaser-static/src/phaser.js +7 -0
  83. package/lib/__templates__/phaser-static/src/scene/BootScene.js +205 -0
  84. package/lib/__templates__/phaser-static/src/scene/DevLoadingScene.js +67 -0
  85. package/lib/__templates__/phaser-static/src/style.css +28 -0
  86. package/lib/__templates__/phaser-static/src/utils/asset-loader.js +267 -0
  87. package/lib/__templates__/phaser-static/src/utils/index.js +2 -0
  88. package/lib/__templates__/phaser-static/src/utils/mark-editable.js +3 -0
  89. package/lib/__templates__/phaser-static/template.config.js +35 -0
  90. package/lib/__templates__/pi-agent/package.json +1 -1
  91. package/lib/__templates__/pi-agent/pnpm-lock.yaml +5 -5
  92. package/lib/__templates__/taro/.cozeproj/scripts/deploy_run.sh +1 -1
  93. package/lib/__templates__/taro/.cozeproj/scripts/dev_run.sh +150 -68
  94. package/lib/__templates__/taro/AGENTS.md +11 -7
  95. package/lib/__templates__/taro/README.md +4 -4
  96. package/lib/__templates__/taro/config/index.ts +10 -2
  97. package/lib/__templates__/taro/pnpm-lock.yaml +5 -5
  98. package/lib/__templates__/taro/server/package.json +1 -1
  99. package/lib/__templates__/taro/server/src/main.ts +8 -2
  100. package/lib/__templates__/templates.json +26 -1
  101. package/lib/__templates__/vite/.coze +5 -0
  102. package/lib/__templates__/vite/package.json +1 -1
  103. package/lib/__templates__/vite/pnpm-lock.yaml +5 -5
  104. package/lib/__templates__/vite/scripts/build.ps1 +16 -0
  105. package/lib/__templates__/vite/scripts/dev.ps1 +63 -0
  106. package/lib/__templates__/vite/scripts/dev.sh +82 -1
  107. package/lib/__templates__/vite/scripts/prepare.ps1 +18 -0
  108. package/lib/__templates__/vite/scripts/start.ps1 +11 -0
  109. package/lib/__templates__/vite/scripts/validate.ps1 +8 -0
  110. package/lib/__templates__/vite/template.config.js +4 -2
  111. package/lib/cli.js +3631 -214
  112. package/lib/deploy/package-project.js +244 -0
  113. package/lib/deploy/package-project.py +183 -0
  114. package/package.json +5 -4
@@ -6,6 +6,7 @@
6
6
 
7
7
 
8
8
 
9
+
9
10
  export const paramsSchema = {
10
11
  type: 'object',
11
12
  properties: {
@@ -18,11 +19,18 @@ export const paramsSchema = {
18
19
  },
19
20
  port: {
20
21
  type: 'number',
21
- default: 8081,
22
+ default: 5000,
22
23
  minimum: 1024,
23
24
  maximum: 65535,
24
25
  description: 'Metro bundler port',
25
26
  },
27
+ serverPort: {
28
+ type: 'number',
29
+ default: 9091,
30
+ minimum: 1024,
31
+ maximum: 65535,
32
+ description: 'Express backend server port',
33
+ },
26
34
  },
27
35
  required: [],
28
36
  additionalProperties: false,
@@ -32,7 +40,8 @@ const config = {
32
40
  description: 'Expo template for React Native applications',
33
41
  paramsSchema,
34
42
  defaultParams: {
35
- port: 9090,
43
+ port: 5000,
44
+ serverPort: 9091,
36
45
  appName: 'my-expo-app',
37
46
  },
38
47
  onBeforeRender: async context => {
@@ -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"]
@@ -0,0 +1,7 @@
1
+ $ErrorActionPreference = "Stop"
2
+
3
+ $port = if ($env:DEPLOY_RUN_PORT) { $env:DEPLOY_RUN_PORT } else { "8000" }
4
+
5
+ Write-Host "Starting static server on port $port..."
6
+ & python -m http.server $port --bind 0.0.0.0
7
+ 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
@@ -47,7 +47,7 @@
47
47
  "class-variance-authority": "^0.7.1",
48
48
  "clsx": "^2.1.1",
49
49
  "cmdk": "^1.1.1",
50
- "coze-coding-dev-sdk": "^0.7.16",
50
+ "coze-coding-dev-sdk": "^0.7.25-beta.8",
51
51
  "date-fns": "^4.1.0",
52
52
  "dotenv": "^17.2.3",
53
53
  "drizzle-kit": "^0.31.8",
@@ -108,8 +108,8 @@ importers:
108
108
  specifier: ^1.1.1
109
109
  version: 1.1.1(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
110
110
  coze-coding-dev-sdk:
111
- specifier: ^0.7.16
112
- version: 0.7.16(openai@6.16.0(ws@8.19.0)(zod@4.3.6))(ws@8.19.0)
111
+ specifier: ^0.7.25-beta.8
112
+ version: 0.7.25-beta.8(openai@6.16.0(ws@8.19.0)(zod@4.3.6))(ws@8.19.0)
113
113
  date-fns:
114
114
  specifier: ^4.1.0
115
115
  version: 4.1.0
@@ -3363,8 +3363,8 @@ packages:
3363
3363
  typescript:
3364
3364
  optional: true
3365
3365
 
3366
- coze-coding-dev-sdk@0.7.16:
3367
- resolution: {integrity: sha512-B7gRPBa+sfrZL8ur0+F/92SOgZgFaWD/fOnCN2DjthnHSdmCYhAJWCfqzG2oO2vwTiYCXkKUuTBZ3MJLMj886g==}
3366
+ coze-coding-dev-sdk@0.7.25-beta.8:
3367
+ resolution: {integrity: sha512-RSKlXCO0W/OPDjx9D9JICn2cGeOJw3iG+y0Pr1AhAf7YdAjjNbBZoG7qfg0Zg2SqgaVN2qSLQFmKPbhNq9ZWSg==}
3368
3368
  engines: {node: '>=18.0.0'}
3369
3369
  hasBin: true
3370
3370
 
@@ -9627,7 +9627,7 @@ snapshots:
9627
9627
  optionalDependencies:
9628
9628
  typescript: 5.9.3
9629
9629
 
9630
- coze-coding-dev-sdk@0.7.16(openai@6.16.0(ws@8.19.0)(zod@4.3.6))(ws@8.19.0):
9630
+ coze-coding-dev-sdk@0.7.25-beta.8(openai@6.16.0(ws@8.19.0)(zod@4.3.6))(ws@8.19.0):
9631
9631
  dependencies:
9632
9632
  '@langchain/core': 1.1.17(openai@6.16.0(ws@8.19.0)(zod@4.3.6))
9633
9633
  '@langchain/openai': 1.2.3(@langchain/core@1.1.17(openai@6.16.0(ws@8.19.0)(zod@4.3.6)))(ws@8.19.0)
@@ -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
+ <% } %>
@@ -7,33 +7,231 @@ PORT="${PORT:-<%= port %>}"
7
7
  COZE_WORKSPACE_PATH="${COZE_WORKSPACE_PATH:-$(pwd)}"
8
8
  DEPLOY_RUN_PORT="${DEPLOY_RUN_PORT:-${PORT}}"
9
9
  <% } else { %>
10
- PORT=<%= port %>
10
+ PORT="${DEPLOY_RUN_PORT:-${PORT:-<%= port %>}}"
11
11
  COZE_WORKSPACE_PATH="${COZE_WORKSPACE_PATH:-$(pwd)}"
12
12
  DEPLOY_RUN_PORT="${DEPLOY_RUN_PORT:-${PORT}}"
13
13
  <% } %>
14
14
 
15
15
  cd "${COZE_WORKSPACE_PATH}"
16
16
 
17
+ list_port_pids() {
18
+ local port=$1
19
+ local pids=""
20
+ local has_tool=0
21
+
22
+ if command -v ss >/dev/null 2>&1; then
23
+ has_tool=1
24
+ pids=$(ss -H -lntp 2>/dev/null | awk -v port="${port}" '$4 ~ ":"port"$"' | grep -o 'pid=[0-9]*' | cut -d= -f2 | sort -u | paste -sd' ' - || true)
25
+ fi
26
+ if [[ -z "${pids}" ]] && command -v lsof >/dev/null 2>&1; then
27
+ has_tool=1
28
+ pids=$(lsof -t -iTCP:"${port}" -sTCP:LISTEN 2>/dev/null | sort -u | paste -sd' ' - || true)
29
+ fi
30
+ if [[ "${has_tool}" -eq 0 ]]; then
31
+ echo "Warning: neither ss nor lsof available, cannot inspect port ${port}." >&2
32
+ fi
33
+
34
+ echo "${pids}"
35
+ }
36
+
17
37
  kill_port_if_listening() {
18
38
  local pids
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)
39
+ pids=$(list_port_pids "${DEPLOY_RUN_PORT}")
20
40
  if [[ -z "${pids}" ]]; then
21
41
  echo "Port ${DEPLOY_RUN_PORT} is free."
22
42
  return
23
43
  fi
24
44
  echo "Port ${DEPLOY_RUN_PORT} in use by PIDs: ${pids} (SIGKILL)"
25
- echo "${pids}" | xargs -I {} kill -9 {}
45
+ echo "${pids}" | xargs -I {} kill -9 {} || true
26
46
  sleep 1
27
- 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)
47
+ pids=$(list_port_pids "${DEPLOY_RUN_PORT}")
28
48
  if [[ -n "${pids}" ]]; then
29
- echo "Warning: port ${DEPLOY_RUN_PORT} still busy after SIGKILL, PIDs: ${pids}"
49
+ echo "端口 ${DEPLOY_RUN_PORT} PID ${pids} 占用且无法清理(SIGKILL 后仍在监听),dev server 无法启动。" >&2
50
+ exit 1
51
+ fi
52
+ echo "Port ${DEPLOY_RUN_PORT} cleared."
53
+ }
54
+
55
+ <% if (process.env.NODE_ENV === 'test') { %>
56
+ echo "Clearing port ${DEPLOY_RUN_PORT} before start."
57
+ kill_port_if_listening
58
+ echo "Starting HTTP service on port ${DEPLOY_RUN_PORT} for dev..."
59
+
60
+ # 测试环境保持服务为前台进程,便于 e2e 收集输出并停止进程。
61
+ exec env PORT="${DEPLOY_RUN_PORT}" pnpm tsx watch src/server.ts
62
+ <% } else { %>
63
+ LOG_DIR="${COZE_LOG_DIR:-${COZE_WORKSPACE_PATH}/logs}"
64
+ LOG_FILE="${LOG_DIR}/server.log"
65
+ PID_FILE="${LOG_DIR}/server.pid"
66
+
67
+ spawn_detached() {
68
+ local cwd="$1"
69
+ local log_file="$2"
70
+ shift 2
71
+
72
+ node - "$cwd" "$log_file" "$@" <<'NODE'
73
+ const fs = require('node:fs');
74
+ const { spawn } = require('node:child_process');
75
+
76
+ const [cwd, logFile, command, ...args] = process.argv.slice(2);
77
+ if (!cwd || !logFile || !command) {
78
+ throw new Error('spawn_detached 缺少 cwd、log_file 或 command');
79
+ }
80
+
81
+ const logFd = fs.openSync(logFile, 'a');
82
+ try {
83
+ const child = spawn(command, args, {
84
+ cwd,
85
+ detached: true,
86
+ env: process.env,
87
+ stdio: ['ignore', logFd, logFd],
88
+ });
89
+ child.unref();
90
+ process.stdout.write(String(child.pid));
91
+ } finally {
92
+ fs.closeSync(logFd);
93
+ }
94
+ NODE
95
+ }
96
+
97
+ stop_detached() {
98
+ local pid="${1:-}"
99
+ if [[ -z "${pid}" ]]; then
100
+ return
101
+ fi
102
+
103
+ kill -TERM -- "-${pid}" 2>/dev/null || kill -TERM "${pid}" 2>/dev/null || true
104
+ sleep 1
105
+ kill -KILL -- "-${pid}" 2>/dev/null || true
106
+ }
107
+
108
+ READY_RETRIES=10
109
+ READY_PROBE_HOSTS=("127.0.0.1" "::1")
110
+ LOG_TAIL_LINES=40
111
+
112
+ dump_log() {
113
+ echo "---- tail -n ${LOG_TAIL_LINES} ${LOG_FILE} ----" >&2
114
+ tail -n "${LOG_TAIL_LINES}" "${LOG_FILE}" >&2 || true
115
+ echo "---- end of ${LOG_FILE} ----" >&2
116
+ }
117
+
118
+ # 仅用于无 ss/lsof 时的兜底探测。服务可能只 bind IPv4 loopback、只 bind IPv6 loopback
119
+ # (server.listen(port, 'localhost') 会变成 ::1 独占),或 bind 双栈通配地址,
120
+ port_connectable() {
121
+ local port=$1
122
+ local host
123
+ for host in "${READY_PROBE_HOSTS[@]}"; do
124
+ if command -v nc >/dev/null 2>&1; then
125
+ if nc -z -w 1 "${host}" "${port}" >/dev/null 2>&1; then
126
+ return 0
127
+ fi
128
+ elif (exec 3<>"/dev/tcp/${host}/${port}") >/dev/null 2>&1; then
129
+ return 0
130
+ fi
131
+ done
132
+ return 1
133
+ }
134
+
135
+ port_probe_available() {
136
+ command -v ss >/dev/null 2>&1 || command -v lsof >/dev/null 2>&1
137
+ }
138
+
139
+ # 端口监听者是否属于本进程组:spawn detached 后 PID == PGID,子孙进程继承该 PGID。
140
+ # 0 = 是;1 = 不是(无人监听,或监听者不属于本进程组);2 = 无探测工具,无法判断
141
+ port_listened_by_pgid() {
142
+ local port=$1 pgid=$2
143
+ local listener owner
144
+
145
+ if ! port_probe_available; then
146
+ return 2
147
+ fi
148
+
149
+ for listener in $(list_port_pids "${port}" 2>/dev/null); do
150
+ owner=$(ps -o pgid= -p "${listener}" 2>/dev/null | tr -d ' ')
151
+ if [[ "${owner}" == "${pgid}" ]]; then
152
+ return 0
153
+ fi
154
+ done
155
+ return 1
156
+ }
157
+
158
+ wait_for_ready() {
159
+ local pid=$1 port=$2
160
+ local attempt=0 owned
161
+
162
+ if ! port_probe_available; then
163
+ echo "Warning: 缺少 ss 与 lsof,无法确认端口监听者归属,仅按 loopback 可连接性判断就绪。" >&2
164
+ fi
165
+
166
+ while [[ "${attempt}" -lt "${READY_RETRIES}" ]]; do
167
+ if ! kill -0 "${pid}" 2>/dev/null; then
168
+ echo "Dev server 进程在启动过程中退出。" >&2
169
+ return 1
170
+ fi
171
+
172
+ if port_listened_by_pgid "${port}" "${pid}"; then
173
+ owned=0
30
174
  else
31
- echo "Port ${DEPLOY_RUN_PORT} cleared."
175
+ owned=$?
176
+ fi
177
+ if [[ "${owned}" -eq 0 ]]; then
178
+ return 0
179
+ fi
180
+ if [[ "${owned}" -eq 2 ]] && port_connectable "${port}"; then
181
+ return 0
32
182
  fi
183
+
184
+ sleep 1
185
+ attempt=$((attempt + 1))
186
+ done
187
+
188
+ return 2
33
189
  }
34
190
 
191
+ # 监听端口的是孙进程(pnpm -> tsx -> node),只清端口会漏掉上层 pnpm/tsx,
192
+ # 所以先按上次记录的 PID 把整个进程组回收掉。
193
+ if [[ -f "${PID_FILE}" ]]; then
194
+ stop_detached "$(cat "${PID_FILE}" 2>/dev/null || true)"
195
+ rm -f "${PID_FILE}"
196
+ fi
197
+
35
198
  echo "Clearing port ${DEPLOY_RUN_PORT} before start."
36
199
  kill_port_if_listening
37
200
  echo "Starting HTTP service on port ${DEPLOY_RUN_PORT} for dev..."
38
201
 
39
- PORT=${DEPLOY_RUN_PORT} pnpm tsx watch src/server.ts
202
+ mkdir -p "${LOG_DIR}"
203
+ : > "${LOG_FILE}"
204
+
205
+ export PORT="${DEPLOY_RUN_PORT}"
206
+ server_pid="$(spawn_detached "${COZE_WORKSPACE_PATH}" "${LOG_FILE}" \
207
+ "$(command -v pnpm)" tsx watch src/server.ts)"
208
+ if [[ -z "${server_pid}" ]]; then
209
+ echo "Dev server failed to start: 未获取到后台进程 PID。" >&2
210
+ dump_log
211
+ exit 1
212
+ fi
213
+ echo "${server_pid}" > "${PID_FILE}"
214
+
215
+ if wait_for_ready "${server_pid}" "${DEPLOY_RUN_PORT}"; then
216
+ ready_status=0
217
+ else
218
+ ready_status=$?
219
+ fi
220
+
221
+ if [[ "${ready_status}" -eq 2 ]]; then
222
+ # 进程还活着但迟迟没监听端口:多半是编译/运行时报错后 tsx watch 驻留,日志里有真正原因。
223
+ echo "Dev server 在 ${READY_RETRIES} 次探测(每次 1s)内未就绪于端口 ${DEPLOY_RUN_PORT}(进程 ${server_pid} 仍在运行)。" >&2
224
+ dump_log
225
+ exit 1
226
+ elif [[ "${ready_status}" -ne 0 ]]; then
227
+ echo "Dev server failed to start. See ${LOG_FILE}." >&2
228
+ dump_log
229
+ stop_detached "${server_pid}"
230
+ rm -f "${PID_FILE}"
231
+ exit 1
232
+ fi
233
+
234
+ echo "Dev server started (PID: ${server_pid}), listening on port ${DEPLOY_RUN_PORT}."
235
+ echo "Log file: ${LOG_FILE}"
236
+ echo "PID file: ${PID_FILE}"
237
+ <% } %>
@@ -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
@@ -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 "Running validate..."
7
+ & pnpm validate
8
+ exit $LASTEXITCODE
@@ -3,6 +3,7 @@
3
3
  import { spawn } from 'child_process';
4
4
  import { resolve, join, basename } from 'path';
5
5
  import { appendFileSync, openSync, closeSync, mkdirSync } from 'fs';
6
+ import { homedir } from 'os';
6
7
 
7
8
 
8
9
 
@@ -65,7 +66,7 @@ const config = {
65
66
  }
66
67
 
67
68
  const cmd = 'pnpm';
68
- const args = ['update', 'coze-coding-dev-sdk@^0.7.0'];
69
+ const args = ['update', 'coze-coding-dev-sdk@^0.7.25-beta.8'];
69
70
  console.log(
70
71
  `\nTriggering: ${cmd} ${args.join(' ')} (running in background)`,
71
72
  );
@@ -74,7 +75,8 @@ const config = {
74
75
  const projectRoot = resolve(outputPath);
75
76
 
76
77
  // Determine log directory
77
- const logDir = process.env.COZE_LOG_DIR || resolve(__dirname, '../.log');
78
+ const cozeHome = process.env.COZE_HOME || join(homedir(), '.coze');
79
+ const logDir = process.env.COZE_LOG_DIR || join(cozeHome, 'logs');
78
80
  mkdirSync(logDir, { recursive: true });
79
81
 
80
82
  // Use project name in log file to avoid conflicts
@@ -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
@@ -27,7 +27,7 @@
27
27
  "@nuxtjs/tailwindcss": "^6.14.0",
28
28
  "@types/node": "^20",
29
29
  "autoprefixer": "^10.4.20",
30
- "coze-coding-dev-sdk": "^0.7.16",
30
+ "coze-coding-dev-sdk": "^0.7.25-beta.8",
31
31
  "eslint": "^9",
32
32
  "eslint-plugin-import": "^2.32.0",
33
33
  "eslint-plugin-vue": "^10",
@@ -34,8 +34,8 @@ importers:
34
34
  specifier: ^10.4.20
35
35
  version: 10.4.27(postcss@8.5.8)
36
36
  coze-coding-dev-sdk:
37
- specifier: ^0.7.16
38
- version: 0.7.17(openai@6.27.0(ws@8.21.3)(zod@4.3.6))(ws@8.21.3)
37
+ specifier: ^0.7.25-beta.8
38
+ version: 0.7.25-beta.8(openai@6.27.0(ws@8.21.3)(zod@4.3.6))(ws@8.21.3)
39
39
  eslint:
40
40
  specifier: ^9
41
41
  version: 9.39.4(jiti@2.7.0)
@@ -2498,8 +2498,8 @@ packages:
2498
2498
  typescript:
2499
2499
  optional: true
2500
2500
 
2501
- coze-coding-dev-sdk@0.7.17:
2502
- resolution: {integrity: sha512-ABq84CkmEtvIAat9QGnfY+b1na5Z7XGyAJP/N2XzqFkVfEF268EwFZLpDOQsBBoYWT+6fmpKLZzBoJDVkQU47w==}
2501
+ coze-coding-dev-sdk@0.7.25-beta.8:
2502
+ resolution: {integrity: sha512-RSKlXCO0W/OPDjx9D9JICn2cGeOJw3iG+y0Pr1AhAf7YdAjjNbBZoG7qfg0Zg2SqgaVN2qSLQFmKPbhNq9ZWSg==}
2503
2503
  engines: {node: '>=18.0.0'}
2504
2504
  hasBin: true
2505
2505
 
@@ -8526,7 +8526,7 @@ snapshots:
8526
8526
  optionalDependencies:
8527
8527
  typescript: 5.9.3
8528
8528
 
8529
- coze-coding-dev-sdk@0.7.17(openai@6.27.0(ws@8.21.3)(zod@4.3.6))(ws@8.21.3):
8529
+ coze-coding-dev-sdk@0.7.25-beta.8(openai@6.27.0(ws@8.21.3)(zod@4.3.6))(ws@8.21.3):
8530
8530
  dependencies:
8531
8531
  '@langchain/core': 1.1.31(openai@6.27.0(ws@8.21.3)(zod@4.3.6))
8532
8532
  '@langchain/openai': 1.2.12(@langchain/core@1.1.31(openai@6.27.0(ws@8.21.3)(zod@4.3.6)))(ws@8.21.3)
@@ -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
+ <% } %>