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

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 (43) hide show
  1. package/docs/deploy.md +1 -12
  2. package/lib/__templates__/expo/.cozeproj/scripts/dev_build.sh +3 -3
  3. package/lib/__templates__/expo/.cozeproj/scripts/dev_run.sh +3 -11
  4. package/lib/__templates__/expo/.cozeproj/scripts/prod_build.sh +3 -3
  5. package/lib/__templates__/expo/client/components/Screen.tsx +25 -65
  6. package/lib/__templates__/expo/client/heroui/components/toast/toast.tsx +2 -6
  7. package/lib/__templates__/expo/client/heroui/helpers/internal/hooks/use-controllable-state.ts +1 -1
  8. package/lib/__templates__/nextjs/.babelrc +15 -0
  9. package/lib/__templates__/nextjs/eslint.config.mjs +5 -11
  10. package/lib/__templates__/nextjs/next.config.ts +0 -10
  11. package/lib/__templates__/nextjs/package.json +6 -3
  12. package/lib/__templates__/nextjs/pnpm-lock.yaml +1071 -136
  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 +10 -86
  17. package/lib/__templates__/nextjs/scripts/prepare.sh +4 -1
  18. package/lib/__templates__/nextjs/src/app/layout.tsx +4 -0
  19. package/lib/__templates__/nextjs/src/server.ts +1 -1
  20. package/lib/__templates__/nuxt-vue/scripts/build.sh +1 -1
  21. package/lib/__templates__/nuxt-vue/scripts/dev.sh +3 -11
  22. package/lib/__templates__/nuxt-vue/scripts/prepare.sh +4 -1
  23. package/lib/__templates__/taro/.cozeproj/scripts/deploy_build.sh +1 -5
  24. package/lib/__templates__/taro/.cozeproj/scripts/deploy_run.sh +0 -4
  25. package/lib/__templates__/taro/.cozeproj/scripts/dev_build.sh +0 -3
  26. package/lib/__templates__/taro/.cozeproj/scripts/dev_run.ps1 +2 -4
  27. package/lib/__templates__/taro/.cozeproj/scripts/dev_run.sh +7 -29
  28. package/lib/__templates__/taro/.cozeproj/scripts/init_env.sh +0 -4
  29. package/lib/__templates__/taro/.cozeproj/scripts/pack.ps1 +1 -3
  30. package/lib/__templates__/taro/.cozeproj/scripts/pack.sh +0 -8
  31. package/lib/__templates__/taro/.cozeproj/scripts/validate.ps1 +1 -3
  32. package/lib/__templates__/taro/.cozeproj/scripts/validate.sh +0 -4
  33. package/lib/__templates__/taro/_gitignore +0 -1
  34. package/lib/__templates__/vite/scripts/build.sh +1 -1
  35. package/lib/__templates__/vite/scripts/dev.sh +3 -11
  36. package/lib/__templates__/vite/scripts/prepare.sh +4 -1
  37. package/lib/cli.js +16 -147
  38. package/package.json +2 -2
  39. package/lib/__templates__/expo/.cozeproj/scripts/prepare-node-modules.sh +0 -212
  40. package/lib/__templates__/nextjs/scripts/prepare-node-modules.sh +0 -212
  41. package/lib/__templates__/nuxt-vue/scripts/prepare-node-modules.sh +0 -212
  42. package/lib/__templates__/taro/.cozeproj/scripts/prepare-node-modules.sh +0 -212
  43. package/lib/__templates__/vite/scripts/prepare-node-modules.sh +0 -212
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-alpha.581217";
2117
+ var version = "0.1.5";
2118
2118
  var description = "coze coding devtools cli";
2119
2119
  var license = "MIT";
2120
2120
  var author = "fanwenjie.fe@bytedance.com";
@@ -9883,38 +9883,18 @@ 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
-
9905
9886
  /**
9906
- * 优先通过模板提供的 wrapper 准备依赖。
9887
+ * 运行 pnpm install
9907
9888
  */
9908
- const prepareDependencies = (projectPath) => {
9909
- logger.info('\nPreparing dependencies with the project wrapper...');
9889
+ const runPnpmInstall = (projectPath) => {
9890
+ logger.info('\nInstalling dependencies with pnpm...');
9910
9891
 
9911
- const command = getDependencyPreparationCommand(projectPath);
9912
- const result = shelljs.exec(command, {
9892
+ const result = shelljs.exec('pnpm install', {
9913
9893
  cwd: projectPath,
9914
9894
  silent: true,
9915
9895
  });
9916
9896
 
9917
- // verbose 模式下输出依赖准备命令的详细日志
9897
+ // verbose 模式下输出 pnpm install 的详细日志
9918
9898
  if (result.stdout) {
9919
9899
  logger.verbose(result.stdout);
9920
9900
  }
@@ -9923,11 +9903,11 @@ const prepareDependencies = (projectPath) => {
9923
9903
  }
9924
9904
 
9925
9905
  if (result.code === 0) {
9926
- logger.success('Dependencies prepared successfully!');
9906
+ logger.success('Dependencies installed successfully!');
9927
9907
  } else {
9928
9908
  // 仅在失败时输出详细信息以便排查
9929
9909
  const errorMessage = [
9930
- `${command} failed with exit code ${result.code}`,
9910
+ `pnpm install failed with exit code ${result.code}`,
9931
9911
  result.stderr ? `\nStderr:\n${result.stderr}` : '',
9932
9912
  result.stdout ? `\nStdout:\n${result.stdout}` : '',
9933
9913
  ]
@@ -10152,7 +10132,7 @@ const installDependenciesStep = ctx => {
10152
10132
  try {
10153
10133
  if (!skipInstall) {
10154
10134
  if (ctx.hasPackageJson) {
10155
- prepareDependencies(ctx.absoluteOutputPath);
10135
+ runPnpmInstall(ctx.absoluteOutputPath);
10156
10136
  ctx.timer.logPhase('Dependencies installation');
10157
10137
  } else {
10158
10138
  logger.info(
@@ -10161,7 +10141,7 @@ const installDependenciesStep = ctx => {
10161
10141
  }
10162
10142
  }
10163
10143
  } catch (error) {
10164
- // 捕获依赖准备失败的情况
10144
+ // 捕获 pnpm install 失败的情况
10165
10145
  installSuccess = false;
10166
10146
  installErrorCode = 1;
10167
10147
  installErrorType = 'execution_failed';
@@ -10248,9 +10228,7 @@ const startDevServerStep = ctx => {
10248
10228
  logger.info('\nNext steps:');
10249
10229
  logger.info(` cd ${ctx.outputPath}`);
10250
10230
  if (skipInstall && ctx.hasPackageJson) {
10251
- logger.info(
10252
- ` ${getDependencyPreparationCommand(ctx.absoluteOutputPath)}`,
10253
- );
10231
+ logger.info(' pnpm install');
10254
10232
  }
10255
10233
  if (skipGit) {
10256
10234
  logger.info(' git init');
@@ -10362,7 +10340,7 @@ const registerCommand$1 = program => {
10362
10340
  .argument('[directory]', 'Output directory for the project')
10363
10341
  .requiredOption('-t, --template <name>', 'Template name')
10364
10342
  .option('-o, --output <path>', 'Output directory', process.cwd())
10365
- .option('--skip-install', 'Skip automatic dependency preparation', false)
10343
+ .option('--skip-install', 'Skip automatic pnpm install', false)
10366
10344
  .option('--skip-git', 'Skip automatic git initialization', false)
10367
10345
  .option(
10368
10346
  '--skip-commit',
@@ -11648,7 +11626,6 @@ function _optionalChain$9(ops) { let lastAccessLHS = undefined; let value = ops[
11648
11626
 
11649
11627
 
11650
11628
 
11651
-
11652
11629
 
11653
11630
 
11654
11631
  const getDeployParentOptions = (command) =>
@@ -11712,106 +11689,6 @@ const resolveCozeAccountId = async (
11712
11689
  }
11713
11690
  };
11714
11691
 
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
-
11815
11692
  const getCreateDeployConfig = (config) => ({
11816
11693
  deploy_config: {
11817
11694
  cpu: config.deploy_config.cpu,
@@ -13503,10 +13380,6 @@ const registerDeploy = (deploy) => {
13503
13380
  collectConnectorId,
13504
13381
  [],
13505
13382
  )
13506
- .option(
13507
- '--deploy-config <json>',
13508
- 'Deployment resources as JSON: cpu, memory_mb, max_instance, max_concurrency',
13509
- )
13510
13383
  .option('--wait', 'Wait for deployment completion')
13511
13384
  .option('--yes', 'Confirm deployment')
13512
13385
  // eslint-disable-next-line @coze-arch/max-line-per-function -- deployment orchestration is one auditable flow
@@ -13514,7 +13387,6 @@ const registerDeploy = (deploy) => {
13514
13387
  const runtime = await getRuntime(command);
13515
13388
  const sourceRoot = node_path.resolve(runtime.cwd, options.sourceRoot || '.');
13516
13389
  const requestedApplicationType = parseApplicationType(options.applicationType);
13517
- const deployConfigOverride = parseDeployConfigOverride(options.deployConfig);
13518
13390
  runtime.output.debug(`[deploy] Reading local project: ${sourceRoot}`);
13519
13391
  const localContext =
13520
13392
  await readDeployLocalContext(
@@ -13595,13 +13467,10 @@ const registerDeploy = (deploy) => {
13595
13467
  ...(isPagesDeployment ? { application_type: 'pages' } : {}),
13596
13468
  ...(cozeFileContent ? { coze_file_content: cozeFileContent } : {}),
13597
13469
  });
13598
- const config = applyDeployConfigOverride(
13599
- withRequestedApplicationType(
13600
- serverConfig,
13601
- requestedApplicationType,
13602
- Boolean(appId),
13603
- ),
13604
- deployConfigOverride,
13470
+ const config = withRequestedApplicationType(
13471
+ serverConfig,
13472
+ requestedApplicationType,
13473
+ Boolean(appId),
13605
13474
  );
13606
13475
  const applicationType = config.application_type;
13607
13476
  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-alpha.581217",
3
+ "version": "0.1.5",
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,212 +0,0 @@
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,212 +0,0 @@
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"