@coze-arch/cli 0.1.5 → 0.1.7

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 (44) hide show
  1. package/docs/deploy.md +12 -1
  2. package/lib/__templates__/expo/.cozeproj/scripts/dev_build.sh +3 -3
  3. package/lib/__templates__/expo/.cozeproj/scripts/dev_run.sh +11 -3
  4. package/lib/__templates__/expo/.cozeproj/scripts/prepare-node-modules.sh +212 -0
  5. package/lib/__templates__/expo/.cozeproj/scripts/prod_build.sh +3 -3
  6. package/lib/__templates__/expo/client/components/Screen.tsx +65 -25
  7. package/lib/__templates__/expo/client/heroui/components/toast/toast.tsx +6 -2
  8. package/lib/__templates__/expo/client/heroui/helpers/internal/hooks/use-controllable-state.ts +1 -1
  9. package/lib/__templates__/nextjs/eslint.config.mjs +11 -5
  10. package/lib/__templates__/nextjs/next.config.ts +10 -0
  11. package/lib/__templates__/nextjs/package.json +2 -5
  12. package/lib/__templates__/nextjs/pnpm-lock.yaml +14 -945
  13. package/lib/__templates__/nextjs/scripts/build.ps1 +1 -1
  14. package/lib/__templates__/nextjs/scripts/build.sh +2 -2
  15. package/lib/__templates__/nextjs/scripts/dev.ps1 +2 -2
  16. package/lib/__templates__/nextjs/scripts/dev.sh +86 -10
  17. package/lib/__templates__/nextjs/scripts/prepare-node-modules.sh +212 -0
  18. package/lib/__templates__/nextjs/scripts/prepare.sh +1 -4
  19. package/lib/__templates__/nextjs/src/app/layout.tsx +0 -4
  20. package/lib/__templates__/nextjs/src/server.ts +1 -1
  21. package/lib/__templates__/nuxt-vue/scripts/build.sh +1 -1
  22. package/lib/__templates__/nuxt-vue/scripts/dev.sh +11 -3
  23. package/lib/__templates__/nuxt-vue/scripts/prepare-node-modules.sh +212 -0
  24. package/lib/__templates__/nuxt-vue/scripts/prepare.sh +1 -4
  25. package/lib/__templates__/taro/.cozeproj/scripts/deploy_build.sh +5 -1
  26. package/lib/__templates__/taro/.cozeproj/scripts/deploy_run.sh +4 -0
  27. package/lib/__templates__/taro/.cozeproj/scripts/dev_build.sh +3 -0
  28. package/lib/__templates__/taro/.cozeproj/scripts/dev_run.ps1 +4 -2
  29. package/lib/__templates__/taro/.cozeproj/scripts/dev_run.sh +29 -7
  30. package/lib/__templates__/taro/.cozeproj/scripts/init_env.sh +4 -0
  31. package/lib/__templates__/taro/.cozeproj/scripts/pack.ps1 +3 -1
  32. package/lib/__templates__/taro/.cozeproj/scripts/pack.sh +8 -0
  33. package/lib/__templates__/taro/.cozeproj/scripts/prepare-node-modules.sh +212 -0
  34. package/lib/__templates__/taro/.cozeproj/scripts/validate.ps1 +3 -1
  35. package/lib/__templates__/taro/.cozeproj/scripts/validate.sh +4 -0
  36. package/lib/__templates__/taro/_gitignore +1 -0
  37. package/lib/__templates__/vite/scripts/build.sh +1 -1
  38. package/lib/__templates__/vite/scripts/dev.ps1 +2 -2
  39. package/lib/__templates__/vite/scripts/dev.sh +11 -3
  40. package/lib/__templates__/vite/scripts/prepare-node-modules.sh +212 -0
  41. package/lib/__templates__/vite/scripts/prepare.sh +1 -4
  42. package/lib/cli.js +147 -16
  43. package/package.json +2 -2
  44. package/lib/__templates__/nextjs/.babelrc +0 -15
@@ -56,9 +56,9 @@ $startupTimeoutSeconds = 30
56
56
  $startupDeadline = (Get-Date).AddSeconds($startupTimeoutSeconds)
57
57
  while ((Get-Date) -lt $startupDeadline) {
58
58
  if ($process.HasExited) {
59
- Write-Error "Dev server exited before listening on port $port."
60
59
  Get-Content $errorLogFile -Tail 20 -ErrorAction SilentlyContinue
61
60
  Remove-Item $pidFile -Force -ErrorAction SilentlyContinue
61
+ Write-Error "Dev server exited before listening on port $port." -ErrorAction Continue
62
62
  exit 1
63
63
  }
64
64
 
@@ -71,9 +71,9 @@ while ((Get-Date) -lt $startupDeadline) {
71
71
  Start-Sleep -Milliseconds 200
72
72
  }
73
73
 
74
- Write-Error "Dev server did not listen on port $port within $startupTimeoutSeconds seconds."
75
74
  Stop-ProcessTree $process.Id
76
75
  Get-Content $errorLogFile -Tail 20 -ErrorAction SilentlyContinue
77
76
  Remove-Item $pidFile -Force -ErrorAction SilentlyContinue
77
+ Write-Error "Dev server did not listen on port $port within $startupTimeoutSeconds seconds." -ErrorAction Continue
78
78
  exit 1
79
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,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"
@@ -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.5";
2117
+ var version = "0.1.7";
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',
@@ -11626,6 +11648,7 @@ function _optionalChain$9(ops) { let lastAccessLHS = undefined; let value = ops[
11626
11648
 
11627
11649
 
11628
11650
 
11651
+
11629
11652
 
11630
11653
 
11631
11654
  const getDeployParentOptions = (command) =>
@@ -11689,6 +11712,106 @@ const resolveCozeAccountId = async (
11689
11712
  }
11690
11713
  };
11691
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
+
11692
11815
  const getCreateDeployConfig = (config) => ({
11693
11816
  deploy_config: {
11694
11817
  cpu: config.deploy_config.cpu,
@@ -13380,6 +13503,10 @@ const registerDeploy = (deploy) => {
13380
13503
  collectConnectorId,
13381
13504
  [],
13382
13505
  )
13506
+ .option(
13507
+ '--deploy-config <json>',
13508
+ 'Deployment resources as JSON: cpu, memory_mb, max_instance, max_concurrency',
13509
+ )
13383
13510
  .option('--wait', 'Wait for deployment completion')
13384
13511
  .option('--yes', 'Confirm deployment')
13385
13512
  // eslint-disable-next-line @coze-arch/max-line-per-function -- deployment orchestration is one auditable flow
@@ -13387,6 +13514,7 @@ const registerDeploy = (deploy) => {
13387
13514
  const runtime = await getRuntime(command);
13388
13515
  const sourceRoot = node_path.resolve(runtime.cwd, options.sourceRoot || '.');
13389
13516
  const requestedApplicationType = parseApplicationType(options.applicationType);
13517
+ const deployConfigOverride = parseDeployConfigOverride(options.deployConfig);
13390
13518
  runtime.output.debug(`[deploy] Reading local project: ${sourceRoot}`);
13391
13519
  const localContext =
13392
13520
  await readDeployLocalContext(
@@ -13467,10 +13595,13 @@ const registerDeploy = (deploy) => {
13467
13595
  ...(isPagesDeployment ? { application_type: 'pages' } : {}),
13468
13596
  ...(cozeFileContent ? { coze_file_content: cozeFileContent } : {}),
13469
13597
  });
13470
- const config = withRequestedApplicationType(
13471
- serverConfig,
13472
- requestedApplicationType,
13473
- Boolean(appId),
13598
+ const config = applyDeployConfigOverride(
13599
+ withRequestedApplicationType(
13600
+ serverConfig,
13601
+ requestedApplicationType,
13602
+ Boolean(appId),
13603
+ ),
13604
+ deployConfigOverride,
13474
13605
  );
13475
13606
  const applicationType = config.application_type;
13476
13607
  const connectorConfigs = getConnectorConfigs(options.connectorId);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coze-arch/cli",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "private": false,
5
5
  "description": "coze coding devtools cli",
6
6
  "license": "MIT",
@@ -94,4 +94,4 @@
94
94
  "coze-dev": "bin/main"
95
95
  }
96
96
  }
97
- }
97
+ }
@@ -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
- }