@coze-arch/cli 0.1.4 → 0.1.5-alpha.581217

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 (49) hide show
  1. package/docs/deploy.md +12 -1
  2. package/lib/__templates__/expo/.cozeproj/scripts/dev_build.ps1 +1 -1
  3. package/lib/__templates__/expo/.cozeproj/scripts/dev_build.sh +3 -3
  4. package/lib/__templates__/expo/.cozeproj/scripts/dev_run.ps1 +3 -3
  5. package/lib/__templates__/expo/.cozeproj/scripts/dev_run.sh +11 -3
  6. package/lib/__templates__/expo/.cozeproj/scripts/prepare-node-modules.sh +212 -0
  7. package/lib/__templates__/expo/.cozeproj/scripts/prod_build.sh +3 -3
  8. package/lib/__templates__/expo/client/components/Screen.tsx +65 -25
  9. package/lib/__templates__/expo/client/heroui/components/toast/toast.tsx +6 -2
  10. package/lib/__templates__/expo/client/heroui/helpers/internal/hooks/use-controllable-state.ts +1 -1
  11. package/lib/__templates__/nextjs/eslint.config.mjs +11 -5
  12. package/lib/__templates__/nextjs/next.config.ts +10 -0
  13. package/lib/__templates__/nextjs/package.json +2 -5
  14. package/lib/__templates__/nextjs/pnpm-lock.yaml +14 -945
  15. package/lib/__templates__/nextjs/scripts/build.ps1 +1 -1
  16. package/lib/__templates__/nextjs/scripts/build.sh +2 -2
  17. package/lib/__templates__/nextjs/scripts/dev.ps1 +2 -2
  18. package/lib/__templates__/nextjs/scripts/dev.sh +86 -10
  19. package/lib/__templates__/nextjs/scripts/prepare-node-modules.sh +212 -0
  20. package/lib/__templates__/nextjs/scripts/prepare.sh +1 -4
  21. package/lib/__templates__/nextjs/src/app/layout.tsx +0 -4
  22. package/lib/__templates__/nextjs/src/server.ts +1 -1
  23. package/lib/__templates__/nuxt-vue/scripts/build.sh +1 -1
  24. package/lib/__templates__/nuxt-vue/scripts/dev.sh +11 -3
  25. package/lib/__templates__/nuxt-vue/scripts/prepare-node-modules.sh +212 -0
  26. package/lib/__templates__/nuxt-vue/scripts/prepare.sh +1 -4
  27. package/lib/__templates__/taro/.cozeproj/scripts/deploy_build.sh +5 -1
  28. package/lib/__templates__/taro/.cozeproj/scripts/deploy_run.sh +4 -0
  29. package/lib/__templates__/taro/.cozeproj/scripts/dev_build.sh +3 -0
  30. package/lib/__templates__/taro/.cozeproj/scripts/dev_run.ps1 +4 -2
  31. package/lib/__templates__/taro/.cozeproj/scripts/dev_run.sh +29 -7
  32. package/lib/__templates__/taro/.cozeproj/scripts/init_env.sh +4 -0
  33. package/lib/__templates__/taro/.cozeproj/scripts/pack.ps1 +3 -1
  34. package/lib/__templates__/taro/.cozeproj/scripts/pack.sh +8 -0
  35. package/lib/__templates__/taro/.cozeproj/scripts/prepare-node-modules.sh +212 -0
  36. package/lib/__templates__/taro/.cozeproj/scripts/validate.ps1 +3 -1
  37. package/lib/__templates__/taro/.cozeproj/scripts/validate.sh +4 -0
  38. package/lib/__templates__/taro/_gitignore +1 -0
  39. package/lib/__templates__/vite/scripts/build.ps1 +1 -4
  40. package/lib/__templates__/vite/scripts/build.sh +1 -1
  41. package/lib/__templates__/vite/scripts/dev.ps1 +23 -7
  42. package/lib/__templates__/vite/scripts/dev.sh +11 -3
  43. package/lib/__templates__/vite/scripts/ensure-deps.ps1 +33 -0
  44. package/lib/__templates__/vite/scripts/prepare-node-modules.sh +212 -0
  45. package/lib/__templates__/vite/scripts/prepare.ps1 +1 -6
  46. package/lib/__templates__/vite/scripts/prepare.sh +1 -4
  47. package/lib/cli.js +154 -20
  48. package/package.json +1 -1
  49. package/lib/__templates__/nextjs/.babelrc +0 -15
@@ -6,7 +6,7 @@ COZE_WORKSPACE_PATH="${COZE_WORKSPACE_PATH:-$(pwd)}"
6
6
  cd "${COZE_WORKSPACE_PATH}"
7
7
 
8
8
  echo "Installing dependencies..."
9
- pnpm install --prefer-frozen-lockfile --prefer-offline --loglevel debug --reporter=append-only
9
+ bash "$COZE_WORKSPACE_PATH/scripts/prepare-node-modules.sh" --prefer-frozen-lockfile --prefer-offline --loglevel debug --reporter=append-only
10
10
 
11
11
  echo "Building frontend with Vite..."
12
12
  pnpm vite build
@@ -51,13 +51,29 @@ try {
51
51
  }
52
52
 
53
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
54
+
55
+ $startupTimeoutSeconds = 30
56
+ $startupDeadline = (Get-Date).AddSeconds($startupTimeoutSeconds)
57
+ while ((Get-Date) -lt $startupDeadline) {
58
+ if ($process.HasExited) {
59
+ Write-Error "Dev server exited before listening on port $port."
60
+ Get-Content $errorLogFile -Tail 20 -ErrorAction SilentlyContinue
61
+ Remove-Item $pidFile -Force -ErrorAction SilentlyContinue
62
+ exit 1
63
+ }
64
+
65
+ if (Get-NetTCPConnection -LocalPort $port -State Listen -ErrorAction SilentlyContinue) {
66
+ Write-Host "Dev server is listening on port $port (PID: $($process.Id))."
67
+ Write-Host "Log file: $logFile"
68
+ exit 0
69
+ }
70
+
71
+ Start-Sleep -Milliseconds 200
59
72
  }
60
73
 
61
- Write-Host "Dev server started (PID: $($process.Id))."
62
- Write-Host "Log file: $logFile"
74
+ Write-Error "Dev server did not listen on port $port within $startupTimeoutSeconds seconds."
75
+ Stop-ProcessTree $process.Id
76
+ Get-Content $errorLogFile -Tail 20 -ErrorAction SilentlyContinue
77
+ Remove-Item $pidFile -Force -ErrorAction SilentlyContinue
78
+ exit 1
63
79
  <% } %>
@@ -45,11 +45,15 @@ LOG_FILE="${LOG_DIR}/server.log"
45
45
  PID_FILE="${LOG_DIR}/server.pid"
46
46
 
47
47
  # detached 出去的进程没人负责回收,超过这个时长就自己退出,避免端口与内存长期泄露。
48
- MAX_RUNTIME_SECONDS=1200
48
+ MAX_RUNTIME_SECONDS=3600
49
+
50
+ timeout_watchdog_enabled() {
51
+ [[ -z "${COZE_EVAL:-}" && -z "${COZE_PROJECT_TYPE:-}" ]]
52
+ }
49
53
 
50
54
  # 真正被 detach 的是这层 bash wrapper:它是进程组 leader,组内 watchdog 到点回收整组
51
55
  # (wrapper -> pnpm -> tsx -> node);被包的进程自己先退出时也顺手清空进程组,不留残余。
52
- RUN_WITH_TIMEOUT='
56
+ RUN_WITH_TIMEOUT="$(declare -f timeout_watchdog_enabled)"'
53
57
  timeout_seconds=$1
54
58
  shift
55
59
 
@@ -57,6 +61,7 @@ shift
57
61
  child_pid=$!
58
62
 
59
63
  # 先忽略 TERM,才能在向整组发 TERM(自己也在组里)之后存活下来补一发 KILL。
64
+ if timeout_watchdog_enabled; then
60
65
  ( trap "" TERM
61
66
  sleep "${timeout_seconds}"
62
67
  echo "[dev] 后台进程运行超过 ${timeout_seconds}s,回收进程组 $$。"
@@ -64,6 +69,7 @@ child_pid=$!
64
69
  sleep 5
65
70
  kill -KILL -- "-$$" 2>/dev/null || true
66
71
  ) &
72
+ fi
67
73
 
68
74
  wait "${child_pid}"
69
75
  kill -KILL -- "-$$" 2>/dev/null || true
@@ -142,7 +148,9 @@ if [[ -z "${server_pid}" ]] || ! kill -0 "${server_pid}" 2>/dev/null; then
142
148
  fi
143
149
 
144
150
  echo "Dev server started (PID: ${server_pid})."
145
- echo "Auto stop after ${MAX_RUNTIME_SECONDS}s."
151
+ if timeout_watchdog_enabled; then
152
+ echo "Auto stop after ${MAX_RUNTIME_SECONDS}s."
153
+ fi
146
154
  echo "Log file: ${LOG_FILE}"
147
155
  echo "PID file: ${PID_FILE}"
148
156
  <% } %>
@@ -0,0 +1,33 @@
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
+ $lockfile = Join-Path $workspace "pnpm-lock.yaml"
7
+ $modulesDirectory = Join-Path $workspace "node_modules"
8
+ $modulesManifest = Join-Path $modulesDirectory ".modules.yaml"
9
+ $lockHashFile = Join-Path $modulesDirectory ".coze-lockfile-sha256"
10
+
11
+ if (-not (Test-Path $lockfile)) {
12
+ throw "pnpm-lock.yaml is required to install dependencies."
13
+ }
14
+
15
+ $lockHash = (Get-FileHash -LiteralPath $lockfile -Algorithm SHA256).Hash
16
+ $cachedLockHash = if (Test-Path $lockHashFile) {
17
+ (Get-Content -LiteralPath $lockHashFile -Raw).Trim()
18
+ } else {
19
+ ""
20
+ }
21
+
22
+ if ((Test-Path $modulesManifest) -and $cachedLockHash -eq $lockHash) {
23
+ Write-Host "Dependencies already match pnpm-lock.yaml; skipping install."
24
+ return
25
+ }
26
+
27
+ Write-Host "Installing dependencies..."
28
+ & pnpm install --frozen-lockfile --prefer-offline --loglevel debug --reporter=append-only
29
+ if ($LASTEXITCODE -ne 0) {
30
+ throw "pnpm install failed with exit code $LASTEXITCODE."
31
+ }
32
+
33
+ Set-Content -LiteralPath $lockHashFile -Value $lockHash -NoNewline
@@ -0,0 +1,212 @@
1
+ #!/usr/bin/env bash
2
+ # Install dependencies on local disk and expose them to the source tree by symlink.
3
+ set -euo pipefail
4
+
5
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)"
6
+ if [ "$(basename "$(dirname "$SCRIPT_DIR")")" = ".cozeproj" ]; then
7
+ PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd -P)"
8
+ else
9
+ PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd -P)"
10
+ fi
11
+
12
+ command -v pnpm >/dev/null 2>&1 || {
13
+ echo "[node_modules] pnpm is required" >&2
14
+ exit 1
15
+ }
16
+
17
+ DRIVE_ROOT="${COZE_DRIVE_ROOT:-/Coze/Drive}"
18
+ if [ -d "$DRIVE_ROOT" ]; then
19
+ DRIVE_ROOT="$(cd "$DRIVE_ROOT" && pwd -P)"
20
+ else
21
+ DRIVE_ROOT="${DRIVE_ROOT%/}"
22
+ fi
23
+ case "$PROJECT_ROOT" in
24
+ "$DRIVE_ROOT"|"$DRIVE_ROOT"/*) ;;
25
+ *)
26
+ (cd "$PROJECT_ROOT" && pnpm install "$@")
27
+ exit 0
28
+ ;;
29
+ esac
30
+
31
+ NM_ROOT="/tmp/nm"
32
+ PROJECT_ID="$(basename "$PROJECT_ROOT")-$(printf '%s' "$PROJECT_ROOT" | cksum | awk '{print $1}')"
33
+ mkdir -p "$NM_ROOT"
34
+ WORK_DIR="$NM_ROOT/$PROJECT_ID"
35
+ case "$WORK_DIR" in
36
+ "$DRIVE_ROOT"|"$DRIVE_ROOT"/*)
37
+ echo "[node_modules] local dependency directory must not be on Coze Drive: $WORK_DIR" >&2
38
+ exit 1
39
+ ;;
40
+ esac
41
+
42
+ LOCK_DIR="$NM_ROOT/$PROJECT_ID.lock"
43
+ LOCK_TIMEOUT_SECONDS="${COZE_NODE_MODULES_LOCK_TIMEOUT_SECONDS:-120}"
44
+ case "$LOCK_TIMEOUT_SECONDS" in
45
+ ''|*[!0-9]*|0)
46
+ echo "[node_modules] COZE_NODE_MODULES_LOCK_TIMEOUT_SECONDS must be a positive integer" >&2
47
+ exit 1
48
+ ;;
49
+ esac
50
+
51
+ lock_owner_is_alive() {
52
+ local owner_pid=""
53
+ [ -f "$LOCK_DIR/pid" ] || return 1
54
+ IFS= read -r owner_pid < "$LOCK_DIR/pid" || return 1
55
+ case "$owner_pid" in
56
+ ''|*[!0-9]*) return 1 ;;
57
+ esac
58
+ kill -0 "$owner_pid" 2>/dev/null
59
+ }
60
+
61
+ release_lock() {
62
+ local owner_pid=""
63
+ [ -f "$LOCK_DIR/pid" ] || return 0
64
+ IFS= read -r owner_pid < "$LOCK_DIR/pid" || true
65
+ if [ "$owner_pid" = "$$" ]; then
66
+ rm -f "$LOCK_DIR/pid"
67
+ rmdir "$LOCK_DIR" 2>/dev/null || true
68
+ fi
69
+ }
70
+
71
+ lock_started_at="$(date +%s)"
72
+ missing_owner_checks=0
73
+ while ! mkdir "$LOCK_DIR" 2>/dev/null; do
74
+ if lock_owner_is_alive; then
75
+ missing_owner_checks=0
76
+ else
77
+ missing_owner_checks=$((missing_owner_checks + 1))
78
+ if [ "$missing_owner_checks" -ge 2 ]; then
79
+ stale_lock_dir="$LOCK_DIR.stale.$$"
80
+ if mv "$LOCK_DIR" "$stale_lock_dir" 2>/dev/null; then
81
+ echo "[node_modules] Recovering stale dependency preparation lock."
82
+ rm -rf "$stale_lock_dir"
83
+ fi
84
+ missing_owner_checks=0
85
+ continue
86
+ fi
87
+ fi
88
+
89
+ lock_now="$(date +%s)"
90
+ if [ $((lock_now - lock_started_at)) -ge "$LOCK_TIMEOUT_SECONDS" ]; then
91
+ echo "[node_modules] Timed out waiting ${LOCK_TIMEOUT_SECONDS}s for dependency preparation lock: $LOCK_DIR" >&2
92
+ exit 1
93
+ fi
94
+ echo "[node_modules] Waiting for another dependency preparation for this project..."
95
+ sleep 1
96
+ done
97
+ printf '%s\n' "$$" > "$LOCK_DIR/pid"
98
+ trap release_lock EXIT
99
+
100
+ mkdir -p "$WORK_DIR"
101
+
102
+ # Previous versions mirrored the whole project into WORK_DIR. That gives pnpm
103
+ # and framework dev servers two paths for the same source tree, which breaks
104
+ # file watching and on-demand compilation. Keep only managed local outputs.
105
+ cleanup_legacy_workspace() {
106
+ local workspace_dir="$1" entry name
107
+ if [ -L "$workspace_dir" ] || { [ -e "$workspace_dir" ] && [ ! -d "$workspace_dir" ]; }; then
108
+ rm -rf "$workspace_dir"
109
+ return
110
+ fi
111
+ if [ ! -d "$workspace_dir" ]; then
112
+ return 0
113
+ fi
114
+
115
+ while IFS= read -r -d '' entry; do
116
+ name="$(basename "$entry")"
117
+ [ "$name" = "node_modules" ] || rm -rf "$entry"
118
+ done < <(find "$workspace_dir" -mindepth 1 -maxdepth 1 -print0)
119
+ }
120
+
121
+ cleanup_legacy_shadow_project() {
122
+ local entry name
123
+ while IFS= read -r -d '' entry; do
124
+ name="$(basename "$entry")"
125
+ case "$name" in
126
+ node_modules|client|server) continue ;;
127
+ esac
128
+ rm -rf "$entry"
129
+ done < <(find "$WORK_DIR" -mindepth 1 -maxdepth 1 -print0)
130
+
131
+ for workspace in client server; do
132
+ cleanup_legacy_workspace "$WORK_DIR/$workspace"
133
+ done
134
+ }
135
+
136
+ link_install_entry() {
137
+ local source_path="$1" target_path="$2"
138
+ rm -rf "$target_path"
139
+ if [ -e "$source_path" ]; then
140
+ ln -s "$source_path" "$target_path"
141
+ fi
142
+ }
143
+
144
+ copy_install_metadata() {
145
+ local filename source_file target_file workspace
146
+ for filename in pnpm-lock.yaml pnpm-workspace.yaml .npmrc; do
147
+ source_file="$PROJECT_ROOT/$filename"
148
+ target_file="$WORK_DIR/$filename"
149
+ rm -f "$target_file"
150
+ if [ -f "$source_file" ]; then
151
+ cp "$source_file" "$target_file"
152
+ fi
153
+ done
154
+
155
+ link_install_entry "$PROJECT_ROOT/package.json" "$WORK_DIR/package.json"
156
+ link_install_entry "$PROJECT_ROOT/patches" "$WORK_DIR/patches"
157
+ link_install_entry "$PROJECT_ROOT/scripts" "$WORK_DIR/scripts"
158
+
159
+ for workspace in client server; do
160
+ if [ -f "$PROJECT_ROOT/$workspace/package.json" ]; then
161
+ mkdir -p "$WORK_DIR/$workspace"
162
+ link_install_entry "$PROJECT_ROOT/$workspace/package.json" "$WORK_DIR/$workspace/package.json"
163
+ link_install_entry "$PROJECT_ROOT/$workspace/scripts" "$WORK_DIR/$workspace/scripts"
164
+ else
165
+ rm -rf "$WORK_DIR/$workspace"
166
+ fi
167
+ done
168
+ }
169
+
170
+ link_node_modules() {
171
+ local source_dir="$1" target_dir="$2"
172
+ local current=""
173
+ mkdir -p "$target_dir"
174
+ if [ -L "$source_dir/node_modules" ]; then
175
+ current="$(readlink "$source_dir/node_modules")"
176
+ case "$current" in
177
+ "$NM_ROOT"/*/node_modules|"$NM_ROOT"/*/*/node_modules) ;;
178
+ *)
179
+ echo "[node_modules] refusing to replace unmanaged symlink: $source_dir/node_modules" >&2
180
+ exit 1
181
+ ;;
182
+ esac
183
+ rm "$source_dir/node_modules"
184
+ elif [ -e "$source_dir/node_modules" ]; then
185
+ rm -rf "$source_dir/node_modules"
186
+ fi
187
+ ln -s "$target_dir" "$source_dir/node_modules"
188
+ }
189
+
190
+ cleanup_legacy_shadow_project
191
+ copy_install_metadata
192
+
193
+ echo "[node_modules] Installing dependencies in $WORK_DIR"
194
+ if ! (cd "$WORK_DIR" && pnpm install "$@"); then
195
+ exit 1
196
+ fi
197
+
198
+ if [ -f "$WORK_DIR/pnpm-lock.yaml" ]; then
199
+ temporary_lockfile="$(mktemp "$PROJECT_ROOT/.pnpm-lock.yaml.XXXXXX")"
200
+ cp "$WORK_DIR/pnpm-lock.yaml" "$temporary_lockfile"
201
+ chmod 0644 "$temporary_lockfile"
202
+ mv -f "$temporary_lockfile" "$PROJECT_ROOT/pnpm-lock.yaml"
203
+ fi
204
+
205
+ link_node_modules "$PROJECT_ROOT" "$WORK_DIR/node_modules"
206
+ for workspace in client server; do
207
+ if [ -f "$PROJECT_ROOT/$workspace/package.json" ]; then
208
+ link_node_modules "$PROJECT_ROOT/$workspace" "$WORK_DIR/$workspace/node_modules"
209
+ fi
210
+ done
211
+
212
+ echo "[node_modules] Dependencies ready"
@@ -1,14 +1,9 @@
1
1
  $ErrorActionPreference = "Stop"
2
2
 
3
3
  $workspace = if ($env:COZE_WORKSPACE_PATH) { $env:COZE_WORKSPACE_PATH } else { (Get-Location).Path }
4
+ & "$PSScriptRoot/ensure-deps.ps1"
4
5
  Set-Location $workspace
5
6
 
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
7
  if (Get-Command coze-dev -ErrorAction SilentlyContinue) {
13
8
  & coze-dev check-bins --help *> $null
14
9
  if ($LASTEXITCODE -eq 0) {
@@ -6,7 +6,4 @@ COZE_WORKSPACE_PATH="${COZE_WORKSPACE_PATH:-$(pwd)}"
6
6
  cd "${COZE_WORKSPACE_PATH}"
7
7
 
8
8
  echo "Installing dependencies..."
9
- pnpm install --prefer-frozen-lockfile --prefer-offline --loglevel debug --reporter=append-only
10
- if command -v coze-dev > /dev/null 2>&1 && coze-dev check-bins --help > /dev/null 2>&1; then
11
- coze-dev check-bins --fix
12
- fi
9
+ bash "$COZE_WORKSPACE_PATH/scripts/prepare-node-modules.sh" --prefer-frozen-lockfile --prefer-offline --loglevel debug --reporter=append-only
package/lib/cli.js CHANGED
@@ -2114,7 +2114,7 @@ const EventBuilder = {
2114
2114
  };
2115
2115
 
2116
2116
  var name = "@coze-arch/cli";
2117
- var version = "0.1.4";
2117
+ var version = "0.1.5-alpha.581217";
2118
2118
  var description = "coze coding devtools cli";
2119
2119
  var license = "MIT";
2120
2120
  var author = "fanwenjie.fe@bytedance.com";
@@ -9883,18 +9883,38 @@ const execute = async (
9883
9883
  };
9884
9884
 
9885
9885
  function _nullishCoalesce$2(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }
9886
+ const getDependencyPreparationCommand = (projectPath) => {
9887
+ if (fs.existsSync(path.join(projectPath, 'scripts', 'prepare.sh'))) {
9888
+ return 'bash ./scripts/prepare.sh';
9889
+ }
9890
+ if (
9891
+ fs.existsSync(
9892
+ path.join(
9893
+ projectPath,
9894
+ '.cozeproj',
9895
+ 'scripts',
9896
+ 'prepare-node-modules.sh',
9897
+ ),
9898
+ )
9899
+ ) {
9900
+ return 'bash ./.cozeproj/scripts/prepare-node-modules.sh';
9901
+ }
9902
+ return 'pnpm install';
9903
+ };
9904
+
9886
9905
  /**
9887
- * 运行 pnpm install
9906
+ * 优先通过模板提供的 wrapper 准备依赖。
9888
9907
  */
9889
- const runPnpmInstall = (projectPath) => {
9890
- logger.info('\nInstalling dependencies with pnpm...');
9908
+ const prepareDependencies = (projectPath) => {
9909
+ logger.info('\nPreparing dependencies with the project wrapper...');
9891
9910
 
9892
- const result = shelljs.exec('pnpm install', {
9911
+ const command = getDependencyPreparationCommand(projectPath);
9912
+ const result = shelljs.exec(command, {
9893
9913
  cwd: projectPath,
9894
9914
  silent: true,
9895
9915
  });
9896
9916
 
9897
- // verbose 模式下输出 pnpm install 的详细日志
9917
+ // verbose 模式下输出依赖准备命令的详细日志
9898
9918
  if (result.stdout) {
9899
9919
  logger.verbose(result.stdout);
9900
9920
  }
@@ -9903,11 +9923,11 @@ const runPnpmInstall = (projectPath) => {
9903
9923
  }
9904
9924
 
9905
9925
  if (result.code === 0) {
9906
- logger.success('Dependencies installed successfully!');
9926
+ logger.success('Dependencies prepared successfully!');
9907
9927
  } else {
9908
9928
  // 仅在失败时输出详细信息以便排查
9909
9929
  const errorMessage = [
9910
- `pnpm install failed with exit code ${result.code}`,
9930
+ `${command} failed with exit code ${result.code}`,
9911
9931
  result.stderr ? `\nStderr:\n${result.stderr}` : '',
9912
9932
  result.stdout ? `\nStdout:\n${result.stdout}` : '',
9913
9933
  ]
@@ -10132,7 +10152,7 @@ const installDependenciesStep = ctx => {
10132
10152
  try {
10133
10153
  if (!skipInstall) {
10134
10154
  if (ctx.hasPackageJson) {
10135
- runPnpmInstall(ctx.absoluteOutputPath);
10155
+ prepareDependencies(ctx.absoluteOutputPath);
10136
10156
  ctx.timer.logPhase('Dependencies installation');
10137
10157
  } else {
10138
10158
  logger.info(
@@ -10141,7 +10161,7 @@ const installDependenciesStep = ctx => {
10141
10161
  }
10142
10162
  }
10143
10163
  } catch (error) {
10144
- // 捕获 pnpm install 失败的情况
10164
+ // 捕获依赖准备失败的情况
10145
10165
  installSuccess = false;
10146
10166
  installErrorCode = 1;
10147
10167
  installErrorType = 'execution_failed';
@@ -10228,7 +10248,9 @@ const startDevServerStep = ctx => {
10228
10248
  logger.info('\nNext steps:');
10229
10249
  logger.info(` cd ${ctx.outputPath}`);
10230
10250
  if (skipInstall && ctx.hasPackageJson) {
10231
- logger.info(' pnpm install');
10251
+ logger.info(
10252
+ ` ${getDependencyPreparationCommand(ctx.absoluteOutputPath)}`,
10253
+ );
10232
10254
  }
10233
10255
  if (skipGit) {
10234
10256
  logger.info(' git init');
@@ -10340,7 +10362,7 @@ const registerCommand$1 = program => {
10340
10362
  .argument('[directory]', 'Output directory for the project')
10341
10363
  .requiredOption('-t, --template <name>', 'Template name')
10342
10364
  .option('-o, --output <path>', 'Output directory', process.cwd())
10343
- .option('--skip-install', 'Skip automatic pnpm install', false)
10365
+ .option('--skip-install', 'Skip automatic dependency preparation', false)
10344
10366
  .option('--skip-git', 'Skip automatic git initialization', false)
10345
10367
  .option(
10346
10368
  '--skip-commit',
@@ -11085,7 +11107,10 @@ class DeployApiClient {
11085
11107
  if (cozeAccount) {
11086
11108
  headers['x-coze-account'] = cozeAccount;
11087
11109
  }
11088
- const lane = _optionalChain$a([this, 'access', _4 => _4.globalOptions, 'access', _5 => _5.lane, 'optionalAccess', _6 => _6.trim, 'call', _7 => _7()]) || _optionalChain$a([this, 'access', _8 => _8.config, 'access', _9 => _9.xTTEnv, 'optionalAccess', _10 => _10.trim, 'call', _11 => _11()]);
11110
+ // Deployment traffic must only enter a PPE lane when the caller explicitly
11111
+ // opts in for this invocation. The shared CLI config may contain xTTEnv for
11112
+ // other command families, but it must not silently affect deployments.
11113
+ const lane = _optionalChain$a([this, 'access', _4 => _4.globalOptions, 'access', _5 => _5.lane, 'optionalAccess', _6 => _6.trim, 'call', _7 => _7()]);
11089
11114
  if (lane) {
11090
11115
  headers['x-use-ppe'] = '1';
11091
11116
  headers['x-tt-env'] = lane;
@@ -11116,7 +11141,7 @@ class DeployApiClient {
11116
11141
  if (!response.ok) {
11117
11142
  const root = isRecord(payload) ? payload : undefined;
11118
11143
  throw new CliError(
11119
- typeof _optionalChain$a([root, 'optionalAccess', _12 => _12.msg]) === 'string'
11144
+ typeof _optionalChain$a([root, 'optionalAccess', _8 => _8.msg]) === 'string'
11120
11145
  ? root.msg.slice(0, MAX_MESSAGE_LENGTH)
11121
11146
  : `Deployment API failed: ${response.status} ${response.statusText}` +
11122
11147
  `${validJson ? '' : '; response was not JSON'}`,
@@ -11549,7 +11574,7 @@ const registerContext = (program) => {
11549
11574
  organization_id: runtime.config.organizationId,
11550
11575
  space_id: runtime.config.spaceId,
11551
11576
  project_id: runtime.config.projectId,
11552
- lane: runtime.globalOptions.lane || runtime.config.xTTEnv,
11577
+ lane: runtime.globalOptions.lane,
11553
11578
  config_path: runtime.globalOptions.config || getSharedConfigPath(),
11554
11579
  });
11555
11580
  });
@@ -11623,6 +11648,7 @@ function _optionalChain$9(ops) { let lastAccessLHS = undefined; let value = ops[
11623
11648
 
11624
11649
 
11625
11650
 
11651
+
11626
11652
 
11627
11653
 
11628
11654
  const getDeployParentOptions = (command) =>
@@ -11686,6 +11712,106 @@ const resolveCozeAccountId = async (
11686
11712
  }
11687
11713
  };
11688
11714
 
11715
+ const RESOURCE_FIELDS = [
11716
+ 'cpu',
11717
+ 'memory_mb',
11718
+ 'max_instance',
11719
+ 'max_concurrency',
11720
+ ] ;
11721
+
11722
+
11723
+
11724
+
11725
+
11726
+
11727
+ const CPU_MEMORY_PAIRS = new Map([
11728
+ [1, 2048],
11729
+ [4, 8192],
11730
+ [8, 16384],
11731
+ [16, 32768],
11732
+ ]);
11733
+
11734
+ const INVALID_JSON = Symbol('invalid-deploy-config-json');
11735
+
11736
+ const invalidDeployConfig = (
11737
+ message,
11738
+ details,
11739
+ ) => new CliError(message, 'INVALID_DEPLOY_CONFIG', details);
11740
+
11741
+ const requireInteger = (
11742
+ value,
11743
+ field,
11744
+ ) => {
11745
+ if (!Number.isInteger(value)) {
11746
+ throw invalidDeployConfig(`deploy_config.${field} must be an integer.`, { field, value });
11747
+ }
11748
+ return value ;
11749
+ };
11750
+
11751
+ const parseDeployConfigOverride = (
11752
+ value,
11753
+ ) => {
11754
+ if (value === undefined) {
11755
+ return undefined;
11756
+ }
11757
+
11758
+ const parsed = safeJsonParse(value, INVALID_JSON);
11759
+ if (parsed === INVALID_JSON) {
11760
+ throw invalidDeployConfig('--deploy-config must be a valid JSON object.');
11761
+ }
11762
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
11763
+ throw invalidDeployConfig('--deploy-config must be a JSON object.');
11764
+ }
11765
+
11766
+ const object = parsed ;
11767
+ const unknownFields = Object.keys(object).filter(
11768
+ field => !RESOURCE_FIELDS.includes(field ),
11769
+ );
11770
+ const missingFields = RESOURCE_FIELDS.filter(field => !(field in object));
11771
+ if (unknownFields.length > 0 || missingFields.length > 0) {
11772
+ throw invalidDeployConfig(
11773
+ '--deploy-config must contain exactly cpu, memory_mb, max_instance, and max_concurrency.',
11774
+ { missing_fields: missingFields, unknown_fields: unknownFields },
11775
+ );
11776
+ }
11777
+
11778
+ const cpu = requireInteger(object.cpu, 'cpu');
11779
+ const memoryMb = requireInteger(object.memory_mb, 'memory_mb');
11780
+ const maxInstance = requireInteger(object.max_instance, 'max_instance');
11781
+ const maxConcurrency = requireInteger(object.max_concurrency, 'max_concurrency');
11782
+ if (CPU_MEMORY_PAIRS.get(cpu) !== memoryMb) {
11783
+ throw invalidDeployConfig(
11784
+ 'deploy_config cpu and memory_mb must use one of: 1/2048, 4/8192, 8/16384, or 16/32768.',
11785
+ { cpu, memory_mb: memoryMb },
11786
+ );
11787
+ }
11788
+ if (maxInstance < 1 || maxInstance > 100) {
11789
+ throw invalidDeployConfig('deploy_config.max_instance must be between 1 and 100.', {
11790
+ max_instance: maxInstance,
11791
+ });
11792
+ }
11793
+ if (maxConcurrency < 10 || maxConcurrency > 1000) {
11794
+ throw invalidDeployConfig('deploy_config.max_concurrency must be between 10 and 1000.', {
11795
+ max_concurrency: maxConcurrency,
11796
+ });
11797
+ }
11798
+
11799
+ return {
11800
+ cpu,
11801
+ memory_mb: memoryMb,
11802
+ max_instance: maxInstance,
11803
+ max_concurrency: maxConcurrency,
11804
+ };
11805
+ };
11806
+
11807
+ const applyDeployConfigOverride = (
11808
+ config,
11809
+ override,
11810
+ ) =>
11811
+ override
11812
+ ? { ...config, deploy_config: { ...config.deploy_config, ...override } }
11813
+ : config;
11814
+
11689
11815
  const getCreateDeployConfig = (config) => ({
11690
11816
  deploy_config: {
11691
11817
  cpu: config.deploy_config.cpu,
@@ -13377,6 +13503,10 @@ const registerDeploy = (deploy) => {
13377
13503
  collectConnectorId,
13378
13504
  [],
13379
13505
  )
13506
+ .option(
13507
+ '--deploy-config <json>',
13508
+ 'Deployment resources as JSON: cpu, memory_mb, max_instance, max_concurrency',
13509
+ )
13380
13510
  .option('--wait', 'Wait for deployment completion')
13381
13511
  .option('--yes', 'Confirm deployment')
13382
13512
  // eslint-disable-next-line @coze-arch/max-line-per-function -- deployment orchestration is one auditable flow
@@ -13384,6 +13514,7 @@ const registerDeploy = (deploy) => {
13384
13514
  const runtime = await getRuntime(command);
13385
13515
  const sourceRoot = node_path.resolve(runtime.cwd, options.sourceRoot || '.');
13386
13516
  const requestedApplicationType = parseApplicationType(options.applicationType);
13517
+ const deployConfigOverride = parseDeployConfigOverride(options.deployConfig);
13387
13518
  runtime.output.debug(`[deploy] Reading local project: ${sourceRoot}`);
13388
13519
  const localContext =
13389
13520
  await readDeployLocalContext(
@@ -13464,10 +13595,13 @@ const registerDeploy = (deploy) => {
13464
13595
  ...(isPagesDeployment ? { application_type: 'pages' } : {}),
13465
13596
  ...(cozeFileContent ? { coze_file_content: cozeFileContent } : {}),
13466
13597
  });
13467
- const config = withRequestedApplicationType(
13468
- serverConfig,
13469
- requestedApplicationType,
13470
- Boolean(appId),
13598
+ const config = applyDeployConfigOverride(
13599
+ withRequestedApplicationType(
13600
+ serverConfig,
13601
+ requestedApplicationType,
13602
+ Boolean(appId),
13603
+ ),
13604
+ deployConfigOverride,
13471
13605
  );
13472
13606
  const applicationType = config.application_type;
13473
13607
  const connectorConfigs = getConnectorConfigs(options.connectorId);
@@ -13486,7 +13620,7 @@ const registerDeploy = (deploy) => {
13486
13620
  risks: config.risk_list || [],
13487
13621
  ...(!appId && deploymentName ? { name: deploymentName } : {}),
13488
13622
  message: options.message,
13489
- lane: runtime.globalOptions.lane || runtime.config.xTTEnv,
13623
+ lane: runtime.globalOptions.lane,
13490
13624
  });
13491
13625
  return;
13492
13626
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coze-arch/cli",
3
- "version": "0.1.4",
3
+ "version": "0.1.5-alpha.581217",
4
4
  "private": false,
5
5
  "description": "coze coding devtools cli",
6
6
  "license": "MIT",
@@ -1,15 +0,0 @@
1
- {
2
- "presets": [
3
- [
4
- "next/babel",
5
- {
6
- "preset-react": {
7
- "development": true
8
- }
9
- }
10
- ]
11
- ],
12
- "plugins": [
13
- "@react-dev-inspector/babel-plugin"
14
- ]
15
- }