@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.
- package/docs/deploy.md +1 -12
- package/lib/__templates__/expo/.cozeproj/scripts/dev_build.sh +3 -3
- package/lib/__templates__/expo/.cozeproj/scripts/dev_run.sh +3 -11
- package/lib/__templates__/expo/.cozeproj/scripts/prod_build.sh +3 -3
- package/lib/__templates__/expo/client/components/Screen.tsx +25 -65
- package/lib/__templates__/expo/client/heroui/components/toast/toast.tsx +2 -6
- package/lib/__templates__/expo/client/heroui/helpers/internal/hooks/use-controllable-state.ts +1 -1
- package/lib/__templates__/nextjs/.babelrc +15 -0
- package/lib/__templates__/nextjs/eslint.config.mjs +5 -11
- package/lib/__templates__/nextjs/next.config.ts +0 -10
- package/lib/__templates__/nextjs/package.json +6 -3
- package/lib/__templates__/nextjs/pnpm-lock.yaml +1071 -136
- package/lib/__templates__/nextjs/scripts/build.ps1 +1 -1
- package/lib/__templates__/nextjs/scripts/build.sh +2 -2
- package/lib/__templates__/nextjs/scripts/dev.ps1 +2 -2
- package/lib/__templates__/nextjs/scripts/dev.sh +10 -86
- package/lib/__templates__/nextjs/scripts/prepare.sh +4 -1
- package/lib/__templates__/nextjs/src/app/layout.tsx +4 -0
- package/lib/__templates__/nextjs/src/server.ts +1 -1
- package/lib/__templates__/nuxt-vue/scripts/build.sh +1 -1
- package/lib/__templates__/nuxt-vue/scripts/dev.sh +3 -11
- package/lib/__templates__/nuxt-vue/scripts/prepare.sh +4 -1
- package/lib/__templates__/taro/.cozeproj/scripts/deploy_build.sh +1 -5
- package/lib/__templates__/taro/.cozeproj/scripts/deploy_run.sh +0 -4
- package/lib/__templates__/taro/.cozeproj/scripts/dev_build.sh +0 -3
- package/lib/__templates__/taro/.cozeproj/scripts/dev_run.ps1 +2 -4
- package/lib/__templates__/taro/.cozeproj/scripts/dev_run.sh +7 -29
- package/lib/__templates__/taro/.cozeproj/scripts/init_env.sh +0 -4
- package/lib/__templates__/taro/.cozeproj/scripts/pack.ps1 +1 -3
- package/lib/__templates__/taro/.cozeproj/scripts/pack.sh +0 -8
- package/lib/__templates__/taro/.cozeproj/scripts/validate.ps1 +1 -3
- package/lib/__templates__/taro/.cozeproj/scripts/validate.sh +0 -4
- package/lib/__templates__/taro/_gitignore +0 -1
- package/lib/__templates__/vite/scripts/build.sh +1 -1
- package/lib/__templates__/vite/scripts/dev.sh +3 -11
- package/lib/__templates__/vite/scripts/prepare.sh +4 -1
- package/lib/cli.js +16 -147
- package/package.json +2 -2
- package/lib/__templates__/expo/.cozeproj/scripts/prepare-node-modules.sh +0 -212
- package/lib/__templates__/nextjs/scripts/prepare-node-modules.sh +0 -212
- package/lib/__templates__/nuxt-vue/scripts/prepare-node-modules.sh +0 -212
- package/lib/__templates__/taro/.cozeproj/scripts/prepare-node-modules.sh +0 -212
- 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
|
|
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
|
-
*
|
|
9887
|
+
* 运行 pnpm install
|
|
9907
9888
|
*/
|
|
9908
|
-
const
|
|
9909
|
-
logger.info('\
|
|
9889
|
+
const runPnpmInstall = (projectPath) => {
|
|
9890
|
+
logger.info('\nInstalling dependencies with pnpm...');
|
|
9910
9891
|
|
|
9911
|
-
const
|
|
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
|
|
9906
|
+
logger.success('Dependencies installed successfully!');
|
|
9927
9907
|
} else {
|
|
9928
9908
|
// 仅在失败时输出详细信息以便排查
|
|
9929
9909
|
const errorMessage = [
|
|
9930
|
-
|
|
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
|
-
|
|
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
|
|
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 =
|
|
13599
|
-
|
|
13600
|
-
|
|
13601
|
-
|
|
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,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"
|