@coze-arch/cli 0.0.36-alpha.844e20 → 0.0.36-alpha.a7a716

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 CHANGED
@@ -101,21 +101,17 @@ V2 接口的所有参数均通过 POST JSON body 发送,不会放入 URL。确
101
101
  `scripts/package-project.py` 仍随源码和 npm 包保留,仅作为 Python 参考备份与行为对照,
102
102
  生产打包链路不会调用 Python。
103
103
 
104
- 服务和小程序部署会读取源码根目录的 `.env` 并加密上传;`COZE_` 前缀为平台保留,CLI
105
- 会过滤这类变量,避免覆盖部署运行时由平台注入的配置。
104
+ 环境变量以当前线上成功版本的 Secret 快照为准,CLI 不再读取源码根目录的 `.env`。
105
+ 更新服务或小程序时,CLI 会读取线上快照中的用户变量并重新加密上传;首次部署没有线上
106
+ 快照,因此使用空的用户变量集合。平台系统变量由 Secret 服务管理,不作为用户变量上传。
106
107
 
107
- 本地环境变量可通过以下命令管理,默认操作当前目录的 `.env`,也可通过
108
- `--source-root` 指定项目目录;这些命令不会请求部署服务:
108
+ 通过 `app_id` 查看当前线上版本的环境变量及快照状态:
109
109
 
110
110
  ```bash
111
111
  coze-dev deploy code env list
112
- coze-dev deploy code env set API_KEY "secret value"
113
- coze-dev deploy code env delete API_KEY
114
- coze-dev deploy code env list --source-root ./projects/example
112
+ coze-dev deploy code env list --app-id 7672644451805691910
115
113
  ```
116
114
 
117
- `env set` 和 `env delete` 不允许操作 `COZE_` 前缀的保留变量。
118
-
119
115
  小程序部署可重复指定渠道:微信为 `10000127`,抖音为 `10000126`:
120
116
 
121
117
  ```bash
@@ -3,6 +3,7 @@
3
3
  import { spawn } from 'child_process';
4
4
  import { resolve, join, basename } from 'path';
5
5
  import { appendFileSync, openSync, closeSync, mkdirSync } from 'fs';
6
+ import { homedir } from 'os';
6
7
 
7
8
 
8
9
 
@@ -74,7 +75,8 @@ const config = {
74
75
  const projectRoot = resolve(outputPath);
75
76
 
76
77
  // Determine log directory
77
- const logDir = process.env.COZE_LOG_DIR || resolve(__dirname, '../.log');
78
+ const cozeHome = process.env.COZE_HOME || join(homedir(), '.coze');
79
+ const logDir = process.env.COZE_LOG_DIR || join(cozeHome, 'logs');
78
80
  mkdirSync(logDir, { recursive: true });
79
81
 
80
82
  // Use project name in log file to avoid conflicts
@@ -8,6 +8,7 @@ coverage/
8
8
 
9
9
  *.log
10
10
  *.tsbuildinfo
11
+ logs/
11
12
  .vite/
12
13
  .cache/
13
14
  node-compile-cache/
@@ -2,10 +2,81 @@
2
2
  set -Eeuo pipefail
3
3
 
4
4
  COZE_WORKSPACE_PATH="${COZE_WORKSPACE_PATH:-$(pwd)}"
5
- PORT="${DEPLOY_RUN_PORT:-${PORT:-<%= port %>}}"
5
+ PORT="${PORT:-<%= port %>}"
6
+ DEPLOY_RUN_PORT="${DEPLOY_RUN_PORT:-${PORT}}"
6
7
  cd "${COZE_WORKSPACE_PATH}"
7
8
 
8
- COZE_PHASER_GAME_ENV=DEV pnpm vite \
9
- --port "${PORT}" \
9
+ get_listening_pids() {
10
+ local port="$1"
11
+
12
+ if command -v lsof >/dev/null 2>&1; then
13
+ lsof -tiTCP:"${port}" -sTCP:LISTEN 2>/dev/null || true
14
+ elif command -v ss >/dev/null 2>&1; then
15
+ ss -H -lntp 2>/dev/null \
16
+ | awk -v port="${port}" '$4 ~ ":"port"$"' \
17
+ | grep -o 'pid=[0-9]*' \
18
+ | cut -d= -f2 \
19
+ | sort -u || true
20
+ else
21
+ echo "Warning: neither lsof nor ss found, cannot check port ${port}." >&2
22
+ fi
23
+ }
24
+
25
+ kill_port_if_listening() {
26
+ local port="$1"
27
+ local pids
28
+
29
+ pids="$(get_listening_pids "${port}")"
30
+ if [[ -z "${pids}" ]]; then
31
+ echo "Port ${port} is free."
32
+ return
33
+ fi
34
+
35
+ echo "Port ${port} is in use by PIDs: ${pids//$'\n'/ } (SIGKILL)"
36
+ echo "${pids}" | xargs kill -9 2>/dev/null || true
37
+ sleep 1
38
+
39
+ pids="$(get_listening_pids "${port}")"
40
+ if [[ -n "${pids}" ]]; then
41
+ echo "Failed to clear port ${port}; remaining PIDs: ${pids//$'\n'/ }." >&2
42
+ return 1
43
+ fi
44
+
45
+ echo "Port ${port} cleared."
46
+ }
47
+
48
+ echo "Clearing port ${DEPLOY_RUN_PORT} before start."
49
+ kill_port_if_listening "${DEPLOY_RUN_PORT}"
50
+
51
+ <% if (process.env.NODE_ENV === 'test') { %>
52
+ # Keep the process attached in tests so the test runner can collect logs and stop it.
53
+ exec env COZE_PHASER_GAME_ENV=DEV pnpm vite \
54
+ --port "${DEPLOY_RUN_PORT}" \
10
55
  --host 127.0.0.1 \
11
56
  --strictPort
57
+ <% } else { %>
58
+ LOG_DIR="${COZE_WORKSPACE_PATH}/logs"
59
+ LOG_FILE="${LOG_DIR}/phaser-dev.log"
60
+ PID_FILE="${LOG_DIR}/phaser-dev.pid"
61
+ mkdir -p "${LOG_DIR}"
62
+
63
+ echo "Starting Phaser dev server on port ${DEPLOY_RUN_PORT}..."
64
+ server_pid="$(COZE_PHASER_GAME_ENV=DEV node scripts/spawn-detached.cjs \
65
+ "${LOG_FILE}" pnpm vite \
66
+ --port "${DEPLOY_RUN_PORT}" \
67
+ --host 127.0.0.1 \
68
+ --strictPort)"
69
+ echo "${server_pid}" > "${PID_FILE}"
70
+
71
+ sleep 1
72
+ if ! kill -0 "${server_pid}" 2>/dev/null; then
73
+ echo "Phaser dev server failed to start. See ${LOG_FILE}." >&2
74
+ tail -n 20 "${LOG_FILE}" >&2 || true
75
+ rm -f "${PID_FILE}"
76
+ exit 1
77
+ fi
78
+
79
+ echo "Phaser dev server started (PID: ${server_pid})."
80
+ echo "Log file: ${LOG_FILE}"
81
+ echo "PID file: ${PID_FILE}"
82
+ <% } %>
@@ -0,0 +1,29 @@
1
+ const fs = require('node:fs');
2
+ const { spawn } = require('node:child_process');
3
+
4
+ const [logFile, command, ...args] = process.argv.slice(2);
5
+
6
+ if (!logFile || !command) {
7
+ process.stderr.write(
8
+ 'Usage: node scripts/spawn-detached.cjs <log-file> <command> [...args]\n',
9
+ );
10
+ process.exit(1);
11
+ }
12
+
13
+ const logFd = fs.openSync(logFile, 'a');
14
+ const child = spawn(command, args, {
15
+ cwd: process.cwd(),
16
+ detached: process.platform !== 'win32',
17
+ env: process.env,
18
+ stdio: ['ignore', logFd, logFd],
19
+ });
20
+
21
+ fs.closeSync(logFd);
22
+ child.unref();
23
+
24
+ if (!child.pid) {
25
+ process.stderr.write('Failed to start detached process.\n');
26
+ process.exit(1);
27
+ }
28
+
29
+ process.stdout.write(String(child.pid));
@@ -2,10 +2,81 @@
2
2
  set -Eeuo pipefail
3
3
 
4
4
  COZE_WORKSPACE_PATH="${COZE_WORKSPACE_PATH:-$(pwd)}"
5
- PORT="${DEPLOY_RUN_PORT:-${PORT:-<%= port %>}}"
5
+ PORT="${PORT:-<%= port %>}"
6
+ DEPLOY_RUN_PORT="${DEPLOY_RUN_PORT:-${PORT}}"
6
7
  cd "${COZE_WORKSPACE_PATH}"
7
8
 
8
- COZE_PHASER_GAME_ENV=PROD pnpm vite preview \
9
- --port "${PORT}" \
9
+ get_listening_pids() {
10
+ local port="$1"
11
+
12
+ if command -v lsof >/dev/null 2>&1; then
13
+ lsof -tiTCP:"${port}" -sTCP:LISTEN 2>/dev/null || true
14
+ elif command -v ss >/dev/null 2>&1; then
15
+ ss -H -lntp 2>/dev/null \
16
+ | awk -v port="${port}" '$4 ~ ":"port"$"' \
17
+ | grep -o 'pid=[0-9]*' \
18
+ | cut -d= -f2 \
19
+ | sort -u || true
20
+ else
21
+ echo "Warning: neither lsof nor ss found, cannot check port ${port}." >&2
22
+ fi
23
+ }
24
+
25
+ kill_port_if_listening() {
26
+ local port="$1"
27
+ local pids
28
+
29
+ pids="$(get_listening_pids "${port}")"
30
+ if [[ -z "${pids}" ]]; then
31
+ echo "Port ${port} is free."
32
+ return
33
+ fi
34
+
35
+ echo "Port ${port} is in use by PIDs: ${pids//$'\n'/ } (SIGKILL)"
36
+ echo "${pids}" | xargs kill -9 2>/dev/null || true
37
+ sleep 1
38
+
39
+ pids="$(get_listening_pids "${port}")"
40
+ if [[ -n "${pids}" ]]; then
41
+ echo "Failed to clear port ${port}; remaining PIDs: ${pids//$'\n'/ }." >&2
42
+ return 1
43
+ fi
44
+
45
+ echo "Port ${port} cleared."
46
+ }
47
+
48
+ echo "Clearing port ${DEPLOY_RUN_PORT} before start."
49
+ kill_port_if_listening "${DEPLOY_RUN_PORT}"
50
+
51
+ <% if (process.env.NODE_ENV === 'test') { %>
52
+ # Keep the process attached in tests so the test runner can collect logs and stop it.
53
+ exec env COZE_PHASER_GAME_ENV=PROD pnpm vite preview \
54
+ --port "${DEPLOY_RUN_PORT}" \
10
55
  --host 127.0.0.1 \
11
56
  --strictPort
57
+ <% } else { %>
58
+ LOG_DIR="${COZE_WORKSPACE_PATH}/logs"
59
+ LOG_FILE="${LOG_DIR}/phaser-start.log"
60
+ PID_FILE="${LOG_DIR}/phaser-start.pid"
61
+ mkdir -p "${LOG_DIR}"
62
+
63
+ echo "Starting Phaser production server on port ${DEPLOY_RUN_PORT}..."
64
+ server_pid="$(COZE_PHASER_GAME_ENV=PROD node scripts/spawn-detached.cjs \
65
+ "${LOG_FILE}" pnpm vite preview \
66
+ --port "${DEPLOY_RUN_PORT}" \
67
+ --host 127.0.0.1 \
68
+ --strictPort)"
69
+ echo "${server_pid}" > "${PID_FILE}"
70
+
71
+ sleep 1
72
+ if ! kill -0 "${server_pid}" 2>/dev/null; then
73
+ echo "Phaser production server failed to start. See ${LOG_FILE}." >&2
74
+ tail -n 20 "${LOG_FILE}" >&2 || true
75
+ rm -f "${PID_FILE}"
76
+ exit 1
77
+ fi
78
+
79
+ echo "Phaser production server started (PID: ${server_pid})."
80
+ echo "Log file: ${LOG_FILE}"
81
+ echo "PID file: ${PID_FILE}"
82
+ <% } %>
@@ -2,6 +2,7 @@
2
2
  import { spawn } from 'child_process';
3
3
  import { resolve, join, basename } from 'path';
4
4
  import { appendFileSync, openSync, closeSync, mkdirSync } from 'fs';
5
+ import { homedir } from 'os';
5
6
 
6
7
 
7
8
 
@@ -81,7 +82,8 @@ const config = {
81
82
  const projectRoot = resolve(outputPath);
82
83
 
83
84
  // Determine log directory
84
- const logDir = process.env.COZE_LOG_DIR || resolve(__dirname, '../.log');
85
+ const cozeHome = process.env.COZE_HOME || join(homedir(), '.coze');
86
+ const logDir = process.env.COZE_LOG_DIR || join(cozeHome, 'logs');
85
87
  mkdirSync(logDir, { recursive: true });
86
88
 
87
89
  // Use project name in log file to avoid conflicts
package/lib/cli.js CHANGED
@@ -1634,7 +1634,7 @@ function createNodeTransport() {
1634
1634
  };
1635
1635
  }
1636
1636
 
1637
- function _nullishCoalesce$d(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain$E(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }/**
1637
+ function _nullishCoalesce$c(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain$E(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }/**
1638
1638
  * Slardar CLI Reporter 主类
1639
1639
  * 封装 @slardar/base 的初始化和上报逻辑
1640
1640
  */
@@ -1691,7 +1691,7 @@ class SlardarCLIReporter {constructor() { SlardarCLIReporter.prototype.__init.ca
1691
1691
  release: config.release,
1692
1692
  env: config.env,
1693
1693
  name: config.name,
1694
- useLocalConfig: _nullishCoalesce$d(config.useLocalConfig, () => ( false)), // 默认使用服务端配置
1694
+ useLocalConfig: _nullishCoalesce$c(config.useLocalConfig, () => ( false)), // 默认使用服务端配置
1695
1695
  domain: config.domain,
1696
1696
  // 设置本地采样率为 100%,确保事件不被过滤
1697
1697
  sample: {
@@ -2113,7 +2113,7 @@ const EventBuilder = {
2113
2113
  };
2114
2114
 
2115
2115
  var name = "@coze-arch/cli";
2116
- var version = "0.0.36-alpha.844e20";
2116
+ var version = "0.0.36-alpha.a7a716";
2117
2117
  var description = "coze coding devtools cli";
2118
2118
  var license = "MIT";
2119
2119
  var author = "fanwenjie.fe@bytedance.com";
@@ -2389,7 +2389,7 @@ const flushSlardar = safeRun('flushSlardar', async () => {
2389
2389
  await reporter.flush();
2390
2390
  });
2391
2391
 
2392
- function _nullishCoalesce$c(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain$B(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }var LogLevel; (function (LogLevel) {
2392
+ function _nullishCoalesce$b(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain$B(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }var LogLevel; (function (LogLevel) {
2393
2393
  const ERROR = 0; LogLevel[LogLevel["ERROR"] = ERROR] = "ERROR";
2394
2394
  const WARN = 1; LogLevel[LogLevel["WARN"] = WARN] = "WARN";
2395
2395
  const SUCCESS = 2; LogLevel[LogLevel["SUCCESS"] = SUCCESS] = "SUCCESS";
@@ -2427,7 +2427,7 @@ class Logger {
2427
2427
 
2428
2428
  constructor(options = {}) {
2429
2429
  this.level = this.parseLogLevel(options.level);
2430
- this.useColor = _nullishCoalesce$c(options.useColor, () => ( this.isColorSupported()));
2430
+ this.useColor = _nullishCoalesce$b(options.useColor, () => ( this.isColorSupported()));
2431
2431
  this.prefix = options.prefix;
2432
2432
  }
2433
2433
 
@@ -2478,7 +2478,7 @@ class Logger {
2478
2478
 
2479
2479
  const icon = this.colorize(options.icon, options.color);
2480
2480
  const prefix = this.prefix ? `${icon} ${this.prefix}` : icon;
2481
- console.log(prefix, options.message, ...(_nullishCoalesce$c(options.args, () => ( []))));
2481
+ console.log(prefix, options.message, ...(_nullishCoalesce$b(options.args, () => ( []))));
2482
2482
  }
2483
2483
 
2484
2484
  error(message, ...args) {
@@ -2846,9 +2846,9 @@ const COZE_HOME_DIR = '.coze';
2846
2846
 
2847
2847
  /**
2848
2848
  * Logs directory name
2849
- * Default: .coze-logs
2849
+ * Default: ~/.coze/logs
2850
2850
  */
2851
- const LOGS_DIR = '.coze-logs';
2851
+ const LOGS_DIR = 'logs';
2852
2852
 
2853
2853
  /**
2854
2854
  * Get the Coze home directory path
@@ -2863,10 +2863,10 @@ const getCozeHome = () =>
2863
2863
  * Get the logs directory path
2864
2864
  * Can be customized via COZE_LOG_DIR environment variable
2865
2865
  *
2866
- * @returns Absolute path to logs directory (default: ~/.coze-logs)
2866
+ * @returns Absolute path to logs directory (default: ~/.coze/logs)
2867
2867
  */
2868
2868
  const getCozeLogsDir = () =>
2869
- process.env.COZE_LOG_DIR || path.join(os.homedir(), LOGS_DIR);
2869
+ process.env.COZE_LOG_DIR || path.join(getCozeHome(), LOGS_DIR);
2870
2870
 
2871
2871
  /**
2872
2872
  * Get path for a specific file/directory within Coze home
@@ -2897,7 +2897,7 @@ const getCozeFilePath = (relativePath) =>
2897
2897
  * @example
2898
2898
  * ```ts
2899
2899
  * const devLog = getCozeLogPath('dev.log');
2900
- * // Returns: ~/.coze-logs/dev.log
2900
+ * // Returns: ~/.coze/logs/dev.log
2901
2901
  * ```
2902
2902
  */
2903
2903
  const getCozeLogPath = (filename) =>
@@ -3831,12 +3831,12 @@ Scalar.PLAIN = 'PLAIN';
3831
3831
  Scalar.QUOTE_DOUBLE = 'QUOTE_DOUBLE';
3832
3832
  Scalar.QUOTE_SINGLE = 'QUOTE_SINGLE';
3833
3833
 
3834
- function _nullishCoalesce$b(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain$v(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
3834
+ function _nullishCoalesce$a(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain$v(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
3835
3835
  const defaultTagPrefix = 'tag:yaml.org,2002:';
3836
3836
  function findTagObject(value, tagName, tags) {
3837
3837
  if (tagName) {
3838
3838
  const match = tags.filter(t => t.tag === tagName);
3839
- const tagObj = _nullishCoalesce$b(match.find(t => !t.format), () => ( match[0]));
3839
+ const tagObj = _nullishCoalesce$a(match.find(t => !t.format), () => ( match[0]));
3840
3840
  if (!tagObj)
3841
3841
  throw new Error(`Tag ${tagName} not found`);
3842
3842
  return tagObj;
@@ -3868,7 +3868,7 @@ function createNode(value, tagName, ctx) {
3868
3868
  if (aliasDuplicateObjects && value && typeof value === 'object') {
3869
3869
  ref = sourceObjects.get(value);
3870
3870
  if (ref) {
3871
- _nullishCoalesce$b(ref.anchor, () => ( (ref.anchor = onAnchor(value))));
3871
+ _nullishCoalesce$a(ref.anchor, () => ( (ref.anchor = onAnchor(value))));
3872
3872
  return new Alias(ref.anchor);
3873
3873
  }
3874
3874
  else {
@@ -4554,7 +4554,7 @@ function stringifyString(item, ctx, onComment, onChompKeep) {
4554
4554
  return res;
4555
4555
  }
4556
4556
 
4557
- function _nullishCoalesce$a(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain$t(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
4557
+ function _nullishCoalesce$9(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain$t(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
4558
4558
  function createStringifyContext(doc, options) {
4559
4559
  const opt = Object.assign({
4560
4560
  blockQuote: true,
@@ -4601,7 +4601,7 @@ function getTagObject(tags, item) {
4601
4601
  if (item.tag) {
4602
4602
  const match = tags.filter(t => t.tag === item.tag);
4603
4603
  if (match.length > 0)
4604
- return _nullishCoalesce$a(match.find(t => t.format === item.format), () => ( match[0]));
4604
+ return _nullishCoalesce$9(match.find(t => t.format === item.format), () => ( match[0]));
4605
4605
  }
4606
4606
  let tagObj = undefined;
4607
4607
  let obj;
@@ -4614,14 +4614,14 @@ function getTagObject(tags, item) {
4614
4614
  match = testMatch;
4615
4615
  }
4616
4616
  tagObj =
4617
- _nullishCoalesce$a(match.find(t => t.format === item.format), () => ( match.find(t => !t.format)));
4617
+ _nullishCoalesce$9(match.find(t => t.format === item.format), () => ( match.find(t => !t.format)));
4618
4618
  }
4619
4619
  else {
4620
4620
  obj = item;
4621
4621
  tagObj = tags.find(t => t.nodeClass && obj instanceof t.nodeClass);
4622
4622
  }
4623
4623
  if (!tagObj) {
4624
- const name = _nullishCoalesce$a(_optionalChain$t([obj, 'optionalAccess', _3 => _3.constructor, 'optionalAccess', _4 => _4.name]), () => ( (obj === null ? 'null' : typeof obj)));
4624
+ const name = _nullishCoalesce$9(_optionalChain$t([obj, 'optionalAccess', _3 => _3.constructor, 'optionalAccess', _4 => _4.name]), () => ( (obj === null ? 'null' : typeof obj)));
4625
4625
  throw new Error(`Tag not resolved for ${name} value`);
4626
4626
  }
4627
4627
  return tagObj;
@@ -4636,7 +4636,7 @@ function stringifyProps(node, tagObj, { anchors, doc }) {
4636
4636
  anchors.add(anchor);
4637
4637
  props.push(`&${anchor}`);
4638
4638
  }
4639
- const tag = _nullishCoalesce$a(node.tag, () => ( (tagObj.default ? null : tagObj.tag)));
4639
+ const tag = _nullishCoalesce$9(node.tag, () => ( (tagObj.default ? null : tagObj.tag)));
4640
4640
  if (tag)
4641
4641
  props.push(doc.directives.tagString(tag));
4642
4642
  return props.join(' ');
@@ -4662,10 +4662,10 @@ function stringify(item, ctx, onComment, onChompKeep) {
4662
4662
  const node = isNode(item)
4663
4663
  ? item
4664
4664
  : ctx.doc.createNode(item, { onTagObj: o => (tagObj = o) });
4665
- _nullishCoalesce$a(tagObj, () => ( (tagObj = getTagObject(ctx.doc.schema.tags, node))));
4665
+ _nullishCoalesce$9(tagObj, () => ( (tagObj = getTagObject(ctx.doc.schema.tags, node))));
4666
4666
  const props = stringifyProps(node, tagObj, ctx);
4667
4667
  if (props.length > 0)
4668
- ctx.indentAtStart = (_nullishCoalesce$a(ctx.indentAtStart, () => ( 0))) + props.length + 1;
4668
+ ctx.indentAtStart = (_nullishCoalesce$9(ctx.indentAtStart, () => ( 0))) + props.length + 1;
4669
4669
  const str = typeof tagObj.stringify === 'function'
4670
4670
  ? tagObj.stringify(node, ctx, onComment, onChompKeep)
4671
4671
  : isScalar(node)
@@ -4678,7 +4678,7 @@ function stringify(item, ctx, onComment, onChompKeep) {
4678
4678
  : `${props}\n${ctx.indent}${str}`;
4679
4679
  }
4680
4680
 
4681
- function _nullishCoalesce$9(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }
4681
+ function _nullishCoalesce$8(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }
4682
4682
  function stringifyPair({ key, value }, ctx, onComment, onChompKeep) {
4683
4683
  const { allNullValues, doc, indent, indentStep, options: { commentString, indentSeq, simpleKeys } } = ctx;
4684
4684
  let keyComment = (isNode(key) && key.comment) || null;
@@ -4788,7 +4788,7 @@ function stringifyPair({ key, value }, ctx, onComment, onChompKeep) {
4788
4788
  const vs0 = valueStr[0];
4789
4789
  const nl0 = valueStr.indexOf('\n');
4790
4790
  const hasNewline = nl0 !== -1;
4791
- const flow = _nullishCoalesce$9(_nullishCoalesce$9(ctx.inFlow, () => ( value.flow)), () => ( value.items.length === 0));
4791
+ const flow = _nullishCoalesce$8(_nullishCoalesce$8(ctx.inFlow, () => ( value.flow)), () => ( value.items.length === 0));
4792
4792
  if (hasNewline || !flow) {
4793
4793
  let hasPropsLine = false;
4794
4794
  if (hasNewline && (vs0 === '&' || vs0 === '!')) {
@@ -4981,9 +4981,9 @@ class Pair {
4981
4981
  }
4982
4982
  }
4983
4983
 
4984
- function _nullishCoalesce$8(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain$p(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
4984
+ function _nullishCoalesce$7(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain$p(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
4985
4985
  function stringifyCollection(collection, ctx, options) {
4986
- const flow = _nullishCoalesce$8(ctx.inFlow, () => ( collection.flow));
4986
+ const flow = _nullishCoalesce$7(ctx.inFlow, () => ( collection.flow));
4987
4987
  const stringify = flow ? stringifyFlowCollection : stringifyBlockCollection;
4988
4988
  return stringify(collection, ctx, options);
4989
4989
  }
@@ -5130,7 +5130,7 @@ function addCommentBefore({ indent, options: { commentString } }, lines, comment
5130
5130
  }
5131
5131
  }
5132
5132
 
5133
- function _nullishCoalesce$7(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain$o(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
5133
+ function _nullishCoalesce$6(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain$o(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
5134
5134
  function findPair(items, key) {
5135
5135
  const k = isScalar(key) ? key.value : key;
5136
5136
  for (const it of items) {
@@ -5227,7 +5227,7 @@ class YAMLMap extends Collection {
5227
5227
  get(key, keepScalar) {
5228
5228
  const it = findPair(this.items, key);
5229
5229
  const node = _optionalChain$o([it, 'optionalAccess', _5 => _5.value]);
5230
- return _nullishCoalesce$7((!keepScalar && isScalar(node) ? node.value : node), () => ( undefined));
5230
+ return _nullishCoalesce$6((!keepScalar && isScalar(node) ? node.value : node), () => ( undefined));
5231
5231
  }
5232
5232
  has(key) {
5233
5233
  return !!findPair(this.items, key);
@@ -7414,7 +7414,7 @@ const getTemplatePatches = (
7414
7414
  ) =>
7415
7415
  patches.filter(patch => patch.template === template);
7416
7416
 
7417
- function _nullishCoalesce$6(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain$d(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
7417
+ function _nullishCoalesce$5(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain$d(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
7418
7418
  const DEFAULT_LEGACY_VERSION = 'legacy';
7419
7419
 
7420
7420
  const loadFlagsWithFallback = async () => {
@@ -7597,7 +7597,7 @@ const executePatch = async (
7597
7597
 
7598
7598
  if (options.dryRun) {
7599
7599
  logger.info(`Detected template: ${template}`);
7600
- logger.info(`Current version: ${_nullishCoalesce$6(projectVersion, () => ( DEFAULT_LEGACY_VERSION))}`);
7600
+ logger.info(`Current version: ${_nullishCoalesce$5(projectVersion, () => ( DEFAULT_LEGACY_VERSION))}`);
7601
7601
  logger.info(`Applied patches: ${appliedPatches.join(', ') || '(none)'}`);
7602
7602
  logger.info('Matched patches:');
7603
7603
  matchedPatches.forEach(patch => {
@@ -7662,7 +7662,7 @@ const registerCommand$5 = program => {
7662
7662
  );
7663
7663
  };
7664
7664
 
7665
- function _nullishCoalesce$5(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain$c(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
7665
+ function _nullishCoalesce$4(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain$c(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
7666
7666
  const d$1 = debug('coze-init-cli:run');
7667
7667
 
7668
7668
  /**
@@ -7811,7 +7811,7 @@ const executeRun = async (commandName, options = {}) => {
7811
7811
  const buildDuration = Date.now() - buildStartTime;
7812
7812
 
7813
7813
  if (code !== 0) {
7814
- const errorMessage = `Command exited with code ${_nullishCoalesce$5(code, () => ( 'unknown'))}${signal ? ` and signal ${signal}` : ''}`;
7814
+ const errorMessage = `Command exited with code ${_nullishCoalesce$4(code, () => ( 'unknown'))}${signal ? ` and signal ${signal}` : ''}`;
7815
7815
  logger.error(errorMessage);
7816
7816
  logger.error(`Check log file for details: ${logFilePath}`);
7817
7817
 
@@ -7823,12 +7823,12 @@ const executeRun = async (commandName, options = {}) => {
7823
7823
  categories: {
7824
7824
  fixDuration: String(fixDuration),
7825
7825
  buildDuration: String(buildDuration),
7826
- exitCode: String(_nullishCoalesce$5(code, () => ( 'unknown'))),
7826
+ exitCode: String(_nullishCoalesce$4(code, () => ( 'unknown'))),
7827
7827
  projectType,
7828
7828
  },
7829
7829
  errorContext: {
7830
- exitCode: String(_nullishCoalesce$5(code, () => ( 'unknown'))),
7831
- signal: _nullishCoalesce$5(signal, () => ( 'none')),
7830
+ exitCode: String(_nullishCoalesce$4(code, () => ( 'unknown'))),
7831
+ signal: _nullishCoalesce$4(signal, () => ( 'none')),
7832
7832
  logFile: logFilePath,
7833
7833
  projectType,
7834
7834
  },
@@ -8847,7 +8847,7 @@ const registerCommand$3 = program => {
8847
8847
  });
8848
8848
  };
8849
8849
 
8850
- function _nullishCoalesce$4(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }
8850
+ function _nullishCoalesce$3(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }
8851
8851
 
8852
8852
 
8853
8853
  const d = debug('coze-init-cli:check-bins');
@@ -8904,7 +8904,7 @@ const checkBins = async (cwd, fix) => {
8904
8904
 
8905
8905
  const bins =
8906
8906
  typeof depPkg.bin === 'string'
8907
- ? { [_nullishCoalesce$4(depName.split('/').pop(), () => ( depName))]: depPkg.bin }
8907
+ ? { [_nullishCoalesce$3(depName.split('/').pop(), () => ( depName))]: depPkg.bin }
8908
8908
  : depPkg.bin;
8909
8909
 
8910
8910
  d('%s declares bins: %o', depName, Object.keys(bins));
@@ -9848,7 +9848,7 @@ const execute = async (
9848
9848
  };
9849
9849
  };
9850
9850
 
9851
- function _nullishCoalesce$3(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }
9851
+ function _nullishCoalesce$2(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }
9852
9852
  /**
9853
9853
  * 运行 pnpm install
9854
9854
  */
@@ -9969,8 +9969,8 @@ const runDev = (projectPath) => {
9969
9969
  // 获取当前 CLI 的可执行文件路径
9970
9970
  // process.argv[0] 是 node,process.argv[1] 是 CLI 入口文件
9971
9971
  // 二者在 CLI 运行时必然存在,兜底空串仅为满足类型收窄,运行时不会命中
9972
- const nodeBin = _nullishCoalesce$3(process.argv[0], () => ( ''));
9973
- const cliPath = _nullishCoalesce$3(process.argv[1], () => ( ''));
9972
+ const nodeBin = _nullishCoalesce$2(process.argv[0], () => ( ''));
9973
+ const cliPath = _nullishCoalesce$2(process.argv[1], () => ( ''));
9974
9974
 
9975
9975
  try {
9976
9976
  // 使用通用的后台执行函数启动开发服务器
@@ -10040,7 +10040,7 @@ const executeTemplateEngineStep = async ctx => {
10040
10040
  templateName: ctx.templateName,
10041
10041
  outputPath: ctx.outputPath,
10042
10042
  command: ctx.command,
10043
- force: _nullishCoalesce$3(ctx.options.force, () => ( false)),
10043
+ force: _nullishCoalesce$2(ctx.options.force, () => ( false)),
10044
10044
  });
10045
10045
 
10046
10046
  // 保存结果到上下文
@@ -10317,7 +10317,7 @@ const registerCommand$1 = program => {
10317
10317
  .allowUnknownOption() // 允许透传参数
10318
10318
  .action(async (directory, options, command) => {
10319
10319
  // 位置参数优先级高于 --output 选项
10320
- const outputPath = _nullishCoalesce$3(directory, () => ( options.output));
10320
+ const outputPath = _nullishCoalesce$2(directory, () => ( options.output));
10321
10321
  // Always use force mode - overwrite existing files without conflict check
10322
10322
  const force = true;
10323
10323
  await executeInit({ ...options, output: outputPath, force }, command);
@@ -10832,6 +10832,7 @@ function _optionalChain$9(ops) { let lastAccessLHS = undefined; let value = ops[
10832
10832
 
10833
10833
 
10834
10834
 
10835
+
10835
10836
  const API_PREFIX = '/api/coding/deployment/v2';
10836
10837
  const CREATE_PROJECT_PATH = '/api/ideserver_api/project/create_vibe_project';
10837
10838
  const LIST_SPACES_PATH = '/api/playground_api/space/list';
@@ -11088,6 +11089,12 @@ class DeployApiClient {
11088
11089
  );
11089
11090
  }
11090
11091
 
11092
+ getOnlineEnvironment(appId) {
11093
+ return this.post(
11094
+ '/environment/get_online', { app_id: appId }, 'app_id',
11095
+ );
11096
+ }
11097
+
11091
11098
  checkRollbackDatabase(body) {
11092
11099
  return this.post(
11093
11100
  '/deploy_history/check_rollback_database', body, 'is_rollback_possible',
@@ -11509,6 +11516,7 @@ const resolveDeployHistoryId = (
11509
11516
  function _optionalChain$6(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
11510
11517
 
11511
11518
  const SOURCE_SNAPSHOT_BYTES = 20;
11519
+ const PROJECT_METADATA_FILE_MODE = 0o644;
11512
11520
 
11513
11521
  const isId = (value) =>
11514
11522
  typeof value === 'string' && /^\d+$/u.test(value);
@@ -11629,7 +11637,11 @@ const writeProjectBinding = async (
11629
11637
  }
11630
11638
  const tempPath = node_path.join(node_path.dirname(path), `.coze-${node_crypto.randomUUID()}.tmp`);
11631
11639
  try {
11632
- await promises.writeFile(tempPath, content, { encoding: 'utf8', mode: 0o600 });
11640
+ await promises.writeFile(tempPath, content, {
11641
+ encoding: 'utf8',
11642
+ mode: PROJECT_METADATA_FILE_MODE,
11643
+ });
11644
+ await promises.chmod(tempPath, PROJECT_METADATA_FILE_MODE);
11633
11645
  await promises.rename(tempPath, path);
11634
11646
  } finally {
11635
11647
  await promises.rm(tempPath, { force: true });
@@ -11653,8 +11665,9 @@ const ensureProjectMetadata = async (
11653
11665
  await promises.writeFile(
11654
11666
  node_path.join(sourceRoot, '.coze'),
11655
11667
  `[project]\nname = ${JSON.stringify(name)}\nproject_type = ${JSON.stringify(projectType)}\n`,
11656
- { encoding: 'utf8', mode: 0o600 },
11668
+ { encoding: 'utf8', mode: PROJECT_METADATA_FILE_MODE },
11657
11669
  );
11670
+ await promises.chmod(node_path.join(sourceRoot, '.coze'), PROJECT_METADATA_FILE_MODE);
11658
11671
  return readProjectMetadata(sourceRoot);
11659
11672
  };
11660
11673
 
@@ -11736,7 +11749,157 @@ const readDeployLocalContext = async (
11736
11749
  return { ...sourceSnapshot, metadata, isPagesDeployment };
11737
11750
  };
11738
11751
 
11752
+ // 服务端 deploy_app/list 的 page_size 上限,超了会被判参数错误。
11753
+ // 客户端先拦一道,是为了把错误说在本地(带上上限值),而不是回一句服务端的通用参数错误。
11754
+ const APP_LIST_MAX_PAGE_SIZE = 100;
11755
+
11756
+ // page_token 是**页码的十进制字符串**(服务端口径,与 deploy_history/list 一致),不是不透明游标。
11757
+ // 所以这里能、也应该在本地校验:`--page-token abc` 早报错,比发出去再被拒强。
11758
+ const parsePositiveInt = (
11759
+ raw,
11760
+ option,
11761
+ code,
11762
+ max,
11763
+ ) => {
11764
+ const value = Number(raw);
11765
+ if (!Number.isSafeInteger(value) || value <= 0) {
11766
+ throw new CliError(`${option} must be a positive integer.`, code, { [option]: raw });
11767
+ }
11768
+ if (max !== undefined && value > max) {
11769
+ throw new CliError(`${option} must not exceed ${String(max)}.`, code, { [option]: raw });
11770
+ }
11771
+ return value;
11772
+ };
11773
+
11774
+ // ⛔ 别再用 `Number(options.pageSize || 20)`:`--page-size abc` 会算出 NaN,
11775
+ // JSON.stringify 把它写成 null 发给服务端,最后表现为「参数没生效」而不是「参数写错了」。
11776
+ const parsePageSize = (
11777
+ raw,
11778
+ fallback,
11779
+ max,
11780
+ ) => {
11781
+ if (raw === undefined || raw === '') {
11782
+ return fallback;
11783
+ }
11784
+ return parsePositiveInt(raw, '--page-size', 'INVALID_PAGE_SIZE', max);
11785
+ };
11786
+
11787
+ const parsePageToken = (raw) => {
11788
+ if (raw === undefined || raw === '') {
11789
+ return undefined;
11790
+ }
11791
+ parsePositiveInt(raw, '--page-token', 'INVALID_PAGE_TOKEN');
11792
+ return raw;
11793
+ };
11794
+
11795
+
11796
+
11797
+
11798
+
11799
+
11800
+
11801
+ // collectAllPages 顺着 next_page_token 把所有页取回来。
11802
+ //
11803
+ // 服务端从「全量单页」改成真分页之后,`app list` 一次只回一页;想要「我的全部应用」就得翻页。
11804
+ // 与其让每个调用方各写一遍循环,不如给一个 --all。
11805
+ //
11806
+ // ⚠️ 不设页数上限截断:静默截断正是这次要修掉的毛病。只防死循环——服务端如果一直回同一个
11807
+ // token(或说 has_more 却不给 token),直接报错,而不是无限翻。
11808
+ const collectAllPages = async (
11809
+ fetchPage,
11810
+ ) => {
11811
+ const items = [];
11812
+ const seen = new Set();
11813
+ let pageToken;
11814
+ let pages = 0;
11815
+ for (;;) {
11816
+ const page = await fetchPage(pageToken);
11817
+ items.push(...(page.items || []));
11818
+ pages += 1;
11819
+ if (!page.has_more) {
11820
+ return { items, pages };
11821
+ }
11822
+ const next = page.next_page_token;
11823
+ if (!next || seen.has(next)) {
11824
+ throw new CliError(
11825
+ 'The server reported more pages but returned no usable next_page_token.',
11826
+ 'INVALID_PAGE_TOKEN',
11827
+ { next_page_token: next, pages },
11828
+ );
11829
+ }
11830
+ seen.add(next);
11831
+ pageToken = next;
11832
+ }
11833
+ };
11834
+
11835
+ async function _asyncOptionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = await fn(value); } else if (op === 'call' || op === 'optionalCall') { value = await fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
11836
+
11739
11837
  const registerDeployReadCommands = (deploy) => {
11838
+ deploy
11839
+ .command('status')
11840
+ .option('--app-id <appId>', 'Application ID')
11841
+ .option('--deploy-id <deployId>', 'Deployment history ID')
11842
+ .action(async (options, command) => {
11843
+ const runtime = await getRuntime(command);
11844
+ const appId = await requireAppId(runtime.cwd, getDeployAppIdOption(options, command));
11845
+ let deployHistoryId = options.deployId;
11846
+ if (!deployHistoryId) {
11847
+ deployHistoryId = await _asyncOptionalChain([(
11848
+ await runtime.client.listDeployHistory({ app_id: appId, page_size: 1 })
11849
+ ), 'access', async _ => _.deploy_history_list, 'optionalAccess', async _2 => _2[0], 'optionalAccess', async _3 => _3.deploy_history_id]);
11850
+ }
11851
+ if (!deployHistoryId) {
11852
+ throw new CliError('No deployment history found.', 'DEPLOYMENT_NOT_FOUND');
11853
+ }
11854
+ const history = await runtime.client.getDeployHistory({
11855
+ app_id: appId,
11856
+ deploy_history_id: deployHistoryId,
11857
+ });
11858
+ runtime.output.print({
11859
+ app_id: appId,
11860
+ deploy_history_id: deployHistoryId,
11861
+ status: getDeployStatusText(history.status),
11862
+ commit_hash: history.commit_hash,
11863
+ domains: history.domain_list || [],
11864
+ error_analysis: history.error_analysis,
11865
+ deploy_detail: formatDeployDetails(history),
11866
+ connector_data_list: history.connector_data_list || [],
11867
+ mobile_artifact_list: history.mobile_artifact_list || [],
11868
+ });
11869
+ });
11870
+
11871
+ deploy
11872
+ .command('list')
11873
+ .option('--app-id <appId>', 'Application ID')
11874
+ .option('--page-size <pageSize>', 'Page size', '10')
11875
+ .option('--page-token <pageToken>', 'Page token (page number)')
11876
+ .action(async (options, command) => {
11877
+ // 先在本地校验:`--page-size abc` 以前算出 NaN 发出去,表现成「参数没生效」。
11878
+ const pageSize = parsePageSize(options.pageSize, 10);
11879
+ const pageToken = parsePageToken(options.pageToken);
11880
+ const runtime = await getRuntime(command);
11881
+ const appId = await requireAppId(runtime.cwd, getDeployAppIdOption(options, command));
11882
+ const data = await runtime.client.listDeployHistory({
11883
+ app_id: appId,
11884
+ page_size: pageSize,
11885
+ page_token: pageToken,
11886
+ });
11887
+ runtime.output.print({
11888
+ items: (data.deploy_history_list || []).map(item => ({
11889
+ deploy_history_id: item.deploy_history_id,
11890
+ status: getDeployStatusText(item.status),
11891
+ commit_hash: item.commit_hash_short || item.commit_hash,
11892
+ created_at: item.created_at,
11893
+ can_rollback: item.can_rollback,
11894
+ deploy_detail: formatDeployDetails(item),
11895
+ connector_data_list: item.connector_data_list || [],
11896
+ mobile_artifact_list: item.mobile_artifact_list || [],
11897
+ })),
11898
+ next_page_token: data.next_page_token,
11899
+ has_more: data.has_more,
11900
+ });
11901
+ });
11902
+
11740
11903
  deploy
11741
11904
  .command('online')
11742
11905
  .description('Show the current online deployment')
@@ -11754,6 +11917,7 @@ const registerDeployReadCommands = (deploy) => {
11754
11917
  created_at: item.created_at,
11755
11918
  deploy_detail: formatDeployDetails(item),
11756
11919
  domains: item.domain_list || [],
11920
+ mobile_artifact_list: item.mobile_artifact_list || [],
11757
11921
  })),
11758
11922
  });
11759
11923
  });
@@ -11796,223 +11960,23 @@ const registerDeployReadCommands = (deploy) => {
11796
11960
  });
11797
11961
  };
11798
11962
 
11799
- function _nullishCoalesce$2(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }
11800
-
11801
- const ENV_KEY_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
11802
- const RESERVED_ENV_PREFIX = 'COZE_';
11803
-
11804
- const assertEnvKey = (key) => {
11805
- if (!ENV_KEY_PATTERN.test(key)) {
11806
- throw new CliError(
11807
- `Invalid environment variable name: ${key}`,
11808
- 'ENV_KEY_INVALID',
11809
- );
11810
- }
11811
- if (key.startsWith(RESERVED_ENV_PREFIX)) {
11812
- throw new CliError(
11813
- `${RESERVED_ENV_PREFIX} is reserved for platform environment variables.`,
11814
- 'ENV_KEY_RESERVED',
11815
- );
11816
- }
11817
- };
11818
-
11819
- const readEnvFile = async (sourceRoot) => {
11820
- try {
11821
- return await promises.readFile(node_path.join(sourceRoot, '.env'), 'utf8');
11822
- } catch (error) {
11823
- if ((error ).code === 'ENOENT') {
11824
- return undefined;
11825
- }
11826
- throw new CliError('Unable to read the local .env file.', 'ENV_FILE_READ_FAILED');
11827
- }
11828
- };
11829
-
11830
- const parseEnvFile = (content) => {
11831
- try {
11832
- const values = node_util.parseEnv(content);
11833
- if (Object.keys(values).some(key => !ENV_KEY_PATTERN.test(key))) {
11834
- throw new Error('invalid environment variable name');
11835
- }
11836
- return values;
11837
- } catch (e) {
11838
- throw new CliError('The local .env file is invalid.', 'ENV_FILE_INVALID');
11839
- }
11840
- };
11841
-
11842
- const assignmentPattern = (key) =>
11843
- new RegExp(`^\\s*(?:export\\s+)?${key}\\s*=`, 'u');
11844
-
11845
- const formatEnvValue = (value) => {
11846
- if (value.includes('\n') || value.includes('\r')) {
11847
- throw new CliError(
11848
- 'Environment variable values must be single-line.',
11849
- 'ENV_VALUE_INVALID',
11850
- );
11851
- }
11852
- if (!value.includes("'")) {
11853
- return `'${value}'`;
11854
- }
11855
- if (!value.includes('"')) {
11856
- return `"${value}"`;
11857
- }
11858
- if (value === value.trim() && !value.includes('#')) {
11859
- return value;
11860
- }
11861
- throw new CliError(
11862
- 'Environment variable values containing both quote types cannot also contain surrounding whitespace or #.',
11863
- 'ENV_VALUE_INVALID',
11864
- );
11865
- };
11866
-
11867
- const writeEnvFile = async (sourceRoot, content) => {
11868
- try {
11869
- await promises.writeFile(node_path.join(sourceRoot, '.env'), content, { encoding: 'utf8', mode: 0o600 });
11870
- } catch (e2) {
11871
- throw new CliError('Unable to write the local .env file.', 'ENV_FILE_WRITE_FAILED');
11872
- }
11873
- };
11874
-
11875
- const listProjectEnv = async (
11876
- sourceRoot,
11877
- ) => {
11878
- const content = await readEnvFile(sourceRoot);
11879
- if (content === undefined) {
11880
- return {};
11881
- }
11882
- return Object.fromEntries(
11883
- Object.entries(parseEnvFile(content))
11884
- .filter(([key]) => !key.startsWith(RESERVED_ENV_PREFIX))
11885
- .map(([key, value]) => [key, _nullishCoalesce$2(value, () => ( ''))]),
11886
- );
11887
- };
11888
-
11889
- const setProjectEnv = async (
11890
- sourceRoot,
11891
- key,
11892
- value,
11893
- ) => {
11894
- assertEnvKey(key);
11895
- const content = (await readEnvFile(sourceRoot)) || '';
11896
- if (content) {
11897
- parseEnvFile(content);
11898
- }
11899
- const lines = content.split(/\r?\n/u);
11900
- const pattern = assignmentPattern(key);
11901
- const replacement = `${key}=${formatEnvValue(value)}`;
11902
- const updatedLines = [];
11903
- let replaced = false;
11904
- for (const line of lines) {
11905
- if (pattern.test(line)) {
11906
- if (!replaced) {
11907
- updatedLines.push(replacement);
11908
- replaced = true;
11909
- }
11910
- } else {
11911
- updatedLines.push(line);
11912
- }
11913
- }
11914
- if (!replaced) {
11915
- while (updatedLines[updatedLines.length - 1] === '') {
11916
- updatedLines.pop();
11917
- }
11918
- updatedLines.push(replacement);
11919
- }
11920
- while (updatedLines[updatedLines.length - 1] === '') {
11921
- updatedLines.pop();
11922
- }
11923
- await writeEnvFile(sourceRoot, `${updatedLines.join('\n')}\n`);
11924
- };
11925
-
11926
- const deleteProjectEnv = async (
11927
- sourceRoot,
11928
- key,
11929
- ) => {
11930
- assertEnvKey(key);
11931
- const content = await readEnvFile(sourceRoot);
11932
- if (content === undefined) {
11933
- return false;
11934
- }
11935
- parseEnvFile(content);
11936
- const pattern = assignmentPattern(key);
11937
- const lines = content.split(/\r?\n/u);
11938
- const filtered = lines.filter(line => !pattern.test(line));
11939
- if (filtered.length === lines.length) {
11940
- return false;
11941
- }
11942
- await writeEnvFile(sourceRoot, filtered.join('\n'));
11943
- return true;
11944
- };
11945
-
11946
- const readProjectEnv = async (
11947
- sourceRoot,
11948
- ) => {
11949
- const content = await readEnvFile(sourceRoot);
11950
- if (content === undefined) {
11951
- return [];
11952
- }
11953
- const values = parseEnvFile(content);
11954
-
11955
- return Object.entries(values)
11956
- .filter(([key]) => !key.startsWith(RESERVED_ENV_PREFIX))
11957
- .map(([key, value]) => ({
11958
- secret_id: '',
11959
- secret_key: key,
11960
- secret_val: _nullishCoalesce$2(value, () => ( '')),
11961
- secret_type: 'user_custom',
11962
- }));
11963
- };
11964
-
11965
- const resolveSourceRoot = (cwd, options) =>
11966
- node_path.resolve(cwd, options.sourceRoot || '.');
11967
-
11968
- const addSourceRootOption = (command) =>
11969
- command.option('--source-root <sourceRoot>', 'Local project root', '.');
11970
-
11971
11963
  const registerEnv = (code) => {
11972
11964
  const env = code
11973
11965
  .command('env')
11974
- .description('Manage the local project .env file');
11966
+ .description('Inspect the current online environment snapshot');
11975
11967
 
11976
- addSourceRootOption(env.command('list').description('List local environment variables')).action(
11977
- async (options, command) => {
11978
- const runtime = await getRuntime(command);
11979
- const sourceRoot = resolveSourceRoot(runtime.cwd, options);
11980
- runtime.output.print({
11981
- source_root: sourceRoot,
11982
- variables: await listProjectEnv(sourceRoot),
11983
- });
11984
- },
11985
- );
11986
-
11987
- addSourceRootOption(
11988
- env
11989
- .command('set <key> <value>')
11990
- .description('Set a local environment variable'),
11991
- ).action(
11992
- async (
11993
- key,
11994
- value,
11995
- options,
11996
- command,
11997
- ) => {
11968
+ env
11969
+ .command('list')
11970
+ .description('List environment variables of the current online deployment')
11971
+ .option('--app-id <appId>', 'Application ID')
11972
+ .action(async (options, command) => {
11998
11973
  const runtime = await getRuntime(command);
11999
- const sourceRoot = resolveSourceRoot(runtime.cwd, options);
12000
- await setProjectEnv(sourceRoot, key, value);
12001
- runtime.output.print({ source_root: sourceRoot, key, updated: true });
12002
- },
12003
- );
12004
-
12005
- addSourceRootOption(
12006
- env.command('delete <key>').description('Delete a local environment variable'),
12007
- ).action(async (key, options, command) => {
12008
- const runtime = await getRuntime(command);
12009
- const sourceRoot = resolveSourceRoot(runtime.cwd, options);
12010
- runtime.output.print({
12011
- source_root: sourceRoot,
12012
- key,
12013
- deleted: await deleteProjectEnv(sourceRoot, key),
11974
+ const appId = await requireAppId(
11975
+ runtime.cwd,
11976
+ getDeployAppIdOption(options, command),
11977
+ );
11978
+ runtime.output.print(await runtime.client.getOnlineEnvironment(appId));
12014
11979
  });
12015
- });
12016
11980
  };
12017
11981
 
12018
11982
  function _nullishCoalesce$1(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain$4(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
@@ -12150,89 +12114,6 @@ const registerMiniProgram = (code) => {
12150
12114
  });
12151
12115
  };
12152
12116
 
12153
- // 服务端 deploy_app/list 的 page_size 上限,超了会被判参数错误。
12154
- // 客户端先拦一道,是为了把错误说在本地(带上上限值),而不是回一句服务端的通用参数错误。
12155
- const APP_LIST_MAX_PAGE_SIZE = 100;
12156
-
12157
- // page_token 是**页码的十进制字符串**(服务端口径,与 deploy_history/list 一致),不是不透明游标。
12158
- // 所以这里能、也应该在本地校验:`--page-token abc` 早报错,比发出去再被拒强。
12159
- const parsePositiveInt = (
12160
- raw,
12161
- option,
12162
- code,
12163
- max,
12164
- ) => {
12165
- const value = Number(raw);
12166
- if (!Number.isSafeInteger(value) || value <= 0) {
12167
- throw new CliError(`${option} must be a positive integer.`, code, { [option]: raw });
12168
- }
12169
- if (max !== undefined && value > max) {
12170
- throw new CliError(`${option} must not exceed ${String(max)}.`, code, { [option]: raw });
12171
- }
12172
- return value;
12173
- };
12174
-
12175
- // ⛔ 别再用 `Number(options.pageSize || 20)`:`--page-size abc` 会算出 NaN,
12176
- // JSON.stringify 把它写成 null 发给服务端,最后表现为「参数没生效」而不是「参数写错了」。
12177
- const parsePageSize = (
12178
- raw,
12179
- fallback,
12180
- max,
12181
- ) => {
12182
- if (raw === undefined || raw === '') {
12183
- return fallback;
12184
- }
12185
- return parsePositiveInt(raw, '--page-size', 'INVALID_PAGE_SIZE', max);
12186
- };
12187
-
12188
- const parsePageToken = (raw) => {
12189
- if (raw === undefined || raw === '') {
12190
- return undefined;
12191
- }
12192
- parsePositiveInt(raw, '--page-token', 'INVALID_PAGE_TOKEN');
12193
- return raw;
12194
- };
12195
-
12196
-
12197
-
12198
-
12199
-
12200
-
12201
-
12202
- // collectAllPages 顺着 next_page_token 把所有页取回来。
12203
- //
12204
- // 服务端从「全量单页」改成真分页之后,`app list` 一次只回一页;想要「我的全部应用」就得翻页。
12205
- // 与其让每个调用方各写一遍循环,不如给一个 --all。
12206
- //
12207
- // ⚠️ 不设页数上限截断:静默截断正是这次要修掉的毛病。只防死循环——服务端如果一直回同一个
12208
- // token(或说 has_more 却不给 token),直接报错,而不是无限翻。
12209
- const collectAllPages = async (
12210
- fetchPage,
12211
- ) => {
12212
- const items = [];
12213
- const seen = new Set();
12214
- let pageToken;
12215
- let pages = 0;
12216
- for (;;) {
12217
- const page = await fetchPage(pageToken);
12218
- items.push(...(page.items || []));
12219
- pages += 1;
12220
- if (!page.has_more) {
12221
- return { items, pages };
12222
- }
12223
- const next = page.next_page_token;
12224
- if (!next || seen.has(next)) {
12225
- throw new CliError(
12226
- 'The server reported more pages but returned no usable next_page_token.',
12227
- 'INVALID_PAGE_TOKEN',
12228
- { next_page_token: next, pages },
12229
- );
12230
- }
12231
- seen.add(next);
12232
- pageToken = next;
12233
- }
12234
- };
12235
-
12236
12117
  function _optionalChain$3(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
12237
12118
 
12238
12119
  const POLL_INTERVAL_MS = 3000;
@@ -12946,7 +12827,7 @@ const createDeploymentWithSourcePackage = async (
12946
12827
  return { uploadMode: 'direct' , result };
12947
12828
  };
12948
12829
 
12949
- function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } async function _asyncOptionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = await fn(value); } else if (op === 'call' || op === 'optionalCall') { value = await fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
12830
+ function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
12950
12831
  const SUPPORTED_MINIPROGRAM_CONNECTOR_IDS = new Set(['10000127', '10000126']);
12951
12832
  const collectConnectorId = (value, previous) => [
12952
12833
  ...previous,
@@ -13093,8 +12974,25 @@ const registerDeploy = (code) => {
13093
12974
  }
13094
12975
  let encryptEnvVariable;
13095
12976
  if (applicationType !== 'pages') {
13096
- runtime.output.debug('[deploy] Reading and encrypting local environment variables...');
13097
- const envSecrets = await readProjectEnv(sourceRoot);
12977
+ runtime.output.debug('[deploy] Loading and encrypting online environment variables...');
12978
+ const onlineEnvironment = appId
12979
+ ? await runtime.client.getOnlineEnvironment(appId)
12980
+ : undefined;
12981
+ if (onlineEnvironment && onlineEnvironment.snapshot_status >= 3) {
12982
+ throw new CliError(
12983
+ onlineEnvironment.status_message ||
12984
+ 'The current online environment snapshot is unavailable.',
12985
+ 'ONLINE_ENVIRONMENT_UNAVAILABLE',
12986
+ );
12987
+ }
12988
+ const envSecrets = (_optionalChain([onlineEnvironment, 'optionalAccess', _ => _.variables]) || [])
12989
+ .filter(variable => variable.source === 'user')
12990
+ .map(variable => ({
12991
+ secret_id: '',
12992
+ secret_key: variable.key,
12993
+ secret_val: variable.value,
12994
+ secret_type: 'user_custom' ,
12995
+ }));
13098
12996
  const encrypted = await runtime.client.encryptProjectSecret(projectId, envSecrets);
13099
12997
  encryptEnvVariable = encrypted.sealed_secrets;
13100
12998
  if (!encryptEnvVariable) {
@@ -13168,73 +13066,11 @@ const registerDeploy = (code) => {
13168
13066
  deploy_history_id: deployHistoryId,
13169
13067
  version: result.version,
13170
13068
  commit_hash: commitHash,
13171
- status: getDeployStatusText(_nullishCoalesce(_optionalChain([history, 'optionalAccess', _ => _.status]), () => ( result.status))),
13069
+ status: getDeployStatusText(_nullishCoalesce(_optionalChain([history, 'optionalAccess', _2 => _2.status]), () => ( result.status))),
13172
13070
  source_package_size_bytes: sourcePackage.sizeBytes,
13173
13071
  upload_mode: deployment.uploadMode,
13174
13072
  local_link: appId && !projectCreated ? 'unchanged' : 'written',
13175
- });
13176
- });
13177
-
13178
- deploy
13179
- .command('status')
13180
- .option('--app-id <appId>', 'Application ID')
13181
- .option('--deploy-id <deployId>', 'Deployment history ID')
13182
- .action(async (options, command) => {
13183
- const runtime = await getRuntime(command);
13184
- const appId = await requireAppId(runtime.cwd, getDeployAppIdOption(options, command));
13185
- let deployHistoryId = options.deployId;
13186
- if (!deployHistoryId) {
13187
- deployHistoryId = await _asyncOptionalChain([(
13188
- await runtime.client.listDeployHistory({ app_id: appId, page_size: 1 })
13189
- ), 'access', async _2 => _2.deploy_history_list, 'optionalAccess', async _3 => _3[0], 'optionalAccess', async _4 => _4.deploy_history_id]);
13190
- }
13191
- if (!deployHistoryId) {
13192
- throw new CliError('No deployment history found.', 'DEPLOYMENT_NOT_FOUND');
13193
- }
13194
- const history = await runtime.client.getDeployHistory({
13195
- app_id: appId,
13196
- deploy_history_id: deployHistoryId,
13197
- });
13198
- runtime.output.print({
13199
- app_id: appId,
13200
- deploy_history_id: deployHistoryId,
13201
- status: getDeployStatusText(history.status),
13202
- commit_hash: history.commit_hash,
13203
- domains: history.domain_list || [],
13204
- error_analysis: history.error_analysis,
13205
- deploy_detail: formatDeployDetails(history),
13206
- connector_data_list: history.connector_data_list || [],
13207
- });
13208
- });
13209
-
13210
- deploy
13211
- .command('list')
13212
- .option('--app-id <appId>', 'Application ID')
13213
- .option('--page-size <pageSize>', 'Page size', '10')
13214
- .option('--page-token <pageToken>', 'Page token (page number)')
13215
- .action(async (options, command) => {
13216
- // 先在本地校验:`--page-size abc` 以前算出 NaN 发出去,表现成「参数没生效」。
13217
- const pageSize = parsePageSize(options.pageSize, 10);
13218
- const pageToken = parsePageToken(options.pageToken);
13219
- const runtime = await getRuntime(command);
13220
- const appId = await requireAppId(runtime.cwd, getDeployAppIdOption(options, command));
13221
- const data = await runtime.client.listDeployHistory({
13222
- app_id: appId,
13223
- page_size: pageSize,
13224
- page_token: pageToken,
13225
- });
13226
- runtime.output.print({
13227
- items: (data.deploy_history_list || []).map(item => ({
13228
- deploy_history_id: item.deploy_history_id,
13229
- status: getDeployStatusText(item.status),
13230
- commit_hash: item.commit_hash_short || item.commit_hash,
13231
- created_at: item.created_at,
13232
- can_rollback: item.can_rollback,
13233
- deploy_detail: formatDeployDetails(item),
13234
- connector_data_list: item.connector_data_list || [],
13235
- })),
13236
- next_page_token: data.next_page_token,
13237
- has_more: data.has_more,
13073
+ mobile_artifact_list: _optionalChain([history, 'optionalAccess', _3 => _3.mobile_artifact_list]) || [],
13238
13074
  });
13239
13075
  });
13240
13076
 
@@ -13337,7 +13173,7 @@ const registerDeploy = (code) => {
13337
13173
  .action(async (options, command) => {
13338
13174
  const runtime = await getRuntime(command);
13339
13175
  const appId = await requireAppId(runtime.cwd, getDeployAppIdOption(options, command));
13340
- let key = _optionalChain([options, 'access', _5 => _5.key, 'optionalAccess', _6 => _6.trim, 'call', _7 => _7()]);
13176
+ let key = _optionalChain([options, 'access', _4 => _4.key, 'optionalAccess', _5 => _5.trim, 'call', _6 => _6()]);
13341
13177
  if (!key) {
13342
13178
  const history = await runtime.client.getDeployHistory({
13343
13179
  app_id: appId,
@@ -13379,7 +13215,7 @@ const registerDeploy = (code) => {
13379
13215
  const runtime = await getRuntime(command);
13380
13216
  const appId = await requireAppId(runtime.cwd, getDeployAppIdOption(options, command));
13381
13217
  const application = await runtime.client.getApplication(appId);
13382
- const commitHash = options.commitId || _optionalChain([application, 'access', _8 => _8.latest_deployment, 'optionalAccess', _9 => _9.commit_hash]);
13218
+ const commitHash = options.commitId || _optionalChain([application, 'access', _7 => _7.latest_deployment, 'optionalAccess', _8 => _8.commit_hash]);
13383
13219
  if (!commitHash) {
13384
13220
  throw new CliError('No deployment commit is available.', 'DEPLOYMENT_NOT_FOUND');
13385
13221
  }
@@ -36,6 +36,7 @@ const LOCAL_METADATA_FILES = new Set([
36
36
  ]);
37
37
  const UPLOAD_SESSION_TEMP_PREFIX = '.coze-deploy-upload-';
38
38
  const REPRODUCIBLE_ARCHIVE_MTIME = new Date(0);
39
+ const PROJECT_METADATA_FILE_MODE = 0o644;
39
40
 
40
41
  const parseArguments = argv => {
41
42
  const positional = [];
@@ -193,6 +194,11 @@ const createTarGzWithoutRoot = async (sourceDir, outputPath, excludeCozeFile = f
193
194
  filter: archivePath => shouldInclude(archivePath, excludeCozeFile),
194
195
  gzip: true,
195
196
  mtime: REPRODUCIBLE_ARCHIVE_MTIME,
197
+ onWriteEntry: entry => {
198
+ if (entry.path === '.coze' && entry.stat?.isFile()) {
199
+ entry.stat.mode = PROJECT_METADATA_FILE_MODE;
200
+ }
201
+ },
196
202
  portable: true,
197
203
  },
198
204
  entries,
@@ -30,6 +30,7 @@ EXCLUDED_PARTS = {
30
30
  UPLOAD_SESSION_FILENAME = ".coze-deploy-upload.json"
31
31
  UPLOAD_SESSION_TEMP_PREFIX = ".coze-deploy-upload-"
32
32
  HOST_LINK_FILENAME = ".host.json"
33
+ PROJECT_METADATA_FILE_MODE = 0o644
33
34
 
34
35
 
35
36
  def build_command_env():
@@ -116,6 +117,8 @@ def should_exclude(tar_info: tarfile.TarInfo, exclude_coze_file=False):
116
117
  return None
117
118
  if any(part in EXCLUDED_PARTS for part in parts):
118
119
  return None
120
+ if parts == (".coze",) and tar_info.isfile():
121
+ tar_info.mode = PROJECT_METADATA_FILE_MODE
119
122
  return tar_info
120
123
 
121
124
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coze-arch/cli",
3
- "version": "0.0.36-alpha.844e20",
3
+ "version": "0.0.36-alpha.a7a716",
4
4
  "private": false,
5
5
  "description": "coze coding devtools cli",
6
6
  "license": "MIT",