@coze-arch/cli 0.1.5 → 0.1.8-alpha.6e99f9

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 (45) 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 +382 -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 +93 -10
  17. package/lib/__templates__/nextjs/scripts/prepare-next-dev-output.sh +122 -0
  18. package/lib/__templates__/nextjs/scripts/prepare-node-modules.sh +382 -0
  19. package/lib/__templates__/nextjs/scripts/prepare.sh +1 -4
  20. package/lib/__templates__/nextjs/src/app/layout.tsx +0 -4
  21. package/lib/__templates__/nextjs/src/server.ts +1 -1
  22. package/lib/__templates__/nuxt-vue/scripts/build.sh +1 -1
  23. package/lib/__templates__/nuxt-vue/scripts/dev.sh +11 -3
  24. package/lib/__templates__/nuxt-vue/scripts/prepare-node-modules.sh +382 -0
  25. package/lib/__templates__/nuxt-vue/scripts/prepare.sh +1 -4
  26. package/lib/__templates__/taro/.cozeproj/scripts/deploy_build.sh +5 -1
  27. package/lib/__templates__/taro/.cozeproj/scripts/deploy_run.sh +4 -0
  28. package/lib/__templates__/taro/.cozeproj/scripts/dev_build.sh +3 -0
  29. package/lib/__templates__/taro/.cozeproj/scripts/dev_run.ps1 +4 -2
  30. package/lib/__templates__/taro/.cozeproj/scripts/dev_run.sh +29 -7
  31. package/lib/__templates__/taro/.cozeproj/scripts/init_env.sh +4 -0
  32. package/lib/__templates__/taro/.cozeproj/scripts/pack.ps1 +3 -1
  33. package/lib/__templates__/taro/.cozeproj/scripts/pack.sh +8 -0
  34. package/lib/__templates__/taro/.cozeproj/scripts/prepare-node-modules.sh +382 -0
  35. package/lib/__templates__/taro/.cozeproj/scripts/validate.ps1 +3 -1
  36. package/lib/__templates__/taro/.cozeproj/scripts/validate.sh +4 -0
  37. package/lib/__templates__/taro/_gitignore +1 -0
  38. package/lib/__templates__/vite/scripts/build.sh +1 -1
  39. package/lib/__templates__/vite/scripts/dev.ps1 +2 -2
  40. package/lib/__templates__/vite/scripts/dev.sh +11 -3
  41. package/lib/__templates__/vite/scripts/prepare-node-modules.sh +382 -0
  42. package/lib/__templates__/vite/scripts/prepare.sh +1 -4
  43. package/lib/cli.js +147 -16
  44. package/package.json +2 -2
  45. package/lib/__templates__/nextjs/.babelrc +0 -15
@@ -0,0 +1,382 @@
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
+ INSTALL_STATE_FILE="$WORK_DIR/.install-state"
102
+
103
+ # Previous versions mirrored the whole project into WORK_DIR. That gives pnpm
104
+ # and framework dev servers two paths for the same source tree, which breaks
105
+ # file watching and on-demand compilation. Keep only managed local outputs.
106
+ cleanup_legacy_workspace() {
107
+ local workspace_dir="$1" entry name
108
+ if [ -L "$workspace_dir" ] || { [ -e "$workspace_dir" ] && [ ! -d "$workspace_dir" ]; }; then
109
+ rm -rf "$workspace_dir"
110
+ return
111
+ fi
112
+ if [ ! -d "$workspace_dir" ]; then
113
+ return 0
114
+ fi
115
+
116
+ while IFS= read -r -d '' entry; do
117
+ name="$(basename "$entry")"
118
+ [ "$name" = "node_modules" ] || rm -rf "$entry"
119
+ done < <(find "$workspace_dir" -mindepth 1 -maxdepth 1 -print0)
120
+ }
121
+
122
+ # caches is reserved for the sibling prepare scripts of this project. They keep
123
+ # regenerable framework output there (the Next helper points .next/dev into it), and that
124
+ # output has to outlive an install, so this cleanup must not read it as leftover.
125
+ cleanup_legacy_shadow_project() {
126
+ local entry name
127
+ while IFS= read -r -d '' entry; do
128
+ name="$(basename "$entry")"
129
+ case "$name" in
130
+ node_modules|client|server|caches|.install-state) continue ;;
131
+ esac
132
+ rm -rf "$entry"
133
+ done < <(find "$WORK_DIR" -mindepth 1 -maxdepth 1 -print0)
134
+
135
+ for workspace in client server; do
136
+ cleanup_legacy_workspace "$WORK_DIR/$workspace"
137
+ done
138
+ }
139
+
140
+ link_install_entry() {
141
+ local source_path="$1" target_path="$2"
142
+ rm -rf "$target_path"
143
+ if [ -e "$source_path" ]; then
144
+ ln -s "$source_path" "$target_path"
145
+ fi
146
+ }
147
+
148
+ hash_install_input() {
149
+ if command -v sha256sum >/dev/null 2>&1; then
150
+ sha256sum | awk '{print $1}'
151
+ elif command -v shasum >/dev/null 2>&1; then
152
+ shasum -a 256 | awk '{print $1}'
153
+ else
154
+ cksum | awk '{print $1 "-" $2}'
155
+ fi
156
+ }
157
+
158
+ append_file_to_install_fingerprint() {
159
+ local relative_path="$1"
160
+ local source_path="$PROJECT_ROOT/$relative_path"
161
+ printf 'path=%s\n' "$relative_path"
162
+ if [ -f "$source_path" ]; then
163
+ cat "$source_path"
164
+ else
165
+ printf '<missing>\n'
166
+ fi
167
+ }
168
+
169
+ append_directory_to_install_fingerprint() {
170
+ local relative_path="$1"
171
+ local source_path="$PROJECT_ROOT/$relative_path"
172
+ local file
173
+ printf 'path=%s\n' "$relative_path"
174
+ if [ ! -d "$source_path" ]; then
175
+ printf '<missing>\n'
176
+ return
177
+ fi
178
+
179
+ while IFS= read -r file; do
180
+ printf 'file=%s\n' "${file#"${PROJECT_ROOT}/"}"
181
+ cat "$file"
182
+ done < <(find -P "$source_path" -type f -print | LC_ALL=C sort)
183
+ }
184
+
185
+ # Everything that can change the resolved dependency tree. The leading version marker
186
+ # invalidates every stored state when this scheme itself changes.
187
+ calculate_install_fingerprint() {
188
+ local filename workspace argument
189
+ {
190
+ printf 'prepare-node-modules-install-state=1\n'
191
+ printf 'node-version=%s\n' "$(node --version)"
192
+ printf 'pnpm-version=%s\n' "$(pnpm --version)"
193
+ printf 'node-env=%s\n' "${NODE_ENV:-}"
194
+ printf 'npm-config-production=%s\n' "${npm_config_production:-}"
195
+ printf 'npm-config-production-upper=%s\n' "${NPM_CONFIG_PRODUCTION:-}"
196
+ printf 'pnpm-config-production=%s\n' "${PNPM_CONFIG_PRODUCTION:-}"
197
+ for argument in "$@"; do
198
+ printf 'install-argument=%s\n' "$argument"
199
+ done
200
+ for filename in package.json pnpm-lock.yaml pnpm-workspace.yaml .npmrc; do
201
+ append_file_to_install_fingerprint "$filename"
202
+ done
203
+ for workspace in client server; do
204
+ append_file_to_install_fingerprint "$workspace/package.json"
205
+ done
206
+ append_directory_to_install_fingerprint patches
207
+ } | hash_install_input
208
+ }
209
+
210
+ install_requires_refresh() {
211
+ local argument
212
+ for argument in "$@"; do
213
+ case "$argument" in
214
+ --force|-f|--lockfile-only|--fix-lockfile) return 0 ;;
215
+ esac
216
+ done
217
+ return 1
218
+ }
219
+
220
+ # Reuse skips pnpm install entirely, so it must not skip side effects that live outside
221
+ # node_modules. preinstall is exempt: it only guards which package manager may run, and
222
+ # there is no install to guard when the tree is already in place.
223
+ package_has_install_lifecycle() {
224
+ local package_path="$1"
225
+ node - "$package_path" <<'NODE'
226
+ const fs = require('node:fs');
227
+ const [packagePath] = process.argv.slice(2);
228
+
229
+ try {
230
+ const packageJson = JSON.parse(fs.readFileSync(packagePath, 'utf8'));
231
+ const scripts = packageJson && typeof packageJson.scripts === 'object' && packageJson.scripts
232
+ ? packageJson.scripts
233
+ : {};
234
+ const hasLifecycle = ['install', 'postinstall', 'prepare'].some(
235
+ name => typeof scripts[name] === 'string' && scripts[name].trim() !== '',
236
+ );
237
+
238
+ process.exit(hasLifecycle ? 0 : 1);
239
+ } catch {
240
+ process.exit(0);
241
+ }
242
+ NODE
243
+ }
244
+
245
+ install_reuse_is_safe() {
246
+ local workspace package_path
247
+ for package_path in "$PROJECT_ROOT/.pnpmfile.cjs" "$PROJECT_ROOT/.pnpmfile.js"; do
248
+ if [ -e "$package_path" ]; then
249
+ echo "[node_modules] Reinstalling because pnpm hooks are present: $package_path"
250
+ return 1
251
+ fi
252
+ done
253
+
254
+ if [ -f "$PROJECT_ROOT/.npmrc" ] && grep -Eq '^[[:space:]]*pnpmfile[[:space:]]*=' "$PROJECT_ROOT/.npmrc"; then
255
+ echo "[node_modules] Reinstalling because .npmrc configures a pnpm hook."
256
+ return 1
257
+ fi
258
+
259
+ for workspace in . client server; do
260
+ package_path="$PROJECT_ROOT/$workspace/package.json"
261
+ [ -f "$package_path" ] || continue
262
+ if package_has_install_lifecycle "$package_path"; then
263
+ echo "[node_modules] Reinstalling because $package_path has an install lifecycle script."
264
+ return 1
265
+ fi
266
+ done
267
+ return 0
268
+ }
269
+
270
+ dependencies_are_ready() {
271
+ local workspace
272
+ [ -f "$WORK_DIR/node_modules/.modules.yaml" ] || return 1
273
+ for workspace in client server; do
274
+ if [ -f "$PROJECT_ROOT/$workspace/package.json" ] &&
275
+ [ ! -f "$WORK_DIR/$workspace/node_modules/.modules.yaml" ]; then
276
+ return 1
277
+ fi
278
+ done
279
+ return 0
280
+ }
281
+
282
+ # 判断顺序按代价从小到大排。指纹要读云盘上的 lockfile 和整个 patches/,所以放最后:只有其余
283
+ # 条件都满足、确实可能复用时才付这份开销。build.sh 和 prepare.sh 不设开关,第一行就返回了。
284
+ install_can_be_reused() {
285
+ local installed_fingerprint=""
286
+
287
+ [ "${COZE_REUSE_NODE_MODULES:-}" = "1" ] || return 1
288
+ install_requires_refresh "$@" && return 1
289
+ [ -f "$INSTALL_STATE_FILE" ] || return 1
290
+ IFS= read -r installed_fingerprint < "$INSTALL_STATE_FILE" || return 1
291
+ dependencies_are_ready || return 1
292
+ install_reuse_is_safe || return 1
293
+ [ "$installed_fingerprint" = "$(calculate_install_fingerprint "$@")" ] || return 1
294
+ return 0
295
+ }
296
+
297
+ write_install_state() {
298
+ local fingerprint="$1" temporary_state
299
+ temporary_state="$(mktemp "$WORK_DIR/.install-state.XXXXXX")"
300
+ printf '%s\n' "$fingerprint" > "$temporary_state"
301
+ mv -f "$temporary_state" "$INSTALL_STATE_FILE"
302
+ }
303
+
304
+ copy_install_metadata() {
305
+ local filename source_file target_file workspace
306
+ for filename in pnpm-lock.yaml pnpm-workspace.yaml .npmrc; do
307
+ source_file="$PROJECT_ROOT/$filename"
308
+ target_file="$WORK_DIR/$filename"
309
+ rm -f "$target_file"
310
+ if [ -f "$source_file" ]; then
311
+ cp "$source_file" "$target_file"
312
+ fi
313
+ done
314
+
315
+ link_install_entry "$PROJECT_ROOT/package.json" "$WORK_DIR/package.json"
316
+ link_install_entry "$PROJECT_ROOT/patches" "$WORK_DIR/patches"
317
+ link_install_entry "$PROJECT_ROOT/scripts" "$WORK_DIR/scripts"
318
+
319
+ for workspace in client server; do
320
+ if [ -f "$PROJECT_ROOT/$workspace/package.json" ]; then
321
+ mkdir -p "$WORK_DIR/$workspace"
322
+ link_install_entry "$PROJECT_ROOT/$workspace/package.json" "$WORK_DIR/$workspace/package.json"
323
+ link_install_entry "$PROJECT_ROOT/$workspace/scripts" "$WORK_DIR/$workspace/scripts"
324
+ else
325
+ rm -rf "$WORK_DIR/$workspace"
326
+ fi
327
+ done
328
+ }
329
+
330
+ link_node_modules() {
331
+ local source_dir="$1" target_dir="$2"
332
+ local current=""
333
+ mkdir -p "$target_dir"
334
+ if [ -L "$source_dir/node_modules" ]; then
335
+ current="$(readlink "$source_dir/node_modules")"
336
+ case "$current" in
337
+ "$NM_ROOT"/*/node_modules|"$NM_ROOT"/*/*/node_modules) ;;
338
+ *)
339
+ echo "[node_modules] refusing to replace unmanaged symlink: $source_dir/node_modules" >&2
340
+ exit 1
341
+ ;;
342
+ esac
343
+ rm "$source_dir/node_modules"
344
+ elif [ -e "$source_dir/node_modules" ]; then
345
+ rm -rf "$source_dir/node_modules"
346
+ fi
347
+ ln -s "$target_dir" "$source_dir/node_modules"
348
+ }
349
+
350
+ cleanup_legacy_shadow_project
351
+ copy_install_metadata
352
+
353
+ if install_can_be_reused "$@"; then
354
+ echo "[node_modules] Reusing unchanged dependencies in $WORK_DIR"
355
+ else
356
+ # A stale state file must not survive a failed install.
357
+ rm -f "$INSTALL_STATE_FILE"
358
+ echo "[node_modules] Installing dependencies in $WORK_DIR"
359
+ if ! (cd "$WORK_DIR" && pnpm install "$@"); then
360
+ exit 1
361
+ fi
362
+
363
+ if [ -f "$WORK_DIR/pnpm-lock.yaml" ]; then
364
+ temporary_lockfile="$(mktemp "$PROJECT_ROOT/.pnpm-lock.yaml.XXXXXX")"
365
+ cp "$WORK_DIR/pnpm-lock.yaml" "$temporary_lockfile"
366
+ chmod 0644 "$temporary_lockfile"
367
+ mv -f "$temporary_lockfile" "$PROJECT_ROOT/pnpm-lock.yaml"
368
+ fi
369
+
370
+ # pnpm may have rewritten the lockfile, so record the fingerprint of the tree as it
371
+ # now stands. Otherwise the next run would see a changed input and reinstall.
372
+ write_install_state "$(calculate_install_fingerprint "$@")"
373
+ fi
374
+
375
+ link_node_modules "$PROJECT_ROOT" "$WORK_DIR/node_modules"
376
+ for workspace in client server; do
377
+ if [ -f "$PROJECT_ROOT/$workspace/package.json" ]; then
378
+ link_node_modules "$PROJECT_ROOT/$workspace" "$WORK_DIR/$workspace/node_modules"
379
+ fi
380
+ done
381
+
382
+ 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.8-alpha.6e99f9";
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.8-alpha.6e99f9",
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
- }