@coze-arch/cli 0.0.37 → 0.0.39-alpha.bdff32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (168) hide show
  1. package/README.md +69 -104
  2. package/docs/deploy.md +181 -0
  3. package/lib/__templates__/expo/.coze +5 -0
  4. package/lib/__templates__/expo/.cozeproj/scripts/dev_build.ps1 +10 -0
  5. package/lib/__templates__/expo/.cozeproj/scripts/dev_build.sh +4 -0
  6. package/lib/__templates__/expo/.cozeproj/scripts/dev_run.ps1 +74 -0
  7. package/lib/__templates__/expo/.cozeproj/scripts/dev_run.sh +108 -19
  8. package/lib/__templates__/expo/.cozeproj/scripts/prod_build.ps1 +15 -0
  9. package/lib/__templates__/expo/.cozeproj/scripts/prod_run.ps1 +10 -0
  10. package/lib/__templates__/expo/.cozeproj/scripts/prod_run.sh +1 -1
  11. package/lib/__templates__/expo/.cozeproj/scripts/server_dev_run.sh +1 -1
  12. package/lib/__templates__/expo/.cozeproj/scripts/validate.ps1 +7 -0
  13. package/lib/__templates__/expo/client/metro.config.js +3 -1
  14. package/lib/__templates__/expo/pnpm-lock.yaml +5 -5
  15. package/lib/__templates__/expo/server/package.json +2 -2
  16. package/lib/__templates__/expo/server/src/index.ts +1 -1
  17. package/lib/__templates__/expo/template.config.js +11 -2
  18. package/lib/__templates__/native-static/.coze +4 -2
  19. package/lib/__templates__/native-static/scripts/serve.ps1 +7 -0
  20. package/lib/__templates__/nextjs/.coze +5 -0
  21. package/lib/__templates__/nextjs/package.json +7 -2
  22. package/lib/__templates__/nextjs/pnpm-lock.yaml +59 -334
  23. package/lib/__templates__/nextjs/scripts/build.ps1 +16 -0
  24. package/lib/__templates__/nextjs/scripts/dev.ps1 +63 -0
  25. package/lib/__templates__/nextjs/scripts/dev.sh +234 -7
  26. package/lib/__templates__/nextjs/scripts/prepare.ps1 +18 -0
  27. package/lib/__templates__/nextjs/scripts/start.ps1 +11 -0
  28. package/lib/__templates__/nextjs/scripts/validate.ps1 +8 -0
  29. package/lib/__templates__/nextjs/template.config.js +4 -2
  30. package/lib/__templates__/nuxt-vue/.coze +5 -0
  31. package/lib/__templates__/nuxt-vue/package.json +1 -1
  32. package/lib/__templates__/nuxt-vue/pnpm-lock.yaml +5 -5
  33. package/lib/__templates__/nuxt-vue/scripts/build.ps1 +12 -0
  34. package/lib/__templates__/nuxt-vue/scripts/dev.ps1 +63 -0
  35. package/lib/__templates__/nuxt-vue/scripts/dev.sh +232 -3
  36. package/lib/__templates__/nuxt-vue/scripts/prepare.ps1 +12 -0
  37. package/lib/__templates__/nuxt-vue/scripts/start.ps1 +11 -0
  38. package/lib/__templates__/nuxt-vue/scripts/validate.ps1 +8 -0
  39. package/lib/__templates__/phaser/.coze +18 -0
  40. package/lib/__templates__/phaser/README.md +45 -0
  41. package/lib/__templates__/phaser/_gitignore +23 -0
  42. package/lib/__templates__/phaser/_npmrc +14 -0
  43. package/lib/__templates__/phaser/assets/image_sequence/coze-game-loading/frame_0001.png +0 -0
  44. package/lib/__templates__/phaser/assets/image_sequence/coze-game-loading/frame_0002.png +0 -0
  45. package/lib/__templates__/phaser/assets/image_sequence/coze-game-loading/frame_0003.png +0 -0
  46. package/lib/__templates__/phaser/assets/image_sequence/coze-game-loading/frame_0004.png +0 -0
  47. package/lib/__templates__/phaser/assets/image_sequence/coze-game-loading/frame_0005.png +0 -0
  48. package/lib/__templates__/phaser/assets/image_sequence/coze-game-loading/frame_0006.png +0 -0
  49. package/lib/__templates__/phaser/assets/image_sequence/coze-game-loading/frame_0007.png +0 -0
  50. package/lib/__templates__/phaser/assets/image_sequence/coze-game-loading/frame_0008.png +0 -0
  51. package/lib/__templates__/phaser/assets/image_sequence/coze-game-loading/frame_0009.png +0 -0
  52. package/lib/__templates__/phaser/assets/image_sequence/coze-game-loading/frame_0010.png +0 -0
  53. package/lib/__templates__/phaser/assets/image_sequence/coze-game-loading/frame_0011.png +0 -0
  54. package/lib/__templates__/phaser/assets/image_sequence/coze-game-loading/frame_0012.png +0 -0
  55. package/lib/__templates__/phaser/assets/image_sequence/coze-game-loading/frame_0013.png +0 -0
  56. package/lib/__templates__/phaser/assets/image_sequence/coze-game-loading/frame_0014.png +0 -0
  57. package/lib/__templates__/phaser/assets/image_sequence/coze-game-loading/frame_0015.png +0 -0
  58. package/lib/__templates__/phaser/assets/image_sequence/coze-game-loading/frame_0016.png +0 -0
  59. package/lib/__templates__/phaser/assets/image_sequence/coze-game-loading/frame_0017.png +0 -0
  60. package/lib/__templates__/phaser/assets/image_sequence/coze-game-loading/frame_0018.png +0 -0
  61. package/lib/__templates__/phaser/assets/image_sequence/coze-game-loading/frame_0019.png +0 -0
  62. package/lib/__templates__/phaser/assets/image_sequence/coze-game-loading/frame_0020.png +0 -0
  63. package/lib/__templates__/phaser/assets/image_sequence/coze-game-loading/frame_0021.png +0 -0
  64. package/lib/__templates__/phaser/assets/image_sequence/coze-game-loading/frame_0022.png +0 -0
  65. package/lib/__templates__/phaser/assets/image_sequence/coze-game-loading/frame_0023.png +0 -0
  66. package/lib/__templates__/phaser/assets/image_sequence/coze-game-loading/frame_0024.png +0 -0
  67. package/lib/__templates__/phaser/assets/image_sequence/coze-game-loading/manifest.json +11 -0
  68. package/lib/__templates__/phaser/debug-runtime/flow-graph.json +20 -0
  69. package/lib/__templates__/phaser/index.html +12 -0
  70. package/lib/__templates__/phaser/package.json +31 -0
  71. package/lib/__templates__/phaser/pnpm-lock.yaml +661 -0
  72. package/lib/__templates__/phaser/scripts/build.ps1 +12 -0
  73. package/lib/__templates__/phaser/scripts/build.sh +8 -0
  74. package/lib/__templates__/phaser/scripts/dev.ps1 +49 -0
  75. package/lib/__templates__/phaser/scripts/dev.sh +82 -0
  76. package/lib/__templates__/phaser/scripts/prepare.ps1 +8 -0
  77. package/lib/__templates__/phaser/scripts/prepare.sh +7 -0
  78. package/lib/__templates__/phaser/scripts/spawn-detached.cjs +29 -0
  79. package/lib/__templates__/phaser/scripts/start.ps1 +49 -0
  80. package/lib/__templates__/phaser/scripts/start.sh +82 -0
  81. package/lib/__templates__/phaser/scripts/validate.ps1 +7 -0
  82. package/lib/__templates__/phaser/scripts/validate.sh +7 -0
  83. package/lib/__templates__/phaser/src/assets.ts +15 -0
  84. package/lib/__templates__/phaser/src/global.d.ts +39 -0
  85. package/lib/__templates__/phaser/src/main.ts +28 -0
  86. package/lib/__templates__/phaser/src/scene/BootScene.ts +213 -0
  87. package/lib/__templates__/phaser/src/scene/DevLoadingScene.ts +69 -0
  88. package/lib/__templates__/phaser/src/style.css +28 -0
  89. package/lib/__templates__/phaser/src/types.ts +32 -0
  90. package/lib/__templates__/phaser/src/utils/asset-loader.ts +319 -0
  91. package/lib/__templates__/phaser/src/utils/index.ts +2 -0
  92. package/lib/__templates__/phaser/src/utils/mark-editable.ts +13 -0
  93. package/lib/__templates__/phaser/template.config.js +43 -0
  94. package/lib/__templates__/phaser/tsconfig.json +23 -0
  95. package/lib/__templates__/phaser/vite.config.ts +96 -0
  96. package/lib/__templates__/phaser-static/.coze +15 -0
  97. package/lib/__templates__/phaser-static/README.md +40 -0
  98. package/lib/__templates__/phaser-static/_gitignore +6 -0
  99. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0001.png +0 -0
  100. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0002.png +0 -0
  101. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0003.png +0 -0
  102. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0004.png +0 -0
  103. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0005.png +0 -0
  104. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0006.png +0 -0
  105. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0007.png +0 -0
  106. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0008.png +0 -0
  107. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0009.png +0 -0
  108. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0010.png +0 -0
  109. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0011.png +0 -0
  110. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0012.png +0 -0
  111. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0013.png +0 -0
  112. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0014.png +0 -0
  113. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0015.png +0 -0
  114. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0016.png +0 -0
  115. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0017.png +0 -0
  116. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0018.png +0 -0
  117. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0019.png +0 -0
  118. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0020.png +0 -0
  119. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0021.png +0 -0
  120. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0022.png +0 -0
  121. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0023.png +0 -0
  122. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0024.png +0 -0
  123. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/manifest.json +11 -0
  124. package/lib/__templates__/phaser-static/debug-runtime/flow-graph.json +20 -0
  125. package/lib/__templates__/phaser-static/index.html +17 -0
  126. package/lib/__templates__/phaser-static/scripts/serve.ps1 +7 -0
  127. package/lib/__templates__/phaser-static/src/assets.js +15 -0
  128. package/lib/__templates__/phaser-static/src/main.js +26 -0
  129. package/lib/__templates__/phaser-static/src/phaser.js +7 -0
  130. package/lib/__templates__/phaser-static/src/scene/BootScene.js +205 -0
  131. package/lib/__templates__/phaser-static/src/scene/DevLoadingScene.js +67 -0
  132. package/lib/__templates__/phaser-static/src/style.css +28 -0
  133. package/lib/__templates__/phaser-static/src/utils/asset-loader.js +267 -0
  134. package/lib/__templates__/phaser-static/src/utils/index.js +2 -0
  135. package/lib/__templates__/phaser-static/src/utils/mark-editable.js +3 -0
  136. package/lib/__templates__/phaser-static/template.config.js +35 -0
  137. package/lib/__templates__/pi-agent/package.json +1 -1
  138. package/lib/__templates__/pi-agent/pnpm-lock.yaml +5 -5
  139. package/lib/__templates__/taro/.coze +6 -0
  140. package/lib/__templates__/taro/.cozeproj/scripts/deploy_build.ps1 +10 -0
  141. package/lib/__templates__/taro/.cozeproj/scripts/deploy_run.ps1 +8 -0
  142. package/lib/__templates__/taro/.cozeproj/scripts/deploy_run.sh +1 -1
  143. package/lib/__templates__/taro/.cozeproj/scripts/dev_build.ps1 +3 -0
  144. package/lib/__templates__/taro/.cozeproj/scripts/dev_run.ps1 +62 -0
  145. package/lib/__templates__/taro/.cozeproj/scripts/dev_run.sh +178 -68
  146. package/lib/__templates__/taro/.cozeproj/scripts/pack.ps1 +7 -0
  147. package/lib/__templates__/taro/.cozeproj/scripts/validate.ps1 +7 -0
  148. package/lib/__templates__/taro/AGENTS.md +11 -7
  149. package/lib/__templates__/taro/README.md +4 -4
  150. package/lib/__templates__/taro/config/index.ts +10 -2
  151. package/lib/__templates__/taro/pnpm-lock.yaml +5 -5
  152. package/lib/__templates__/taro/server/package.json +1 -1
  153. package/lib/__templates__/taro/server/src/main.ts +8 -2
  154. package/lib/__templates__/templates.json +51 -1
  155. package/lib/__templates__/vite/.coze +5 -0
  156. package/lib/__templates__/vite/package.json +1 -1
  157. package/lib/__templates__/vite/pnpm-lock.yaml +5 -5
  158. package/lib/__templates__/vite/scripts/build.ps1 +16 -0
  159. package/lib/__templates__/vite/scripts/dev.ps1 +63 -0
  160. package/lib/__templates__/vite/scripts/dev.sh +110 -1
  161. package/lib/__templates__/vite/scripts/prepare.ps1 +18 -0
  162. package/lib/__templates__/vite/scripts/start.ps1 +11 -0
  163. package/lib/__templates__/vite/scripts/validate.ps1 +8 -0
  164. package/lib/__templates__/vite/template.config.js +4 -2
  165. package/lib/cli.js +3719 -211
  166. package/lib/deploy/package-project.js +244 -0
  167. package/lib/deploy/package-project.py +183 -0
  168. package/package.json +5 -2
package/lib/cli.js CHANGED
@@ -14,7 +14,7 @@ var perf_hooks = require('perf_hooks');
14
14
  var fs$1 = require('fs/promises');
15
15
  var os = require('os');
16
16
  var jsYaml = require('js-yaml');
17
- var toml = require('@iarna/toml');
17
+ var TOML = require('@iarna/toml');
18
18
  var crypto = require('crypto');
19
19
  var fastGlob = require('fast-glob');
20
20
  var child_process = require('child_process');
@@ -23,6 +23,13 @@ var Ajv = require('ajv');
23
23
  var minimist = require('minimist');
24
24
  var changeCase = require('change-case');
25
25
  var ejs = require('ejs');
26
+ var node_os = require('node:os');
27
+ var promises = require('node:fs/promises');
28
+ var node_crypto = require('node:crypto');
29
+ var node_child_process = require('node:child_process');
30
+ var node_util = require('node:util');
31
+ var tar = require('tar');
32
+ var node_stream = require('node:stream');
26
33
 
27
34
  /**
28
35
  * 读取 templates.json 配置
@@ -1628,7 +1635,7 @@ function createNodeTransport() {
1628
1635
  };
1629
1636
  }
1630
1637
 
1631
- 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; }/**
1638
+ function _nullishCoalesce$c(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain$G(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; }/**
1632
1639
  * Slardar CLI Reporter 主类
1633
1640
  * 封装 @slardar/base 的初始化和上报逻辑
1634
1641
  */
@@ -1685,7 +1692,7 @@ class SlardarCLIReporter {constructor() { SlardarCLIReporter.prototype.__init.ca
1685
1692
  release: config.release,
1686
1693
  env: config.env,
1687
1694
  name: config.name,
1688
- useLocalConfig: _nullishCoalesce$a(config.useLocalConfig, () => ( false)), // 默认使用服务端配置
1695
+ useLocalConfig: _nullishCoalesce$c(config.useLocalConfig, () => ( false)), // 默认使用服务端配置
1689
1696
  domain: config.domain,
1690
1697
  // 设置本地采样率为 100%,确保事件不被过滤
1691
1698
  sample: {
@@ -1700,7 +1707,7 @@ class SlardarCLIReporter {constructor() { SlardarCLIReporter.prototype.__init.ca
1700
1707
  this.client.on('send', (ev) => {
1701
1708
  log$6(
1702
1709
  'send hook called for event: %s',
1703
- (_optionalChain$t([ev, 'optionalAccess', _ => _.ev_type]) ) || 'unknown',
1710
+ (_optionalChain$G([ev, 'optionalAccess', _ => _.ev_type]) ) || 'unknown',
1704
1711
  );
1705
1712
  });
1706
1713
 
@@ -1758,7 +1765,7 @@ class SlardarCLIReporter {constructor() { SlardarCLIReporter.prototype.__init.ca
1758
1765
  )
1759
1766
  : undefined;
1760
1767
 
1761
- _optionalChain$t([this, 'access', _2 => _2.client, 'access', _3 => _3.sendEvent, 'optionalCall', _4 => _4({
1768
+ _optionalChain$G([this, 'access', _2 => _2.client, 'access', _3 => _3.sendEvent, 'optionalCall', _4 => _4({
1762
1769
  name,
1763
1770
  metrics: cleanMetrics ,
1764
1771
  categories: cleanCategories ,
@@ -1829,7 +1836,7 @@ class SlardarCLIReporter {constructor() { SlardarCLIReporter.prototype.__init.ca
1829
1836
  log$6('Reporting JS error:', {
1830
1837
  name: error.name,
1831
1838
  message: error.message.slice(0, 100),
1832
- stack: _optionalChain$t([error, 'access', _5 => _5.stack, 'optionalAccess', _6 => _6.slice, 'call', _7 => _7(0, 200)]),
1839
+ stack: _optionalChain$G([error, 'access', _5 => _5.stack, 'optionalAccess', _6 => _6.slice, 'call', _7 => _7(0, 200)]),
1833
1840
  extra,
1834
1841
  source,
1835
1842
  });
@@ -1849,7 +1856,7 @@ class SlardarCLIReporter {constructor() { SlardarCLIReporter.prototype.__init.ca
1849
1856
  if (!this.ensureInitialized()) {
1850
1857
  return;
1851
1858
  }
1852
- _optionalChain$t([this, 'access', _8 => _8.client, 'access', _9 => _9.context, 'optionalAccess', _10 => _10.set, 'call', _11 => _11(key, value)]);
1859
+ _optionalChain$G([this, 'access', _8 => _8.client, 'access', _9 => _9.context, 'optionalAccess', _10 => _10.set, 'call', _11 => _11(key, value)]);
1853
1860
  }
1854
1861
 
1855
1862
  /**
@@ -1860,7 +1867,7 @@ class SlardarCLIReporter {constructor() { SlardarCLIReporter.prototype.__init.ca
1860
1867
  return;
1861
1868
  }
1862
1869
  log$6('Merging context:', context);
1863
- _optionalChain$t([this, 'access', _12 => _12.client, 'access', _13 => _13.context, 'optionalAccess', _14 => _14.merge, 'call', _15 => _15(context)]);
1870
+ _optionalChain$G([this, 'access', _12 => _12.client, 'access', _13 => _13.context, 'optionalAccess', _14 => _14.merge, 'call', _15 => _15(context)]);
1864
1871
  }
1865
1872
 
1866
1873
  /**
@@ -1870,7 +1877,7 @@ class SlardarCLIReporter {constructor() { SlardarCLIReporter.prototype.__init.ca
1870
1877
  if (!this.ensureInitialized()) {
1871
1878
  return;
1872
1879
  }
1873
- _optionalChain$t([this, 'access', _16 => _16.client, 'access', _17 => _17.context, 'optionalAccess', _18 => _18.delete, 'call', _19 => _19(key)]);
1880
+ _optionalChain$G([this, 'access', _16 => _16.client, 'access', _17 => _17.context, 'optionalAccess', _18 => _18.delete, 'call', _19 => _19(key)]);
1874
1881
  }
1875
1882
 
1876
1883
  /**
@@ -1880,7 +1887,7 @@ class SlardarCLIReporter {constructor() { SlardarCLIReporter.prototype.__init.ca
1880
1887
  if (!this.ensureInitialized()) {
1881
1888
  return;
1882
1889
  }
1883
- _optionalChain$t([this, 'access', _20 => _20.client, 'access', _21 => _21.context, 'optionalAccess', _22 => _22.clear, 'call', _23 => _23()]);
1890
+ _optionalChain$G([this, 'access', _20 => _20.client, 'access', _21 => _21.context, 'optionalAccess', _22 => _22.clear, 'call', _23 => _23()]);
1884
1891
  }
1885
1892
 
1886
1893
  /**
@@ -1917,7 +1924,7 @@ class SlardarCLIReporter {constructor() { SlardarCLIReporter.prototype.__init.ca
1917
1924
  return;
1918
1925
  }
1919
1926
  log$6('Flushing Slardar data...');
1920
- _optionalChain$t([this, 'access', _24 => _24.client, 'access', _25 => _25.getSender, 'optionalCall', _26 => _26(), 'optionalAccess', _27 => _27.flush, 'call', _28 => _28()]);
1927
+ _optionalChain$G([this, 'access', _24 => _24.client, 'access', _25 => _25.getSender, 'optionalCall', _26 => _26(), 'optionalAccess', _27 => _27.flush, 'call', _28 => _28()]);
1921
1928
  log$6('Waiting %dms for events to be sent...', waitMs);
1922
1929
  await new Promise(resolve => setTimeout(resolve, waitMs));
1923
1930
  log$6('Slardar data flushed');
@@ -1936,7 +1943,7 @@ class SlardarCLIReporter {constructor() { SlardarCLIReporter.prototype.__init.ca
1936
1943
  */
1937
1944
  const reporter = new SlardarCLIReporter();
1938
1945
 
1939
- function _optionalChain$s(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; }
1946
+ function _optionalChain$F(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; }
1940
1947
 
1941
1948
 
1942
1949
 
@@ -1996,11 +2003,11 @@ const EventBuilder = {
1996
2003
  name: CLI_EVENTS.CLI_COMMAND,
1997
2004
  categories: {
1998
2005
  command,
1999
- args: _optionalChain$s([options, 'optionalAccess', _ => _.args]),
2006
+ args: _optionalChain$F([options, 'optionalAccess', _ => _.args]),
2000
2007
  status: 'running' ,
2001
- ..._optionalChain$s([options, 'optionalAccess', _2 => _2.categories]),
2008
+ ..._optionalChain$F([options, 'optionalAccess', _2 => _2.categories]),
2002
2009
  },
2003
- metrics: _optionalChain$s([options, 'optionalAccess', _3 => _3.metrics]),
2010
+ metrics: _optionalChain$F([options, 'optionalAccess', _3 => _3.metrics]),
2004
2011
  };
2005
2012
  },
2006
2013
 
@@ -2021,13 +2028,13 @@ const EventBuilder = {
2021
2028
  name: CLI_EVENTS.CLI_COMMAND_COMPLETE,
2022
2029
  categories: {
2023
2030
  command,
2024
- args: _optionalChain$s([options, 'optionalAccess', _4 => _4.args]),
2031
+ args: _optionalChain$F([options, 'optionalAccess', _4 => _4.args]),
2025
2032
  status: success ? ('success' ) : ('fail' ),
2026
- ..._optionalChain$s([options, 'optionalAccess', _5 => _5.categories]),
2033
+ ..._optionalChain$F([options, 'optionalAccess', _5 => _5.categories]),
2027
2034
  },
2028
2035
  metrics: {
2029
2036
  duration,
2030
- ...(_optionalChain$s([options, 'optionalAccess', _6 => _6.errorCode]) && { errorCode: options.errorCode }),
2037
+ ...(_optionalChain$F([options, 'optionalAccess', _6 => _6.errorCode]) && { errorCode: options.errorCode }),
2031
2038
  },
2032
2039
  };
2033
2040
  },
@@ -2048,12 +2055,12 @@ const EventBuilder = {
2048
2055
  name: CLI_EVENTS.NETWORK_REQUEST,
2049
2056
  categories: {
2050
2057
  url,
2051
- method: _optionalChain$s([options, 'optionalAccess', _7 => _7.method]) || 'GET',
2052
- statusCode: _optionalChain$s([options, 'optionalAccess', _8 => _8.statusCode, 'optionalAccess', _9 => _9.toString, 'call', _10 => _10()]),
2053
- status: _optionalChain$s([options, 'optionalAccess', _11 => _11.success]) ? ('success' ) : ('fail' ),
2058
+ method: _optionalChain$F([options, 'optionalAccess', _7 => _7.method]) || 'GET',
2059
+ statusCode: _optionalChain$F([options, 'optionalAccess', _8 => _8.statusCode, 'optionalAccess', _9 => _9.toString, 'call', _10 => _10()]),
2060
+ status: _optionalChain$F([options, 'optionalAccess', _11 => _11.success]) ? ('success' ) : ('fail' ),
2054
2061
  },
2055
2062
  metrics: {
2056
- duration: _optionalChain$s([options, 'optionalAccess', _12 => _12.duration]),
2063
+ duration: _optionalChain$F([options, 'optionalAccess', _12 => _12.duration]),
2057
2064
  },
2058
2065
  };
2059
2066
  },
@@ -2075,11 +2082,11 @@ const EventBuilder = {
2075
2082
  categories: {
2076
2083
  operation,
2077
2084
  filePath,
2078
- status: _optionalChain$s([options, 'optionalAccess', _13 => _13.success]) ? ('success' ) : ('fail' ),
2085
+ status: _optionalChain$F([options, 'optionalAccess', _13 => _13.success]) ? ('success' ) : ('fail' ),
2079
2086
  },
2080
2087
  metrics: {
2081
- duration: _optionalChain$s([options, 'optionalAccess', _14 => _14.duration]),
2082
- fileSize: _optionalChain$s([options, 'optionalAccess', _15 => _15.fileSize]),
2088
+ duration: _optionalChain$F([options, 'optionalAccess', _14 => _14.duration]),
2089
+ fileSize: _optionalChain$F([options, 'optionalAccess', _15 => _15.fileSize]),
2083
2090
  },
2084
2091
  };
2085
2092
  },
@@ -2107,7 +2114,7 @@ const EventBuilder = {
2107
2114
  };
2108
2115
 
2109
2116
  var name = "@coze-arch/cli";
2110
- var version = "0.0.37";
2117
+ var version = "0.0.39-alpha.bdff32";
2111
2118
  var description = "coze coding devtools cli";
2112
2119
  var license = "MIT";
2113
2120
  var author = "fanwenjie.fe@bytedance.com";
@@ -2119,6 +2126,7 @@ var bin = {
2119
2126
  var files = [
2120
2127
  "lib",
2121
2128
  "bin",
2129
+ "docs/deploy.md",
2122
2130
  "lib/**/.npmrc",
2123
2131
  "!**/*.tsbuildinfo",
2124
2132
  "!**/*.map",
@@ -2155,7 +2163,9 @@ var dependencies = {
2155
2163
  "fast-glob": "^3.3.3",
2156
2164
  "js-yaml": "^4.2.0",
2157
2165
  minimist: "^1.2.8",
2158
- shelljs: "^0.10.0"
2166
+ pnpm: "9.0.0",
2167
+ shelljs: "^0.10.0",
2168
+ tar: "^7.5.22"
2159
2169
  };
2160
2170
  var devDependencies = {
2161
2171
  "@coze-arch/cli-logger": "workspace:*",
@@ -2215,7 +2225,7 @@ var packageJson = {
2215
2225
  cozePublishConfig: cozePublishConfig
2216
2226
  };
2217
2227
 
2218
- function _optionalChain$r(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; }/**
2228
+ 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; }/**
2219
2229
  * Slardar 监控初始化和上报
2220
2230
  */
2221
2231
 
@@ -2318,11 +2328,11 @@ const reportCommandComplete = safeRun(
2318
2328
  ,
2319
2329
  ) => {
2320
2330
  const event = EventBuilder.cliCommandComplete(command, success, duration, {
2321
- args: _optionalChain$r([options, 'optionalAccess', _ => _.args]),
2322
- errorCode: _optionalChain$r([options, 'optionalAccess', _2 => _2.errorCode]),
2331
+ args: _optionalChain$E([options, 'optionalAccess', _ => _.args]),
2332
+ errorCode: _optionalChain$E([options, 'optionalAccess', _2 => _2.errorCode]),
2323
2333
  categories: {
2324
- ...(_optionalChain$r([options, 'optionalAccess', _3 => _3.errorMessage]) && { errorMessage: options.errorMessage }),
2325
- ..._optionalChain$r([options, 'optionalAccess', _4 => _4.categories]),
2334
+ ...(_optionalChain$E([options, 'optionalAccess', _3 => _3.errorMessage]) && { errorMessage: options.errorMessage }),
2335
+ ..._optionalChain$E([options, 'optionalAccess', _4 => _4.categories]),
2326
2336
  },
2327
2337
  });
2328
2338
  reporter.sendEvent(event.name, event.metrics, event.categories);
@@ -2381,7 +2391,7 @@ const flushSlardar = safeRun('flushSlardar', async () => {
2381
2391
  await reporter.flush();
2382
2392
  });
2383
2393
 
2384
- function _nullishCoalesce$9(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain$q(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) {
2394
+ function _nullishCoalesce$b(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; }var LogLevel; (function (LogLevel) {
2385
2395
  const ERROR = 0; LogLevel[LogLevel["ERROR"] = ERROR] = "ERROR";
2386
2396
  const WARN = 1; LogLevel[LogLevel["WARN"] = WARN] = "WARN";
2387
2397
  const SUCCESS = 2; LogLevel[LogLevel["SUCCESS"] = SUCCESS] = "SUCCESS";
@@ -2419,7 +2429,7 @@ class Logger {
2419
2429
 
2420
2430
  constructor(options = {}) {
2421
2431
  this.level = this.parseLogLevel(options.level);
2422
- this.useColor = _nullishCoalesce$9(options.useColor, () => ( this.isColorSupported()));
2432
+ this.useColor = _nullishCoalesce$b(options.useColor, () => ( this.isColorSupported()));
2423
2433
  this.prefix = options.prefix;
2424
2434
  }
2425
2435
 
@@ -2428,7 +2438,7 @@ class Logger {
2428
2438
  return level;
2429
2439
  }
2430
2440
 
2431
- const envLevel = _optionalChain$q([process, 'access', _ => _.env, 'access', _2 => _2.LOG_LEVEL, 'optionalAccess', _3 => _3.toLowerCase, 'call', _4 => _4()]);
2441
+ const envLevel = _optionalChain$D([process, 'access', _ => _.env, 'access', _2 => _2.LOG_LEVEL, 'optionalAccess', _3 => _3.toLowerCase, 'call', _4 => _4()]);
2432
2442
  if (envLevel && envLevel in LOG_LEVEL_MAP) {
2433
2443
  // envLevel 已通过 `in` 检查确认为 LOG_LEVEL_MAP 的键;
2434
2444
  // 显式判空以满足 noUncheckedIndexedAccess,运行时行为不变
@@ -2445,7 +2455,7 @@ class Logger {
2445
2455
  // 简单检测:Node.js 环境且支持 TTY
2446
2456
  return (
2447
2457
  typeof process !== 'undefined' &&
2448
- _optionalChain$q([process, 'access', _5 => _5.stdout, 'optionalAccess', _6 => _6.isTTY]) === true &&
2458
+ _optionalChain$D([process, 'access', _5 => _5.stdout, 'optionalAccess', _6 => _6.isTTY]) === true &&
2449
2459
  process.env.NO_COLOR === undefined
2450
2460
  );
2451
2461
  }
@@ -2470,7 +2480,7 @@ class Logger {
2470
2480
 
2471
2481
  const icon = this.colorize(options.icon, options.color);
2472
2482
  const prefix = this.prefix ? `${icon} ${this.prefix}` : icon;
2473
- console.log(prefix, options.message, ...(_nullishCoalesce$9(options.args, () => ( []))));
2483
+ console.log(prefix, options.message, ...(_nullishCoalesce$b(options.args, () => ( []))));
2474
2484
  }
2475
2485
 
2476
2486
  error(message, ...args) {
@@ -2815,7 +2825,7 @@ const executeWarmup = async (options) => {
2815
2825
  /**
2816
2826
  * 注册 warmup 命令到 program
2817
2827
  */
2818
- const registerCommand$6 = program => {
2828
+ const registerCommand$7 = program => {
2819
2829
  program
2820
2830
  .command('warmup')
2821
2831
  .description('Pre-install dependencies for templates to speed up init')
@@ -2838,9 +2848,9 @@ const COZE_HOME_DIR = '.coze';
2838
2848
 
2839
2849
  /**
2840
2850
  * Logs directory name
2841
- * Default: .coze-logs
2851
+ * Default: ~/.coze/logs
2842
2852
  */
2843
- const LOGS_DIR = '.coze-logs';
2853
+ const LOGS_DIR = 'logs';
2844
2854
 
2845
2855
  /**
2846
2856
  * Get the Coze home directory path
@@ -2855,10 +2865,10 @@ const getCozeHome = () =>
2855
2865
  * Get the logs directory path
2856
2866
  * Can be customized via COZE_LOG_DIR environment variable
2857
2867
  *
2858
- * @returns Absolute path to logs directory (default: ~/.coze-logs)
2868
+ * @returns Absolute path to logs directory (default: ~/.coze/logs)
2859
2869
  */
2860
2870
  const getCozeLogsDir = () =>
2861
- process.env.COZE_LOG_DIR || path.join(os.homedir(), LOGS_DIR);
2871
+ process.env.COZE_LOG_DIR || path.join(getCozeHome(), LOGS_DIR);
2862
2872
 
2863
2873
  /**
2864
2874
  * Get path for a specific file/directory within Coze home
@@ -2889,7 +2899,7 @@ const getCozeFilePath = (relativePath) =>
2889
2899
  * @example
2890
2900
  * ```ts
2891
2901
  * const devLog = getCozeLogPath('dev.log');
2892
- * // Returns: ~/.coze-logs/dev.log
2902
+ * // Returns: ~/.coze/logs/dev.log
2893
2903
  * ```
2894
2904
  */
2895
2905
  const getCozeLogPath = (filename) =>
@@ -3227,7 +3237,7 @@ const executeUpdate = (
3227
3237
  /**
3228
3238
  * 注册 update 命令到 program
3229
3239
  */
3230
- const registerCommand$5 = program => {
3240
+ const registerCommand$6 = program => {
3231
3241
  program
3232
3242
  .command('update <package>')
3233
3243
  .description('Update a package dependency')
@@ -3253,7 +3263,7 @@ const registerCommand$5 = program => {
3253
3263
  });
3254
3264
  };
3255
3265
 
3256
- 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; }// Safe JSON parsing utilities with type safety and error handling
3266
+ 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; }// Safe JSON parsing utilities with type safety and error handling
3257
3267
  // Provides fallback values, validation, and error monitoring capabilities
3258
3268
 
3259
3269
  /**
@@ -3353,12 +3363,12 @@ function safeJsonParse(
3353
3363
  const parsed = JSON.parse(String(input));
3354
3364
 
3355
3365
  // Optional validation
3356
- if (_optionalChain$p([options, 'optionalAccess', _ => _.validate])) {
3366
+ if (_optionalChain$C([options, 'optionalAccess', _ => _.validate])) {
3357
3367
  if (options.validate(parsed)) {
3358
3368
  return parsed;
3359
3369
  } else {
3360
3370
  const validationError = new Error('JSON validation failed');
3361
- _optionalChain$p([options, 'access', _2 => _2.onError, 'optionalCall', _3 => _3(validationError, input)]);
3371
+ _optionalChain$C([options, 'access', _2 => _2.onError, 'optionalCall', _3 => _3(validationError, input)]);
3362
3372
 
3363
3373
  if (options.throwOnValidationError) {
3364
3374
  throw validationError;
@@ -3370,10 +3380,10 @@ function safeJsonParse(
3370
3380
  return parsed;
3371
3381
  } catch (error) {
3372
3382
  // Re-throw validation errors when throwOnValidationError is true
3373
- if (error instanceof Error && error.message === 'JSON validation failed' && _optionalChain$p([options, 'optionalAccess', _4 => _4.throwOnValidationError])) {
3383
+ if (error instanceof Error && error.message === 'JSON validation failed' && _optionalChain$C([options, 'optionalAccess', _4 => _4.throwOnValidationError])) {
3374
3384
  throw error;
3375
3385
  }
3376
- _optionalChain$p([options, 'optionalAccess', _5 => _5.onError, 'optionalCall', _6 => _6(error , input)]);
3386
+ _optionalChain$C([options, 'optionalAccess', _5 => _5.onError, 'optionalCall', _6 => _6(error , input)]);
3377
3387
  return defaultValue;
3378
3388
  }
3379
3389
  }
@@ -3413,7 +3423,7 @@ function isNode(node) {
3413
3423
  }
3414
3424
  const hasAnchor = (node) => (isScalar(node) || isCollection(node)) && !!node.anchor;
3415
3425
 
3416
- 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; }
3426
+ 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; }
3417
3427
  const BREAK = Symbol('break visit');
3418
3428
  const SKIP = Symbol('skip children');
3419
3429
  const REMOVE = Symbol('remove node');
@@ -3526,15 +3536,15 @@ function callVisitor(key, node, visitor, path) {
3526
3536
  if (typeof visitor === 'function')
3527
3537
  return visitor(key, node, path);
3528
3538
  if (isMap(node))
3529
- return _optionalChain$o([visitor, 'access', _ => _.Map, 'optionalCall', _2 => _2(key, node, path)]);
3539
+ return _optionalChain$B([visitor, 'access', _ => _.Map, 'optionalCall', _2 => _2(key, node, path)]);
3530
3540
  if (isSeq(node))
3531
- return _optionalChain$o([visitor, 'access', _3 => _3.Seq, 'optionalCall', _4 => _4(key, node, path)]);
3541
+ return _optionalChain$B([visitor, 'access', _3 => _3.Seq, 'optionalCall', _4 => _4(key, node, path)]);
3532
3542
  if (isPair(node))
3533
- return _optionalChain$o([visitor, 'access', _5 => _5.Pair, 'optionalCall', _6 => _6(key, node, path)]);
3543
+ return _optionalChain$B([visitor, 'access', _5 => _5.Pair, 'optionalCall', _6 => _6(key, node, path)]);
3534
3544
  if (isScalar(node))
3535
- return _optionalChain$o([visitor, 'access', _7 => _7.Scalar, 'optionalCall', _8 => _8(key, node, path)]);
3545
+ return _optionalChain$B([visitor, 'access', _7 => _7.Scalar, 'optionalCall', _8 => _8(key, node, path)]);
3536
3546
  if (isAlias(node))
3537
- return _optionalChain$o([visitor, 'access', _9 => _9.Alias, 'optionalCall', _10 => _10(key, node, path)]);
3547
+ return _optionalChain$B([visitor, 'access', _9 => _9.Alias, 'optionalCall', _10 => _10(key, node, path)]);
3538
3548
  return undefined;
3539
3549
  }
3540
3550
  function replaceNode(key, path, node) {
@@ -3625,7 +3635,7 @@ function applyReviver(reviver, obj, key, val) {
3625
3635
  return reviver.call(obj, key, val);
3626
3636
  }
3627
3637
 
3628
- function _optionalChain$n(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; }
3638
+ function _optionalChain$A(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; }
3629
3639
  /**
3630
3640
  * Recursively convert any node or its contents to native JavaScript
3631
3641
  *
@@ -3655,7 +3665,7 @@ function toJS(value, arg, ctx) {
3655
3665
  ctx.onCreate(res);
3656
3666
  return res;
3657
3667
  }
3658
- if (typeof value === 'bigint' && !_optionalChain$n([ctx, 'optionalAccess', _ => _.keep]))
3668
+ if (typeof value === 'bigint' && !_optionalChain$A([ctx, 'optionalAccess', _ => _.keep]))
3659
3669
  return Number(value);
3660
3670
  return value;
3661
3671
  }
@@ -3693,7 +3703,7 @@ class NodeBase {
3693
3703
  }
3694
3704
  }
3695
3705
 
3696
- function _optionalChain$m(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; }
3706
+ function _optionalChain$z(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; }
3697
3707
  class Alias extends NodeBase {
3698
3708
  constructor(source) {
3699
3709
  super(ALIAS);
@@ -3709,10 +3719,10 @@ class Alias extends NodeBase {
3709
3719
  * instance of the `source` anchor before this node.
3710
3720
  */
3711
3721
  resolve(doc, ctx) {
3712
- if (_optionalChain$m([ctx, 'optionalAccess', _ => _.maxAliasCount]) === 0)
3722
+ if (_optionalChain$z([ctx, 'optionalAccess', _ => _.maxAliasCount]) === 0)
3713
3723
  throw new ReferenceError('Alias resolution is disabled');
3714
3724
  let nodes;
3715
- if (_optionalChain$m([ctx, 'optionalAccess', _2 => _2.aliasResolveCache])) {
3725
+ if (_optionalChain$z([ctx, 'optionalAccess', _2 => _2.aliasResolveCache])) {
3716
3726
  nodes = ctx.aliasResolveCache;
3717
3727
  }
3718
3728
  else {
@@ -3751,7 +3761,7 @@ class Alias extends NodeBase {
3751
3761
  data = anchors.get(source);
3752
3762
  }
3753
3763
  /* istanbul ignore if */
3754
- if (_optionalChain$m([data, 'optionalAccess', _3 => _3.res]) === undefined) {
3764
+ if (_optionalChain$z([data, 'optionalAccess', _3 => _3.res]) === undefined) {
3755
3765
  const msg = 'This should not happen: Alias anchor was not resolved?';
3756
3766
  throw new ReferenceError(msg);
3757
3767
  }
@@ -3803,7 +3813,7 @@ function getAliasCount(doc, node, anchors) {
3803
3813
  return 1;
3804
3814
  }
3805
3815
 
3806
- function _optionalChain$l(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; }
3816
+ function _optionalChain$y(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; }
3807
3817
  const isScalarValue = (value) => !value || (typeof value !== 'function' && typeof value !== 'object');
3808
3818
  class Scalar extends NodeBase {
3809
3819
  constructor(value) {
@@ -3811,7 +3821,7 @@ class Scalar extends NodeBase {
3811
3821
  this.value = value;
3812
3822
  }
3813
3823
  toJSON(arg, ctx) {
3814
- return _optionalChain$l([ctx, 'optionalAccess', _ => _.keep]) ? this.value : toJS(this.value, arg, ctx);
3824
+ return _optionalChain$y([ctx, 'optionalAccess', _ => _.keep]) ? this.value : toJS(this.value, arg, ctx);
3815
3825
  }
3816
3826
  toString() {
3817
3827
  return String(this.value);
@@ -3823,17 +3833,17 @@ Scalar.PLAIN = 'PLAIN';
3823
3833
  Scalar.QUOTE_DOUBLE = 'QUOTE_DOUBLE';
3824
3834
  Scalar.QUOTE_SINGLE = 'QUOTE_SINGLE';
3825
3835
 
3826
- function _nullishCoalesce$8(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain$k(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; }
3836
+ function _nullishCoalesce$a(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain$x(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; }
3827
3837
  const defaultTagPrefix = 'tag:yaml.org,2002:';
3828
3838
  function findTagObject(value, tagName, tags) {
3829
3839
  if (tagName) {
3830
3840
  const match = tags.filter(t => t.tag === tagName);
3831
- const tagObj = _nullishCoalesce$8(match.find(t => !t.format), () => ( match[0]));
3841
+ const tagObj = _nullishCoalesce$a(match.find(t => !t.format), () => ( match[0]));
3832
3842
  if (!tagObj)
3833
3843
  throw new Error(`Tag ${tagName} not found`);
3834
3844
  return tagObj;
3835
3845
  }
3836
- return tags.find(t => _optionalChain$k([t, 'access', _ => _.identify, 'optionalCall', _2 => _2(value)]) && !t.format);
3846
+ return tags.find(t => _optionalChain$x([t, 'access', _ => _.identify, 'optionalCall', _2 => _2(value)]) && !t.format);
3837
3847
  }
3838
3848
  function createNode(value, tagName, ctx) {
3839
3849
  if (isDocument(value))
@@ -3841,7 +3851,7 @@ function createNode(value, tagName, ctx) {
3841
3851
  if (isNode(value))
3842
3852
  return value;
3843
3853
  if (isPair(value)) {
3844
- const map = _optionalChain$k([ctx, 'access', _3 => _3.schema, 'access', _4 => _4[MAP], 'access', _5 => _5.createNode, 'optionalCall', _6 => _6(ctx.schema, null, ctx)]);
3854
+ const map = _optionalChain$x([ctx, 'access', _3 => _3.schema, 'access', _4 => _4[MAP], 'access', _5 => _5.createNode, 'optionalCall', _6 => _6(ctx.schema, null, ctx)]);
3845
3855
  map.items.push(value);
3846
3856
  return map;
3847
3857
  }
@@ -3860,7 +3870,7 @@ function createNode(value, tagName, ctx) {
3860
3870
  if (aliasDuplicateObjects && value && typeof value === 'object') {
3861
3871
  ref = sourceObjects.get(value);
3862
3872
  if (ref) {
3863
- _nullishCoalesce$8(ref.anchor, () => ( (ref.anchor = onAnchor(value))));
3873
+ _nullishCoalesce$a(ref.anchor, () => ( (ref.anchor = onAnchor(value))));
3864
3874
  return new Alias(ref.anchor);
3865
3875
  }
3866
3876
  else {
@@ -3868,7 +3878,7 @@ function createNode(value, tagName, ctx) {
3868
3878
  sourceObjects.set(value, ref);
3869
3879
  }
3870
3880
  }
3871
- if (_optionalChain$k([tagName, 'optionalAccess', _7 => _7.startsWith, 'call', _8 => _8('!!')]))
3881
+ if (_optionalChain$x([tagName, 'optionalAccess', _7 => _7.startsWith, 'call', _8 => _8('!!')]))
3872
3882
  tagName = defaultTagPrefix + tagName.slice(2);
3873
3883
  let tagObj = findTagObject(value, tagName, schema.tags);
3874
3884
  if (!tagObj) {
@@ -3893,9 +3903,9 @@ function createNode(value, tagName, ctx) {
3893
3903
  onTagObj(tagObj);
3894
3904
  delete ctx.onTagObj;
3895
3905
  }
3896
- const node = _optionalChain$k([tagObj, 'optionalAccess', _9 => _9.createNode])
3906
+ const node = _optionalChain$x([tagObj, 'optionalAccess', _9 => _9.createNode])
3897
3907
  ? tagObj.createNode(ctx.schema, value, ctx)
3898
- : typeof _optionalChain$k([tagObj, 'optionalAccess', _10 => _10.nodeClass, 'optionalAccess', _11 => _11.from]) === 'function'
3908
+ : typeof _optionalChain$x([tagObj, 'optionalAccess', _10 => _10.nodeClass, 'optionalAccess', _11 => _11.from]) === 'function'
3899
3909
  ? tagObj.nodeClass.from(ctx.schema, value, ctx)
3900
3910
  : new Scalar(value);
3901
3911
  if (tagName)
@@ -4213,7 +4223,7 @@ function consumeMoreIndentedLines(text, i, indent) {
4213
4223
  return end;
4214
4224
  }
4215
4225
 
4216
- function _optionalChain$j(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; }
4226
+ function _optionalChain$w(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; }
4217
4227
  const getFoldOptions = (ctx, isBlock) => ({
4218
4228
  indentAtStart: isBlock ? ctx.indent.length : ctx.indentAtStart,
4219
4229
  lineWidth: ctx.options.lineWidth,
@@ -4498,9 +4508,9 @@ function plainString(item, ctx, onComment, onChompKeep) {
4498
4508
  // booleans get parsed with those types in v1.2 (e.g. '42', 'true' & '0.9e-3'),
4499
4509
  // and others in v1.1.
4500
4510
  if (actualString) {
4501
- const test = (tag) => tag.default && tag.tag !== 'tag:yaml.org,2002:str' && _optionalChain$j([tag, 'access', _ => _.test, 'optionalAccess', _2 => _2.test, 'call', _3 => _3(str)]);
4511
+ const test = (tag) => tag.default && tag.tag !== 'tag:yaml.org,2002:str' && _optionalChain$w([tag, 'access', _ => _.test, 'optionalAccess', _2 => _2.test, 'call', _3 => _3(str)]);
4502
4512
  const { compat, tags } = ctx.doc.schema;
4503
- if (tags.some(test) || _optionalChain$j([compat, 'optionalAccess', _4 => _4.some, 'call', _5 => _5(test)]))
4513
+ if (tags.some(test) || _optionalChain$w([compat, 'optionalAccess', _4 => _4.some, 'call', _5 => _5(test)]))
4504
4514
  return quotedString(value, ctx);
4505
4515
  }
4506
4516
  return implicitKey
@@ -4546,7 +4556,7 @@ function stringifyString(item, ctx, onComment, onChompKeep) {
4546
4556
  return res;
4547
4557
  }
4548
4558
 
4549
- function _nullishCoalesce$7(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain$i(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; }
4559
+ function _nullishCoalesce$9(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; }
4550
4560
  function createStringifyContext(doc, options) {
4551
4561
  const opt = Object.assign({
4552
4562
  blockQuote: true,
@@ -4593,27 +4603,27 @@ function getTagObject(tags, item) {
4593
4603
  if (item.tag) {
4594
4604
  const match = tags.filter(t => t.tag === item.tag);
4595
4605
  if (match.length > 0)
4596
- return _nullishCoalesce$7(match.find(t => t.format === item.format), () => ( match[0]));
4606
+ return _nullishCoalesce$9(match.find(t => t.format === item.format), () => ( match[0]));
4597
4607
  }
4598
4608
  let tagObj = undefined;
4599
4609
  let obj;
4600
4610
  if (isScalar(item)) {
4601
4611
  obj = item.value;
4602
- let match = tags.filter(t => _optionalChain$i([t, 'access', _ => _.identify, 'optionalCall', _2 => _2(obj)]));
4612
+ let match = tags.filter(t => _optionalChain$v([t, 'access', _ => _.identify, 'optionalCall', _2 => _2(obj)]));
4603
4613
  if (match.length > 1) {
4604
4614
  const testMatch = match.filter(t => t.test);
4605
4615
  if (testMatch.length > 0)
4606
4616
  match = testMatch;
4607
4617
  }
4608
4618
  tagObj =
4609
- _nullishCoalesce$7(match.find(t => t.format === item.format), () => ( match.find(t => !t.format)));
4619
+ _nullishCoalesce$9(match.find(t => t.format === item.format), () => ( match.find(t => !t.format)));
4610
4620
  }
4611
4621
  else {
4612
4622
  obj = item;
4613
4623
  tagObj = tags.find(t => t.nodeClass && obj instanceof t.nodeClass);
4614
4624
  }
4615
4625
  if (!tagObj) {
4616
- const name = _nullishCoalesce$7(_optionalChain$i([obj, 'optionalAccess', _3 => _3.constructor, 'optionalAccess', _4 => _4.name]), () => ( (obj === null ? 'null' : typeof obj)));
4626
+ const name = _nullishCoalesce$9(_optionalChain$v([obj, 'optionalAccess', _3 => _3.constructor, 'optionalAccess', _4 => _4.name]), () => ( (obj === null ? 'null' : typeof obj)));
4617
4627
  throw new Error(`Tag not resolved for ${name} value`);
4618
4628
  }
4619
4629
  return tagObj;
@@ -4628,7 +4638,7 @@ function stringifyProps(node, tagObj, { anchors, doc }) {
4628
4638
  anchors.add(anchor);
4629
4639
  props.push(`&${anchor}`);
4630
4640
  }
4631
- const tag = _nullishCoalesce$7(node.tag, () => ( (tagObj.default ? null : tagObj.tag)));
4641
+ const tag = _nullishCoalesce$9(node.tag, () => ( (tagObj.default ? null : tagObj.tag)));
4632
4642
  if (tag)
4633
4643
  props.push(doc.directives.tagString(tag));
4634
4644
  return props.join(' ');
@@ -4639,7 +4649,7 @@ function stringify(item, ctx, onComment, onChompKeep) {
4639
4649
  if (isAlias(item)) {
4640
4650
  if (ctx.doc.directives)
4641
4651
  return item.toString(ctx);
4642
- if (_optionalChain$i([ctx, 'access', _5 => _5.resolvedAliases, 'optionalAccess', _6 => _6.has, 'call', _7 => _7(item)])) {
4652
+ if (_optionalChain$v([ctx, 'access', _5 => _5.resolvedAliases, 'optionalAccess', _6 => _6.has, 'call', _7 => _7(item)])) {
4643
4653
  throw new TypeError(`Cannot stringify circular structure without alias nodes`);
4644
4654
  }
4645
4655
  else {
@@ -4654,10 +4664,10 @@ function stringify(item, ctx, onComment, onChompKeep) {
4654
4664
  const node = isNode(item)
4655
4665
  ? item
4656
4666
  : ctx.doc.createNode(item, { onTagObj: o => (tagObj = o) });
4657
- _nullishCoalesce$7(tagObj, () => ( (tagObj = getTagObject(ctx.doc.schema.tags, node))));
4667
+ _nullishCoalesce$9(tagObj, () => ( (tagObj = getTagObject(ctx.doc.schema.tags, node))));
4658
4668
  const props = stringifyProps(node, tagObj, ctx);
4659
4669
  if (props.length > 0)
4660
- ctx.indentAtStart = (_nullishCoalesce$7(ctx.indentAtStart, () => ( 0))) + props.length + 1;
4670
+ ctx.indentAtStart = (_nullishCoalesce$9(ctx.indentAtStart, () => ( 0))) + props.length + 1;
4661
4671
  const str = typeof tagObj.stringify === 'function'
4662
4672
  ? tagObj.stringify(node, ctx, onComment, onChompKeep)
4663
4673
  : isScalar(node)
@@ -4670,7 +4680,7 @@ function stringify(item, ctx, onComment, onChompKeep) {
4670
4680
  : `${props}\n${ctx.indent}${str}`;
4671
4681
  }
4672
4682
 
4673
- function _nullishCoalesce$6(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }
4683
+ function _nullishCoalesce$8(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }
4674
4684
  function stringifyPair({ key, value }, ctx, onComment, onChompKeep) {
4675
4685
  const { allNullValues, doc, indent, indentStep, options: { commentString, indentSeq, simpleKeys } } = ctx;
4676
4686
  let keyComment = (isNode(key) && key.comment) || null;
@@ -4780,7 +4790,7 @@ function stringifyPair({ key, value }, ctx, onComment, onChompKeep) {
4780
4790
  const vs0 = valueStr[0];
4781
4791
  const nl0 = valueStr.indexOf('\n');
4782
4792
  const hasNewline = nl0 !== -1;
4783
- const flow = _nullishCoalesce$6(_nullishCoalesce$6(ctx.inFlow, () => ( value.flow)), () => ( value.items.length === 0));
4793
+ const flow = _nullishCoalesce$8(_nullishCoalesce$8(ctx.inFlow, () => ( value.flow)), () => ( value.items.length === 0));
4784
4794
  if (hasNewline || !flow) {
4785
4795
  let hasPropsLine = false;
4786
4796
  if (hasNewline && (vs0 === '&' || vs0 === '!')) {
@@ -4821,7 +4831,7 @@ function warn(logLevel, warning) {
4821
4831
  }
4822
4832
  }
4823
4833
 
4824
- function _optionalChain$h(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; }
4834
+ function _optionalChain$u(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; }
4825
4835
  // If the value associated with a merge key is a single mapping node, each of
4826
4836
  // its key/value pairs is inserted into the current mapping, unless the key
4827
4837
  // already exists in it. If the value associated with the merge key is a
@@ -4845,7 +4855,7 @@ const isMergeKey = (ctx, key) => (merge.identify(key) ||
4845
4855
  (isScalar(key) &&
4846
4856
  (!key.type || key.type === Scalar.PLAIN) &&
4847
4857
  merge.identify(key.value))) &&
4848
- _optionalChain$h([ctx, 'optionalAccess', _ => _.doc, 'access', _2 => _2.schema, 'access', _3 => _3.tags, 'access', _4 => _4.some, 'call', _5 => _5(tag => tag.tag === merge.tag && tag.default)]);
4858
+ _optionalChain$u([ctx, 'optionalAccess', _ => _.doc, 'access', _2 => _2.schema, 'access', _3 => _3.tags, 'access', _4 => _4.some, 'call', _5 => _5(tag => tag.tag === merge.tag && tag.default)]);
4849
4859
  function addMergeToJSMap(ctx, map, value) {
4850
4860
  const source = resolveAliasValue(ctx, value);
4851
4861
  if (isSeq(source))
@@ -4885,7 +4895,7 @@ function resolveAliasValue(ctx, value) {
4885
4895
  return ctx && isAlias(value) ? value.resolve(ctx.doc, ctx) : value;
4886
4896
  }
4887
4897
 
4888
- function _optionalChain$g(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; }
4898
+ 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; }
4889
4899
  function addPairToJSMap(ctx, map, { key, value }) {
4890
4900
  if (isNode(key) && key.addToJSMap)
4891
4901
  key.addToJSMap(ctx, map, value);
@@ -4922,7 +4932,7 @@ function stringifyKey(key, jsKey, ctx) {
4922
4932
  // eslint-disable-next-line @typescript-eslint/no-base-to-string
4923
4933
  if (typeof jsKey !== 'object')
4924
4934
  return String(jsKey);
4925
- if (isNode(key) && _optionalChain$g([ctx, 'optionalAccess', _ => _.doc])) {
4935
+ if (isNode(key) && _optionalChain$t([ctx, 'optionalAccess', _ => _.doc])) {
4926
4936
  const strCtx = createStringifyContext(ctx.doc, {});
4927
4937
  strCtx.anchors = new Set();
4928
4938
  for (const node of ctx.anchors.keys())
@@ -4942,7 +4952,7 @@ function stringifyKey(key, jsKey, ctx) {
4942
4952
  return JSON.stringify(jsKey);
4943
4953
  }
4944
4954
 
4945
- function _optionalChain$f(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; }
4955
+ function _optionalChain$s(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; }
4946
4956
  function createPair(key, value, ctx) {
4947
4957
  const k = createNode(key, undefined, ctx);
4948
4958
  const v = createNode(value, undefined, ctx);
@@ -4963,19 +4973,19 @@ class Pair {
4963
4973
  return new Pair(key, value);
4964
4974
  }
4965
4975
  toJSON(_, ctx) {
4966
- const pair = _optionalChain$f([ctx, 'optionalAccess', _2 => _2.mapAsMap]) ? new Map() : {};
4976
+ const pair = _optionalChain$s([ctx, 'optionalAccess', _2 => _2.mapAsMap]) ? new Map() : {};
4967
4977
  return addPairToJSMap(ctx, pair, this);
4968
4978
  }
4969
4979
  toString(ctx, onComment, onChompKeep) {
4970
- return _optionalChain$f([ctx, 'optionalAccess', _3 => _3.doc])
4980
+ return _optionalChain$s([ctx, 'optionalAccess', _3 => _3.doc])
4971
4981
  ? stringifyPair(this, ctx, onComment, onChompKeep)
4972
4982
  : JSON.stringify(this);
4973
4983
  }
4974
4984
  }
4975
4985
 
4976
- function _nullishCoalesce$5(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; }
4986
+ function _nullishCoalesce$7(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain$r(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; }
4977
4987
  function stringifyCollection(collection, ctx, options) {
4978
- const flow = _nullishCoalesce$5(ctx.inFlow, () => ( collection.flow));
4988
+ const flow = _nullishCoalesce$7(ctx.inFlow, () => ( collection.flow));
4979
4989
  const stringify = flow ? stringifyFlowCollection : stringifyBlockCollection;
4980
4990
  return stringify(collection, ctx, options);
4981
4991
  }
@@ -5067,7 +5077,7 @@ function stringifyFlowCollection({ items }, ctx, { flowChars, itemIndent }) {
5067
5077
  if (iv.commentBefore)
5068
5078
  reqNewline = true;
5069
5079
  }
5070
- else if (item.value == null && _optionalChain$e([ik, 'optionalAccess', _ => _.comment])) {
5080
+ else if (item.value == null && _optionalChain$r([ik, 'optionalAccess', _ => _.comment])) {
5071
5081
  comment = ik.comment;
5072
5082
  }
5073
5083
  }
@@ -5122,7 +5132,7 @@ function addCommentBefore({ indent, options: { commentString } }, lines, comment
5122
5132
  }
5123
5133
  }
5124
5134
 
5125
- function _nullishCoalesce$4(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; }
5135
+ function _nullishCoalesce$6(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain$q(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; }
5126
5136
  function findPair(items, key) {
5127
5137
  const k = isScalar(key) ? key.value : key;
5128
5138
  for (const it of items) {
@@ -5183,12 +5193,12 @@ class YAMLMap extends Collection {
5183
5193
  _pair = pair;
5184
5194
  else if (!pair || typeof pair !== 'object' || !('key' in pair)) {
5185
5195
  // In TypeScript, this never happens.
5186
- _pair = new Pair(pair, _optionalChain$d([pair, 'optionalAccess', _2 => _2.value]));
5196
+ _pair = new Pair(pair, _optionalChain$q([pair, 'optionalAccess', _2 => _2.value]));
5187
5197
  }
5188
5198
  else
5189
5199
  _pair = new Pair(pair.key, pair.value);
5190
5200
  const prev = findPair(this.items, _pair.key);
5191
- const sortEntries = _optionalChain$d([this, 'access', _3 => _3.schema, 'optionalAccess', _4 => _4.sortMapEntries]);
5201
+ const sortEntries = _optionalChain$q([this, 'access', _3 => _3.schema, 'optionalAccess', _4 => _4.sortMapEntries]);
5192
5202
  if (prev) {
5193
5203
  if (!overwrite)
5194
5204
  throw new Error(`Key ${_pair.key} already set`);
@@ -5218,8 +5228,8 @@ class YAMLMap extends Collection {
5218
5228
  }
5219
5229
  get(key, keepScalar) {
5220
5230
  const it = findPair(this.items, key);
5221
- const node = _optionalChain$d([it, 'optionalAccess', _5 => _5.value]);
5222
- return _nullishCoalesce$4((!keepScalar && isScalar(node) ? node.value : node), () => ( undefined));
5231
+ const node = _optionalChain$q([it, 'optionalAccess', _5 => _5.value]);
5232
+ return _nullishCoalesce$6((!keepScalar && isScalar(node) ? node.value : node), () => ( undefined));
5223
5233
  }
5224
5234
  has(key) {
5225
5235
  return !!findPair(this.items, key);
@@ -5233,8 +5243,8 @@ class YAMLMap extends Collection {
5233
5243
  * @returns Instance of Type, Map, or Object
5234
5244
  */
5235
5245
  toJSON(_, ctx, Type) {
5236
- const map = Type ? new Type() : _optionalChain$d([ctx, 'optionalAccess', _6 => _6.mapAsMap]) ? new Map() : {};
5237
- if (_optionalChain$d([ctx, 'optionalAccess', _7 => _7.onCreate]))
5246
+ const map = Type ? new Type() : _optionalChain$q([ctx, 'optionalAccess', _6 => _6.mapAsMap]) ? new Map() : {};
5247
+ if (_optionalChain$q([ctx, 'optionalAccess', _7 => _7.onCreate]))
5238
5248
  ctx.onCreate(map);
5239
5249
  for (const item of this.items)
5240
5250
  addPairToJSMap(ctx, map, item);
@@ -5259,7 +5269,7 @@ class YAMLMap extends Collection {
5259
5269
  }
5260
5270
  }
5261
5271
 
5262
- 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; }
5272
+ 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; }
5263
5273
  class YAMLSeq extends Collection {
5264
5274
  static get tagName() {
5265
5275
  return 'tag:yaml.org,2002:seq';
@@ -5322,7 +5332,7 @@ class YAMLSeq extends Collection {
5322
5332
  }
5323
5333
  toJSON(_, ctx) {
5324
5334
  const seq = [];
5325
- if (_optionalChain$c([ctx, 'optionalAccess', _2 => _2.onCreate]))
5335
+ if (_optionalChain$p([ctx, 'optionalAccess', _2 => _2.onCreate]))
5326
5336
  ctx.onCreate(seq);
5327
5337
  let i = 0;
5328
5338
  for (const item of this.items)
@@ -5401,7 +5411,7 @@ function createPairs(schema, iterable, ctx) {
5401
5411
  return pairs;
5402
5412
  }
5403
5413
 
5404
- 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; }
5414
+ 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; }
5405
5415
  class YAMLOMap extends YAMLSeq {
5406
5416
  constructor() {
5407
5417
  super();
@@ -5420,7 +5430,7 @@ class YAMLOMap extends YAMLSeq {
5420
5430
  if (!ctx)
5421
5431
  return super.toJSON(_);
5422
5432
  const map = new Map();
5423
- if (_optionalChain$b([ctx, 'optionalAccess', _2 => _2.onCreate]))
5433
+ if (_optionalChain$o([ctx, 'optionalAccess', _2 => _2.onCreate]))
5424
5434
  ctx.onCreate(map);
5425
5435
  for (const pair of this.items) {
5426
5436
  let key, value;
@@ -5538,7 +5548,7 @@ const isDirExists = async (file) => {
5538
5548
  }
5539
5549
  };
5540
5550
 
5541
- function _optionalChain$a(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; }// ABOUTME: Project type detection utility
5551
+ function _optionalChain$n(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; }// ABOUTME: Project type detection utility
5542
5552
 
5543
5553
  /**
5544
5554
  * 支持的项目类型枚举
@@ -5640,7 +5650,7 @@ const collectProjectInfo = async (
5640
5650
  }
5641
5651
 
5642
5652
  const scripts = Object.entries(
5643
- (_optionalChain$a([packageJson, 'optionalAccess', _ => _.scripts]) ) || {},
5653
+ (_optionalChain$n([packageJson, 'optionalAccess', _ => _.scripts]) ) || {},
5644
5654
  ).reduce((acc, [name, script]) => {
5645
5655
  if (typeof script === 'string') {
5646
5656
  acc[name] = script;
@@ -5794,7 +5804,7 @@ const detectProjectType = async (
5794
5804
  };
5795
5805
  };
5796
5806
 
5797
- function _optionalChain$9(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; }
5807
+ function _optionalChain$m(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; }
5798
5808
 
5799
5809
 
5800
5810
  /**
@@ -5806,7 +5816,7 @@ function _optionalChain$9(ops) { let lastAccessLHS = undefined; let value = ops[
5806
5816
  const parseConfigContent = (content) => {
5807
5817
  // 1. 尝试 TOML 格式 (默认)
5808
5818
  try {
5809
- const config = toml.parse(content);
5819
+ const config = TOML.parse(content);
5810
5820
  return config ;
5811
5821
  } catch (error) {
5812
5822
  // TOML 解析失败,继续尝试其他格式
@@ -5840,7 +5850,7 @@ const parseConfigContent = (content) => {
5840
5850
  */
5841
5851
  const parseTomlConfigContent = (content) => {
5842
5852
  try {
5843
- return toml.parse(content) ;
5853
+ return TOML.parse(content) ;
5844
5854
  } catch (e) {
5845
5855
  return null;
5846
5856
  }
@@ -5921,7 +5931,7 @@ const saveTomlCozeConfig = async (
5921
5931
  projectPath,
5922
5932
  `.coze.tmp-${process.pid}-${Date.now()}`,
5923
5933
  );
5924
- const content = toml.stringify(config );
5934
+ const content = TOML.stringify(config );
5925
5935
 
5926
5936
  try {
5927
5937
  await fs$1.writeFile(tempCozeConfigPath, content, 'utf-8');
@@ -5953,35 +5963,66 @@ const saveProjectPatchState = async (
5953
5963
  await saveTomlCozeConfig(config, projectPath);
5954
5964
  };
5955
5965
 
5956
- /**
5957
- * 获取指定命令的配置
5958
- *
5959
- * @param config - .coze 配置对象
5960
- * @param commandName - 命令名称 (dev/build/start)
5961
- * @returns 命令配置数组
5962
- */
5963
- const getCommandConfig = (
5966
+
5967
+
5968
+ const getDefaultCommandConfig = (
5964
5969
  config,
5965
5970
  commandName,
5966
5971
  ) => {
5967
- let commandConfig;
5972
+ switch (commandName) {
5973
+ case 'dev':
5974
+ return _optionalChain$m([config, 'access', _ => _.dev, 'optionalAccess', _2 => _2.run]);
5975
+ case 'build':
5976
+ return _optionalChain$m([config, 'access', _3 => _3.deploy, 'optionalAccess', _4 => _4.build]);
5977
+ case 'start':
5978
+ return _optionalChain$m([config, 'access', _5 => _5.deploy, 'optionalAccess', _6 => _6.run]);
5979
+ case 'validate':
5980
+ return _optionalChain$m([config, 'access', _7 => _7.dev, 'optionalAccess', _8 => _8.validate]);
5981
+ default:
5982
+ throw new Error(`Unknown command: ${commandName}`);
5983
+ }
5984
+ };
5968
5985
 
5986
+ const getWindowsCommandConfig = (
5987
+ config,
5988
+ commandName,
5989
+ ) => {
5969
5990
  switch (commandName) {
5970
5991
  case 'dev':
5971
- commandConfig = _optionalChain$9([config, 'access', _ => _.dev, 'optionalAccess', _2 => _2.run]);
5972
- break;
5992
+ return _optionalChain$m([config, 'access', _9 => _9.dev, 'optionalAccess', _10 => _10.run_win]);
5973
5993
  case 'build':
5974
- commandConfig = _optionalChain$9([config, 'access', _3 => _3.deploy, 'optionalAccess', _4 => _4.build]);
5975
- break;
5994
+ return _optionalChain$m([config, 'access', _11 => _11.deploy, 'optionalAccess', _12 => _12.build_win]);
5976
5995
  case 'start':
5977
- commandConfig = _optionalChain$9([config, 'access', _5 => _5.deploy, 'optionalAccess', _6 => _6.run]);
5978
- break;
5996
+ return _optionalChain$m([config, 'access', _13 => _13.deploy, 'optionalAccess', _14 => _14.run_win]);
5979
5997
  case 'validate':
5980
- commandConfig = _optionalChain$9([config, 'access', _7 => _7.dev, 'optionalAccess', _8 => _8.validate]);
5981
- break;
5998
+ return _optionalChain$m([config, 'access', _15 => _15.dev, 'optionalAccess', _16 => _16.validate_win]);
5982
5999
  default:
5983
6000
  throw new Error(`Unknown command: ${commandName}`);
5984
6001
  }
6002
+ };
6003
+
6004
+ /**
6005
+ * 获取指定命令的配置
6006
+ *
6007
+ * Windows 优先使用非空的 *_win 配置;其他平台(包括 WSL)始终使用默认配置。
6008
+ *
6009
+ * @param config - .coze 配置对象
6010
+ * @param commandName - 命令名称 (dev/build/start)
6011
+ * @returns 命令配置数组
6012
+ */
6013
+ const getCommandConfig = (
6014
+ config,
6015
+ commandName,
6016
+ platform = process.platform,
6017
+ ) => {
6018
+ const defaultCommandConfig = getDefaultCommandConfig(config, commandName);
6019
+ const windowsCommandConfig =
6020
+ platform === 'win32'
6021
+ ? getWindowsCommandConfig(config, commandName)
6022
+ : undefined;
6023
+ const commandConfig = _optionalChain$m([windowsCommandConfig, 'optionalAccess', _17 => _17.length])
6024
+ ? windowsCommandConfig
6025
+ : defaultCommandConfig;
5985
6026
 
5986
6027
  if (!commandConfig || commandConfig.length === 0) {
5987
6028
  throw new Error(
@@ -6128,7 +6169,7 @@ const byFlag = (flag) => {
6128
6169
  return predicate;
6129
6170
  };
6130
6171
 
6131
- function _optionalChain$8(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; }
6172
+ function _optionalChain$l(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; }
6132
6173
 
6133
6174
 
6134
6175
 
@@ -6159,7 +6200,7 @@ echo "Validate passed!"
6159
6200
  * @returns
6160
6201
  */
6161
6202
  const isCozeValid$3 = (cozeConfig) => {
6162
- if (_optionalChain$8([cozeConfig, 'access', _ => _.dev, 'optionalAccess', _2 => _2.validate])) {
6203
+ if (_optionalChain$l([cozeConfig, 'access', _ => _.dev, 'optionalAccess', _2 => _2.validate])) {
6163
6204
  logger.info('[patch-expo-validate] NOT APPLY: dev.validate exists');
6164
6205
  return false;
6165
6206
  }
@@ -6304,7 +6345,7 @@ const patchExpoValidate = {
6304
6345
  },
6305
6346
  };
6306
6347
 
6307
- function _optionalChain$7(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; }
6348
+ function _optionalChain$k(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; }
6308
6349
 
6309
6350
 
6310
6351
 
@@ -6337,7 +6378,7 @@ echo "Validate passed!"
6337
6378
  * @returns
6338
6379
  */
6339
6380
  const isCozeValid$2 = (cozeConfig) => {
6340
- if (_optionalChain$7([cozeConfig, 'access', _ => _.dev, 'optionalAccess', _2 => _2.validate])) {
6381
+ if (_optionalChain$k([cozeConfig, 'access', _ => _.dev, 'optionalAccess', _2 => _2.validate])) {
6341
6382
  logger.info('[patch-nextjs-validate] NOT APPLY: dev.validate exists');
6342
6383
  return false;
6343
6384
  }
@@ -6485,7 +6526,7 @@ const patchNextjsValidate = {
6485
6526
  },
6486
6527
  };
6487
6528
 
6488
- 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; }
6529
+ function _optionalChain$j(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; }
6489
6530
 
6490
6531
  const PATCH_ID$5 = 'nextjs/validate-concurrently@0.0.30';
6491
6532
  const PACKAGE_JSON_FILE$3 = 'package.json';
@@ -6518,7 +6559,7 @@ const readPackageJson = async (projectFolder) => {
6518
6559
  };
6519
6560
 
6520
6561
  const getTargetValidateScript = (packageJson) => {
6521
- const validateScript = _optionalChain$6([packageJson, 'access', _ => _.scripts, 'optionalAccess', _2 => _2.validate]);
6562
+ const validateScript = _optionalChain$j([packageJson, 'access', _ => _.scripts, 'optionalAccess', _2 => _2.validate]);
6522
6563
  if (typeof validateScript !== 'string') {
6523
6564
  return null;
6524
6565
  }
@@ -6535,7 +6576,7 @@ const getTargetValidateScript = (packageJson) => {
6535
6576
 
6536
6577
  const canStackAfterNextjsValidatePatch = async (context, packageJson) => {
6537
6578
  const scripts = packageJson.scripts || {};
6538
- if (typeof scripts.validate !== 'undefined' || typeof scripts['ts-check'] !== 'string' || _optionalChain$6([context, 'access', _3 => _3.cozeConfig, 'access', _4 => _4.dev, 'optionalAccess', _5 => _5.validate])) {
6579
+ if (typeof scripts.validate !== 'undefined' || typeof scripts['ts-check'] !== 'string' || _optionalChain$j([context, 'access', _3 => _3.cozeConfig, 'access', _4 => _4.dev, 'optionalAccess', _5 => _5.validate])) {
6539
6580
  return false;
6540
6581
  }
6541
6582
 
@@ -6604,7 +6645,7 @@ const patchNextjsValidateConcurrently = {
6604
6645
  apply: patchPackageJson$2,
6605
6646
  };
6606
6647
 
6607
- function _optionalChain$5(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; }
6648
+ function _optionalChain$i(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; }
6608
6649
 
6609
6650
 
6610
6651
 
@@ -6637,7 +6678,7 @@ echo "Validate passed!"
6637
6678
  * @returns
6638
6679
  */
6639
6680
  const isCozeValid$1 = (cozeConfig) => {
6640
- if (_optionalChain$5([cozeConfig, 'access', _ => _.dev, 'optionalAccess', _2 => _2.validate])) {
6681
+ if (_optionalChain$i([cozeConfig, 'access', _ => _.dev, 'optionalAccess', _2 => _2.validate])) {
6641
6682
  logger.info('[patch-vite-validate] NOT APPLY: dev.validate exists');
6642
6683
  return false;
6643
6684
  }
@@ -6782,7 +6823,7 @@ const patchViteValidate = {
6782
6823
  },
6783
6824
  };
6784
6825
 
6785
- 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; }
6826
+ function _optionalChain$h(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; }
6786
6827
 
6787
6828
 
6788
6829
 
@@ -6819,7 +6860,7 @@ echo "Validate passed!"
6819
6860
  * @returns
6820
6861
  */
6821
6862
  const isCozeValid = (cozeConfig) => {
6822
- if (_optionalChain$4([cozeConfig, 'access', _ => _.dev, 'optionalAccess', _2 => _2.validate])) {
6863
+ if (_optionalChain$h([cozeConfig, 'access', _ => _.dev, 'optionalAccess', _2 => _2.validate])) {
6823
6864
  logger.info('[patch-taro-validate] NOT APPLY: dev.validate exists');
6824
6865
  return false;
6825
6866
  }
@@ -6968,7 +7009,7 @@ const patchTaroValidate = {
6968
7009
  },
6969
7010
  };
6970
7011
 
6971
- 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; }
7012
+ function _optionalChain$g(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; }
6972
7013
  const PATCH_ID$2 = 'taro/update-pack-script-for-tt-build@0.0.13';
6973
7014
  const PACKAGE_JSON_FILE = 'package.json';
6974
7015
  const PACK_SCRIPT_FILE = '.cozeproj/scripts/pack.sh';
@@ -7047,12 +7088,12 @@ const readPackageScripts = async (
7047
7088
  const packageJsonContent = await fs$1.readFile(packageJsonPath, 'utf-8');
7048
7089
  const packageJson = safeJsonParse(packageJsonContent, null);
7049
7090
 
7050
- return _optionalChain$3([packageJson, 'optionalAccess', _ => _.scripts]) || null;
7091
+ return _optionalChain$g([packageJson, 'optionalAccess', _ => _.scripts]) || null;
7051
7092
  };
7052
7093
 
7053
7094
  const hasBuildTtScript = async (projectFolder) => {
7054
7095
  const scripts = await readPackageScripts(projectFolder);
7055
- return typeof _optionalChain$3([scripts, 'optionalAccess', _2 => _2['build:tt']]) === 'string';
7096
+ return typeof _optionalChain$g([scripts, 'optionalAccess', _2 => _2['build:tt']]) === 'string';
7056
7097
  };
7057
7098
 
7058
7099
  const hasLegacyPackScript = async (projectFolder) => {
@@ -7406,7 +7447,7 @@ const getTemplatePatches = (
7406
7447
  ) =>
7407
7448
  patches.filter(patch => patch.template === template);
7408
7449
 
7409
- function _nullishCoalesce$3(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain$2(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; }
7450
+ function _nullishCoalesce$5(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain$f(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; }
7410
7451
  const DEFAULT_LEGACY_VERSION = 'legacy';
7411
7452
 
7412
7453
  const loadFlagsWithFallback = async () => {
@@ -7512,7 +7553,7 @@ const getNextPatchState = (
7512
7553
 
7513
7554
  ) => ({
7514
7555
  template,
7515
- version: _optionalChain$2([config, 'access', _ => _.project, 'optionalAccess', _2 => _2.version]) || DEFAULT_LEGACY_VERSION,
7556
+ version: _optionalChain$f([config, 'access', _ => _.project, 'optionalAccess', _2 => _2.version]) || DEFAULT_LEGACY_VERSION,
7516
7557
  appliedPatches: [...appliedPatches, patchId],
7517
7558
  });
7518
7559
 
@@ -7536,15 +7577,15 @@ const executePatch = async (
7536
7577
  }
7537
7578
 
7538
7579
  const template =
7539
- _optionalChain$2([config, 'access', _3 => _3.project, 'optionalAccess', _4 => _4.template]) || (await detectTemplateKey(projectFolder));
7580
+ _optionalChain$f([config, 'access', _3 => _3.project, 'optionalAccess', _4 => _4.template]) || (await detectTemplateKey(projectFolder));
7540
7581
 
7541
7582
  if (!template) {
7542
7583
  logger.info('Patch skipped: template not detected');
7543
7584
  return;
7544
7585
  }
7545
7586
 
7546
- const appliedPatches = [...(_optionalChain$2([config, 'access', _5 => _5.project, 'optionalAccess', _6 => _6.appliedPatches]) || [])];
7547
- const projectVersion = _optionalChain$2([config, 'access', _7 => _7.project, 'optionalAccess', _8 => _8.version]);
7587
+ const appliedPatches = [...(_optionalChain$f([config, 'access', _5 => _5.project, 'optionalAccess', _6 => _6.appliedPatches]) || [])];
7588
+ const projectVersion = _optionalChain$f([config, 'access', _7 => _7.project, 'optionalAccess', _8 => _8.version]);
7548
7589
  const flags = await loadFlagsWithFallback();
7549
7590
 
7550
7591
  const context = {
@@ -7589,7 +7630,7 @@ const executePatch = async (
7589
7630
 
7590
7631
  if (options.dryRun) {
7591
7632
  logger.info(`Detected template: ${template}`);
7592
- logger.info(`Current version: ${_nullishCoalesce$3(projectVersion, () => ( DEFAULT_LEGACY_VERSION))}`);
7633
+ logger.info(`Current version: ${_nullishCoalesce$5(projectVersion, () => ( DEFAULT_LEGACY_VERSION))}`);
7593
7634
  logger.info(`Applied patches: ${appliedPatches.join(', ') || '(none)'}`);
7594
7635
  logger.info('Matched patches:');
7595
7636
  matchedPatches.forEach(patch => {
@@ -7630,7 +7671,7 @@ const executePatch = async (
7630
7671
  }
7631
7672
  };
7632
7673
 
7633
- const registerCommand$4 = program => {
7674
+ const registerCommand$5 = program => {
7634
7675
  program
7635
7676
  .command('patch')
7636
7677
  .description('Apply template patches for existing projects')
@@ -7647,14 +7688,14 @@ const registerCommand$4 = program => {
7647
7688
  ) => {
7648
7689
  await executePatch({
7649
7690
  directory,
7650
- dryRun: _optionalChain$2([command, 'optionalAccess', _9 => _9.dryRun]),
7651
- showFlags: _optionalChain$2([command, 'optionalAccess', _10 => _10.showFlags]),
7691
+ dryRun: _optionalChain$f([command, 'optionalAccess', _9 => _9.dryRun]),
7692
+ showFlags: _optionalChain$f([command, 'optionalAccess', _10 => _10.showFlags]),
7652
7693
  });
7653
7694
  },
7654
7695
  );
7655
7696
  };
7656
7697
 
7657
- function _nullishCoalesce$2(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain$1(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; }
7698
+ function _nullishCoalesce$4(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; }
7658
7699
  const d$1 = debug('coze-init-cli:run');
7659
7700
 
7660
7701
  /**
@@ -7785,12 +7826,12 @@ const executeRun = async (commandName, options = {}) => {
7785
7826
  }
7786
7827
 
7787
7828
  // 将输出同时写入控制台和日志文件
7788
- _optionalChain$1([childProcess, 'access', _ => _.stdout, 'optionalAccess', _2 => _2.on, 'call', _3 => _3('data', (data) => {
7829
+ _optionalChain$e([childProcess, 'access', _ => _.stdout, 'optionalAccess', _2 => _2.on, 'call', _3 => _3('data', (data) => {
7789
7830
  process.stdout.write(data);
7790
7831
  logStream.write(data);
7791
7832
  })]);
7792
7833
 
7793
- _optionalChain$1([childProcess, 'access', _4 => _4.stderr, 'optionalAccess', _5 => _5.on, 'call', _6 => _6('data', (data) => {
7834
+ _optionalChain$e([childProcess, 'access', _4 => _4.stderr, 'optionalAccess', _5 => _5.on, 'call', _6 => _6('data', (data) => {
7794
7835
  process.stderr.write(data);
7795
7836
  logStream.write(data);
7796
7837
  })]);
@@ -7803,7 +7844,7 @@ const executeRun = async (commandName, options = {}) => {
7803
7844
  const buildDuration = Date.now() - buildStartTime;
7804
7845
 
7805
7846
  if (code !== 0) {
7806
- const errorMessage = `Command exited with code ${_nullishCoalesce$2(code, () => ( 'unknown'))}${signal ? ` and signal ${signal}` : ''}`;
7847
+ const errorMessage = `Command exited with code ${_nullishCoalesce$4(code, () => ( 'unknown'))}${signal ? ` and signal ${signal}` : ''}`;
7807
7848
  logger.error(errorMessage);
7808
7849
  logger.error(`Check log file for details: ${logFilePath}`);
7809
7850
 
@@ -7815,12 +7856,12 @@ const executeRun = async (commandName, options = {}) => {
7815
7856
  categories: {
7816
7857
  fixDuration: String(fixDuration),
7817
7858
  buildDuration: String(buildDuration),
7818
- exitCode: String(_nullishCoalesce$2(code, () => ( 'unknown'))),
7859
+ exitCode: String(_nullishCoalesce$4(code, () => ( 'unknown'))),
7819
7860
  projectType,
7820
7861
  },
7821
7862
  errorContext: {
7822
- exitCode: String(_nullishCoalesce$2(code, () => ( 'unknown'))),
7823
- signal: _nullishCoalesce$2(signal, () => ( 'none')),
7863
+ exitCode: String(_nullishCoalesce$4(code, () => ( 'unknown'))),
7864
+ signal: _nullishCoalesce$4(signal, () => ( 'none')),
7824
7865
  logFile: logFilePath,
7825
7866
  projectType,
7826
7867
  },
@@ -7896,7 +7937,7 @@ const executeRun = async (commandName, options = {}) => {
7896
7937
  /**
7897
7938
  * 注册 dev/build/start 命令到 program
7898
7939
  */
7899
- const registerCommand$3 = program => {
7940
+ const registerCommand$4 = program => {
7900
7941
  // dev 命令
7901
7942
  program
7902
7943
  .command('dev')
@@ -8734,7 +8775,7 @@ const scanRoutesOnce = async (
8734
8775
  }
8735
8776
  };
8736
8777
 
8737
- 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; }// Route manifest generation command
8778
+ 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; }// Route manifest generation command
8738
8779
 
8739
8780
 
8740
8781
  const log = debug('coze:routes');
@@ -8822,7 +8863,7 @@ const executeRoutes = async (
8822
8863
  /**
8823
8864
  * Register routes command to program
8824
8865
  */
8825
- const registerCommand$2 = program => {
8866
+ const registerCommand$3 = program => {
8826
8867
  program
8827
8868
  .command('routes')
8828
8869
  .description('Generate routes manifest for the current project')
@@ -8835,11 +8876,11 @@ const registerCommand$2 = program => {
8835
8876
  'Output file path (defaults to ~/.coze/routes.json)',
8836
8877
  )
8837
8878
  .action(async (directory, options) => {
8838
- await executeRoutes({ directory, output: _optionalChain([options, 'optionalAccess', _ => _.output]) });
8879
+ await executeRoutes({ directory, output: _optionalChain$d([options, 'optionalAccess', _ => _.output]) });
8839
8880
  });
8840
8881
  };
8841
8882
 
8842
- function _nullishCoalesce$1(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }
8883
+ function _nullishCoalesce$3(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }
8843
8884
 
8844
8885
 
8845
8886
  const d = debug('coze-init-cli:check-bins');
@@ -8896,7 +8937,7 @@ const checkBins = async (cwd, fix) => {
8896
8937
 
8897
8938
  const bins =
8898
8939
  typeof depPkg.bin === 'string'
8899
- ? { [_nullishCoalesce$1(depName.split('/').pop(), () => ( depName))]: depPkg.bin }
8940
+ ? { [_nullishCoalesce$3(depName.split('/').pop(), () => ( depName))]: depPkg.bin }
8900
8941
  : depPkg.bin;
8901
8942
 
8902
8943
  d('%s declares bins: %o', depName, Object.keys(bins));
@@ -8946,7 +8987,7 @@ const checkBins = async (cwd, fix) => {
8946
8987
  d('pnpm i --force completed');
8947
8988
  };
8948
8989
 
8949
- const registerCommand$1 = program => {
8990
+ const registerCommand$2 = program => {
8950
8991
  program
8951
8992
  .command('check-bins')
8952
8993
  .description(
@@ -9138,6 +9179,7 @@ const shouldRenderFile = (filePath) => {
9138
9179
  '.prettierrc',
9139
9180
  '.babelrc',
9140
9181
  '.sh',
9182
+ '.ps1',
9141
9183
  ]);
9142
9184
 
9143
9185
  const ext = path.extname(filePath).toLowerCase();
@@ -9840,7 +9882,7 @@ const execute = async (
9840
9882
  };
9841
9883
  };
9842
9884
 
9843
- function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }
9885
+ function _nullishCoalesce$2(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }
9844
9886
  /**
9845
9887
  * 运行 pnpm install
9846
9888
  */
@@ -9961,8 +10003,8 @@ const runDev = (projectPath) => {
9961
10003
  // 获取当前 CLI 的可执行文件路径
9962
10004
  // process.argv[0] 是 node,process.argv[1] 是 CLI 入口文件
9963
10005
  // 二者在 CLI 运行时必然存在,兜底空串仅为满足类型收窄,运行时不会命中
9964
- const nodeBin = _nullishCoalesce(process.argv[0], () => ( ''));
9965
- const cliPath = _nullishCoalesce(process.argv[1], () => ( ''));
10006
+ const nodeBin = _nullishCoalesce$2(process.argv[0], () => ( ''));
10007
+ const cliPath = _nullishCoalesce$2(process.argv[1], () => ( ''));
9966
10008
 
9967
10009
  try {
9968
10010
  // 使用通用的后台执行函数启动开发服务器
@@ -10032,7 +10074,7 @@ const executeTemplateEngineStep = async ctx => {
10032
10074
  templateName: ctx.templateName,
10033
10075
  outputPath: ctx.outputPath,
10034
10076
  command: ctx.command,
10035
- force: _nullishCoalesce(ctx.options.force, () => ( false)),
10077
+ force: _nullishCoalesce$2(ctx.options.force, () => ( false)),
10036
10078
  });
10037
10079
 
10038
10080
  // 保存结果到上下文
@@ -10291,7 +10333,7 @@ const executeInit = async (
10291
10333
  /**
10292
10334
  * 注册 init 命令到 program
10293
10335
  */
10294
- const registerCommand = program => {
10336
+ const registerCommand$1 = program => {
10295
10337
  program
10296
10338
  .command('init')
10297
10339
  .description('Initialize a new project from a template')
@@ -10306,67 +10348,3533 @@ const registerCommand = program => {
10306
10348
  false,
10307
10349
  )
10308
10350
  .option('--skip-dev', 'Skip automatic dev server start', false)
10351
+ .addHelpText('after', generateTemplatesHelpText())
10309
10352
  .allowUnknownOption() // 允许透传参数
10310
10353
  .action(async (directory, options, command) => {
10311
10354
  // 位置参数优先级高于 --output 选项
10312
- const outputPath = _nullishCoalesce(directory, () => ( options.output));
10355
+ const outputPath = _nullishCoalesce$2(directory, () => ( options.output));
10313
10356
  // Always use force mode - overwrite existing files without conflict check
10314
10357
  const force = true;
10315
10358
  await executeInit({ ...options, output: outputPath, force }, command);
10316
10359
  });
10317
10360
  };
10318
10361
 
10319
- const commands = [
10320
- registerCommand,
10321
- registerCommand$3,
10322
- registerCommand$6,
10323
- registerCommand$4,
10324
- registerCommand$5,
10325
- registerCommand$2,
10326
- registerCommand$1,
10362
+ const deployCommands = new WeakSet();
10363
+
10364
+ const markDeployCommand = (command) => {
10365
+ deployCommands.add(command);
10366
+ return command;
10367
+ };
10368
+
10369
+ const findDeployCommand = (command) => {
10370
+ let current = command;
10371
+ while (current) {
10372
+ if (deployCommands.has(current)) {
10373
+ return current;
10374
+ }
10375
+ current = current.parent;
10376
+ }
10377
+ throw new Error('Unable to resolve the coze-dev deploy command context.');
10378
+ };
10379
+
10380
+ class CliError extends Error {
10381
+ constructor(
10382
+ message,
10383
+ code = 'DEPLOY_CLI_ERROR',
10384
+ details,
10385
+ ) {
10386
+ super(message);this.code = code;this.details = details; this.name = 'CliError';
10387
+ }
10388
+ }
10389
+
10390
+ const toErrorPayload = (error) => {
10391
+ if (error instanceof CliError) {
10392
+ return { code: error.code, message: error.message, details: error.details };
10393
+ }
10394
+ return {
10395
+ code: 'INTERNAL_ERROR',
10396
+ message: error instanceof Error ? error.message : String(error),
10397
+ };
10398
+ };
10399
+
10400
+ const APPLICATION_TYPES = new Set([
10401
+ 'service',
10402
+ 'pages',
10403
+ 'mini_program',
10404
+ ]);
10405
+
10406
+ const PAGES_SERVICE_TYPE = 3;
10407
+
10408
+ const inferApplicationTypeFromProjectType = (
10409
+ projectType,
10410
+ ) => {
10411
+ switch (projectType) {
10412
+ case 'miniapp':
10413
+ case 'miniprogram':
10414
+ return 'mini_program';
10415
+ case undefined:
10416
+ case '':
10417
+ return undefined;
10418
+ default:
10419
+ return 'service';
10420
+ }
10421
+ };
10422
+
10423
+ const parseApplicationType = (
10424
+ value,
10425
+ ) => {
10426
+ if (!value) {
10427
+ return undefined;
10428
+ }
10429
+ if (!APPLICATION_TYPES.has(value )) {
10430
+ throw new CliError(
10431
+ `Unsupported application type ${value}; expected service, pages, or mini_program.`,
10432
+ 'INVALID_APPLICATION_TYPE',
10433
+ );
10434
+ }
10435
+ return value ;
10436
+ };
10437
+
10438
+ const withRequestedApplicationType = (
10439
+ config,
10440
+ requestedType,
10441
+ hasApplication = false,
10442
+ ) => {
10443
+ if (!requestedType) {
10444
+ return config;
10445
+ }
10446
+ if (hasApplication && config.application_type !== requestedType) {
10447
+ throw new CliError(
10448
+ `Application type mismatch: the application is ${config.application_type}, but ${requestedType} was requested.`,
10449
+ 'APPLICATION_TYPE_MISMATCH',
10450
+ );
10451
+ }
10452
+ if (requestedType !== 'pages') {
10453
+ if (config.application_type !== requestedType) {
10454
+ throw new CliError(
10455
+ `Application type mismatch: server resolved ${config.application_type}, but ${requestedType} was requested.`,
10456
+ 'APPLICATION_TYPE_MISMATCH',
10457
+ );
10458
+ }
10459
+ return config;
10460
+ }
10461
+ return {
10462
+ ...config,
10463
+ application_type: 'pages',
10464
+ deploy_config: {
10465
+ ...config.deploy_config,
10466
+ service_type: PAGES_SERVICE_TYPE,
10467
+ computer_id: undefined,
10468
+ },
10469
+ };
10470
+ };
10471
+
10472
+ 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; }
10473
+ const DEFAULT_CONFIG = {
10474
+ apiBaseUrl: 'https://code.coze.cn/',
10475
+ openApiBaseUrl: 'https://api.coze.cn',
10476
+ clientId: '95438868623436343239609434490626.app.coze',
10477
+ };
10478
+
10479
+ const getSharedConfigPath = () =>
10480
+ node_path.join(node_os.homedir(), '.coze', 'cli', 'config.json');
10481
+
10482
+ const getLegacyConfigPath = () => node_path.join(node_os.homedir(), '.coze', 'config.json');
10483
+
10484
+ const getDesktopRuntimePaths = (
10485
+
10486
+
10487
+ ) => [
10488
+ {
10489
+ path: node_path.join(node_os.homedir(), '.coze', 'desktop', 'runtime.beta.json'),
10490
+ source: 'desktop_beta',
10491
+ },
10492
+ {
10493
+ path: node_path.join(node_os.homedir(), '.coze', 'desktop', 'runtime.json'),
10494
+ source: 'desktop',
10495
+ },
10327
10496
  ];
10328
10497
 
10329
- const main = async () => {
10330
- // 初始化 Slardar 监控
10331
- initSlardar();
10498
+ const isRecord$3 = (value) =>
10499
+ typeof value === 'object' && value !== null && !Array.isArray(value);
10332
10500
 
10333
- // 监听未捕获的异常
10334
- process.on('uncaughtException', async (error) => {
10335
- reportError(error, {
10336
- type: 'uncaughtException',
10337
- context: 'global',
10501
+ const readJson = async (path) => {
10502
+ try {
10503
+ const parsed = safeJsonParse(await promises.readFile(path, 'utf8'), undefined);
10504
+ return isRecord$3(parsed) ? parsed : undefined;
10505
+ } catch (error) {
10506
+ if ((error ).code === 'ENOENT') {
10507
+ return undefined;
10508
+ }
10509
+ throw new CliError(`Unable to read config ${path}: ${String(error)}`, 'CONFIG_INVALID');
10510
+ }
10511
+ };
10512
+
10513
+ const readDesktopAccessTokens = async () => {
10514
+ const candidates = [];
10515
+ for (const { path, source } of getDesktopRuntimePaths()) {
10516
+ try {
10517
+ const runtime = safeJsonParse(await promises.readFile(path, 'utf8'), undefined);
10518
+ if (!isRecord$3(runtime) || !isRecord$3(runtime.patToken)) {
10519
+ continue;
10520
+ }
10521
+ const {accessToken} = runtime.patToken;
10522
+ if (typeof accessToken === 'string' && accessToken.trim()) {
10523
+ candidates.push({ accessToken: accessToken.trim(), source });
10524
+ }
10525
+ } catch (error) {
10526
+ }
10527
+ }
10528
+ return candidates;
10529
+ };
10530
+
10531
+ const configuredPath = (options) =>
10532
+ _optionalChain$c([options, 'optionalAccess', _ => _.config]) || process.env.COZE_CONFIG_FILE;
10533
+
10534
+ const loadConfig = async (options = {}) => {
10535
+ const customPath = configuredPath(options);
10536
+ const globalConfig = customPath
10537
+ ? await readJson(node_path.resolve(customPath))
10538
+ : (await readJson(getSharedConfigPath())) || (await readJson(getLegacyConfigPath()));
10539
+ const fixedAccessTokenCandidates = await readDesktopAccessTokens();
10540
+ const environmentAccessToken = _optionalChain$c([process, 'access', _2 => _2.env, 'access', _3 => _3.COZE_API_TOKEN, 'optionalAccess', _4 => _4.trim, 'call', _5 => _5()]);
10541
+ if (environmentAccessToken) {
10542
+ fixedAccessTokenCandidates.push({
10543
+ accessToken: environmentAccessToken,
10544
+ source: 'environment',
10338
10545
  });
10339
- await flushSlardar();
10340
- process.exit(1);
10341
- });
10546
+ }
10547
+ const fixedAccessToken = _optionalChain$c([fixedAccessTokenCandidates, 'access', _6 => _6[0], 'optionalAccess', _7 => _7.accessToken]);
10548
+ const config = {
10549
+ ...DEFAULT_CONFIG,
10550
+ ...globalConfig,
10551
+ ...(fixedAccessToken
10552
+ ? {
10553
+ accessToken: fixedAccessToken,
10554
+ // Desktop PAT and COZE_API_TOKEN are fixed runtime credentials. Never
10555
+ // combine them with refresh metadata from an earlier OAuth login.
10556
+ refreshToken: undefined,
10557
+ tokenExpiresAt: undefined,
10558
+ }
10559
+ : {}),
10560
+ fixedAccessTokenCandidates,
10561
+ oauthAccessToken:
10562
+ typeof _optionalChain$c([globalConfig, 'optionalAccess', _8 => _8.accessToken]) === 'string' ? globalConfig.accessToken : undefined,
10563
+ oauthRefreshToken:
10564
+ typeof _optionalChain$c([globalConfig, 'optionalAccess', _9 => _9.refreshToken]) === 'string' ? globalConfig.refreshToken : undefined,
10565
+ oauthTokenExpiresAt:
10566
+ typeof _optionalChain$c([globalConfig, 'optionalAccess', _10 => _10.tokenExpiresAt]) === 'number' ? globalConfig.tokenExpiresAt : undefined,
10567
+ fixedAccessTokenResolved: fixedAccessTokenCandidates.length === 0,
10568
+ ...(process.env.COZE_ORG_ID ? { organizationId: process.env.COZE_ORG_ID } : {}),
10569
+ ...(process.env.COZE_ACCOUNT_ID ? { cozeAccountId: process.env.COZE_ACCOUNT_ID } : {}),
10570
+ ...(process.env.COZE_SPACE_ID ? { spaceId: process.env.COZE_SPACE_ID } : {}),
10571
+ ...(process.env.COZE_PROJECT_ID ? { projectId: process.env.COZE_PROJECT_ID } : {}),
10572
+ ...(options.orgId ? { organizationId: options.orgId } : {}),
10573
+ ...(options.spaceId ? { spaceId: options.spaceId } : {}),
10574
+ ...(options.apiBaseUrl ? { apiBaseUrl: options.apiBaseUrl } : {}),
10575
+ // Runtime-only trust decision: a value persisted in config.json must never enable
10576
+ // project-secret injection for an OAuth access token.
10577
+ injectApiToken: Boolean(fixedAccessToken),
10578
+ };
10579
+ return config;
10580
+ };
10342
10581
 
10343
- // 监听未处理的 Promise rejection
10344
- process.on('unhandledRejection', async (reason) => {
10345
- const error = reason instanceof Error ? reason : new Error(String(reason));
10346
- reportError(error, {
10347
- type: 'unhandledRejection',
10348
- context: 'global',
10582
+ const saveSharedConfig = async (
10583
+ patch,
10584
+ options = {},
10585
+ ) => {
10586
+ const target = node_path.resolve(configuredPath(options) || getSharedConfigPath());
10587
+ const existing = (await readJson(target)) || {};
10588
+ const temp = node_path.join(node_path.dirname(target), `.config-${node_crypto.randomUUID()}.tmp`);
10589
+ await promises.mkdir(node_path.dirname(target), { recursive: true });
10590
+ try {
10591
+ await promises.writeFile(temp, `${JSON.stringify({ ...existing, ...patch }, null, 2)}\n`, {
10592
+ encoding: 'utf8',
10593
+ mode: 0o600,
10349
10594
  });
10350
- await flushSlardar();
10351
- process.exit(1);
10595
+ await promises.rename(temp, target);
10596
+ } finally {
10597
+ await promises.rm(temp, { force: true });
10598
+ }
10599
+ };
10600
+
10601
+ 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; }
10602
+
10603
+ const FIVE_MINUTES = 5 * 60 * 1000;
10604
+ const HTTP_UNAUTHORIZED = 401;
10605
+
10606
+
10607
+
10608
+
10609
+
10610
+
10611
+
10612
+ const resolveExpiry = (expiresIn) =>
10613
+ expiresIn > 946684800 ? expiresIn * 1000 : Date.now() + expiresIn * 1000;
10614
+
10615
+ const parseJson = async (response) => {
10616
+ const text = await response.text();
10617
+ if (!text) {
10618
+ return {};
10619
+ }
10620
+ const parsed = safeJsonParse(text, {});
10621
+ return typeof parsed === 'object' && parsed !== null
10622
+ ? (parsed )
10623
+ : {};
10624
+ };
10625
+
10626
+ const isRecord$2 = (value) =>
10627
+ typeof value === 'object' && value !== null && !Array.isArray(value);
10628
+
10629
+ const validateFixedAccessToken = async (
10630
+ accessToken,
10631
+ config,
10632
+ ) => {
10633
+ const response = await fetch(new URL('/v1/users/me', config.openApiBaseUrl), {
10634
+ headers: { authorization: `Bearer ${accessToken}` },
10352
10635
  });
10636
+ const payload = await parseJson(response);
10637
+ if (response.ok) {
10638
+ return true;
10639
+ }
10640
+ if (response.status === HTTP_UNAUTHORIZED) {
10641
+ return false;
10642
+ }
10643
+ throw new CliError(
10644
+ typeof payload.msg === 'string'
10645
+ ? payload.msg
10646
+ : 'Unable to validate the current login.',
10647
+ 'AUTH_STATUS_FAILED',
10648
+ { status: response.status },
10649
+ );
10650
+ };
10353
10651
 
10354
- const program = new commander.Command();
10652
+ const resolveFixedAccessToken = async (config) => {
10653
+ if (
10654
+ config.fixedAccessTokenResolved ||
10655
+ !_optionalChain$b([config, 'access', _ => _.fixedAccessTokenCandidates, 'optionalAccess', _2 => _2.length])
10656
+ ) {
10657
+ config.fixedAccessTokenResolved = true;
10658
+ return;
10659
+ }
10660
+ for (const candidate of config.fixedAccessTokenCandidates || []) {
10661
+ if (await validateFixedAccessToken(candidate.accessToken, config)) {
10662
+ config.accessToken = candidate.accessToken;
10663
+ config.refreshToken = undefined;
10664
+ config.tokenExpiresAt = undefined;
10665
+ config.injectApiToken = true;
10666
+ config.fixedAccessTokenResolved = true;
10667
+ return;
10668
+ }
10669
+ }
10670
+ config.accessToken = config.oauthAccessToken;
10671
+ config.refreshToken = config.oauthRefreshToken;
10672
+ config.tokenExpiresAt = config.oauthTokenExpiresAt;
10673
+ config.injectApiToken = false;
10674
+ config.fixedAccessTokenResolved = true;
10675
+ };
10355
10676
 
10356
- program
10357
- .name('coze-dev')
10358
- .description(
10359
- 'Coze Coding CLI - Project template engine for frontend stacks',
10360
- )
10361
- .version(packageJson.version);
10677
+ const getCurrentUser = async (
10678
+ config,
10679
+ options,
10680
+ ) => {
10681
+ const token = await getAccessToken(config, options);
10682
+ const response = await fetch(new URL('/v1/users/me', config.openApiBaseUrl), {
10683
+ headers: { authorization: `Bearer ${token}` },
10684
+ });
10685
+ const payload = await parseJson(response);
10686
+ if (!response.ok) {
10687
+ throw new CliError(
10688
+ typeof payload.msg === 'string'
10689
+ ? payload.msg
10690
+ : 'Unable to validate the current login. Run `coze-dev deploy auth login` again.',
10691
+ response.status === HTTP_UNAUTHORIZED ? 'AUTH_REQUIRED' : 'AUTH_STATUS_FAILED',
10692
+ { status: response.status },
10693
+ );
10694
+ }
10695
+ return isRecord$2(payload.data) ? payload.data : payload;
10696
+ };
10362
10697
 
10363
- commands.forEach(initCmd => initCmd(program));
10698
+ const clearAuthPatch = {
10699
+ accessToken: undefined,
10700
+ refreshToken: undefined,
10701
+ tokenExpiresAt: undefined,
10702
+ organizationId: undefined,
10703
+ enterpriseId: undefined,
10704
+ spaceId: undefined,
10705
+ projectId: undefined,
10706
+ };
10364
10707
 
10365
- // help 输出中添加模板信息
10366
- program.addHelpText('after', generateTemplatesHelpText());
10708
+ const getAccessToken = async (
10709
+ config,
10710
+ options,
10711
+ ) => {
10712
+ await resolveFixedAccessToken(config);
10713
+ if (!config.accessToken) {
10714
+ throw new CliError(
10715
+ 'No shared login found. Run `coze-dev deploy auth login` first.',
10716
+ 'AUTH_REQUIRED',
10717
+ );
10718
+ }
10719
+ if (!config.refreshToken || !config.tokenExpiresAt) {
10720
+ return config.accessToken;
10721
+ }
10722
+ if (Date.now() < config.tokenExpiresAt - FIVE_MINUTES) {
10723
+ return config.accessToken;
10724
+ }
10367
10725
 
10368
- // 使用 parseAsync 等待命令执行完成
10369
- await program.parseAsync(process.argv);
10726
+ const response = await fetch(
10727
+ new URL('/api/permission/oauth2/token', config.openApiBaseUrl),
10728
+ {
10729
+ method: 'POST',
10730
+ headers: { 'content-type': 'application/json' },
10731
+ body: JSON.stringify({
10732
+ grant_type: 'refresh_token',
10733
+ client_id: config.clientId,
10734
+ refresh_token: config.refreshToken,
10735
+ }),
10736
+ },
10737
+ );
10738
+ const payload = await parseJson(response);
10739
+ if (!response.ok || typeof payload.access_token !== 'string') {
10740
+ throw new CliError(
10741
+ typeof payload.error_description === 'string'
10742
+ ? payload.error_description
10743
+ : 'Shared login has expired. Run `coze-dev deploy auth login` again.',
10744
+ 'AUTH_REFRESH_FAILED',
10745
+ );
10746
+ }
10747
+ const token = payload ;
10748
+ const patch = {
10749
+ accessToken: token.access_token,
10750
+ refreshToken: token.refresh_token || config.refreshToken,
10751
+ tokenExpiresAt: resolveExpiry(token.expires_in),
10752
+ };
10753
+ Object.assign(config, patch);
10754
+ await saveSharedConfig(patch, options);
10755
+ return token.access_token;
10756
+ };
10757
+
10758
+ const saveOAuthToken = async (
10759
+ config,
10760
+ options,
10761
+ token,
10762
+ ) => {
10763
+ const patch = {
10764
+ accessToken: token.access_token,
10765
+ refreshToken: token.refresh_token,
10766
+ tokenExpiresAt: resolveExpiry(token.expires_in),
10767
+ organizationId: undefined,
10768
+ enterpriseId: undefined,
10769
+ spaceId: undefined,
10770
+ projectId: undefined,
10771
+ };
10772
+ Object.assign(config, patch);
10773
+ await saveSharedConfig(patch, options);
10774
+ };
10775
+
10776
+ const logout = async (
10777
+ config,
10778
+ options,
10779
+ ) => {
10780
+ Object.assign(config, clearAuthPatch);
10781
+ await saveSharedConfig(clearAuthPatch, options);
10782
+ };
10783
+
10784
+ const getAuthStatus = async (
10785
+ config,
10786
+ options,
10787
+ ) => {
10788
+ if (!config.accessToken) {
10789
+ return { logged_in: false };
10790
+ }
10791
+ const user = await getCurrentUser(config, options);
10792
+ return {
10793
+ logged_in: true,
10794
+ user,
10795
+ token_expires_at: config.tokenExpiresAt
10796
+ ? new Date(config.tokenExpiresAt).toISOString()
10797
+ : 'Never (PAT)',
10798
+ };
10799
+ };
10800
+
10801
+ const DEFAULT_POLL_INTERVAL_MS = 5000;
10802
+ const SLOW_DOWN_INCREMENT_MS = 5000;
10803
+
10804
+ const isRecord$1 = (value) =>
10805
+ typeof value === 'object' && value !== null && !Array.isArray(value);
10806
+
10807
+ const readPayload = async (response) => {
10808
+ const text = await response.text();
10809
+ const payload = safeJsonParse(text, {});
10810
+ return isRecord$1(payload) ? payload : {};
10811
+ };
10812
+
10813
+ const post = async (
10814
+ baseUrl,
10815
+ path,
10816
+ body,
10817
+ ) => {
10818
+ const response = await fetch(new URL(path, baseUrl), {
10819
+ method: 'POST',
10820
+ headers: { 'content-type': 'application/json' },
10821
+ body: JSON.stringify(body),
10822
+ });
10823
+ return { payload: await readPayload(response), response };
10824
+ };
10825
+
10826
+ const requireString = (
10827
+ payload,
10828
+ key,
10829
+ ) => {
10830
+ const value = payload[key];
10831
+ if (typeof value !== 'string' || !value) {
10832
+ throw new CliError(`OAuth response returned no ${key}.`, 'INVALID_AUTH_RESPONSE');
10833
+ }
10834
+ return value;
10835
+ };
10836
+
10837
+ const requireNumber = (
10838
+ payload,
10839
+ key,
10840
+ ) => {
10841
+ const value = Number(payload[key]);
10842
+ if (!Number.isFinite(value) || value <= 0) {
10843
+ throw new CliError(`OAuth response returned no ${key}.`, 'INVALID_AUTH_RESPONSE');
10844
+ }
10845
+ return value;
10846
+ };
10847
+
10848
+ const requestDeviceCode = async (config) => {
10849
+ const { payload, response } = await post(
10850
+ config.openApiBaseUrl,
10851
+ '/api/permission/oauth2/device/code',
10852
+ { client_id: config.clientId },
10853
+ );
10854
+ if (!response.ok) {
10855
+ throw new CliError(
10856
+ typeof payload.error_description === 'string'
10857
+ ? payload.error_description
10858
+ : 'Unable to start OAuth login.',
10859
+ 'AUTH_LOGIN_FAILED',
10860
+ { status: response.status },
10861
+ );
10862
+ }
10863
+ return {
10864
+ device_code: requireString(payload, 'device_code'),
10865
+ user_code: requireString(payload, 'user_code'),
10866
+ verification_uri: requireString(payload, 'verification_uri'),
10867
+ expires_in: requireNumber(payload, 'expires_in'),
10868
+ interval:
10869
+ typeof payload.interval === 'number' && payload.interval > 0
10870
+ ? payload.interval
10871
+ : undefined,
10872
+ };
10873
+ };
10874
+
10875
+ const buildVerificationUrl = (deviceCode) => {
10876
+ const url = new URL(deviceCode.verification_uri);
10877
+ url.searchParams.set('user_code', deviceCode.user_code);
10878
+ return url.toString();
10879
+ };
10880
+
10881
+ const openBrowser = (url) => {
10882
+ const command =
10883
+ process.platform === 'darwin'
10884
+ ? 'open'
10885
+ : process.platform === 'win32'
10886
+ ? 'cmd'
10887
+ : 'xdg-open';
10888
+ const args = process.platform === 'win32' ? ['/c', 'start', '""', url] : [url];
10889
+ try {
10890
+ const child = node_child_process.spawn(command, args, { detached: true, stdio: 'ignore' });
10891
+ child.on('error', () => undefined);
10892
+ child.unref();
10893
+ } catch (error) {
10894
+ }
10895
+ };
10896
+
10897
+ const sleep = async (milliseconds) =>
10898
+ new Promise(resolve => setTimeout(resolve, milliseconds));
10899
+
10900
+ const pollToken = async (
10901
+ config,
10902
+ deviceCode,
10903
+ ) => {
10904
+ const expiresAt = Date.now() + deviceCode.expires_in * 1000;
10905
+ let interval = (deviceCode.interval || DEFAULT_POLL_INTERVAL_MS / 1000) * 1000;
10906
+ while (Date.now() < expiresAt) {
10907
+ const { payload, response } = await post(
10908
+ config.openApiBaseUrl,
10909
+ '/api/permission/oauth2/token',
10910
+ {
10911
+ grant_type: 'urn:ietf:params:oauth:grant-type:device_code',
10912
+ client_id: config.clientId,
10913
+ device_code: deviceCode.device_code,
10914
+ },
10915
+ );
10916
+ if (response.ok) {
10917
+ return {
10918
+ access_token: requireString(payload, 'access_token'),
10919
+ refresh_token: requireString(payload, 'refresh_token'),
10920
+ expires_in: requireNumber(payload, 'expires_in'),
10921
+ };
10922
+ }
10923
+ if (payload.error === 'authorization_pending') {
10924
+ await sleep(interval);
10925
+ continue;
10926
+ }
10927
+ if (payload.error === 'slow_down') {
10928
+ interval += SLOW_DOWN_INCREMENT_MS;
10929
+ await sleep(interval);
10930
+ continue;
10931
+ }
10932
+ throw new CliError(
10933
+ typeof payload.error_description === 'string'
10934
+ ? payload.error_description
10935
+ : 'OAuth authorization failed.',
10936
+ 'AUTH_LOGIN_FAILED',
10937
+ { oauth_error: payload.error, status: response.status },
10938
+ );
10939
+ }
10940
+ throw new CliError('OAuth authorization expired. Please try again.', 'AUTH_LOGIN_EXPIRED');
10941
+ };
10942
+
10943
+ const loginWithOAuth = async (
10944
+ config,
10945
+ options,
10946
+ callbacks,
10947
+ ) => {
10948
+ const deviceCode = await requestDeviceCode(config);
10949
+ const verificationUrl = buildVerificationUrl(deviceCode);
10950
+ callbacks.onVerification(verificationUrl);
10951
+ openBrowser(verificationUrl);
10952
+ await saveOAuthToken(config, options, await pollToken(config, deviceCode));
10953
+ };
10954
+
10955
+ function _optionalChain$a(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; }
10956
+
10957
+
10958
+
10959
+
10960
+
10961
+
10962
+
10963
+
10964
+
10965
+
10966
+
10967
+
10968
+
10969
+
10970
+
10971
+
10972
+
10973
+
10974
+ const API_PREFIX = '/api/coding/deployment/v2';
10975
+ const CREATE_PROJECT_PATH = '/api/ideserver_api/project/create_vibe_project';
10976
+ const LIST_SPACES_PATH = '/api/playground_api/space/list';
10977
+ const ENCRYPT_PROJECT_SECRET_PATH =
10978
+ '/api/permission_api/project_secret/encrypt_project_secret';
10979
+ const MAX_MESSAGE_LENGTH = 512;
10980
+
10981
+ const isRecord = (value) =>
10982
+ typeof value === 'object' && value !== null && !Array.isArray(value);
10983
+
10984
+
10985
+
10986
+
10987
+
10988
+
10989
+
10990
+ const parseResponse = async (response) => {
10991
+ const text = await response.text();
10992
+ if (!text) {
10993
+ return { payload: {}, text, validJson: true };
10994
+ }
10995
+ const invalid = Symbol('invalid-json');
10996
+ const parsed = safeJsonParse(text, invalid);
10997
+ return parsed === invalid
10998
+ ? { payload: undefined, text, validJson: false }
10999
+ : { payload: parsed, text, validJson: true };
11000
+ };
11001
+
11002
+
11003
+
11004
+
11005
+
11006
+
11007
+
11008
+
11009
+
11010
+ const responseExcerpt = (text) => {
11011
+ const compact = text.replace(/\s+/gu, ' ').trim();
11012
+ return compact ? compact.slice(0, MAX_MESSAGE_LENGTH) : undefined;
11013
+ };
11014
+
11015
+ const unwrap = (
11016
+ payload,
11017
+ expectedKey,
11018
+ responseMetadata,
11019
+ ) => {
11020
+ const root = isRecord(payload) ? payload : undefined;
11021
+ const first = isRecord(_optionalChain$a([root, 'optionalAccess', _ => _.data])) ? root.data : undefined;
11022
+ const second = isRecord(_optionalChain$a([first, 'optionalAccess', _2 => _2.data])) ? first.data : undefined;
11023
+ const envelope = [root, first].find(candidate => candidate && 'code' in candidate);
11024
+ if (_optionalChain$a([envelope, 'optionalAccess', _3 => _3.code]) !== undefined && Number(envelope.code) !== 0) {
11025
+ throw new CliError(
11026
+ typeof envelope.msg === 'string'
11027
+ ? envelope.msg.slice(0, MAX_MESSAGE_LENGTH)
11028
+ : 'The deployment request was rejected.',
11029
+ 'API_REJECTED',
11030
+ { business_code: envelope.code, ...responseMetadata },
11031
+ );
11032
+ }
11033
+ if (!expectedKey) {
11034
+ return (second || first || root || {}) ;
11035
+ }
11036
+ const matched = [second, first, root].find(
11037
+ candidate => candidate && expectedKey in candidate,
11038
+ );
11039
+ if (!matched) {
11040
+ throw new CliError(
11041
+ `Deployment API returned no ${expectedKey}.`,
11042
+ 'INVALID_RESPONSE',
11043
+ );
11044
+ }
11045
+ return matched ;
11046
+ };
11047
+
11048
+ class DeployApiClient {
11049
+ constructor(
11050
+ config,
11051
+ globalOptions,
11052
+ ) {this.config = config;this.globalOptions = globalOptions;}
11053
+
11054
+ debug(message) {
11055
+ if (this.globalOptions.debug) {
11056
+ process.stderr.write(`[debug] [api] ${message}\n`);
11057
+ }
11058
+ }
11059
+
11060
+ async post(
11061
+ path,
11062
+ body,
11063
+ expectedKey,
11064
+ useApiPrefix = true,
11065
+ ) {
11066
+ const token = await getAccessToken(this.config, this.globalOptions);
11067
+ const headers = {
11068
+ authorization: `Bearer ${token}`,
11069
+ 'content-type': 'application/json',
11070
+ 'agw-js-conv': 'str',
11071
+ 'x-request-from-coze-cli': '1',
11072
+ };
11073
+ // Only a fixed runtime credential (desktop PAT or COZE_API_TOKEN) may become
11074
+ // a project runtime secret. OAuth credentials remain authentication-only.
11075
+ if (
11076
+ this.config.injectApiToken &&
11077
+ path === '/deploy_history/create' &&
11078
+ useApiPrefix
11079
+ ) {
11080
+ headers['x-coze-deploy-inject-api-token'] = 'true';
11081
+ }
11082
+ // Coze account id: an explicit COZE_ACCOUNT_ID (config.cozeAccountId) always wins;
11083
+ // otherwise fall back to the organization id resolved from login/config.
11084
+ const cozeAccount = this.config.cozeAccountId || this.config.organizationId;
11085
+ if (cozeAccount) {
11086
+ headers['x-coze-account'] = cozeAccount;
11087
+ }
11088
+ const lane = _optionalChain$a([this, 'access', _4 => _4.globalOptions, 'access', _5 => _5.lane, 'optionalAccess', _6 => _6.trim, 'call', _7 => _7()]) || _optionalChain$a([this, 'access', _8 => _8.config, 'access', _9 => _9.xTTEnv, 'optionalAccess', _10 => _10.trim, 'call', _11 => _11()]);
11089
+ if (lane) {
11090
+ headers['x-use-ppe'] = '1';
11091
+ headers['x-tt-env'] = lane;
11092
+ }
11093
+ const requestUrl = new URL(
11094
+ `${useApiPrefix ? API_PREFIX : ''}${path}`,
11095
+ this.config.apiBaseUrl,
11096
+ );
11097
+ this.debug(
11098
+ `POST ${requestUrl.toString()}${lane ? ` lane=${lane}` : ''}`,
11099
+ );
11100
+ const response = await fetch(
11101
+ requestUrl,
11102
+ { method: 'POST', headers, body: JSON.stringify(body) },
11103
+ );
11104
+ const responseMetadata = {
11105
+ status: response.status,
11106
+ status_text: response.statusText,
11107
+ log_id: response.headers.get('x-tt-logid') || undefined,
11108
+ request_path: requestUrl.pathname,
11109
+ content_type: response.headers.get('content-type') || undefined,
11110
+ };
11111
+ this.debug(
11112
+ `${response.status} ${response.statusText} ${requestUrl.pathname}` +
11113
+ `${responseMetadata.log_id ? ` log_id=${responseMetadata.log_id}` : ' log_id=unavailable'}`,
11114
+ );
11115
+ const { payload, text, validJson } = await parseResponse(response);
11116
+ if (!response.ok) {
11117
+ const root = isRecord(payload) ? payload : undefined;
11118
+ throw new CliError(
11119
+ typeof _optionalChain$a([root, 'optionalAccess', _12 => _12.msg]) === 'string'
11120
+ ? root.msg.slice(0, MAX_MESSAGE_LENGTH)
11121
+ : `Deployment API failed: ${response.status} ${response.statusText}` +
11122
+ `${validJson ? '' : '; response was not JSON'}`,
11123
+ response.status === 401 ? 'AUTH_REQUIRED' : 'HTTP_ERROR',
11124
+ {
11125
+ ...responseMetadata,
11126
+ response_excerpt: responseExcerpt(text),
11127
+ },
11128
+ );
11129
+ }
11130
+ if (!validJson) {
11131
+ throw new CliError(
11132
+ `Deployment API returned invalid JSON (${response.status}).`,
11133
+ 'INVALID_RESPONSE',
11134
+ {
11135
+ ...responseMetadata,
11136
+ response_excerpt: responseExcerpt(text),
11137
+ },
11138
+ );
11139
+ }
11140
+ return unwrap(payload, expectedKey, responseMetadata);
11141
+ }
11142
+
11143
+ createDeploymentProject(body) {
11144
+ return this.post(
11145
+ CREATE_PROJECT_PATH,
11146
+ body,
11147
+ 'project_id',
11148
+ false,
11149
+ );
11150
+ }
11151
+
11152
+ // 回读当前登录态对应的 Coze 账号 id。无入参:账号由服务端从登录态解析(X-Coze-Account →
11153
+ // access token → 兜底登录用户),客户端传什么都只有「等于登录态」一种合法取值。
11154
+ // 只在建 Project 前用一次,用来定这个 Project 下应用的账号归属。
11155
+ getCozeAccount() {
11156
+ return this.post(
11157
+ '/account/get',
11158
+ {},
11159
+ 'coze_account_id',
11160
+ );
11161
+ }
11162
+
11163
+ listSpaces(body
11164
+
11165
+
11166
+
11167
+
11168
+ ) {
11169
+ return this.post(
11170
+ LIST_SPACES_PATH,
11171
+ body,
11172
+ 'bot_space_list',
11173
+ false,
11174
+ );
11175
+ }
11176
+
11177
+ encryptProjectSecret(projectId, secrets) {
11178
+ return this.post(
11179
+ ENCRYPT_PROJECT_SECRET_PATH,
11180
+ {
11181
+ project_id: projectId,
11182
+ encrypt_secrets: {
11183
+ secrets,
11184
+ cred_providers: [],
11185
+ },
11186
+ },
11187
+ 'sealed_secrets',
11188
+ false,
11189
+ );
11190
+ }
11191
+
11192
+ // 列当前登录用户名下的 Application,跨 Project。服务端从登录态取 user_id,
11193
+ // 请求体里只有分页参数(deploy_app/list 已去掉 project_id / user_id 两个寻址入参)。
11194
+ listApplications(body) {
11195
+ return this.post(
11196
+ '/deploy_app/list', body, 'items',
11197
+ );
11198
+ }
11199
+
11200
+ getApplication(appId) {
11201
+ return this.post('/deploy_app/get', { app_id: appId }, 'app_id');
11202
+ }
11203
+
11204
+ updateApplication(body) {
11205
+ return this.post('/deploy_app/update', body, 'app_id');
11206
+ }
11207
+
11208
+ // 删除 Application:服务端只接受 **Stopped** 状态,其余状态会带上当前状态报错(先 stop 再 delete)。
11209
+ // 已删除的再删一次是幂等成功。
11210
+ deleteApplication(appId) {
11211
+ return this.post('/deploy_app/delete', { app_id: appId });
11212
+ }
11213
+
11214
+ getDeployConfig(body
11215
+
11216
+
11217
+
11218
+
11219
+
11220
+ ) {
11221
+ return this.post('/deploy_config/get', body, 'deploy_config');
11222
+ }
11223
+
11224
+ createDeployHistory(body) {
11225
+ return this.post('/deploy_history/create', body, 'app_id');
11226
+ }
11227
+
11228
+ preDeployUpload(body
11229
+
11230
+
11231
+ ) {
11232
+ return this.post('/deploy_history/pre_upload', body, 'upload_url');
11233
+ }
11234
+
11235
+ getDeployHistory(body) {
11236
+ return this.post('/deploy_history/get', body, 'deploy_history_id');
11237
+ }
11238
+
11239
+ listDeployHistory(body) {
11240
+ return this.post
11241
+
11242
+
11243
+
11244
+ ('/deploy_history/list', body, 'deploy_history_list');
11245
+ }
11246
+
11247
+ getOnlineDeployHistory(appId) {
11248
+ return this.post(
11249
+ '/deploy_history/get_online', { app_id: appId }, 'deploy_history_list',
11250
+ );
11251
+ }
11252
+
11253
+ getOnlineEnvironment(appId) {
11254
+ return this.post(
11255
+ '/environment/get_online', { app_id: appId }, 'app_id',
11256
+ );
11257
+ }
11258
+
11259
+ checkRollbackDatabase(body) {
11260
+ return this.post(
11261
+ '/deploy_history/check_rollback_database', body, 'is_rollback_possible',
11262
+ );
11263
+ }
11264
+
11265
+ cancelDeployHistory(body) {
11266
+ return this.post('/deploy_history/cancel', body);
11267
+ }
11268
+
11269
+ rollbackDeployHistory(body
11270
+
11271
+
11272
+
11273
+ ) {
11274
+ return this.post(
11275
+ '/deploy_history/rollback', body, 'new_deploy_history_id',
11276
+ );
11277
+ }
11278
+
11279
+ stopApplication(appId) {
11280
+ return this.post('/application/stop', { app_id: appId });
11281
+ }
11282
+
11283
+ resumeApplication(appId) {
11284
+ return this.post('/application/resume', { app_id: appId });
11285
+ }
11286
+
11287
+ // 暂停是可逆的:只把线上 Unit 从 Ready 改成 Paused,函数留着,可被 resume 推回 Ready。
11288
+ // stop 会连函数一起删、落到 Stopped,只能靠重新部署恢复 —— resume 配对的是 pause,不是 stop。
11289
+ pauseApplication(appId) {
11290
+ return this.post('/application/pause', { app_id: appId });
11291
+ }
11292
+
11293
+ // PV / UV。入参是 app_id,但服务端反查 project_id 后按 **Project** 聚合 —— 埋点链路只有
11294
+ // project 维度,同一 Project 下多个 Application 拿到的是同一份数据。
11295
+ getUserAnalyticsMetrics(body) {
11296
+ return this.post(
11297
+ '/metrics/user_analytics/get', body, 'charts',
11298
+ );
11299
+ }
11300
+
11301
+ getBuildLog(body) {
11302
+ return this.post('/deploy_history/log', body, 'log');
11303
+ }
11304
+
11305
+ searchRuntimeLog(body) {
11306
+ return this.post(
11307
+ '/runtime_log/search', body, 'logs',
11308
+ );
11309
+ }
11310
+
11311
+ getRuntimeLogCount(appId) {
11312
+ return this.post(
11313
+ '/runtime_log/count', { app_id: appId }, 'limit',
11314
+ );
11315
+ }
11316
+
11317
+ getDeployCount(appId) {
11318
+ return this.post(
11319
+ '/deploy_history/get_count', { app_id: appId }, 'success_count',
11320
+ );
11321
+ }
11322
+
11323
+ getApplicationMetrics(body) {
11324
+ return this.post(
11325
+ '/metrics/get', body, 'charts',
11326
+ );
11327
+ }
11328
+
11329
+ getHostedUsageMonthly(body) {
11330
+ return this.post(
11331
+ '/hosted_usage/monthly', body, 'summary',
11332
+ );
11333
+ }
11334
+
11335
+ authorizeMiniProgram(body
11336
+
11337
+
11338
+
11339
+
11340
+
11341
+
11342
+ ) {
11343
+ return this.post
11344
+
11345
+
11346
+
11347
+ ('/mini_program/auth', body);
11348
+ }
11349
+
11350
+ createMiniProgramPreview(body
11351
+
11352
+
11353
+
11354
+
11355
+
11356
+ ) {
11357
+ return this.post
11358
+
11359
+
11360
+
11361
+
11362
+ ('/mini_program/preview', body);
11363
+ }
11364
+
11365
+ listDomains(appId, unitType) {
11366
+ return this.post(
11367
+ '/domain/list', {
11368
+ app_id: appId,
11369
+ ...(unitType === undefined ? {} : { unit_type: unitType }),
11370
+ }, 'items',
11371
+ );
11372
+ }
11373
+
11374
+ createDomain(body) {
11375
+ return this.post('/domain/create', body, 'domain');
11376
+ }
11377
+
11378
+ // 改的是系统分配的 <prefix>.coze.site 里的 prefix,不是 createDomain 加进来的自定义域名 ——
11379
+ // 那类域名服务端只提供 create/delete,域名串本身不可改。
11380
+ updateDefaultDomainPrefix(body) {
11381
+ return this.post
11382
+
11383
+
11384
+
11385
+
11386
+ ('/domain/update_default_prefix', body, 'new_domain_host_canonical');
11387
+ }
11388
+
11389
+ getMiniProgramAuthStatus(body) {
11390
+ return this.post
11391
+
11392
+
11393
+
11394
+
11395
+ ('/api/coding/deployment/auth/status', body, 'is_authorized', false);
11396
+ }
11397
+
11398
+ bindMiniProgramAuth(body
11399
+
11400
+
11401
+
11402
+
11403
+
11404
+ ) {
11405
+ return this.post
11406
+
11407
+
11408
+
11409
+
11410
+
11411
+
11412
+ ('/api/coding/deployment/auth/bind', body, 'bind_status', false);
11413
+ }
11414
+
11415
+ submitMiniProgramAuthCode(body
11416
+
11417
+
11418
+
11419
+
11420
+
11421
+ ) {
11422
+ return this.post(
11423
+ '/api/coding/deployment/auth/submit_code', body, undefined, false,
11424
+ );
11425
+ }
11426
+
11427
+ unbindMiniProgramAuth(body) {
11428
+ return this.post(
11429
+ '/api/coding/deployment/auth/unbind', body, undefined, false,
11430
+ );
11431
+ }
11432
+ }
11433
+
11434
+ const textValue = (value) => {
11435
+ if (typeof value === 'string') {
11436
+ return value;
11437
+ }
11438
+ return JSON.stringify(value, null, 2);
11439
+ };
11440
+
11441
+ class Output {
11442
+ constructor(
11443
+ format,
11444
+ debugEnabled = false,
11445
+ ) {this.format = format;this.debugEnabled = debugEnabled;}
11446
+
11447
+ print(value) {
11448
+ process.stdout.write(
11449
+ this.format === 'json'
11450
+ ? `${JSON.stringify(value, null, 2)}\n`
11451
+ : `${textValue(value)}\n`,
11452
+ );
11453
+ }
11454
+
11455
+ info(message) {
11456
+ if (this.format === 'text') {
11457
+ process.stderr.write(`${message}\n`);
11458
+ }
11459
+ }
11460
+
11461
+ notice(message) {
11462
+ process.stderr.write(`${message}\n`);
11463
+ }
11464
+
11465
+ warn(message) {
11466
+ process.stderr.write(`Warning: ${message}\n`);
11467
+ }
11468
+
11469
+ debug(message) {
11470
+ if (this.debugEnabled) {
11471
+ process.stderr.write(`[debug] ${message}\n`);
11472
+ }
11473
+ }
11474
+ }
11475
+
11476
+ const runtimes = new WeakMap();
11477
+
11478
+ const getRuntime = async (command) => {
11479
+ const deploy = findDeployCommand(command);
11480
+ let runtime = runtimes.get(deploy);
11481
+ if (!runtime) {
11482
+ runtime = (async () => {
11483
+ const options = deploy.opts();
11484
+ const config = await loadConfig(options);
11485
+ return {
11486
+ client: new DeployApiClient(config, options),
11487
+ config,
11488
+ cwd: process.cwd(),
11489
+ globalOptions: options,
11490
+ output: new Output(options.format || 'json', options.debug),
11491
+ };
11492
+ })();
11493
+ runtimes.set(deploy, runtime);
11494
+ }
11495
+ return runtime;
11496
+ };
11497
+
11498
+ const PRIVACY_POLICY_URL = 'https://docs.coze.cn/guides/privacy';
11499
+ const TERMS_OF_SERVICE_URL = 'https://docs.coze.cn/guides/terms-of-service';
11500
+
11501
+ const registerAuth = (program) => {
11502
+ const auth = program.command('auth').description('Manage deployment CLI authentication');
11503
+
11504
+ auth
11505
+ .command('login')
11506
+ .description('Login with Coze OAuth and save shared credentials')
11507
+ .action(async (_options, command) => {
11508
+ const runtime = await getRuntime(command);
11509
+ await loginWithOAuth(runtime.config, runtime.globalOptions, {
11510
+ onVerification: url => {
11511
+ runtime.output.notice(
11512
+ [
11513
+ 'Open this URL to authorize coze-dev deploy:',
11514
+ url,
11515
+ `Privacy Policy: ${PRIVACY_POLICY_URL}`,
11516
+ `Terms of Service: ${TERMS_OF_SERVICE_URL}`,
11517
+ ].join('\n'),
11518
+ );
11519
+ },
11520
+ });
11521
+ runtime.output.print({ success: true, logged_in: true, method: 'OAuth' });
11522
+ });
11523
+
11524
+ auth
11525
+ .command('status')
11526
+ .description('Check and refresh the current shared login')
11527
+ .action(async (_options, command) => {
11528
+ const runtime = await getRuntime(command);
11529
+ runtime.output.print(await getAuthStatus(runtime.config, runtime.globalOptions));
11530
+ });
11531
+
11532
+ auth
11533
+ .command('logout')
11534
+ .description('Clear shared credentials and account context')
11535
+ .action(async (_options, command) => {
11536
+ const runtime = await getRuntime(command);
11537
+ await logout(runtime.config, runtime.globalOptions);
11538
+ runtime.output.print({ success: true, logged_out: true });
11539
+ });
11540
+ };
11541
+
11542
+ const execFileAsync = node_util.promisify(node_child_process.execFile);
11543
+
11544
+ const registerContext = (program) => {
11545
+ const context = program.command('context').description('Show or update deployment context');
11546
+ context.command('show').action(async (_options, command) => {
11547
+ const runtime = await getRuntime(command);
11548
+ runtime.output.print({
11549
+ organization_id: runtime.config.organizationId,
11550
+ space_id: runtime.config.spaceId,
11551
+ project_id: runtime.config.projectId,
11552
+ lane: runtime.globalOptions.lane || runtime.config.xTTEnv,
11553
+ config_path: runtime.globalOptions.config || getSharedConfigPath(),
11554
+ });
11555
+ });
11556
+ context
11557
+ .command('use')
11558
+ .option('--space-id <spaceId>', 'Default Space ID')
11559
+ .option('--project-id <projectId>', 'Default Project ID')
11560
+ .action(async (options, command) => {
11561
+ const runtime = await getRuntime(command);
11562
+ await saveSharedConfig(
11563
+ {
11564
+ ...(options.spaceId ? { spaceId: options.spaceId } : {}),
11565
+ ...(options.projectId ? { projectId: options.projectId } : {}),
11566
+ },
11567
+ runtime.globalOptions,
11568
+ );
11569
+ runtime.output.print({
11570
+ space_id: options.spaceId || runtime.config.spaceId,
11571
+ project_id: options.projectId || runtime.config.projectId,
11572
+ });
11573
+ });
11574
+ };
11575
+
11576
+ const registerDoctor = (program) => {
11577
+ program
11578
+ .command('doctor')
11579
+ .description('Check deployment CLI prerequisites and shared login')
11580
+ .action(async (_options, command) => {
11581
+ const runtime = await getRuntime(command);
11582
+ let gitAvailable = true;
11583
+ try {
11584
+ await execFileAsync('git', ['--version']);
11585
+ } catch (e) {
11586
+ gitAvailable = false;
11587
+ }
11588
+ runtime.output.print({
11589
+ ok: gitAvailable && Boolean(runtime.config.accessToken),
11590
+ git: gitAvailable ? 'ok' : 'missing',
11591
+ login: runtime.config.accessToken ? 'reused' : 'missing',
11592
+ login_config: runtime.globalOptions.config || getSharedConfigPath(),
11593
+ project_id: runtime.config.projectId || 'not configured',
11594
+ });
11595
+ });
11596
+ };
11597
+
11598
+ function _optionalChain$9(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; }
11599
+
11600
+
11601
+
11602
+
11603
+
11604
+
11605
+
11606
+
11607
+
11608
+
11609
+
11610
+
11611
+
11612
+
11613
+
11614
+
11615
+
11616
+
11617
+
11618
+
11619
+
11620
+
11621
+
11622
+
11623
+
11624
+
11625
+
11626
+
11627
+
11628
+ const getDeployParentOptions = (command) =>
11629
+ _optionalChain$9([command, 'access', _ => _.parent, 'optionalAccess', _2 => _2.opts, 'call', _3 => _3()]) || {};
11630
+
11631
+ const getDeployAppIdOption = (
11632
+ options,
11633
+ command,
11634
+ ) => options.appId || getDeployParentOptions(command).appId;
11635
+
11636
+ function _optionalChain$8(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$1(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; }
11637
+
11638
+ const isAccountId = (value) => /^[1-9]\d*$/u.test(value);
11639
+
11640
+ /**
11641
+ * 定出这个 Project 下的应用该归属哪个 Coze 账号,写进 project_settings.extra.coze_account_id。
11642
+ *
11643
+ * 优先级(与 api-client 里 x-coze-account 的取值顺序一致,不另立一套口径):
11644
+ * 1. COZE_ACCOUNT_ID(config.cozeAccountId)—— 用户显式指定
11645
+ * 2. COZE_ORG_ID / --org-id(config.organizationId)—— 用户显式指定组织
11646
+ * 3. 登录态回读(deploy v2 account/get)
11647
+ *
11648
+ * ⚠️ 1、2 命中时**不打接口**:本地已经知道账号了,再问一次服务端只是多一个 RTT 和一个失败点。
11649
+ *
11650
+ * 拿不到就返回 undefined(不写 extra),部署照常继续:服务端在 deploy_history/create 里仍会
11651
+ * 按同一条阶梯解析账号,结果与不加这段逻辑时完全一致 —— 只是无登录态的预览初始化那条链路
11652
+ * 少了 Project 上这份归属记录。这是一个辅助接口,不该成为首次部署的单点。
11653
+ */
11654
+ const resolveCozeAccountId = async (
11655
+ runtime,
11656
+ ) => {
11657
+ const configured =
11658
+ _optionalChain$8([runtime, 'access', _ => _.config, 'access', _2 => _2.cozeAccountId, 'optionalAccess', _3 => _3.trim, 'call', _4 => _4()]) || _optionalChain$8([runtime, 'access', _5 => _5.config, 'access', _6 => _6.organizationId, 'optionalAccess', _7 => _7.trim, 'call', _8 => _8()]);
11659
+ if (configured) {
11660
+ if (!isAccountId(configured)) {
11661
+ // 不把非法值写进 Project —— 它会被服务端当成「明确但损坏的归属」直接报错。
11662
+ // 该值仍会作为 x-coze-account 发出去,由服务端给出明确的参数错误。
11663
+ runtime.output.debug(
11664
+ `[deploy] Ignoring malformed Coze account id for project settings: ${configured}`,
11665
+ );
11666
+ return undefined;
11667
+ }
11668
+ runtime.output.debug(`[deploy] Using configured Coze account ${configured}`);
11669
+ return configured;
11670
+ }
11671
+ try {
11672
+ const accountId = await _asyncOptionalChain$1([(await runtime.client.getCozeAccount()), 'access', async _9 => _9.coze_account_id, 'optionalAccess', async _10 => _10.trim, 'call', async _11 => _11()]);
11673
+ if (!accountId || !isAccountId(accountId)) {
11674
+ runtime.output.debug(
11675
+ `[deploy] Deployment API returned no usable Coze account id: ${String(accountId)}`,
11676
+ );
11677
+ return undefined;
11678
+ }
11679
+ runtime.output.debug(`[deploy] Resolved Coze account ${accountId} from the current login`);
11680
+ return accountId;
11681
+ } catch (error) {
11682
+ runtime.output.warn(
11683
+ `Unable to resolve the Coze account from the current login; the project will be created without an explicit account: ${String(error)}`,
11684
+ );
11685
+ return undefined;
11686
+ }
11687
+ };
11688
+
11689
+ const getCreateDeployConfig = (config) => ({
11690
+ deploy_config: {
11691
+ cpu: config.deploy_config.cpu,
11692
+ memory_mb: config.deploy_config.memory_mb,
11693
+ max_instance: config.deploy_config.max_instance,
11694
+ max_concurrency: config.deploy_config.max_concurrency,
11695
+ },
11696
+ service_type: config.deploy_config.service_type,
11697
+ ...(config.deploy_config.computer_id
11698
+ ? { computer_id: config.deploy_config.computer_id }
11699
+ : {}),
11700
+ });
11701
+
11702
+ const DEPLOY_STATUS = {
11703
+ pending: 1,
11704
+ running: 2,
11705
+ succeeded: 3,
11706
+ failed: 4,
11707
+ canceled: 5,
11708
+ interrupted: 6,
11709
+ preDeploy: 7,
11710
+ } ;
11711
+
11712
+ const STATUS_NAMES = {
11713
+ [DEPLOY_STATUS.pending]: 'Pending',
11714
+ [DEPLOY_STATUS.running]: 'Running',
11715
+ [DEPLOY_STATUS.succeeded]: 'Succeeded',
11716
+ [DEPLOY_STATUS.failed]: 'Failed',
11717
+ [DEPLOY_STATUS.canceled]: 'Canceled',
11718
+ [DEPLOY_STATUS.interrupted]: 'Interrupted',
11719
+ [DEPLOY_STATUS.preDeploy]: 'WaitingForUpload',
11720
+ };
11721
+
11722
+ /**
11723
+ * 终态 = 不会再变了。
11724
+ *
11725
+ * ⚠️ `interrupted(6)` **不是**终态,别再往这里加。它是过程态:服务端某条流水线自身轮询超时时,
11726
+ * 会把整次部署标成 Interrupted 并安排稍后重新触发(`base_pipe.NewInterruptedResult`),之后仍
11727
+ * 会推进到 Succeeded。安卓构建 10 分钟起步,几乎必然经过至少一次 Interrupted —— 把它当终态会
11728
+ * 让 `deploy --wait` 在构建中途就收工返回,此时 APK 还没产出,`mobile_artifact_list` 是空的。
11729
+ */
11730
+ const TERMINAL_STATUSES = new Set([
11731
+ DEPLOY_STATUS.succeeded,
11732
+ DEPLOY_STATUS.failed,
11733
+ DEPLOY_STATUS.canceled,
11734
+ ]);
11735
+
11736
+ const getDeployStatusText = (status) =>
11737
+ status ? STATUS_NAMES[status] || 'Unknown' : 'Unknown';
11738
+
11739
+ /** 这次部署的结果是否已经定下来了(到了终态就不会再变)。 */
11740
+ const isDeploymentSettled = (status) =>
11741
+ status !== undefined && TERMINAL_STATUSES.has(status);
11742
+
11743
+ function _optionalChain$7(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; }
11744
+
11745
+ const formatDeployDetails = (history) =>
11746
+ (_optionalChain$7([history, 'optionalAccess', _ => _.deploy_detail]) || []).map(detail => ({
11747
+ target: detail.target,
11748
+ status: getDeployStatusText(detail.status),
11749
+ deploy_log_key: detail.deploy_log_key,
11750
+ deploy_log_url: detail.deploy_log_url,
11751
+ }));
11752
+
11753
+ const getDeployLogKeys = (history) =>
11754
+ [...new Set(
11755
+ (history.deploy_detail || [])
11756
+ .map(detail => _optionalChain$7([detail, 'access', _2 => _2.deploy_log_key, 'optionalAccess', _3 => _3.trim, 'call', _4 => _4()]))
11757
+ .filter((key) => Boolean(key)),
11758
+ )];
11759
+
11760
+ const normalizePositiveId = (value) => {
11761
+ const normalized = value === undefined ? '' : String(value).trim();
11762
+ return /^[1-9]\d*$/.test(normalized) ? normalized : undefined;
11763
+ };
11764
+
11765
+ const resolveDeployHistoryId = (
11766
+ deployHistoryId,
11767
+ previousDeployHistoryId,
11768
+ ) =>
11769
+ normalizePositiveId(deployHistoryId) || normalizePositiveId(previousDeployHistoryId);
11770
+
11771
+ 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; }
11772
+
11773
+ const SOURCE_SNAPSHOT_BYTES = 20;
11774
+ const PROJECT_METADATA_FILE_MODE = 0o644;
11775
+
11776
+ const isId = (value) =>
11777
+ typeof value === 'string' && /^\d+$/u.test(value);
11778
+
11779
+
11780
+ const resolveAppId = async (cwd, appId) => {
11781
+ const explicit = _optionalChain$6([appId, 'optionalAccess', _ => _.trim, 'call', _2 => _2()]);
11782
+ if (explicit) {
11783
+ return explicit;
11784
+ }
11785
+ try {
11786
+ return (await readProjectMetadata(node_path.resolve(cwd))).appId;
11787
+ } catch (error) {
11788
+ if ((error ).code === 'COZE_FILE_NOT_FOUND') {
11789
+ return undefined;
11790
+ }
11791
+ throw error;
11792
+ }
11793
+ };
11794
+
11795
+ const requireAppId = async (cwd, appId) => {
11796
+ const resolved = await resolveAppId(cwd, appId);
11797
+ if (!resolved) {
11798
+ throw new CliError(
11799
+ 'Application ID is required. Pass --app-id or use a directory whose .coze [project] contains app_id.',
11800
+ 'APP_ID_REQUIRED',
11801
+ );
11802
+ }
11803
+ return resolved;
11804
+ };
11805
+
11806
+ const resolveSourceSnapshot = (sourceRootInput) => {
11807
+ const sourceRoot = node_path.resolve(sourceRootInput);
11808
+ const commitHash = node_crypto.randomBytes(SOURCE_SNAPSHOT_BYTES).toString('hex');
11809
+ return { commitHash, sourceRoot };
11810
+ };
11811
+
11812
+ const readProjectMetadata = async (
11813
+ sourceRoot,
11814
+ ) => {
11815
+ let cozeFileContent = '';
11816
+ try {
11817
+ cozeFileContent = await promises.readFile(node_path.join(sourceRoot, '.coze'), 'utf8');
11818
+ } catch (error) {
11819
+ if ((error ).code === 'ENOENT') {
11820
+ throw new CliError(
11821
+ `No .coze file found in ${sourceRoot}.`,
11822
+ 'COZE_FILE_NOT_FOUND',
11823
+ );
11824
+ }
11825
+ throw error;
11826
+ }
11827
+ const projectSection = _optionalChain$6([cozeFileContent, 'access', _3 => _3.match, 'call', _4 => _4(
11828
+ /^\s*\[project\]\s*(?:#.*)?$([\s\S]*?)(?=^\s*\[[^\]]+\]\s*(?:#.*)?$|(?![\s\S]))/mu,
11829
+ ), 'optionalAccess', _5 => _5[1]]);
11830
+ const readProjectString = (key) =>
11831
+ _optionalChain$6([projectSection
11832
+ , 'optionalAccess', _6 => _6.match, 'call', _7 => _7(new RegExp(`^\\s*${key}\\s*=\\s*["']([^"']+)["']`, 'mu')), 'optionalAccess', _8 => _8[1]
11833
+ , 'optionalAccess', _9 => _9.trim, 'call', _10 => _10()]);
11834
+ const name = readProjectString('name');
11835
+ const projectType = readProjectString('project_type');
11836
+ const projectId = readProjectString('project_id');
11837
+ const appId = readProjectString('app_id');
11838
+ const hasUnquotedId = (key) =>
11839
+ Boolean(_optionalChain$6([projectSection, 'optionalAccess', _11 => _11.match, 'call', _12 => _12(new RegExp(`^\\s*${key}\\s*=\\s*(?!["'])\\S+`, 'mu'))]));
11840
+ if (hasUnquotedId('project_id') || hasUnquotedId('app_id')) {
11841
+ throw new CliError(
11842
+ '.coze [project].project_id and app_id must be quoted decimal strings.',
11843
+ 'INVALID_COZE_FILE',
11844
+ );
11845
+ }
11846
+ if (projectId && !isId(projectId)) {
11847
+ throw new CliError('.coze [project].project_id must be a quoted decimal string.', 'INVALID_COZE_FILE');
11848
+ }
11849
+ if (appId && !isId(appId)) {
11850
+ throw new CliError('.coze [project].app_id must be a quoted decimal string.', 'INVALID_COZE_FILE');
11851
+ }
11852
+ return { name, projectType, projectId, appId, cozeFileContent };
11853
+ };
11854
+
11855
+ const updateProjectValue = (content, key, value) => {
11856
+ const sectionMatch = /^\s*\[project\]\s*(?:#.*)?$/mu.exec(content);
11857
+ if (!sectionMatch || sectionMatch.index === undefined) {
11858
+ const prefix = `[project]\n${key} = ${JSON.stringify(value)}\n\n`;
11859
+ return `${prefix}${content}`;
11860
+ }
11861
+ const sectionStart = sectionMatch.index + sectionMatch[0].length;
11862
+ const following = content.slice(sectionStart);
11863
+ const nextSection = /^\s*\[[^\]]+\]\s*(?:#.*)?$/mu.exec(following);
11864
+ const sectionEnd = _optionalChain$6([nextSection, 'optionalAccess', _13 => _13.index]) === undefined
11865
+ ? content.length
11866
+ : sectionStart + nextSection.index;
11867
+ const before = content.slice(0, sectionStart);
11868
+ let body = content.slice(sectionStart, sectionEnd);
11869
+ const keyPattern = new RegExp(`^(\\s*)${key}\\s*=.*$`, 'mu');
11870
+ if (keyPattern.test(body)) {
11871
+ body = body.replace(keyPattern, `$1${key} = ${JSON.stringify(value)}`);
11872
+ } else {
11873
+ const separator = body.startsWith('\n') || body.startsWith('\r\n') ? '' : '\n';
11874
+ body = `${separator}${body}`;
11875
+ const trailingNewline = body.endsWith('\n') ? '' : '\n';
11876
+ body = `${body}${trailingNewline}${key} = ${JSON.stringify(value)}\n`;
11877
+ }
11878
+ return `${before}${body}${content.slice(sectionEnd)}`;
11879
+ };
11880
+
11881
+ const writeProjectBinding = async (
11882
+ sourceRoot,
11883
+ binding,
11884
+ ) => {
11885
+ const path = node_path.join(sourceRoot, '.coze');
11886
+ let content = await promises.readFile(path, 'utf8');
11887
+ if (binding.projectId) {
11888
+ content = updateProjectValue(content, 'project_id', binding.projectId);
11889
+ }
11890
+ if (binding.appId) {
11891
+ content = updateProjectValue(content, 'app_id', binding.appId);
11892
+ }
11893
+ const tempPath = node_path.join(node_path.dirname(path), `.coze-${node_crypto.randomUUID()}.tmp`);
11894
+ try {
11895
+ await promises.writeFile(tempPath, content, {
11896
+ encoding: 'utf8',
11897
+ mode: PROJECT_METADATA_FILE_MODE,
11898
+ });
11899
+ await promises.chmod(tempPath, PROJECT_METADATA_FILE_MODE);
11900
+ await promises.rename(tempPath, path);
11901
+ } finally {
11902
+ await promises.rm(tempPath, { force: true });
11903
+ }
11904
+ return readProjectMetadata(sourceRoot);
11905
+ };
11906
+
11907
+ const ensureProjectMetadata = async (
11908
+ sourceRoot,
11909
+ options,
11910
+ ) => {
11911
+ try {
11912
+ return await readProjectMetadata(sourceRoot);
11913
+ } catch (error) {
11914
+ if ((error ).code !== 'COZE_FILE_NOT_FOUND' || !options.allowCreate) {
11915
+ throw error;
11916
+ }
11917
+ }
11918
+ const name = _optionalChain$6([options, 'access', _14 => _14.name, 'optionalAccess', _15 => _15.trim, 'call', _16 => _16()]) || 'Pages application';
11919
+ const projectType = _optionalChain$6([options, 'access', _17 => _17.projectType, 'optionalAccess', _18 => _18.trim, 'call', _19 => _19()]) || 'web';
11920
+ await promises.writeFile(
11921
+ node_path.join(sourceRoot, '.coze'),
11922
+ `[project]\nname = ${JSON.stringify(name)}\nproject_type = ${JSON.stringify(projectType)}\n`,
11923
+ { encoding: 'utf8', mode: PROJECT_METADATA_FILE_MODE },
11924
+ );
11925
+ await promises.chmod(node_path.join(sourceRoot, '.coze'), PROJECT_METADATA_FILE_MODE);
11926
+ return readProjectMetadata(sourceRoot);
11927
+ };
11928
+
11929
+ function _optionalChain$5(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; }
11930
+ const isFile = async (path) => {
11931
+ try {
11932
+ return (await promises.stat(path)).isFile();
11933
+ } catch (error) {
11934
+ if ((error ).code === 'ENOENT') {
11935
+ return false;
11936
+ }
11937
+ throw error;
11938
+ }
11939
+ };
11940
+
11941
+ const validatePagesSource = async (
11942
+ sourceRoot,
11943
+ cozeFileContent,
11944
+ ) => {
11945
+ if (await isFile(node_path.join(sourceRoot, 'index.html'))) {
11946
+ return;
11947
+ }
11948
+
11949
+ let config;
11950
+ try {
11951
+ config = TOML.parse(cozeFileContent);
11952
+ } catch (error) {
11953
+ throw new CliError(
11954
+ `Unable to parse .coze: ${error instanceof Error ? error.message : String(error)}`,
11955
+ 'INVALID_COZE_FILE',
11956
+ );
11957
+ }
11958
+ const project = config.project ;
11959
+ if (typeof _optionalChain$5([project, 'optionalAccess', _ => _.template]) !== 'string' || project.template.trim().toLowerCase() !== 'nextjs') {
11960
+ throw new CliError(
11961
+ 'Pages source contains no index.html; .coze project.template must be "nextjs".',
11962
+ 'PAGES_BUILD_CONFIG_REQUIRED',
11963
+ );
11964
+ }
11965
+ const deploy = config.deploy ;
11966
+ const build = _optionalChain$5([deploy, 'optionalAccess', _2 => _2.build]);
11967
+ if (!Array.isArray(build) || build.length === 0 || !build.every(part => typeof part === 'string' && part.length > 0)) {
11968
+ throw new CliError(
11969
+ 'Pages source contains no index.html; .coze deploy.build must be a non-empty string array.',
11970
+ 'PAGES_BUILD_CONFIG_REQUIRED',
11971
+ );
11972
+ }
11973
+ };
11974
+
11975
+ const readDeployLocalContext = async (
11976
+ sourceRoot,
11977
+ requestedApplicationType,
11978
+ appId,
11979
+ client,
11980
+ ) => {
11981
+ const sourceSnapshot = resolveSourceSnapshot(sourceRoot);
11982
+ let applicationTypeHint = requestedApplicationType;
11983
+ let effectiveAppId = appId;
11984
+ if (!effectiveAppId) {
11985
+ try {
11986
+ effectiveAppId = (await ensureProjectMetadata(sourceRoot, { allowCreate: false })).appId;
11987
+ } catch (error) {
11988
+ if ((error ).code !== 'COZE_FILE_NOT_FOUND') {
11989
+ throw error;
11990
+ }
11991
+ }
11992
+ }
11993
+ if (!applicationTypeHint && effectiveAppId) {
11994
+ applicationTypeHint = (await client.getApplication(effectiveAppId)).application_type;
11995
+ }
11996
+ const isPagesDeployment = applicationTypeHint === 'pages';
11997
+ const metadata = await ensureProjectMetadata(sourceRoot, {
11998
+ allowCreate: isPagesDeployment,
11999
+ projectType: isPagesDeployment ? 'web' : undefined,
12000
+ });
12001
+ if (isPagesDeployment) {
12002
+ await validatePagesSource(sourceRoot, metadata.cozeFileContent);
12003
+ }
12004
+ return { ...sourceSnapshot, metadata, isPagesDeployment };
12005
+ };
12006
+
12007
+ 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; }
12008
+
12009
+ /**
12010
+ * 把 `mobile_artifact_list` 连同「这个空数组到底什么意思」一起输出。
12011
+ *
12012
+ * 产物是部署过程中逐步落库的:APK 要等安卓构建跑完才写进去,比部署记录本身晚好几分钟。部署没到
12013
+ * 终态时,空的 `mobile_artifact_list` 只代表「还没产出来」,不代表「没有产物」—— 可这两种情况在
12014
+ * 输出里长得一模一样,调用方(尤其是 agent)会把前者读成后者,然后得出「部署成功但系统没返回
12015
+ * APK 下载地址」这种错误结论。线上真发生过。
12016
+ *
12017
+ * 所以未定终态时额外带一个 `artifacts_pending: true`;这个字段不出现,就表示这份列表已经是最终
12018
+ * 结果。`mobile_artifact_list` 本身保持恒存在,避免破坏已有脚本的读法。
12019
+ */
12020
+ const mobileArtifactsOutput = (
12021
+ history,
12022
+ status = _optionalChain$4([history, 'optionalAccess', _ => _.status]),
12023
+ ) => ({
12024
+ mobile_artifact_list: _optionalChain$4([history, 'optionalAccess', _2 => _2.mobile_artifact_list]) || [],
12025
+ ...(isDeploymentSettled(status) ? {} : { artifacts_pending: true }),
12026
+ });
12027
+
12028
+ // 服务端 deploy_app/list 的 page_size 上限,超了会被判参数错误。
12029
+ // 客户端先拦一道,是为了把错误说在本地(带上上限值),而不是回一句服务端的通用参数错误。
12030
+ const APP_LIST_MAX_PAGE_SIZE = 100;
12031
+
12032
+ // page_token 是**页码的十进制字符串**(服务端口径,与 deploy_history/list 一致),不是不透明游标。
12033
+ // 所以这里能、也应该在本地校验:`--page-token abc` 早报错,比发出去再被拒强。
12034
+ const parsePositiveInt = (
12035
+ raw,
12036
+ option,
12037
+ code,
12038
+ max,
12039
+ ) => {
12040
+ const value = Number(raw);
12041
+ if (!Number.isSafeInteger(value) || value <= 0) {
12042
+ throw new CliError(`${option} must be a positive integer.`, code, { [option]: raw });
12043
+ }
12044
+ if (max !== undefined && value > max) {
12045
+ throw new CliError(`${option} must not exceed ${String(max)}.`, code, { [option]: raw });
12046
+ }
12047
+ return value;
12048
+ };
12049
+
12050
+ // ⛔ 别再用 `Number(options.pageSize || 20)`:`--page-size abc` 会算出 NaN,
12051
+ // JSON.stringify 把它写成 null 发给服务端,最后表现为「参数没生效」而不是「参数写错了」。
12052
+ const parsePageSize = (
12053
+ raw,
12054
+ fallback,
12055
+ max,
12056
+ ) => {
12057
+ if (raw === undefined || raw === '') {
12058
+ return fallback;
12059
+ }
12060
+ return parsePositiveInt(raw, '--page-size', 'INVALID_PAGE_SIZE', max);
12061
+ };
12062
+
12063
+ const parsePageToken = (raw) => {
12064
+ if (raw === undefined || raw === '') {
12065
+ return undefined;
12066
+ }
12067
+ parsePositiveInt(raw, '--page-token', 'INVALID_PAGE_TOKEN');
12068
+ return raw;
12069
+ };
12070
+
12071
+
12072
+
12073
+
12074
+
12075
+
12076
+
12077
+ // collectAllPages 顺着 next_page_token 把所有页取回来。
12078
+ //
12079
+ // 服务端从「全量单页」改成真分页之后,`app list` 一次只回一页;想要「我的全部应用」就得翻页。
12080
+ // 与其让每个调用方各写一遍循环,不如给一个 --all。
12081
+ //
12082
+ // ⚠️ 不设页数上限截断:静默截断正是这次要修掉的毛病。只防死循环——服务端如果一直回同一个
12083
+ // token(或说 has_more 却不给 token),直接报错,而不是无限翻。
12084
+ const collectAllPages = async (
12085
+ fetchPage,
12086
+ ) => {
12087
+ const items = [];
12088
+ const seen = new Set();
12089
+ let pageToken;
12090
+ let pages = 0;
12091
+ for (;;) {
12092
+ const page = await fetchPage(pageToken);
12093
+ items.push(...(page.items || []));
12094
+ pages += 1;
12095
+ if (!page.has_more) {
12096
+ return { items, pages };
12097
+ }
12098
+ const next = page.next_page_token;
12099
+ if (!next || seen.has(next)) {
12100
+ throw new CliError(
12101
+ 'The server reported more pages but returned no usable next_page_token.',
12102
+ 'INVALID_PAGE_TOKEN',
12103
+ { next_page_token: next, pages },
12104
+ );
12105
+ }
12106
+ seen.add(next);
12107
+ pageToken = next;
12108
+ }
12109
+ };
12110
+
12111
+ 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; }
12112
+
12113
+ const registerDeployReadCommands = (deploy) => {
12114
+ deploy
12115
+ .command('status')
12116
+ .option('--app-id <appId>', 'Application ID')
12117
+ .option('--deploy-id <deployId>', 'Deployment history ID')
12118
+ .action(async (options, command) => {
12119
+ const runtime = await getRuntime(command);
12120
+ const appId = await requireAppId(runtime.cwd, getDeployAppIdOption(options, command));
12121
+ let deployHistoryId = options.deployId;
12122
+ if (!deployHistoryId) {
12123
+ deployHistoryId = await _asyncOptionalChain([(
12124
+ await runtime.client.listDeployHistory({ app_id: appId, page_size: 1 })
12125
+ ), 'access', async _ => _.deploy_history_list, 'optionalAccess', async _2 => _2[0], 'optionalAccess', async _3 => _3.deploy_history_id]);
12126
+ }
12127
+ if (!deployHistoryId) {
12128
+ throw new CliError('No deployment history found.', 'DEPLOYMENT_NOT_FOUND');
12129
+ }
12130
+ const history = await runtime.client.getDeployHistory({
12131
+ app_id: appId,
12132
+ deploy_history_id: deployHistoryId,
12133
+ });
12134
+ runtime.output.print({
12135
+ app_id: appId,
12136
+ deploy_history_id: deployHistoryId,
12137
+ status: getDeployStatusText(history.status),
12138
+ commit_hash: history.commit_hash,
12139
+ commit_message: history.commit_message,
12140
+ domains: history.domain_list || [],
12141
+ error_analysis: history.error_analysis,
12142
+ deploy_detail: formatDeployDetails(history),
12143
+ connector_data_list: history.connector_data_list || [],
12144
+ ...mobileArtifactsOutput(history),
12145
+ });
12146
+ });
12147
+
12148
+ deploy
12149
+ .command('list')
12150
+ .option('--app-id <appId>', 'Application ID')
12151
+ .option('--page-size <pageSize>', 'Page size', '10')
12152
+ .option('--page-token <pageToken>', 'Page token (page number)')
12153
+ .action(async (options, command) => {
12154
+ // 先在本地校验:`--page-size abc` 以前算出 NaN 发出去,表现成「参数没生效」。
12155
+ const pageSize = parsePageSize(options.pageSize, 10);
12156
+ const pageToken = parsePageToken(options.pageToken);
12157
+ const runtime = await getRuntime(command);
12158
+ const appId = await requireAppId(runtime.cwd, getDeployAppIdOption(options, command));
12159
+ const data = await runtime.client.listDeployHistory({
12160
+ app_id: appId,
12161
+ page_size: pageSize,
12162
+ page_token: pageToken,
12163
+ });
12164
+ runtime.output.print({
12165
+ items: (data.deploy_history_list || []).map(item => ({
12166
+ deploy_history_id: item.deploy_history_id,
12167
+ status: getDeployStatusText(item.status),
12168
+ commit_hash: item.commit_hash_short || item.commit_hash,
12169
+ commit_message: item.commit_message,
12170
+ created_at: item.created_at,
12171
+ can_rollback: item.can_rollback,
12172
+ deploy_detail: formatDeployDetails(item),
12173
+ connector_data_list: item.connector_data_list || [],
12174
+ ...mobileArtifactsOutput(item),
12175
+ })),
12176
+ next_page_token: data.next_page_token,
12177
+ has_more: data.has_more,
12178
+ });
12179
+ });
12180
+
12181
+ deploy
12182
+ .command('online')
12183
+ .description('Show the current online deployment')
12184
+ .option('--app-id <appId>', 'Application ID')
12185
+ .action(async (options, command) => {
12186
+ const runtime = await getRuntime(command);
12187
+ const appId = await requireAppId(runtime.cwd, getDeployAppIdOption(options, command));
12188
+ const data = await runtime.client.getOnlineDeployHistory(appId);
12189
+ runtime.output.print({
12190
+ app_id: appId,
12191
+ items: (data.deploy_history_list || []).map(item => ({
12192
+ deploy_history_id: item.deploy_history_id,
12193
+ status: getDeployStatusText(item.status),
12194
+ commit_hash: item.commit_hash_short || item.commit_hash,
12195
+ commit_message: item.commit_message,
12196
+ created_at: item.created_at,
12197
+ deploy_detail: formatDeployDetails(item),
12198
+ domains: item.domain_list || [],
12199
+ ...mobileArtifactsOutput(item),
12200
+ })),
12201
+ });
12202
+ });
12203
+
12204
+ deploy
12205
+ .command('rollback-check')
12206
+ .description('Check whether a deployment supports database rollback')
12207
+ .requiredOption('--deploy-id <deployId>', 'Target deployment history ID')
12208
+ .option('--app-id <appId>', 'Application ID')
12209
+ .action(async (options, command) => {
12210
+ const runtime = await getRuntime(command);
12211
+ const appId = await requireAppId(runtime.cwd, getDeployAppIdOption(options, command));
12212
+ const data = await runtime.client.checkRollbackDatabase({
12213
+ app_id: appId,
12214
+ deploy_history_id: options.deployId || '',
12215
+ });
12216
+ runtime.output.print({ app_id: appId, deploy_history_id: options.deployId, ...data });
12217
+ });
12218
+
12219
+ deploy
12220
+ .command('log-count')
12221
+ .description('Show runtime log count and limit')
12222
+ .option('--app-id <appId>', 'Application ID')
12223
+ .action(async (options, command) => {
12224
+ const runtime = await getRuntime(command);
12225
+ const appId = await requireAppId(runtime.cwd, getDeployAppIdOption(options, command));
12226
+ const data = await runtime.client.getRuntimeLogCount(appId);
12227
+ runtime.output.print({ app_id: appId, ...data });
12228
+ });
12229
+
12230
+ deploy
12231
+ .command('count')
12232
+ .description('Show successful deployment count')
12233
+ .option('--app-id <appId>', 'Application ID')
12234
+ .action(async (options, command) => {
12235
+ const runtime = await getRuntime(command);
12236
+ const appId = await requireAppId(runtime.cwd, getDeployAppIdOption(options, command));
12237
+ const data = await runtime.client.getDeployCount(appId);
12238
+ runtime.output.print({ app_id: appId, ...data });
12239
+ });
12240
+ };
12241
+
12242
+ const registerEnv = (code) => {
12243
+ const env = code
12244
+ .command('env')
12245
+ .description('Inspect the current online environment snapshot');
12246
+
12247
+ env
12248
+ .command('list')
12249
+ .description('List environment variables of the current online deployment')
12250
+ .option('--app-id <appId>', 'Application ID')
12251
+ .action(async (options, command) => {
12252
+ const runtime = await getRuntime(command);
12253
+ const appId = await requireAppId(
12254
+ runtime.cwd,
12255
+ getDeployAppIdOption(options, command),
12256
+ );
12257
+ runtime.output.print(await runtime.client.getOnlineEnvironment(appId));
12258
+ });
12259
+ };
12260
+
12261
+ /* eslint-disable security/detect-non-literal-fs-filename -- validated project-local build output paths */
12262
+
12263
+ const BUILD_OUTPUT_DIRS = new Set(['dist', 'dist-tt']);
12264
+ const EXCLUDED_PARTS = new Set([
12265
+ '.git',
12266
+ '.env',
12267
+ 'node_modules',
12268
+ ]);
12269
+ const REPRODUCIBLE_ARCHIVE_MTIME = new Date(0);
12270
+
12271
+ const validateBuildOutput = async (
12272
+ sourceRoot,
12273
+ buildOutputDir,
12274
+ ) => {
12275
+ if (!BUILD_OUTPUT_DIRS.has(buildOutputDir)) {
12276
+ throw new CliError(
12277
+ `Unsupported Mini-program build output directory: ${buildOutputDir}.`,
12278
+ 'SOURCE_PACKAGE_FAILED',
12279
+ );
12280
+ }
12281
+ const buildOutputRoot = node_path.resolve(sourceRoot, buildOutputDir);
12282
+ try {
12283
+ const info = await promises.lstat(buildOutputRoot);
12284
+ if (info.isSymbolicLink() || !info.isDirectory()) {
12285
+ throw new Error('build output must be a regular directory');
12286
+ }
12287
+ const realSourceRoot = await promises.realpath(sourceRoot);
12288
+ const realBuildOutputRoot = await promises.realpath(buildOutputRoot);
12289
+ const relativeOutput = node_path.relative(realSourceRoot, realBuildOutputRoot);
12290
+ if (!relativeOutput || relativeOutput.startsWith('..')) {
12291
+ throw new Error('build output must be inside the source root');
12292
+ }
12293
+ } catch (error) {
12294
+ throw new CliError(
12295
+ `Invalid Mini-program build output ${buildOutputRoot}: ${error instanceof Error ? error.message : String(error)}`,
12296
+ 'SOURCE_PACKAGE_FAILED',
12297
+ );
12298
+ }
12299
+ };
12300
+
12301
+ const shouldInclude = (
12302
+ archivePath,
12303
+ entry,
12304
+ ) => {
12305
+ if ('isSymbolicLink' in entry && entry.isSymbolicLink()) {
12306
+ return false;
12307
+ }
12308
+ return !archivePath.split(/[\\/]/u).some(part =>
12309
+ EXCLUDED_PARTS.has(part) || part.startsWith('.git'),
12310
+ );
12311
+ };
12312
+
12313
+ const createMiniProgramPackage = async (
12314
+ sourceRoot,
12315
+ buildOutputDir,
12316
+ ) => {
12317
+ const resolvedSourceRoot = node_path.resolve(sourceRoot);
12318
+ await validateBuildOutput(resolvedSourceRoot, buildOutputDir);
12319
+ const tempDirectory = await promises.mkdtemp(node_path.join(node_os.tmpdir(), 'coze-mini-program-source-'));
12320
+ const outputPath = node_path.join(tempDirectory, 'source.tar.gz');
12321
+ try {
12322
+ await tar.create(
12323
+ {
12324
+ cwd: resolvedSourceRoot,
12325
+ file: outputPath,
12326
+ filter: shouldInclude,
12327
+ gzip: true,
12328
+ mtime: REPRODUCIBLE_ARCHIVE_MTIME,
12329
+ portable: true,
12330
+ },
12331
+ [buildOutputDir],
12332
+ );
12333
+ const info = await promises.stat(outputPath);
12334
+ if (info.size === 0) {
12335
+ throw new Error('source archive is empty');
12336
+ }
12337
+ return {
12338
+ path: outputPath,
12339
+ sizeBytes: info.size,
12340
+ cleanup: () => promises.rm(tempDirectory, { recursive: true, force: true }),
12341
+ };
12342
+ } catch (error) {
12343
+ await promises.rm(tempDirectory, { recursive: true, force: true });
12344
+ throw new CliError(
12345
+ `Unable to package Mini-program build output: ${error instanceof Error ? error.message : String(error)}`,
12346
+ 'SOURCE_PACKAGE_FAILED',
12347
+ );
12348
+ }
12349
+ };
12350
+
12351
+ function _nullishCoalesce$1(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } 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; }
12352
+ const CONNECTOR_IDS = {
12353
+ wechat: '10000127',
12354
+ douyin: '10000126',
12355
+ } ;
12356
+
12357
+ const MINI_PROGRAM_BUILD_OUTPUT_DIRS = {
12358
+ wechat: 'dist',
12359
+ douyin: 'dist-tt',
12360
+ } ;
12361
+
12362
+
12363
+
12364
+
12365
+
12366
+
12367
+
12368
+
12369
+
12370
+
12371
+
12372
+
12373
+
12374
+
12375
+
12376
+ const resolveConnectorId = (platform) => {
12377
+ const connectorId = CONNECTOR_IDS[platform ];
12378
+ if (!connectorId) {
12379
+ throw new CliError(
12380
+ `Unsupported Mini-program platform ${String(platform)}; expected wechat or douyin.`,
12381
+ 'INVALID_MINIPROGRAM_PLATFORM',
12382
+ );
12383
+ }
12384
+ return connectorId;
12385
+ };
12386
+
12387
+ const resolveBuildOutputDir = (platform) => {
12388
+ const outputDir =
12389
+ MINI_PROGRAM_BUILD_OUTPUT_DIRS[platform ];
12390
+ if (!outputDir) {
12391
+ throw new CliError(
12392
+ `Unsupported Mini-program platform ${String(platform)}; expected wechat or douyin.`,
12393
+ 'INVALID_MINIPROGRAM_PLATFORM',
12394
+ );
12395
+ }
12396
+ return outputDir;
12397
+ };
12398
+
12399
+ const resolveProjectId = async (
12400
+ command,
12401
+ options,
12402
+ ) => {
12403
+ if (_optionalChain$3([options, 'access', _ => _.projectId, 'optionalAccess', _2 => _2.trim, 'call', _3 => _3()])) {
12404
+ return options.projectId.trim();
12405
+ }
12406
+ const runtime = await getRuntime(command);
12407
+ const sourceRoot = node_path.resolve(runtime.cwd, options.sourceRoot || '.');
12408
+ const metadata = await readProjectMetadata(sourceRoot);
12409
+ if (!metadata.projectId) {
12410
+ throw new CliError(
12411
+ 'Project ID is required. Pass --project-id or use a source directory whose .coze [project] contains project_id.',
12412
+ 'PROJECT_ID_REQUIRED',
12413
+ );
12414
+ }
12415
+ return metadata.projectId;
12416
+ };
12417
+
12418
+ const MINI_PROGRAM_AUTH_STATUS = {
12419
+ authorized: 1,
12420
+ needAuthorize: 2,
12421
+ boundToOtherUser: 3,
12422
+ } ;
12423
+
12424
+ const getBoundToOtherUserMessage = (platform) => {
12425
+ const platformName = platform === 'wechat' ? 'WeChat' : 'Douyin';
12426
+ const platformConsole =
12427
+ platform === 'wechat' ? 'WeChat Public Platform' : 'Douyin Open Platform';
12428
+ return [
12429
+ `This ${platformName} Mini-program AppID is authorized by another Coze user.`,
12430
+ `If this is an AppID you manage, revoke Coze's previous third-party platform authorization in the ${platformConsole}, then rerun this auth command. The CLI will recheck the AppID and authorize it for your current Coze account.`,
12431
+ 'If this is not your AppID, change --mini-app-id to an AppID for which you have administrator permission, then rerun this auth command.',
12432
+ ].join(' ');
12433
+ };
12434
+
12435
+ const getAuthRequiredMessage = () =>
12436
+ 'This Mini-program AppID is not authorized for the current Coze user. Run `coze-dev deploy mini-program auth` first.';
12437
+
12438
+ const getPreviewFailureMessage = (data
12439
+
12440
+
12441
+ ) =>
12442
+ _optionalChain$3([data, 'access', _4 => _4.stderr, 'optionalAccess', _5 => _5.trim, 'call', _6 => _6()]) || _optionalChain$3([data, 'access', _7 => _7.stdout, 'optionalAccess', _8 => _8.trim, 'call', _9 => _9()]) || 'Mini-program preview failed.';
12443
+
12444
+ const registerAuthorizationCommand = (miniProgram) => {
12445
+ miniProgram
12446
+ .command('auth')
12447
+ .description('Authorize a Mini-program AppID for the current Coze user')
12448
+ .requiredOption('--platform <platform>', 'wechat or douyin')
12449
+ .requiredOption('--mini-app-id <miniAppId>', 'Mini-program AppID')
12450
+ .option('--project-id <projectId>', 'Deployment Project ID')
12451
+ .option('--source-root <sourceRoot>', 'Directory containing .coze', '.')
12452
+ .action(async (options, command) => {
12453
+ const runtime = await getRuntime(command);
12454
+ const projectId = await resolveProjectId(command, options);
12455
+ const authorization = await runtime.client.authorizeMiniProgram({
12456
+ project_id: projectId,
12457
+ app_id: options.miniAppId || '',
12458
+ connector_id: resolveConnectorId(options.platform),
12459
+ redirect_url: 'https://code.coze.cn/coding/auth/callback/miniprogram',
12460
+ });
12461
+ if (authorization.status === MINI_PROGRAM_AUTH_STATUS.needAuthorize) {
12462
+ runtime.output.print({
12463
+ project_id: projectId,
12464
+ mini_app_id: options.miniAppId,
12465
+ platform: options.platform,
12466
+ authorization_required: true,
12467
+ auth_url: authorization.auth_url,
12468
+ });
12469
+ return;
12470
+ }
12471
+ if (authorization.status === MINI_PROGRAM_AUTH_STATUS.boundToOtherUser) {
12472
+ throw new CliError(
12473
+ getBoundToOtherUserMessage(options.platform),
12474
+ 'MINIPROGRAM_AUTHORIZED_BY_OTHER_USER',
12475
+ );
12476
+ }
12477
+ if (authorization.status !== MINI_PROGRAM_AUTH_STATUS.authorized) {
12478
+ throw new CliError(
12479
+ `Unexpected Mini-program authorization status: ${String(authorization.status)}.`,
12480
+ 'INVALID_RESPONSE',
12481
+ );
12482
+ }
12483
+ runtime.output.print({
12484
+ project_id: projectId,
12485
+ mini_app_id: options.miniAppId,
12486
+ platform: options.platform,
12487
+ authorized: true,
12488
+ });
12489
+ });
12490
+ };
12491
+
12492
+ const registerPreviewCommand = (miniProgram) => {
12493
+ miniProgram
12494
+ .command('preview')
12495
+ .description('Create a Mini-program preview QR code from the local build artifact')
12496
+ .requiredOption('--platform <platform>', 'wechat or douyin')
12497
+ .requiredOption('--mini-app-id <miniAppId>', 'Mini-program AppID')
12498
+ .option('--project-id <projectId>', 'Deployment Project ID')
12499
+ .option('--source-root <sourceRoot>', 'Directory containing dist or dist-tt', '.')
12500
+ .option('--server-url <serverUrl>', 'Public HTTPS server URL to whitelist for this preview')
12501
+ .action(async (options, command) => {
12502
+ const runtime = await getRuntime(command);
12503
+ const projectId = await resolveProjectId(command, options);
12504
+ const authorization = await runtime.client.getMiniProgramAuthStatus({
12505
+ project_id: projectId,
12506
+ connector_id: resolveConnectorId(options.platform),
12507
+ });
12508
+ if (
12509
+ !authorization.is_authorized ||
12510
+ authorization.bound_related_id !== options.miniAppId
12511
+ ) {
12512
+ throw new CliError(
12513
+ getAuthRequiredMessage(),
12514
+ 'MINIPROGRAM_AUTH_REQUIRED',
12515
+ );
12516
+ }
12517
+ const sourceRoot = node_path.resolve(runtime.cwd, options.sourceRoot || '.');
12518
+ const buildOutputDir = resolveBuildOutputDir(options.platform);
12519
+ const sourcePackage = await createMiniProgramPackage(
12520
+ sourceRoot,
12521
+ buildOutputDir,
12522
+ );
12523
+ try {
12524
+ const content = await promises.readFile(sourcePackage.path);
12525
+ const data = await runtime.client.createMiniProgramPreview({
12526
+ project_id: projectId,
12527
+ app_id: options.miniAppId || '',
12528
+ connector_id: resolveConnectorId(options.platform),
12529
+ source_package_base64: content.toString('base64'),
12530
+ ...(options.serverUrl ? { server_url: options.serverUrl } : {}),
12531
+ });
12532
+ if (data.failed) {
12533
+ throw new CliError(
12534
+ getPreviewFailureMessage(data),
12535
+ 'MINIPROGRAM_PREVIEW_FAILED',
12536
+ );
12537
+ }
12538
+ runtime.output.print({
12539
+ project_id: projectId,
12540
+ mini_app_id: options.miniAppId,
12541
+ platform: options.platform,
12542
+ source_package_size_bytes: sourcePackage.sizeBytes,
12543
+ ...data,
12544
+ });
12545
+ } finally {
12546
+ await sourcePackage.cleanup();
12547
+ }
12548
+ });
12549
+ };
12550
+
12551
+ const registerMiniProgram = (code) => {
12552
+ const miniProgram = code
12553
+ .command('mini-program')
12554
+ .alias('miniprogram')
12555
+ .description('Manage WeChat or Douyin Mini-program authorization');
12556
+
12557
+ miniProgram
12558
+ .command('status')
12559
+ .requiredOption('--platform <platform>', 'wechat or douyin')
12560
+ .option('--project-id <projectId>', 'Deployment Project ID')
12561
+ .option('--source-root <sourceRoot>', 'Directory containing .coze', '.')
12562
+ .action(async (options, command) => {
12563
+ const runtime = await getRuntime(command);
12564
+ const projectId = await resolveProjectId(command, options);
12565
+ const connectorId = resolveConnectorId(options.platform);
12566
+ const data = await runtime.client.getMiniProgramAuthStatus({
12567
+ project_id: projectId,
12568
+ connector_id: connectorId,
12569
+ });
12570
+ runtime.output.print({ project_id: projectId, platform: options.platform, ...data });
12571
+ });
12572
+
12573
+ miniProgram
12574
+ .command('bind')
12575
+ .requiredOption('--platform <platform>', 'wechat or douyin')
12576
+ .requiredOption('--mini-app-id <miniAppId>', 'Mini-program AppID')
12577
+ .requiredOption('--redirect-url <redirectUrl>', 'OAuth callback URL')
12578
+ .option('--project-id <projectId>', 'Deployment Project ID')
12579
+ .option('--source-root <sourceRoot>', 'Directory containing .coze', '.')
12580
+ .option('--override', 'Move an AppID already bound to another project owned by you')
12581
+ .action(async (options, command) => {
12582
+ const runtime = await getRuntime(command);
12583
+ const projectId = await resolveProjectId(command, options);
12584
+ const connectorId = resolveConnectorId(options.platform);
12585
+ const data = await runtime.client.bindMiniProgramAuth({
12586
+ project_id: projectId,
12587
+ connector_id: connectorId,
12588
+ redirect_url: options.redirectUrl || '',
12589
+ auth_params: { app_id: options.miniAppId || '' },
12590
+ override: _nullishCoalesce$1(options.override, () => ( false)),
12591
+ });
12592
+ runtime.output.print({
12593
+ project_id: projectId,
12594
+ platform: options.platform,
12595
+ mini_app_id: options.miniAppId,
12596
+ ...data,
12597
+ });
12598
+ });
12599
+
12600
+ miniProgram
12601
+ .command('submit-code')
12602
+ .requiredOption('--platform <platform>', 'wechat or douyin')
12603
+ .requiredOption('--mini-app-id <miniAppId>', 'Mini-program AppID')
12604
+ .requiredOption('--code <code>', 'OAuth authorization code')
12605
+ .requiredOption('--verify-state <verifyState>', 'State returned by bind')
12606
+ .option('--project-id <projectId>', 'Deployment Project ID')
12607
+ .option('--source-root <sourceRoot>', 'Directory containing .coze', '.')
12608
+ .action(async (options, command) => {
12609
+ const runtime = await getRuntime(command);
12610
+ const projectId = await resolveProjectId(command, options);
12611
+ await runtime.client.submitMiniProgramAuthCode({
12612
+ project_id: projectId,
12613
+ connector_id: resolveConnectorId(options.platform),
12614
+ code: options.code || '',
12615
+ verify_state: options.verifyState || '',
12616
+ auth_params: { app_id: options.miniAppId || '' },
12617
+ });
12618
+ runtime.output.print({ project_id: projectId, platform: options.platform, bound: true });
12619
+ });
12620
+
12621
+ miniProgram
12622
+ .command('unbind')
12623
+ .requiredOption('--platform <platform>', 'wechat or douyin')
12624
+ .option('--project-id <projectId>', 'Deployment Project ID')
12625
+ .option('--source-root <sourceRoot>', 'Directory containing .coze', '.')
12626
+ .action(async (options, command) => {
12627
+ const runtime = await getRuntime(command);
12628
+ const projectId = await resolveProjectId(command, options);
12629
+ await runtime.client.unbindMiniProgramAuth({
12630
+ project_id: projectId,
12631
+ connector_id: resolveConnectorId(options.platform),
12632
+ });
12633
+ runtime.output.print({ project_id: projectId, platform: options.platform, unbound: true });
12634
+ });
12635
+
12636
+ registerAuthorizationCommand(miniProgram);
12637
+ registerPreviewCommand(miniProgram);
12638
+ };
12639
+
12640
+ function _optionalChain$2(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; }
12641
+
12642
+ const POLL_INTERVAL_MS = 3000;
12643
+ const MAX_CONSECUTIVE_RETRIES = 5;
12644
+ const TRANSIENT_RPC_ERROR_CODE = 230000001;
12645
+ /**
12646
+ * `--wait` 的总时长上限。
12647
+ *
12648
+ * Interrupted 不再算终态(见 status.ts),轮询只能靠这个兜底,否则一次卡住的部署会把 CLI
12649
+ * 永远挂在这里。取 60min 是照安卓构建定的:实测 10 分钟起步,中途还会经历若干次
12650
+ * Interrupted → 重新触发。
12651
+ */
12652
+ const POLL_TIMEOUT_MS = 3600000; // 60min
12653
+ /** 心跳间隔:text 模式下每隔这么久报一次「还在跑」,免得长构建看起来像挂死。 */
12654
+ const HEARTBEAT_MS = 30000;
12655
+
12656
+ const wait = async () =>
12657
+ new Promise(resolve => setTimeout(resolve, POLL_INTERVAL_MS));
12658
+
12659
+ const isRetryablePollError = (error) =>
12660
+ error instanceof CliError &&
12661
+ error.code === 'API_REJECTED' &&
12662
+ Number(_optionalChain$2([error, 'access', _ => _.details, 'optionalAccess', _2 => _2.business_code])) === TRANSIENT_RPC_ERROR_CODE;
12663
+
12664
+ const pollHistory = async (
12665
+ command,
12666
+ appId,
12667
+ deployHistoryId,
12668
+ timeoutMs = POLL_TIMEOUT_MS,
12669
+ ) => {
12670
+ const runtime = await getRuntime(command);
12671
+ const startedAt = Date.now();
12672
+ let consecutiveFailures = 0;
12673
+ let lastStatus;
12674
+ let lastBeatAt = startedAt;
12675
+ while (true) {
12676
+ const elapsed = () => Math.floor((Date.now() - startedAt) / 1000);
12677
+ try {
12678
+ const history = await runtime.client.getDeployHistory({
12679
+ app_id: appId,
12680
+ deploy_history_id: deployHistoryId,
12681
+ });
12682
+ consecutiveFailures = 0;
12683
+ const status = getDeployStatusText(history.status);
12684
+ runtime.output.debug(
12685
+ `[deploy] History ${deployHistoryId}: ${status} (${String(elapsed())}s elapsed)`,
12686
+ );
12687
+ if (history.status && TERMINAL_STATUSES.has(history.status)) {
12688
+ return history;
12689
+ }
12690
+ // 长构建(安卓十几分钟)期间给点动静:状态一变就报,否则每 30s 报一次还活着。
12691
+ // output.info 只在 text 模式写 stderr,json 模式是 no-op,不会污染机器可读输出。
12692
+ if (history.status !== lastStatus) {
12693
+ lastStatus = history.status;
12694
+ lastBeatAt = Date.now();
12695
+ runtime.output.info(`[deploy] ${status} (${String(elapsed())}s)`);
12696
+ } else if (Date.now() - lastBeatAt >= HEARTBEAT_MS) {
12697
+ lastBeatAt = Date.now();
12698
+ runtime.output.info(`[deploy] still ${status} (${String(elapsed())}s)`);
12699
+ }
12700
+ } catch (error) {
12701
+ if (!isRetryablePollError(error) || consecutiveFailures >= MAX_CONSECUTIVE_RETRIES) {
12702
+ throw error;
12703
+ }
12704
+ consecutiveFailures += 1;
12705
+ runtime.output.debug(
12706
+ `[deploy] Status check failed transiently; retrying (${String(consecutiveFailures)}/${String(MAX_CONSECUTIVE_RETRIES)}).`,
12707
+ );
12708
+ }
12709
+ if (Date.now() - startedAt >= timeoutMs) {
12710
+ throw new CliError(
12711
+ `Timed out after ${String(elapsed())}s waiting for deployment ${deployHistoryId}; ` +
12712
+ `last status: ${getDeployStatusText(lastStatus)}. The deployment may still be running — ` +
12713
+ 'check it with `coze-dev deploy status`.',
12714
+ 'DEPLOY_WAIT_TIMEOUT',
12715
+ { app_id: appId, deploy_history_id: deployHistoryId, last_status: lastStatus },
12716
+ );
12717
+ }
12718
+ await wait();
12719
+ }
12720
+ };
12721
+
12722
+ const GENERAL_PROJECT_TYPE = 9;
12723
+
12724
+ /**
12725
+ * Map `.coze` `[project].project_type` to the VibeProjectType used when creating the
12726
+ * deployment project.
12727
+ *
12728
+ * The values on the left are the ones the deploy server understands (see `cozefileutil`
12729
+ * `ResolveDeployKindByProjectType` / `GeneralProjectTypeByCozeProjectType` in coze-coding);
12730
+ * the numbers on the right are `VibeProjectType` (idl/coze.coding.ide/project.thrift).
12731
+ *
12732
+ * Keeping the two in sync matters beyond project metadata: the created project type decides
12733
+ * the project-scoped `COZE_PROJECT_TYPE` secret injected into the runtime, whether a Postgres
12734
+ * database is provisioned for the project, and whether the traffic gateway enforces inbound
12735
+ * auth. Creating an `agent` project as General(9) therefore deploys successfully but leaves a
12736
+ * dead service: the agent template reads `COZE_PROJECT_TYPE` to pick its graph and needs
12737
+ * `PGDATABASE_URL` on startup.
12738
+ *
12739
+ * VibeProjectType WebApp(3) and AssistantAgent(8) are intentionally absent: no `.coze`
12740
+ * project_type maps to them.
12741
+ */
12742
+ const resolveCreationProjectType = (
12743
+ projectType,
12744
+ ) => {
12745
+ switch (projectType) {
12746
+ case 'agent':
12747
+ return 1;
12748
+ case 'workflow':
12749
+ case 'automation':
12750
+ return 2;
12751
+ case 'app':
12752
+ return 4;
12753
+ case 'skill':
12754
+ return 5;
12755
+ case 'web':
12756
+ case 'backend':
12757
+ return 6;
12758
+ case 'miniapp':
12759
+ case 'miniprogram':
12760
+ return 7;
12761
+ default:
12762
+ return GENERAL_PROJECT_TYPE;
12763
+ }
12764
+ };
12765
+
12766
+ const formatDeployment = (deployment) =>
12767
+ typeof deployment === 'object' && deployment
12768
+ ? {
12769
+ ...(deployment ),
12770
+ status: getDeployStatusText(
12771
+ Number((deployment ).status),
12772
+ ),
12773
+ }
12774
+ : undefined;
12775
+
12776
+ const formatApplication = (application) => ({
12777
+ ...application,
12778
+ online_deployment: formatDeployment(application.online_deployment),
12779
+ latest_deployment: formatDeployment(application.latest_deployment),
12780
+ });
12781
+
12782
+ // 对应 IDL 的 MetricTimeRange,数值与 V1 保持一致。
12783
+ const TIME_RANGES = {
12784
+ day: 1,
12785
+ week: 2,
12786
+ month: 3,
12787
+ yesterday: 4,
12788
+ 'three-days': 5,
12789
+ };
12790
+
12791
+ const resolveTimeRange = (value) => {
12792
+ const timeRange = TIME_RANGES[value || 'day'];
12793
+ if (!timeRange) {
12794
+ throw new CliError(
12795
+ `Invalid time range; expected one of ${Object.keys(TIME_RANGES).join(', ')}.`,
12796
+ 'INVALID_TIME_RANGE',
12797
+ { time_range: value },
12798
+ );
12799
+ }
12800
+ return timeRange;
12801
+ };
12802
+
12803
+ const UNIT_TYPES = { dev: 1, prod: 2 };
12804
+
12805
+ // 改 Application 本身的两条写操作,都要显式 --yes 才生效。
12806
+ // 单独拎出来是因为它们和 registerApp 里其余只读命令性质不同(会改线上资产),
12807
+ // 顺带让 registerApp 保持在 max-line-per-function 之内。
12808
+ const registerAppMutations = (app) => {
12809
+ app
12810
+ .command('rename <name>')
12811
+ .description('Rename an application')
12812
+ .option('--app-id <appId>', 'Application ID')
12813
+ .option('--yes', 'Confirm rename')
12814
+ .action(async (name, options, command) => {
12815
+ if (!options.yes) {
12816
+ throw new CliError('Pass --yes to rename the application.', 'CONFIRMATION_REQUIRED');
12817
+ }
12818
+ const normalizedName = name.trim();
12819
+ if (!normalizedName || normalizedName.length > 255) {
12820
+ throw new CliError(
12821
+ 'Application name must contain 1 to 255 characters.',
12822
+ 'INVALID_APPLICATION_NAME',
12823
+ );
12824
+ }
12825
+ const runtime = await getRuntime(command);
12826
+ const appId = await requireAppId(runtime.cwd, options.appId);
12827
+ const application = await runtime.client.updateApplication({
12828
+ app_id: appId,
12829
+ name: normalizedName,
12830
+ });
12831
+ runtime.output.print(
12832
+ formatApplication(application ),
12833
+ );
12834
+ });
12835
+ app
12836
+ // 删除是终态、不可撤销,所以和 rename 一样必须显式 --yes。
12837
+ //
12838
+ // 服务端只接受 **Stopped** 的应用:还在服务的先 `code deploy stop --yes`,否则会拿到一条
12839
+ // 带当前状态的报错。这里刻意不替用户先停 —— 停服会真的把线上服务摘掉,那得是用户自己按的。
12840
+ .command('delete')
12841
+ .description('Delete a stopped application (irreversible)')
12842
+ .option('--app-id <appId>', 'Application ID')
12843
+ .option('--yes', 'Confirm delete')
12844
+ .action(async (options, command) => {
12845
+ if (!options.yes) {
12846
+ throw new CliError('Pass --yes to delete the application.', 'CONFIRMATION_REQUIRED');
12847
+ }
12848
+ const runtime = await getRuntime(command);
12849
+ const appId = await requireAppId(runtime.cwd, options.appId);
12850
+ await runtime.client.deleteApplication(appId);
12851
+ // 本地 .coze 里的 app_id 不动(这条命令可能是在别的目录带 --app-id 跑的),但要说清楚:
12852
+ // 不清掉它,同目录下一次 deploy 会打到一个已删除的应用上、被服务端拒。
12853
+ runtime.output.print({
12854
+ app_id: appId,
12855
+ deleted: true,
12856
+ note: 'Remove app_id from .coze [project] before deploying this directory again.',
12857
+ });
12858
+ });
12859
+ };
12860
+
12861
+ const registerApp = (code) => {
12862
+ const app = code.command('app').description('Manage deployment applications');
12863
+ registerAppMutations(app);
12864
+ app
12865
+ .command('list')
12866
+ // 列的是当前登录用户名下**跨 Project** 的全部 Application。没有 --project-id:
12867
+ // V2 的资产归属是 Owner 而不是 Project,同一个 Project 下的应用可以分属不同用户。
12868
+ // 也不传 user_id:服务端直接从登录态取,客户端传了也只能传自己。
12869
+ //
12870
+ // ⚠️ 服务端是真分页(一页最多 100 条),一次调用只回一页。要「我的全部应用」用 --all,
12871
+ // 它顺着 next_page_token 翻到底 —— 别再默认第一页就是全部。
12872
+ .option('--page-token <pageToken>', 'Pagination token (page number)')
12873
+ .option('--page-size <pageSize>', 'Page size', '20')
12874
+ .option('--all', 'Fetch every page by following next_page_token')
12875
+ .action(async (options, command) => {
12876
+ const pageSize = parsePageSize(options.pageSize, 20, APP_LIST_MAX_PAGE_SIZE);
12877
+ const pageToken = parsePageToken(options.pageToken);
12878
+ if (options.all && pageToken) {
12879
+ throw new CliError(
12880
+ '--all fetches every page and cannot be combined with --page-token.',
12881
+ 'INVALID_PAGE_TOKEN',
12882
+ { page_token: options.pageToken },
12883
+ );
12884
+ }
12885
+ const runtime = await getRuntime(command);
12886
+ const format = (items) =>
12887
+ items.map(item => formatApplication(item ));
12888
+ if (options.all) {
12889
+ const { items, pages } = await collectAllPages(next =>
12890
+ runtime.client.listApplications({ page_token: next, page_size: pageSize }),
12891
+ );
12892
+ runtime.output.print({ items: format(items), pages, has_more: false });
12893
+ return;
12894
+ }
12895
+ const data = await runtime.client.listApplications({
12896
+ page_token: pageToken,
12897
+ page_size: pageSize,
12898
+ });
12899
+ runtime.output.print({
12900
+ items: format(data.items),
12901
+ next_page_token: data.next_page_token,
12902
+ has_more: data.has_more,
12903
+ });
12904
+ });
12905
+ app
12906
+ .command('show')
12907
+ .requiredOption('--app-id <appId>', 'Application ID')
12908
+ .action(async (options, command) => {
12909
+ const runtime = await getRuntime(command);
12910
+ runtime.output.print(
12911
+ formatApplication(
12912
+ (await runtime.client.getApplication(options.appId))
12913
+
12914
+
12915
+ ,
12916
+ ),
12917
+ );
12918
+ });
12919
+ app
12920
+ .command('analytics')
12921
+ .description('Show PV / UV charts')
12922
+ .option('--app-id <appId>', 'Application ID')
12923
+ .option(
12924
+ '--time-range <timeRange>',
12925
+ `Time range: ${Object.keys(TIME_RANGES).join(', ')}`,
12926
+ 'day',
12927
+ )
12928
+ .action(async (options, command) => {
12929
+ const timeRange = resolveTimeRange(options.timeRange);
12930
+ const runtime = await getRuntime(command);
12931
+ const appId = await requireAppId(runtime.cwd, options.appId);
12932
+ const data = await runtime.client.getUserAnalyticsMetrics({
12933
+ app_id: appId,
12934
+ time_range: timeRange,
12935
+ });
12936
+ runtime.output.print({ app_id: appId, charts: data.charts || [] });
12937
+ });
12938
+ app
12939
+ .command('metrics')
12940
+ .description('Show application runtime metrics')
12941
+ .option('--app-id <appId>', 'Application ID')
12942
+ .option(
12943
+ '--time-range <timeRange>',
12944
+ `Time range: ${Object.keys(TIME_RANGES).join(', ')}`,
12945
+ 'day',
12946
+ )
12947
+ .action(async (options, command) => {
12948
+ const timeRange = resolveTimeRange(options.timeRange);
12949
+ const runtime = await getRuntime(command);
12950
+ const appId = await requireAppId(runtime.cwd, options.appId);
12951
+ const data = await runtime.client.getApplicationMetrics({
12952
+ app_id: appId,
12953
+ time_range: timeRange,
12954
+ });
12955
+ runtime.output.print({
12956
+ app_id: appId,
12957
+ charts: data.charts || [],
12958
+ stats: data.stats || [],
12959
+ });
12960
+ });
12961
+ app
12962
+ .command('usage')
12963
+ .description('Show monthly hosted usage')
12964
+ .option('--app-id <appId>', 'Application ID')
12965
+ .requiredOption('--bill-month <billMonth>', 'Billing month in YYYY-MM format')
12966
+ .action(async (options, command) => {
12967
+ const billMonth = options.billMonth || '';
12968
+ if (!/^\d{4}-(?:0[1-9]|1[0-2])$/u.test(billMonth)) {
12969
+ throw new CliError(
12970
+ 'Invalid billing month; expected YYYY-MM.',
12971
+ 'INVALID_BILL_MONTH',
12972
+ { bill_month: billMonth },
12973
+ );
12974
+ }
12975
+ const runtime = await getRuntime(command);
12976
+ const appId = await requireAppId(runtime.cwd, options.appId);
12977
+ const data = await runtime.client.getHostedUsageMonthly({
12978
+ app_id: appId,
12979
+ bill_month: billMonth,
12980
+ });
12981
+ runtime.output.print({ app_id: appId, summary: data.summary });
12982
+ });
12983
+ };
12984
+
12985
+ const registerDomain = (code) => {
12986
+ const domain = code.command('domain').description('Manage application domains');
12987
+ domain
12988
+ .command('list')
12989
+ .option('--app-id <appId>', 'Application ID')
12990
+ .option('--unit-type <unitType>', 'Unit type: dev or prod', 'prod')
12991
+ .action(async (options, command) => {
12992
+ const unitType = UNIT_TYPES[options.unitType || 'prod'];
12993
+ if (!unitType) {
12994
+ throw new CliError(
12995
+ 'Invalid unit type; expected dev or prod.',
12996
+ 'INVALID_UNIT_TYPE',
12997
+ { unit_type: options.unitType },
12998
+ );
12999
+ }
13000
+ const runtime = await getRuntime(command);
13001
+ const appId = await requireAppId(runtime.cwd, options.appId);
13002
+ const data = await runtime.client.listDomains(appId, unitType);
13003
+ runtime.output.print({
13004
+ app_id: appId,
13005
+ unit_type: options.unitType || 'prod',
13006
+ items: (data.items || []).map(item => ({
13007
+ id: item.id,
13008
+ domain_host: item.domain_host,
13009
+ })),
13010
+ });
13011
+ });
13012
+ domain
13013
+ // 改的是系统分配的 <prefix>.coze.site 的 prefix,不是 `domain add` 加进来的自定义域名 ——
13014
+ // 那类域名服务端只有 create/delete,域名串本身改不了。
13015
+ //
13016
+ // 和 rename 一样要 --yes:旧默认域名会立刻停止指向本应用,已经发出去的链接会失效。
13017
+ .command('set-prefix <prefix>')
13018
+ .description('Change the default domain prefix (<prefix>.coze.site)')
13019
+ .option('--app-id <appId>', 'Application ID')
13020
+ .option('--yes', 'Confirm prefix change')
13021
+ .action(async (prefix, options, command) => {
13022
+ if (!options.yes) {
13023
+ throw new CliError(
13024
+ 'Pass --yes to change the default domain prefix.',
13025
+ 'CONFIRMATION_REQUIRED',
13026
+ );
13027
+ }
13028
+ const normalizedPrefix = prefix.trim();
13029
+ // 只做形态校验:长度、保留词、占用与权益都由服务端判,客户端不复制第二套规则。
13030
+ if (!/^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/u.test(normalizedPrefix)) {
13031
+ throw new CliError(
13032
+ 'Invalid prefix; use lowercase letters, digits and hyphens, not starting or ending with a hyphen.',
13033
+ 'INVALID_DOMAIN_PREFIX',
13034
+ { prefix },
13035
+ );
13036
+ }
13037
+ const runtime = await getRuntime(command);
13038
+ const appId = await requireAppId(runtime.cwd, options.appId);
13039
+ const data = await runtime.client.updateDefaultDomainPrefix({
13040
+ app_id: appId,
13041
+ prefix: normalizedPrefix,
13042
+ });
13043
+ runtime.output.print({
13044
+ app_id: appId,
13045
+ prefix: normalizedPrefix,
13046
+ old_domain_host: data.old_domain_host_canonical,
13047
+ new_domain_host: data.new_domain_host_canonical,
13048
+ });
13049
+ });
13050
+ domain
13051
+ .command('add <domain>')
13052
+ .option('--app-id <appId>', 'Application ID')
13053
+ .action(async (domainHost, options, command) => {
13054
+ if (!/^[a-zA-Z0-9](?:[a-zA-Z0-9-]*\.)+[a-zA-Z0-9-]+$/u.test(domainHost)) {
13055
+ throw new CliError('Invalid domain.', 'INVALID_DOMAIN', { domain: domainHost });
13056
+ }
13057
+ const runtime = await getRuntime(command);
13058
+ const appId = await requireAppId(runtime.cwd, options.appId);
13059
+ await runtime.client.createDomain({ app_id: appId, domain: domainHost });
13060
+ runtime.output.print({ app_id: appId, domain: domainHost });
13061
+ });
13062
+ };
13063
+
13064
+ const PACKAGE_SCRIPT_CANDIDATES = [
13065
+ node_path.resolve(__dirname, 'deploy/package-project.js'),
13066
+ node_path.resolve(__dirname, '../../../scripts/deploy/package-project.js'),
13067
+ ];
13068
+
13069
+ const packageCommand = (args) => {
13070
+ const packageScript = PACKAGE_SCRIPT_CANDIDATES.find(candidate =>
13071
+ node_fs.existsSync(candidate),
13072
+ );
13073
+ if (!packageScript) {
13074
+ throw new CliError(
13075
+ 'The deployment packaging script is missing from this coze-dev installation.',
13076
+ 'SOURCE_PACKAGE_FAILED',
13077
+ );
13078
+ }
13079
+ return [packageScript, ...args];
13080
+ };
13081
+
13082
+ const runPackageScript = async (args, debug = false) =>
13083
+ new Promise((resolvePromise, reject) => {
13084
+ const child = node_child_process.spawn(process.execPath, packageCommand(args), {
13085
+ stdio: ['ignore', 'pipe', 'pipe'],
13086
+ });
13087
+ let errorOutput = '';
13088
+ const forward = (chunk) => {
13089
+ const text = chunk.toString();
13090
+ if (debug) {
13091
+ process.stderr.write(text);
13092
+ }
13093
+ errorOutput = `${errorOutput}${text}`.slice(-65536);
13094
+ };
13095
+ child.stdout.on('data', forward);
13096
+ child.stderr.on('data', forward);
13097
+ child.once('error', reject);
13098
+ child.once('close', code => {
13099
+ if (code === 0) {
13100
+ resolvePromise();
13101
+ return;
13102
+ }
13103
+ reject(new Error(
13104
+ `Packaging process exited with code ${String(code)}${errorOutput ? `\n${errorOutput.trim()}` : ''}`,
13105
+ ));
13106
+ });
13107
+ });
13108
+
13109
+
13110
+
13111
+
13112
+
13113
+
13114
+
13115
+
13116
+
13117
+
13118
+
13119
+
13120
+ const createSourcePackageArchive = async (
13121
+ sourceRoot,
13122
+ applicationType = 'service',
13123
+ debug = false,
13124
+ ) => {
13125
+ const tempDirectory = await promises.mkdtemp(node_path.join(node_os.tmpdir(), 'coze-deploy-source-'));
13126
+ const outputPath = node_path.join(tempDirectory, 'source.tar.gz');
13127
+ try {
13128
+ await runPackageScript(
13129
+ [sourceRoot, outputPath, ...(applicationType === 'pages' ? ['--pages'] : [])],
13130
+ debug,
13131
+ );
13132
+ const info = await promises.stat(outputPath);
13133
+ if (info.size === 0) {
13134
+ throw new CliError('Source package is empty.', 'SOURCE_PACKAGE_FAILED');
13135
+ }
13136
+ return {
13137
+ path: outputPath,
13138
+ sizeBytes: info.size,
13139
+ cleanup: () => promises.rm(tempDirectory, { recursive: true, force: true }),
13140
+ };
13141
+ } catch (error) {
13142
+ await promises.rm(tempDirectory, { recursive: true, force: true });
13143
+ if (error instanceof CliError) {
13144
+ throw error;
13145
+ }
13146
+ throw new CliError(
13147
+ `Unable to package local source: ${error instanceof Error ? error.message : String(error)}`,
13148
+ 'SOURCE_PACKAGE_FAILED',
13149
+ );
13150
+ }
13151
+ };
13152
+
13153
+ const UPLOAD_SESSION_FILENAME = '.coze-deploy-upload.json';
13154
+
13155
+
13156
+
13157
+
13158
+
13159
+
13160
+
13161
+
13162
+
13163
+
13164
+
13165
+ const isUploadSession = (value) => {
13166
+ if (!value || typeof value !== 'object') {
13167
+ return false;
13168
+ }
13169
+ const session = value ;
13170
+ return typeof session.idempotencyKey === 'string' &&
13171
+ typeof session.createdAt === 'number' &&
13172
+ typeof session.sourcePackageSizeBytes === 'number' &&
13173
+ Boolean(session.request && typeof session.request === 'object');
13174
+ };
13175
+
13176
+ const readUploadSession = async (sourceRoot) => {
13177
+ try {
13178
+ const parsed = safeJsonParse(
13179
+ await promises.readFile(node_path.join(sourceRoot, UPLOAD_SESSION_FILENAME), 'utf8'),
13180
+ undefined,
13181
+ );
13182
+ return isUploadSession(parsed) ? parsed : undefined;
13183
+ } catch (error) {
13184
+ if ((error ).code === 'ENOENT') {
13185
+ return undefined;
13186
+ }
13187
+ throw error;
13188
+ }
13189
+ };
13190
+
13191
+ const writeUploadSession = async (sourceRoot, session) => {
13192
+ const path = node_path.join(sourceRoot, UPLOAD_SESSION_FILENAME);
13193
+ const tempPath = node_path.join(node_path.dirname(path), `.coze-deploy-upload-${node_crypto.randomUUID()}.tmp`);
13194
+ await promises.mkdir(node_path.dirname(path), { recursive: true });
13195
+ try {
13196
+ await promises.writeFile(tempPath, `${JSON.stringify(session, null, 2)}\n`, { encoding: 'utf8', mode: 0o600 });
13197
+ await promises.rename(tempPath, path);
13198
+ } finally {
13199
+ await promises.rm(tempPath, { force: true });
13200
+ }
13201
+ };
13202
+
13203
+ const removeUploadSession = async (sourceRoot) => {
13204
+ await promises.rm(node_path.join(sourceRoot, UPLOAD_SESSION_FILENAME), { force: true });
13205
+ };
13206
+
13207
+ function _optionalChain$1(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; }
13208
+ const INLINE_SOURCE_PACKAGE_MAX_BYTES = 1024 * 1024;
13209
+ const PRE_DEPLOY_SESSION_TTL_MS = 2 * 60 * 60 * 1000;
13210
+
13211
+ const uploadFile = async (
13212
+ uploadUrl,
13213
+ requiredHeaders,
13214
+ archive,
13215
+ ) => {
13216
+ const uploadRequest = {
13217
+ method: 'PUT',
13218
+ headers: requiredHeaders,
13219
+ body: node_stream.Readable.toWeb(node_fs.createReadStream(archive.path)) ,
13220
+ duplex: 'half',
13221
+ };
13222
+ const response = await fetch(uploadUrl, uploadRequest);
13223
+ if (!response.ok) {
13224
+ throw new CliError(`Direct artifact upload failed: ${response.status} ${response.statusText}`, 'ARTIFACT_UPLOAD_FAILED');
13225
+ }
13226
+ };
13227
+
13228
+ const createDeploymentWithSourcePackage = async (
13229
+ client,
13230
+ request,
13231
+ archive,
13232
+ sourceRoot,
13233
+ ) => {
13234
+ if (archive.sizeBytes <= INLINE_SOURCE_PACKAGE_MAX_BYTES) {
13235
+ const content = await promises.readFile(archive.path);
13236
+ return {
13237
+ uploadMode: 'inline' ,
13238
+ result: await client.createDeployHistory({ ...request, source_package_base64: content.toString('base64') }),
13239
+ };
13240
+ }
13241
+
13242
+ const savedSession = await readUploadSession(sourceRoot);
13243
+ let retryRequest = request;
13244
+ let reconciledSession = savedSession;
13245
+ if (_optionalChain$1([savedSession, 'optionalAccess', _ => _.appId]) && savedSession.deployHistoryId) {
13246
+ const history = await client.getDeployHistory({
13247
+ app_id: savedSession.appId,
13248
+ deploy_history_id: savedSession.deployHistoryId,
13249
+ });
13250
+ switch (history.status) {
13251
+ case DEPLOY_STATUS.preDeploy:
13252
+ // The server is authoritative for the session lifetime. Reuse the
13253
+ // original key even if the local two-hour clock is close to expiry;
13254
+ // pre_upload will either refresh the URL or release an expired slot.
13255
+ break;
13256
+ case DEPLOY_STATUS.pending:
13257
+ case DEPLOY_STATUS.running:
13258
+ case DEPLOY_STATUS.interrupted:
13259
+ case DEPLOY_STATUS.succeeded:
13260
+ // The previous create request was accepted but its response may have
13261
+ // been lost. Do not upload or create another deployment.
13262
+ await removeUploadSession(sourceRoot);
13263
+ return {
13264
+ uploadMode: 'direct' ,
13265
+ result: {
13266
+ app_id: savedSession.appId,
13267
+ deploy_history_id: savedSession.deployHistoryId,
13268
+ status: history.status,
13269
+ version: typeof history.version === 'number' ? history.version : undefined,
13270
+ },
13271
+ };
13272
+ case DEPLOY_STATUS.failed:
13273
+ case DEPLOY_STATUS.canceled:
13274
+ // The reserved history can no longer be claimed. Start a new upload
13275
+ // against the Application that pre_upload already created.
13276
+ await removeUploadSession(sourceRoot);
13277
+ reconciledSession = undefined;
13278
+ retryRequest = {
13279
+ ...request,
13280
+ project_id: undefined,
13281
+ app_id: savedSession.appId,
13282
+ };
13283
+ break;
13284
+ default:
13285
+ throw new CliError(
13286
+ `Unable to reconcile pre-deploy history ${savedSession.deployHistoryId}: unknown status ${String(history.status)}.`,
13287
+ 'INVALID_RESPONSE',
13288
+ );
13289
+ }
13290
+ }
13291
+ const liveSavedSession = reconciledSession && (
13292
+ reconciledSession.appId && reconciledSession.deployHistoryId ||
13293
+ Date.now() - reconciledSession.createdAt < PRE_DEPLOY_SESSION_TTL_MS
13294
+ )
13295
+ ? reconciledSession
13296
+ : undefined;
13297
+ if (liveSavedSession && liveSavedSession.sourcePackageSizeBytes !== archive.sizeBytes) {
13298
+ throw new CliError(
13299
+ 'A different source package is waiting for upload. Cancel that deployment or wait for its two-hour session to expire.',
13300
+ 'PRE_DEPLOY_SOURCE_CHANGED',
13301
+ );
13302
+ }
13303
+ if (reconciledSession && !liveSavedSession) {
13304
+ await removeUploadSession(sourceRoot);
13305
+ }
13306
+ const resumableSession = liveSavedSession;
13307
+ const session = resumableSession || {
13308
+ idempotencyKey: node_crypto.randomUUID(),
13309
+ createdAt: Date.now(),
13310
+ sourcePackageSizeBytes: archive.sizeBytes,
13311
+ request: retryRequest,
13312
+ };
13313
+ // Persist before preDeployUpload: if the server creates PreDeploy but the response is lost,
13314
+ // the next CLI run must reuse the same idempotency key.
13315
+ await writeUploadSession(sourceRoot, session);
13316
+ const preDeploy = await client.preDeployUpload({
13317
+ ...session.request,
13318
+ source_package_size_bytes: String(archive.sizeBytes),
13319
+ idempotency_key: session.idempotencyKey,
13320
+ });
13321
+ await writeUploadSession(sourceRoot, {
13322
+ ...session,
13323
+ appId: preDeploy.app_id,
13324
+ deployHistoryId: preDeploy.deploy_history_id,
13325
+ uploadReceipt: preDeploy.upload_receipt,
13326
+ });
13327
+ await uploadFile(preDeploy.upload_url, preDeploy.required_headers || {}, archive);
13328
+ const result = await client.createDeployHistory({
13329
+ ...session.request,
13330
+ project_id: undefined,
13331
+ app_id: preDeploy.app_id,
13332
+ pre_deploy_history_id: preDeploy.deploy_history_id,
13333
+ upload_receipt: preDeploy.upload_receipt,
13334
+ source_package_size_bytes: String(archive.sizeBytes),
13335
+ });
13336
+ await removeUploadSession(sourceRoot);
13337
+ return { uploadMode: 'direct' , result };
13338
+ };
13339
+
13340
+ 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; }
13341
+ const SUPPORTED_MINIPROGRAM_CONNECTOR_IDS = new Set(['10000127', '10000126']);
13342
+ const collectConnectorId = (value, previous) => [
13343
+ ...previous,
13344
+ value,
13345
+ ];
13346
+
13347
+ const getConnectorConfigs = (connectorIds) =>
13348
+ (connectorIds || []).map(connectorId => {
13349
+ if (!SUPPORTED_MINIPROGRAM_CONNECTOR_IDS.has(connectorId)) {
13350
+ throw new CliError(
13351
+ `Unsupported connector ID ${connectorId}; expected 10000127 (WeChat) or 10000126 (Douyin).`,
13352
+ 'INVALID_CONNECTOR_ID',
13353
+ );
13354
+ }
13355
+ return { connector_id: connectorId };
13356
+ });
13357
+
13358
+ // Keep deployment option and output contracts together for auditing against the V2 IDL.
13359
+ // eslint-disable-next-line @coze-arch/max-line-per-function -- keep V2 deployment contracts together
13360
+ const registerDeploy = (deploy) => {
13361
+ deploy
13362
+ .description('Deploy an application using deployment V2')
13363
+ .option('--source-root <sourceRoot>', 'Local source root', '.')
13364
+ .option('--project-id <projectId>', 'Project ID for the first deployment')
13365
+ .option('--app-id <appId>', 'Application ID')
13366
+ .option(
13367
+ '--application-type <type>',
13368
+ 'Deployment application type: service, pages, or mini_program',
13369
+ )
13370
+ .option('-n, --name <name>', 'Application name for the first deployment')
13371
+ .option('--message <message>', 'Deployment message')
13372
+ .option(
13373
+ '--connector-id <connectorId>',
13374
+ 'Mini-program channel: 10000127 (WeChat) or 10000126 (Douyin); repeatable',
13375
+ collectConnectorId,
13376
+ [],
13377
+ )
13378
+ .option('--wait', 'Wait for deployment completion')
13379
+ .option('--yes', 'Confirm deployment')
13380
+ // eslint-disable-next-line @coze-arch/max-line-per-function -- deployment orchestration is one auditable flow
13381
+ .action(async (options, command) => {
13382
+ const runtime = await getRuntime(command);
13383
+ const sourceRoot = node_path.resolve(runtime.cwd, options.sourceRoot || '.');
13384
+ const requestedApplicationType = parseApplicationType(options.applicationType);
13385
+ runtime.output.debug(`[deploy] Reading local project: ${sourceRoot}`);
13386
+ const localContext =
13387
+ await readDeployLocalContext(
13388
+ sourceRoot,
13389
+ requestedApplicationType,
13390
+ options.appId,
13391
+ runtime.client,
13392
+ );
13393
+ const { commitHash, isPagesDeployment } = localContext;
13394
+ let { metadata } = localContext;
13395
+ const deploymentName = _nullishCoalesce(options.name, () => ( metadata.name));
13396
+ let projectId = options.projectId || metadata.projectId;
13397
+ let appId = options.appId || metadata.appId;
13398
+ const appIdFromCoze = Boolean(metadata.appId && !options.appId);
13399
+ let projectCreated = false;
13400
+ let linkedApplicationType;
13401
+ if (appId) {
13402
+ const linkedApplication = await runtime.client.getApplication(appId);
13403
+ linkedApplicationType = linkedApplication.application_type;
13404
+ const linkedProjectId = linkedApplication.project_id;
13405
+ if (!options.appId && projectId && linkedProjectId && projectId !== linkedProjectId) {
13406
+ throw new CliError(
13407
+ `Project ${projectId} does not own application ${appId}; it belongs to project ${linkedProjectId}.`,
13408
+ 'PROJECT_ID_CONFLICT',
13409
+ );
13410
+ }
13411
+ if (options.appId && linkedProjectId) {
13412
+ projectId = linkedProjectId;
13413
+ } else {
13414
+ projectId ||= linkedProjectId;
13415
+ }
13416
+ if (!projectId) {
13417
+ throw new CliError(
13418
+ `Application ${appId} did not return its associated project_id.`,
13419
+ 'INVALID_RESPONSE',
13420
+ );
13421
+ }
13422
+ const inferredApplicationType = linkedApplicationType === 'pages'
13423
+ ? 'pages'
13424
+ : inferApplicationTypeFromProjectType(metadata.projectType);
13425
+ const targetApplicationType = requestedApplicationType || inferredApplicationType;
13426
+ if (appIdFromCoze && targetApplicationType && linkedApplicationType !== targetApplicationType) {
13427
+ runtime.output.warn(
13428
+ `The linked application ${appId} is ${linkedApplicationType}, but ${targetApplicationType} is required. A new application will be created and written to .coze.`,
13429
+ );
13430
+ appId = undefined;
13431
+ }
13432
+ }
13433
+ if (!projectId) {
13434
+ runtime.output.debug(
13435
+ '[deploy] Creating a dedicated deployment project in personal space...',
13436
+ );
13437
+ // 账号归属只在建 Project 这一次定死:写进 project_settings.extra 之后,有登录态的首次
13438
+ // 部署和无登录态的预览初始化读到的是同一个账号。本地已经知道账号就不打这次接口。
13439
+ const cozeAccountId = await resolveCozeAccountId(runtime);
13440
+ const project = await runtime.client.createDeploymentProject({
13441
+ space_id: '0',
13442
+ user_query: deploymentName || 'CLI deployment project',
13443
+ project_type: resolveCreationProjectType(metadata.projectType),
13444
+ create_source: 'cli',
13445
+ project_settings: {
13446
+ project_symbol: 'v3.5',
13447
+ ...(cozeAccountId ? { extra: { coze_account_id: cozeAccountId } } : {}),
13448
+ },
13449
+ });
13450
+ projectId = project.project_id;
13451
+ projectCreated = true;
13452
+ }
13453
+ if (metadata.projectId !== projectId) {
13454
+ metadata = await writeProjectBinding(sourceRoot, { projectId });
13455
+ }
13456
+ runtime.output.debug(`[deploy] Using project ${projectId} from ${projectCreated ? 'new project' : options.projectId ? '--project-id' : appId ? 'application binding' : '.coze'}`);
13457
+ const cozeFileContent = metadata.cozeFileContent;
13458
+ runtime.output.debug('[deploy] Loading deployment configuration...');
13459
+ const serverConfig = await runtime.client.getDeployConfig({
13460
+ ...(appId ? { app_id: appId } : { project_id: projectId }),
13461
+ commit_hash: commitHash,
13462
+ ...(isPagesDeployment ? { application_type: 'pages' } : {}),
13463
+ ...(cozeFileContent ? { coze_file_content: cozeFileContent } : {}),
13464
+ });
13465
+ const config = withRequestedApplicationType(
13466
+ serverConfig,
13467
+ requestedApplicationType,
13468
+ Boolean(appId),
13469
+ );
13470
+ const applicationType = config.application_type;
13471
+ const connectorConfigs = getConnectorConfigs(options.connectorId);
13472
+ if (!options.yes) {
13473
+ runtime.output.debug('[deploy] Preflight complete; confirmation is required.');
13474
+ runtime.output.print({
13475
+ confirmation_required: true,
13476
+ app_id: appId,
13477
+ project_id: projectId,
13478
+ application_type: applicationType,
13479
+ commit_hash: commitHash,
13480
+ source_root: sourceRoot,
13481
+ deploy_config: config.deploy_config,
13482
+ current_version: config.current_version,
13483
+ next_version: config.next_version,
13484
+ risks: config.risk_list || [],
13485
+ ...(!appId && deploymentName ? { name: deploymentName } : {}),
13486
+ message: options.message,
13487
+ lane: runtime.globalOptions.lane || runtime.config.xTTEnv,
13488
+ });
13489
+ return;
13490
+ }
13491
+ let encryptEnvVariable;
13492
+ if (applicationType !== 'pages') {
13493
+ runtime.output.debug('[deploy] Loading and encrypting online environment variables...');
13494
+ const onlineEnvironment = appId
13495
+ ? await runtime.client.getOnlineEnvironment(appId)
13496
+ : undefined;
13497
+ if (onlineEnvironment && onlineEnvironment.snapshot_status >= 3) {
13498
+ throw new CliError(
13499
+ onlineEnvironment.status_message ||
13500
+ 'The current online environment snapshot is unavailable.',
13501
+ 'ONLINE_ENVIRONMENT_UNAVAILABLE',
13502
+ );
13503
+ }
13504
+ const envSecrets = (_optionalChain([onlineEnvironment, 'optionalAccess', _ => _.variables]) || [])
13505
+ .filter(variable => variable.source === 'user')
13506
+ .map(variable => ({
13507
+ secret_id: '',
13508
+ secret_key: variable.key,
13509
+ secret_val: variable.value,
13510
+ secret_type: 'user_custom' ,
13511
+ }));
13512
+ const encrypted = await runtime.client.encryptProjectSecret(projectId, envSecrets);
13513
+ encryptEnvVariable = encrypted.sealed_secrets;
13514
+ if (!encryptEnvVariable) {
13515
+ throw new CliError(
13516
+ 'The project secret encryption API returned no sealed_secrets.',
13517
+ 'INVALID_RESPONSE',
13518
+ );
13519
+ }
13520
+ }
13521
+ runtime.output.debug(
13522
+ `[deploy] Building and packaging ${applicationType} artifact...`,
13523
+ );
13524
+ const sourcePackage = await createSourcePackageArchive(
13525
+ sourceRoot,
13526
+ applicationType,
13527
+ runtime.globalOptions.debug,
13528
+ );
13529
+ runtime.output.debug(
13530
+ `[deploy] Package ready: ${String(sourcePackage.sizeBytes)} bytes`,
13531
+ );
13532
+ runtime.output.debug('[deploy] Uploading package and creating deployment...');
13533
+ const deploymentRequest = {
13534
+ ...(appId ? { app_id: appId } : { project_id: projectId }),
13535
+ application_type: applicationType,
13536
+ commit_hash: commitHash,
13537
+ ...(options.message ? { commit_message: options.message } : {}),
13538
+ ...(!appId
13539
+ ? { name: deploymentName, source_root: sourceRoot }
13540
+ : {}),
13541
+ is_sync_db_to_prod: false,
13542
+ table_sync_configs: [],
13543
+ connector_configs: connectorConfigs,
13544
+ ...(cozeFileContent ? { coze_file_content: cozeFileContent } : {}),
13545
+ ...(encryptEnvVariable
13546
+ ? { encrypt_env_variable: encryptEnvVariable }
13547
+ : {}),
13548
+ ...getCreateDeployConfig(config),
13549
+ };
13550
+ let deployment;
13551
+ try {
13552
+ deployment = await createDeploymentWithSourcePackage(runtime.client, deploymentRequest, sourcePackage, sourceRoot);
13553
+ } finally {
13554
+ await sourcePackage.cleanup();
13555
+ }
13556
+ const { result } = deployment;
13557
+ const deployHistoryId = resolveDeployHistoryId(
13558
+ result.deploy_history_id,
13559
+ result.prev_deploy_history_id,
13560
+ );
13561
+ if (!deployHistoryId) {
13562
+ throw new CliError('Deployment response returned no deploy_history_id.', 'INVALID_RESPONSE');
13563
+ }
13564
+ if (metadata.appId !== result.app_id || metadata.projectId !== projectId) {
13565
+ await writeProjectBinding(sourceRoot, {
13566
+ projectId,
13567
+ appId: result.app_id,
13568
+ });
13569
+ if (!appId) {
13570
+ runtime.output.warn(`Created application ${result.app_id} and saved it to .coze.`);
13571
+ }
13572
+ }
13573
+ if (options.wait) {
13574
+ runtime.output.debug('[deploy] Deployment accepted; waiting for completion...');
13575
+ } else {
13576
+ runtime.output.debug('[deploy] Deployment accepted.');
13577
+ }
13578
+ const history = options.wait
13579
+ ? await pollHistory(command, result.app_id, deployHistoryId)
13580
+ : undefined;
13581
+ // 不带 --wait 时 history 是 undefined,产物必然还没落库:这里一定会带上
13582
+ // artifacts_pending,而不是甩一个看起来像「查过了,没有」的空数组出去。
13583
+ const effectiveStatus = _nullishCoalesce(_optionalChain([history, 'optionalAccess', _2 => _2.status]), () => ( result.status));
13584
+ runtime.output.print({
13585
+ app_id: result.app_id,
13586
+ deploy_history_id: deployHistoryId,
13587
+ version: result.version,
13588
+ commit_hash: commitHash,
13589
+ status: getDeployStatusText(effectiveStatus),
13590
+ source_package_size_bytes: sourcePackage.sizeBytes,
13591
+ upload_mode: deployment.uploadMode,
13592
+ local_link: appId && !projectCreated ? 'unchanged' : 'written',
13593
+ ...mobileArtifactsOutput(history, effectiveStatus),
13594
+ });
13595
+ });
13596
+
13597
+ registerDeployReadCommands(deploy);
13598
+
13599
+ deploy
13600
+ .command('cancel')
13601
+ .requiredOption('--deploy-id <deployId>', 'Deployment history ID')
13602
+ .option('--app-id <appId>', 'Application ID')
13603
+ .option('--yes', 'Confirm cancellation')
13604
+ .action(async (options, command) => {
13605
+ const parentOptions = getDeployParentOptions(command);
13606
+ if (!options.yes && !parentOptions.yes) {
13607
+ throw new CliError('Pass --yes to cancel deployment.', 'CONFIRMATION_REQUIRED');
13608
+ }
13609
+ const runtime = await getRuntime(command);
13610
+ const appId = await requireAppId(runtime.cwd, getDeployAppIdOption(options, command));
13611
+ await runtime.client.cancelDeployHistory({
13612
+ app_id: appId,
13613
+ deploy_history_id: options.deployId || '',
13614
+ });
13615
+ runtime.output.print({ app_id: appId, canceled: true });
13616
+ });
13617
+
13618
+ deploy
13619
+ .command('rollback')
13620
+ .requiredOption('--deploy-id <deployId>', 'Target deployment history ID')
13621
+ .option('--app-id <appId>', 'Application ID')
13622
+ .option('--rollback-database', 'Rollback database')
13623
+ .option('--yes', 'Confirm rollback')
13624
+ .action(async (options, command) => {
13625
+ const parentOptions = getDeployParentOptions(command);
13626
+ if (!options.yes && !parentOptions.yes) {
13627
+ throw new CliError('Pass --yes to rollback.', 'CONFIRMATION_REQUIRED');
13628
+ }
13629
+ const runtime = await getRuntime(command);
13630
+ const appId = await requireAppId(runtime.cwd, getDeployAppIdOption(options, command));
13631
+ const data = await runtime.client.rollbackDeployHistory({
13632
+ app_id: appId,
13633
+ target_deploy_history_id: options.deployId || '',
13634
+ rollback_database: _nullishCoalesce(options.rollbackDatabase, () => ( false)),
13635
+ });
13636
+ runtime.output.print({ app_id: appId, ...data });
13637
+ });
13638
+
13639
+ // stop 不可逆(删函数 → Stopped,只能重新部署),pause 可逆(→ Paused,resume 能推回 Ready)。
13640
+ const applicationActions = {
13641
+ stop: (client, appId) => client.stopApplication(appId),
13642
+ resume: (client, appId) => client.resumeApplication(appId),
13643
+ pause: (client, appId) => client.pauseApplication(appId),
13644
+ } ;
13645
+
13646
+ for (const action of Object.keys(applicationActions) ) {
13647
+ deploy
13648
+ .command(action)
13649
+ .option('--app-id <appId>', 'Application ID')
13650
+ .option('--yes', `Confirm ${action}`)
13651
+ .action(async (options, command) => {
13652
+ const parentOptions = getDeployParentOptions(command);
13653
+ if (!options.yes && !parentOptions.yes) {
13654
+ throw new CliError(`Pass --yes to ${action}.`, 'CONFIRMATION_REQUIRED');
13655
+ }
13656
+ const runtime = await getRuntime(command);
13657
+ const appId = await requireAppId(runtime.cwd, getDeployAppIdOption(options, command));
13658
+ await applicationActions[action](runtime.client, appId);
13659
+ runtime.output.print({ app_id: appId, action, success: true });
13660
+ });
13661
+ }
13662
+
13663
+ deploy
13664
+ .command('logs')
13665
+ .option('--app-id <appId>', 'Application ID')
13666
+ .option('--start-time <startTime>', 'Start time in milliseconds')
13667
+ .option('--end-time <endTime>', 'End time in milliseconds')
13668
+ .option('--limit <limit>', 'Page size')
13669
+ .option('--cursor <cursor>', 'Pagination cursor')
13670
+ .option('--query <query>', 'Log keyword')
13671
+ .option('--level <level>', 'all, info, warn, or error')
13672
+ .action(async (options, command) => {
13673
+ const runtime = await getRuntime(command);
13674
+ const appId = await requireAppId(runtime.cwd, getDeployAppIdOption(options, command));
13675
+ runtime.output.print(
13676
+ await runtime.client.searchRuntimeLog({
13677
+ app_id: appId,
13678
+ start_time: options.startTime,
13679
+ end_time: options.endTime,
13680
+ limit: options.limit,
13681
+ cursor: options.cursor,
13682
+ query: options.query,
13683
+ level: options.level,
13684
+ }),
13685
+ );
13686
+ });
13687
+
13688
+ deploy
13689
+ .command('build-log')
13690
+ .requiredOption('--deploy-id <deployId>', 'Deployment history ID')
13691
+ .option('--key <key>', 'Deployment log key; inferred when the deployment has one log')
13692
+ .option('--app-id <appId>', 'Application ID')
13693
+ .action(async (options, command) => {
13694
+ const runtime = await getRuntime(command);
13695
+ const appId = await requireAppId(runtime.cwd, getDeployAppIdOption(options, command));
13696
+ let key = _optionalChain([options, 'access', _3 => _3.key, 'optionalAccess', _4 => _4.trim, 'call', _5 => _5()]);
13697
+ if (!key) {
13698
+ const history = await runtime.client.getDeployHistory({
13699
+ app_id: appId,
13700
+ deploy_history_id: options.deployId || '',
13701
+ });
13702
+ const keys = getDeployLogKeys(history);
13703
+ if (keys.length === 0) {
13704
+ throw new CliError(
13705
+ 'The deployment has no build log key yet. Retry after deployment stages start.',
13706
+ 'BUILD_LOG_NOT_READY',
13707
+ );
13708
+ }
13709
+ if (keys.length > 1) {
13710
+ throw new CliError(
13711
+ 'The deployment has multiple build logs. Pass --key using deploy status output.',
13712
+ 'BUILD_LOG_KEY_REQUIRED',
13713
+ { available_keys: keys },
13714
+ );
13715
+ }
13716
+ key = keys[0];
13717
+ }
13718
+ if (!key) {
13719
+ throw new CliError('Deployment log key is empty.', 'BUILD_LOG_NOT_READY');
13720
+ }
13721
+ runtime.output.print(
13722
+ await runtime.client.getBuildLog({
13723
+ app_id: appId,
13724
+ deploy_history_id: options.deployId || '',
13725
+ key,
13726
+ }),
13727
+ );
13728
+ });
13729
+
13730
+ deploy
13731
+ .command('config')
13732
+ .option('--app-id <appId>', 'Application ID')
13733
+ .option('--commit-id <commitId>', 'Commit hash')
13734
+ .action(async (options, command) => {
13735
+ const runtime = await getRuntime(command);
13736
+ const appId = await requireAppId(runtime.cwd, getDeployAppIdOption(options, command));
13737
+ const application = await runtime.client.getApplication(appId);
13738
+ const commitHash = options.commitId || _optionalChain([application, 'access', _6 => _6.latest_deployment, 'optionalAccess', _7 => _7.commit_hash]);
13739
+ if (!commitHash) {
13740
+ throw new CliError('No deployment commit is available.', 'DEPLOYMENT_NOT_FOUND');
13741
+ }
13742
+ const applicationType = application.application_type;
13743
+ const cozeFileContent = applicationType === 'pages'
13744
+ ? undefined
13745
+ : (await readProjectMetadata(node_path.resolve(runtime.cwd))).cozeFileContent;
13746
+ runtime.output.print(
13747
+ await runtime.client.getDeployConfig({
13748
+ app_id: appId,
13749
+ commit_hash: commitHash,
13750
+ ...(applicationType === 'pages' ? { application_type: 'pages' } : {}),
13751
+ ...(cozeFileContent ? { coze_file_content: cozeFileContent } : {}),
13752
+ }),
13753
+ );
13754
+ });
13755
+ };
13756
+
13757
+ const registerCommands = (program) => {
13758
+ registerAuth(program);
13759
+ registerContext(program);
13760
+ registerDoctor(program);
13761
+
13762
+ // Keep deployment operations directly under `coze-dev deploy` so the common
13763
+ // path is concise: `coze-dev deploy`, `coze-dev deploy status`, etc.
13764
+ registerDeploy(program);
13765
+ registerApp(program);
13766
+ registerDomain(program);
13767
+ registerEnv(program);
13768
+ registerMiniProgram(program);
13769
+
13770
+ // Preserve the original `coze-dev deploy code ...` hierarchy for scripts and
13771
+ // older plugin versions that still rely on it.
13772
+ const code = program.command('code', { hidden: true }).description('Legacy deployment operations');
13773
+ registerApp(code);
13774
+ registerDeploy(code.command('deploy'));
13775
+ registerDomain(code);
13776
+ registerEnv(code);
13777
+ registerMiniProgram(code);
13778
+ };
13779
+
13780
+ const configureDeployCommand = (command) => {
13781
+ markDeployCommand(command)
13782
+ .description('Deploy and manage Coze applications')
13783
+ .enablePositionalOptions()
13784
+ .option('--format <format>', 'Output format: json or text', 'json')
13785
+ .option('--config <path>', 'Shared Coze CLI config path')
13786
+ .option('--org-id <id>', 'Override organization ID')
13787
+ .option('--space-id <id>', 'Override space ID')
13788
+ .option('--lane <name>', 'Route API requests to the specified PPE lane')
13789
+ .option('--api-base-url <url>', 'Override API base URL')
13790
+ .option('--debug', 'Print debug diagnostics')
13791
+ .showHelpAfterError()
13792
+ .exitOverride();
13793
+ registerCommands(command);
13794
+ return command;
13795
+ };
13796
+
13797
+ const registerCommand = (program) => {
13798
+ configureDeployCommand(program.command('deploy'));
13799
+ };
13800
+
13801
+ const readFormat = (argv) => {
13802
+ const index = argv.indexOf('--format');
13803
+ return index >= 0 && argv[index + 1] === 'text' ? 'text' : 'json';
13804
+ };
13805
+
13806
+ const handleDeployError = (error, argv = process.argv) => {
13807
+ if (
13808
+ error instanceof commander.CommanderError &&
13809
+ ['commander.helpDisplayed', 'commander.version'].includes(error.code)
13810
+ ) {
13811
+ return;
13812
+ }
13813
+ const output = new Output(readFormat(argv), argv.includes('--debug'));
13814
+ output.print({ error: toErrorPayload(error) });
13815
+ process.exitCode = error instanceof commander.CommanderError ? 4 : 1;
13816
+ };
13817
+
13818
+ const commands = [
13819
+ registerCommand$1,
13820
+ registerCommand$4,
13821
+ registerCommand$7,
13822
+ registerCommand$5,
13823
+ registerCommand$6,
13824
+ registerCommand$3,
13825
+ registerCommand$2,
13826
+ registerCommand,
13827
+ ];
13828
+
13829
+ const main = async () => {
13830
+ // 初始化 Slardar 监控
13831
+ initSlardar();
13832
+
13833
+ // 监听未捕获的异常
13834
+ process.on('uncaughtException', async (error) => {
13835
+ reportError(error, {
13836
+ type: 'uncaughtException',
13837
+ context: 'global',
13838
+ });
13839
+ await flushSlardar();
13840
+ process.exit(1);
13841
+ });
13842
+
13843
+ // 监听未处理的 Promise rejection
13844
+ process.on('unhandledRejection', async (reason) => {
13845
+ const error = reason instanceof Error ? reason : new Error(String(reason));
13846
+ reportError(error, {
13847
+ type: 'unhandledRejection',
13848
+ context: 'global',
13849
+ });
13850
+ await flushSlardar();
13851
+ process.exit(1);
13852
+ });
13853
+
13854
+ const program = new commander.Command();
13855
+
13856
+ program
13857
+ .name('coze-dev')
13858
+ .description(
13859
+ 'Coze Coding CLI - Project template engine for frontend stacks',
13860
+ )
13861
+ .version(packageJson.version);
13862
+
13863
+ commands.forEach(initCmd => initCmd(program));
13864
+
13865
+ // 在 help 输出中添加模板信息
13866
+ program.addHelpText('after', generateTemplatesHelpText());
13867
+
13868
+ // 使用 parseAsync 等待命令执行完成
13869
+ try {
13870
+ await program.parseAsync(process.argv);
13871
+ } catch (error) {
13872
+ if (process.argv[2] === 'deploy') {
13873
+ handleDeployError(error);
13874
+ } else {
13875
+ throw error;
13876
+ }
13877
+ }
10370
13878
 
10371
13879
  // 统一在命令执行完成后 flush
10372
13880
  // 注意:如果命令中调用了 process.exit(),不会执行到这里