@coze-arch/cli 0.0.37 → 0.1.3-alpha.8d71d5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +69 -104
- package/docs/deploy.md +181 -0
- package/lib/__templates__/expo/.cozeproj/scripts/dev_run.sh +108 -19
- package/lib/__templates__/expo/.cozeproj/scripts/prod_run.sh +1 -1
- package/lib/__templates__/expo/.cozeproj/scripts/server_dev_run.sh +1 -1
- package/lib/__templates__/expo/client/metro.config.js +3 -1
- package/lib/__templates__/expo/pnpm-lock.yaml +5 -5
- package/lib/__templates__/expo/server/package.json +2 -2
- package/lib/__templates__/expo/server/src/index.ts +1 -1
- package/lib/__templates__/expo/template.config.js +11 -2
- package/lib/__templates__/native-static/.coze +4 -2
- package/lib/__templates__/native-static/scripts/serve.ps1 +7 -0
- package/lib/__templates__/nextjs/.coze +5 -0
- package/lib/__templates__/nextjs/package.json +2 -2
- package/lib/__templates__/nextjs/pnpm-lock.yaml +5 -5
- package/lib/__templates__/nextjs/scripts/build.ps1 +16 -0
- package/lib/__templates__/nextjs/scripts/dev.ps1 +63 -0
- package/lib/__templates__/nextjs/scripts/dev.sh +234 -7
- package/lib/__templates__/nextjs/scripts/prepare.ps1 +18 -0
- package/lib/__templates__/nextjs/scripts/start.ps1 +11 -0
- package/lib/__templates__/nextjs/scripts/validate.ps1 +8 -0
- package/lib/__templates__/nextjs/template.config.js +4 -2
- package/lib/__templates__/nuxt-vue/.coze +5 -0
- package/lib/__templates__/nuxt-vue/package.json +1 -1
- package/lib/__templates__/nuxt-vue/pnpm-lock.yaml +5 -5
- package/lib/__templates__/nuxt-vue/scripts/build.ps1 +12 -0
- package/lib/__templates__/nuxt-vue/scripts/dev.ps1 +63 -0
- package/lib/__templates__/nuxt-vue/scripts/dev.sh +232 -3
- package/lib/__templates__/nuxt-vue/scripts/prepare.ps1 +12 -0
- package/lib/__templates__/nuxt-vue/scripts/start.ps1 +11 -0
- package/lib/__templates__/nuxt-vue/scripts/validate.ps1 +8 -0
- package/lib/__templates__/phaser/.coze +18 -0
- package/lib/__templates__/phaser/README.md +45 -0
- package/lib/__templates__/phaser/_gitignore +23 -0
- package/lib/__templates__/phaser/_npmrc +14 -0
- package/lib/__templates__/phaser/assets/image_sequence/coze-game-loading/frame_0001.png +0 -0
- package/lib/__templates__/phaser/assets/image_sequence/coze-game-loading/frame_0002.png +0 -0
- package/lib/__templates__/phaser/assets/image_sequence/coze-game-loading/frame_0003.png +0 -0
- package/lib/__templates__/phaser/assets/image_sequence/coze-game-loading/frame_0004.png +0 -0
- package/lib/__templates__/phaser/assets/image_sequence/coze-game-loading/frame_0005.png +0 -0
- package/lib/__templates__/phaser/assets/image_sequence/coze-game-loading/frame_0006.png +0 -0
- package/lib/__templates__/phaser/assets/image_sequence/coze-game-loading/frame_0007.png +0 -0
- package/lib/__templates__/phaser/assets/image_sequence/coze-game-loading/frame_0008.png +0 -0
- package/lib/__templates__/phaser/assets/image_sequence/coze-game-loading/frame_0009.png +0 -0
- package/lib/__templates__/phaser/assets/image_sequence/coze-game-loading/frame_0010.png +0 -0
- package/lib/__templates__/phaser/assets/image_sequence/coze-game-loading/frame_0011.png +0 -0
- package/lib/__templates__/phaser/assets/image_sequence/coze-game-loading/frame_0012.png +0 -0
- package/lib/__templates__/phaser/assets/image_sequence/coze-game-loading/frame_0013.png +0 -0
- package/lib/__templates__/phaser/assets/image_sequence/coze-game-loading/frame_0014.png +0 -0
- package/lib/__templates__/phaser/assets/image_sequence/coze-game-loading/frame_0015.png +0 -0
- package/lib/__templates__/phaser/assets/image_sequence/coze-game-loading/frame_0016.png +0 -0
- package/lib/__templates__/phaser/assets/image_sequence/coze-game-loading/frame_0017.png +0 -0
- package/lib/__templates__/phaser/assets/image_sequence/coze-game-loading/frame_0018.png +0 -0
- package/lib/__templates__/phaser/assets/image_sequence/coze-game-loading/frame_0019.png +0 -0
- package/lib/__templates__/phaser/assets/image_sequence/coze-game-loading/frame_0020.png +0 -0
- package/lib/__templates__/phaser/assets/image_sequence/coze-game-loading/frame_0021.png +0 -0
- package/lib/__templates__/phaser/assets/image_sequence/coze-game-loading/frame_0022.png +0 -0
- package/lib/__templates__/phaser/assets/image_sequence/coze-game-loading/frame_0023.png +0 -0
- package/lib/__templates__/phaser/assets/image_sequence/coze-game-loading/frame_0024.png +0 -0
- package/lib/__templates__/phaser/assets/image_sequence/coze-game-loading/manifest.json +11 -0
- package/lib/__templates__/phaser/debug-runtime/flow-graph.json +20 -0
- package/lib/__templates__/phaser/index.html +12 -0
- package/lib/__templates__/phaser/package.json +31 -0
- package/lib/__templates__/phaser/pnpm-lock.yaml +661 -0
- package/lib/__templates__/phaser/scripts/build.ps1 +12 -0
- package/lib/__templates__/phaser/scripts/build.sh +8 -0
- package/lib/__templates__/phaser/scripts/dev.ps1 +49 -0
- package/lib/__templates__/phaser/scripts/dev.sh +82 -0
- package/lib/__templates__/phaser/scripts/prepare.ps1 +8 -0
- package/lib/__templates__/phaser/scripts/prepare.sh +7 -0
- package/lib/__templates__/phaser/scripts/spawn-detached.cjs +29 -0
- package/lib/__templates__/phaser/scripts/start.ps1 +49 -0
- package/lib/__templates__/phaser/scripts/start.sh +82 -0
- package/lib/__templates__/phaser/scripts/validate.ps1 +7 -0
- package/lib/__templates__/phaser/scripts/validate.sh +7 -0
- package/lib/__templates__/phaser/src/assets.ts +15 -0
- package/lib/__templates__/phaser/src/global.d.ts +39 -0
- package/lib/__templates__/phaser/src/main.ts +28 -0
- package/lib/__templates__/phaser/src/scene/BootScene.ts +213 -0
- package/lib/__templates__/phaser/src/scene/DevLoadingScene.ts +69 -0
- package/lib/__templates__/phaser/src/style.css +28 -0
- package/lib/__templates__/phaser/src/types.ts +32 -0
- package/lib/__templates__/phaser/src/utils/asset-loader.ts +319 -0
- package/lib/__templates__/phaser/src/utils/index.ts +2 -0
- package/lib/__templates__/phaser/src/utils/mark-editable.ts +13 -0
- package/lib/__templates__/phaser/template.config.js +43 -0
- package/lib/__templates__/phaser/tsconfig.json +23 -0
- package/lib/__templates__/phaser/vite.config.ts +96 -0
- package/lib/__templates__/phaser-static/.coze +15 -0
- package/lib/__templates__/phaser-static/README.md +40 -0
- package/lib/__templates__/phaser-static/_gitignore +6 -0
- package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0001.png +0 -0
- package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0002.png +0 -0
- package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0003.png +0 -0
- package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0004.png +0 -0
- package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0005.png +0 -0
- package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0006.png +0 -0
- package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0007.png +0 -0
- package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0008.png +0 -0
- package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0009.png +0 -0
- package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0010.png +0 -0
- package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0011.png +0 -0
- package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0012.png +0 -0
- package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0013.png +0 -0
- package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0014.png +0 -0
- package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0015.png +0 -0
- package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0016.png +0 -0
- package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0017.png +0 -0
- package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0018.png +0 -0
- package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0019.png +0 -0
- package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0020.png +0 -0
- package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0021.png +0 -0
- package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0022.png +0 -0
- package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0023.png +0 -0
- package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0024.png +0 -0
- package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/manifest.json +11 -0
- package/lib/__templates__/phaser-static/debug-runtime/flow-graph.json +20 -0
- package/lib/__templates__/phaser-static/index.html +17 -0
- package/lib/__templates__/phaser-static/scripts/serve.ps1 +7 -0
- package/lib/__templates__/phaser-static/src/assets.js +15 -0
- package/lib/__templates__/phaser-static/src/main.js +26 -0
- package/lib/__templates__/phaser-static/src/phaser.js +7 -0
- package/lib/__templates__/phaser-static/src/scene/BootScene.js +205 -0
- package/lib/__templates__/phaser-static/src/scene/DevLoadingScene.js +67 -0
- package/lib/__templates__/phaser-static/src/style.css +28 -0
- package/lib/__templates__/phaser-static/src/utils/asset-loader.js +267 -0
- package/lib/__templates__/phaser-static/src/utils/index.js +2 -0
- package/lib/__templates__/phaser-static/src/utils/mark-editable.js +3 -0
- package/lib/__templates__/phaser-static/template.config.js +35 -0
- package/lib/__templates__/pi-agent/package.json +1 -1
- package/lib/__templates__/pi-agent/pnpm-lock.yaml +5 -5
- package/lib/__templates__/taro/.cozeproj/scripts/deploy_run.sh +1 -1
- package/lib/__templates__/taro/.cozeproj/scripts/dev_run.sh +178 -68
- package/lib/__templates__/taro/AGENTS.md +11 -7
- package/lib/__templates__/taro/README.md +4 -4
- package/lib/__templates__/taro/config/index.ts +10 -2
- package/lib/__templates__/taro/pnpm-lock.yaml +5 -5
- package/lib/__templates__/taro/server/package.json +1 -1
- package/lib/__templates__/taro/server/src/main.ts +8 -2
- package/lib/__templates__/templates.json +51 -1
- package/lib/__templates__/vite/.coze +5 -0
- package/lib/__templates__/vite/package.json +1 -1
- package/lib/__templates__/vite/pnpm-lock.yaml +5 -5
- package/lib/__templates__/vite/scripts/build.ps1 +16 -0
- package/lib/__templates__/vite/scripts/dev.ps1 +63 -0
- package/lib/__templates__/vite/scripts/dev.sh +110 -1
- package/lib/__templates__/vite/scripts/prepare.ps1 +18 -0
- package/lib/__templates__/vite/scripts/start.ps1 +11 -0
- package/lib/__templates__/vite/scripts/validate.ps1 +8 -0
- package/lib/__templates__/vite/template.config.js +4 -2
- package/lib/cli.js +3718 -211
- package/lib/deploy/package-project.js +244 -0
- package/lib/deploy/package-project.py +183 -0
- 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
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
2006
|
+
args: _optionalChain$F([options, 'optionalAccess', _ => _.args]),
|
|
2000
2007
|
status: 'running' ,
|
|
2001
|
-
..._optionalChain$
|
|
2008
|
+
..._optionalChain$F([options, 'optionalAccess', _2 => _2.categories]),
|
|
2002
2009
|
},
|
|
2003
|
-
metrics: _optionalChain$
|
|
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$
|
|
2031
|
+
args: _optionalChain$F([options, 'optionalAccess', _4 => _4.args]),
|
|
2025
2032
|
status: success ? ('success' ) : ('fail' ),
|
|
2026
|
-
..._optionalChain$
|
|
2033
|
+
..._optionalChain$F([options, 'optionalAccess', _5 => _5.categories]),
|
|
2027
2034
|
},
|
|
2028
2035
|
metrics: {
|
|
2029
2036
|
duration,
|
|
2030
|
-
...(_optionalChain$
|
|
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$
|
|
2052
|
-
statusCode: _optionalChain$
|
|
2053
|
-
status: _optionalChain$
|
|
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$
|
|
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$
|
|
2085
|
+
status: _optionalChain$F([options, 'optionalAccess', _13 => _13.success]) ? ('success' ) : ('fail' ),
|
|
2079
2086
|
},
|
|
2080
2087
|
metrics: {
|
|
2081
|
-
duration: _optionalChain$
|
|
2082
|
-
fileSize: _optionalChain$
|
|
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.
|
|
2117
|
+
var version = "0.1.3-alpha.8d71d5";
|
|
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
|
-
|
|
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$
|
|
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$
|
|
2322
|
-
errorCode: _optionalChain$
|
|
2331
|
+
args: _optionalChain$E([options, 'optionalAccess', _ => _.args]),
|
|
2332
|
+
errorCode: _optionalChain$E([options, 'optionalAccess', _2 => _2.errorCode]),
|
|
2323
2333
|
categories: {
|
|
2324
|
-
...(_optionalChain$
|
|
2325
|
-
..._optionalChain$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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:
|
|
2851
|
+
* Default: ~/.coze/logs
|
|
2842
2852
|
*/
|
|
2843
|
-
const LOGS_DIR = '
|
|
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
|
|
2868
|
+
* @returns Absolute path to logs directory (default: ~/.coze/logs)
|
|
2859
2869
|
*/
|
|
2860
2870
|
const getCozeLogsDir = () =>
|
|
2861
|
-
process.env.COZE_LOG_DIR || path.join(
|
|
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
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
3539
|
+
return _optionalChain$B([visitor, 'access', _ => _.Map, 'optionalCall', _2 => _2(key, node, path)]);
|
|
3530
3540
|
if (isSeq(node))
|
|
3531
|
-
return _optionalChain$
|
|
3541
|
+
return _optionalChain$B([visitor, 'access', _3 => _3.Seq, 'optionalCall', _4 => _4(key, node, path)]);
|
|
3532
3542
|
if (isPair(node))
|
|
3533
|
-
return _optionalChain$
|
|
3543
|
+
return _optionalChain$B([visitor, 'access', _5 => _5.Pair, 'optionalCall', _6 => _6(key, node, path)]);
|
|
3534
3544
|
if (isScalar(node))
|
|
3535
|
-
return _optionalChain$
|
|
3545
|
+
return _optionalChain$B([visitor, 'access', _7 => _7.Scalar, 'optionalCall', _8 => _8(key, node, path)]);
|
|
3536
3546
|
if (isAlias(node))
|
|
3537
|
-
return _optionalChain$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
3722
|
+
if (_optionalChain$z([ctx, 'optionalAccess', _ => _.maxAliasCount]) === 0)
|
|
3713
3723
|
throw new ReferenceError('Alias resolution is disabled');
|
|
3714
3724
|
let nodes;
|
|
3715
|
-
if (_optionalChain$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
3906
|
+
const node = _optionalChain$x([tagObj, 'optionalAccess', _9 => _9.createNode])
|
|
3897
3907
|
? tagObj.createNode(ctx.schema, value, ctx)
|
|
3898
|
-
: typeof _optionalChain$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
5222
|
-
return _nullishCoalesce$
|
|
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$
|
|
5237
|
-
if (_optionalChain$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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 =
|
|
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
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
5972
|
-
break;
|
|
5992
|
+
return _optionalChain$m([config, 'access', _9 => _9.dev, 'optionalAccess', _10 => _10.run_win]);
|
|
5973
5993
|
case 'build':
|
|
5974
|
-
|
|
5975
|
-
break;
|
|
5994
|
+
return _optionalChain$m([config, 'access', _11 => _11.deploy, 'optionalAccess', _12 => _12.build_win]);
|
|
5976
5995
|
case 'start':
|
|
5977
|
-
|
|
5978
|
-
break;
|
|
5996
|
+
return _optionalChain$m([config, 'access', _13 => _13.deploy, 'optionalAccess', _14 => _14.run_win]);
|
|
5979
5997
|
case 'validate':
|
|
5980
|
-
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
7547
|
-
const projectVersion = _optionalChain$
|
|
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$
|
|
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$
|
|
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$
|
|
7651
|
-
showFlags: _optionalChain$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
7859
|
+
exitCode: String(_nullishCoalesce$4(code, () => ( 'unknown'))),
|
|
7819
7860
|
projectType,
|
|
7820
7861
|
},
|
|
7821
7862
|
errorContext: {
|
|
7822
|
-
exitCode: String(_nullishCoalesce$
|
|
7823
|
-
signal: _nullishCoalesce$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
8990
|
+
const registerCommand$2 = program => {
|
|
8950
8991
|
program
|
|
8951
8992
|
.command('check-bins')
|
|
8952
8993
|
.description(
|
|
@@ -9840,7 +9881,7 @@ const execute = async (
|
|
|
9840
9881
|
};
|
|
9841
9882
|
};
|
|
9842
9883
|
|
|
9843
|
-
function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }
|
|
9884
|
+
function _nullishCoalesce$2(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }
|
|
9844
9885
|
/**
|
|
9845
9886
|
* 运行 pnpm install
|
|
9846
9887
|
*/
|
|
@@ -9961,8 +10002,8 @@ const runDev = (projectPath) => {
|
|
|
9961
10002
|
// 获取当前 CLI 的可执行文件路径
|
|
9962
10003
|
// process.argv[0] 是 node,process.argv[1] 是 CLI 入口文件
|
|
9963
10004
|
// 二者在 CLI 运行时必然存在,兜底空串仅为满足类型收窄,运行时不会命中
|
|
9964
|
-
const nodeBin = _nullishCoalesce(process.argv[0], () => ( ''));
|
|
9965
|
-
const cliPath = _nullishCoalesce(process.argv[1], () => ( ''));
|
|
10005
|
+
const nodeBin = _nullishCoalesce$2(process.argv[0], () => ( ''));
|
|
10006
|
+
const cliPath = _nullishCoalesce$2(process.argv[1], () => ( ''));
|
|
9966
10007
|
|
|
9967
10008
|
try {
|
|
9968
10009
|
// 使用通用的后台执行函数启动开发服务器
|
|
@@ -10032,7 +10073,7 @@ const executeTemplateEngineStep = async ctx => {
|
|
|
10032
10073
|
templateName: ctx.templateName,
|
|
10033
10074
|
outputPath: ctx.outputPath,
|
|
10034
10075
|
command: ctx.command,
|
|
10035
|
-
force: _nullishCoalesce(ctx.options.force, () => ( false)),
|
|
10076
|
+
force: _nullishCoalesce$2(ctx.options.force, () => ( false)),
|
|
10036
10077
|
});
|
|
10037
10078
|
|
|
10038
10079
|
// 保存结果到上下文
|
|
@@ -10291,7 +10332,7 @@ const executeInit = async (
|
|
|
10291
10332
|
/**
|
|
10292
10333
|
* 注册 init 命令到 program
|
|
10293
10334
|
*/
|
|
10294
|
-
const registerCommand = program => {
|
|
10335
|
+
const registerCommand$1 = program => {
|
|
10295
10336
|
program
|
|
10296
10337
|
.command('init')
|
|
10297
10338
|
.description('Initialize a new project from a template')
|
|
@@ -10306,67 +10347,3533 @@ const registerCommand = program => {
|
|
|
10306
10347
|
false,
|
|
10307
10348
|
)
|
|
10308
10349
|
.option('--skip-dev', 'Skip automatic dev server start', false)
|
|
10350
|
+
.addHelpText('after', generateTemplatesHelpText())
|
|
10309
10351
|
.allowUnknownOption() // 允许透传参数
|
|
10310
10352
|
.action(async (directory, options, command) => {
|
|
10311
10353
|
// 位置参数优先级高于 --output 选项
|
|
10312
|
-
const outputPath = _nullishCoalesce(directory, () => ( options.output));
|
|
10354
|
+
const outputPath = _nullishCoalesce$2(directory, () => ( options.output));
|
|
10313
10355
|
// Always use force mode - overwrite existing files without conflict check
|
|
10314
10356
|
const force = true;
|
|
10315
10357
|
await executeInit({ ...options, output: outputPath, force }, command);
|
|
10316
10358
|
});
|
|
10317
10359
|
};
|
|
10318
10360
|
|
|
10319
|
-
const
|
|
10320
|
-
|
|
10321
|
-
|
|
10322
|
-
|
|
10323
|
-
|
|
10324
|
-
|
|
10325
|
-
|
|
10326
|
-
|
|
10361
|
+
const deployCommands = new WeakSet();
|
|
10362
|
+
|
|
10363
|
+
const markDeployCommand = (command) => {
|
|
10364
|
+
deployCommands.add(command);
|
|
10365
|
+
return command;
|
|
10366
|
+
};
|
|
10367
|
+
|
|
10368
|
+
const findDeployCommand = (command) => {
|
|
10369
|
+
let current = command;
|
|
10370
|
+
while (current) {
|
|
10371
|
+
if (deployCommands.has(current)) {
|
|
10372
|
+
return current;
|
|
10373
|
+
}
|
|
10374
|
+
current = current.parent;
|
|
10375
|
+
}
|
|
10376
|
+
throw new Error('Unable to resolve the coze-dev deploy command context.');
|
|
10377
|
+
};
|
|
10378
|
+
|
|
10379
|
+
class CliError extends Error {
|
|
10380
|
+
constructor(
|
|
10381
|
+
message,
|
|
10382
|
+
code = 'DEPLOY_CLI_ERROR',
|
|
10383
|
+
details,
|
|
10384
|
+
) {
|
|
10385
|
+
super(message);this.code = code;this.details = details; this.name = 'CliError';
|
|
10386
|
+
}
|
|
10387
|
+
}
|
|
10388
|
+
|
|
10389
|
+
const toErrorPayload = (error) => {
|
|
10390
|
+
if (error instanceof CliError) {
|
|
10391
|
+
return { code: error.code, message: error.message, details: error.details };
|
|
10392
|
+
}
|
|
10393
|
+
return {
|
|
10394
|
+
code: 'INTERNAL_ERROR',
|
|
10395
|
+
message: error instanceof Error ? error.message : String(error),
|
|
10396
|
+
};
|
|
10397
|
+
};
|
|
10398
|
+
|
|
10399
|
+
const APPLICATION_TYPES = new Set([
|
|
10400
|
+
'service',
|
|
10401
|
+
'pages',
|
|
10402
|
+
'mini_program',
|
|
10403
|
+
]);
|
|
10404
|
+
|
|
10405
|
+
const PAGES_SERVICE_TYPE = 3;
|
|
10406
|
+
|
|
10407
|
+
const inferApplicationTypeFromProjectType = (
|
|
10408
|
+
projectType,
|
|
10409
|
+
) => {
|
|
10410
|
+
switch (projectType) {
|
|
10411
|
+
case 'miniapp':
|
|
10412
|
+
case 'miniprogram':
|
|
10413
|
+
return 'mini_program';
|
|
10414
|
+
case undefined:
|
|
10415
|
+
case '':
|
|
10416
|
+
return undefined;
|
|
10417
|
+
default:
|
|
10418
|
+
return 'service';
|
|
10419
|
+
}
|
|
10420
|
+
};
|
|
10421
|
+
|
|
10422
|
+
const parseApplicationType = (
|
|
10423
|
+
value,
|
|
10424
|
+
) => {
|
|
10425
|
+
if (!value) {
|
|
10426
|
+
return undefined;
|
|
10427
|
+
}
|
|
10428
|
+
if (!APPLICATION_TYPES.has(value )) {
|
|
10429
|
+
throw new CliError(
|
|
10430
|
+
`Unsupported application type ${value}; expected service, pages, or mini_program.`,
|
|
10431
|
+
'INVALID_APPLICATION_TYPE',
|
|
10432
|
+
);
|
|
10433
|
+
}
|
|
10434
|
+
return value ;
|
|
10435
|
+
};
|
|
10436
|
+
|
|
10437
|
+
const withRequestedApplicationType = (
|
|
10438
|
+
config,
|
|
10439
|
+
requestedType,
|
|
10440
|
+
hasApplication = false,
|
|
10441
|
+
) => {
|
|
10442
|
+
if (!requestedType) {
|
|
10443
|
+
return config;
|
|
10444
|
+
}
|
|
10445
|
+
if (hasApplication && config.application_type !== requestedType) {
|
|
10446
|
+
throw new CliError(
|
|
10447
|
+
`Application type mismatch: the application is ${config.application_type}, but ${requestedType} was requested.`,
|
|
10448
|
+
'APPLICATION_TYPE_MISMATCH',
|
|
10449
|
+
);
|
|
10450
|
+
}
|
|
10451
|
+
if (requestedType !== 'pages') {
|
|
10452
|
+
if (config.application_type !== requestedType) {
|
|
10453
|
+
throw new CliError(
|
|
10454
|
+
`Application type mismatch: server resolved ${config.application_type}, but ${requestedType} was requested.`,
|
|
10455
|
+
'APPLICATION_TYPE_MISMATCH',
|
|
10456
|
+
);
|
|
10457
|
+
}
|
|
10458
|
+
return config;
|
|
10459
|
+
}
|
|
10460
|
+
return {
|
|
10461
|
+
...config,
|
|
10462
|
+
application_type: 'pages',
|
|
10463
|
+
deploy_config: {
|
|
10464
|
+
...config.deploy_config,
|
|
10465
|
+
service_type: PAGES_SERVICE_TYPE,
|
|
10466
|
+
computer_id: undefined,
|
|
10467
|
+
},
|
|
10468
|
+
};
|
|
10469
|
+
};
|
|
10470
|
+
|
|
10471
|
+
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; }
|
|
10472
|
+
const DEFAULT_CONFIG = {
|
|
10473
|
+
apiBaseUrl: 'https://code.coze.cn/',
|
|
10474
|
+
openApiBaseUrl: 'https://api.coze.cn',
|
|
10475
|
+
clientId: '95438868623436343239609434490626.app.coze',
|
|
10476
|
+
};
|
|
10477
|
+
|
|
10478
|
+
const getSharedConfigPath = () =>
|
|
10479
|
+
node_path.join(node_os.homedir(), '.coze', 'cli', 'config.json');
|
|
10480
|
+
|
|
10481
|
+
const getLegacyConfigPath = () => node_path.join(node_os.homedir(), '.coze', 'config.json');
|
|
10482
|
+
|
|
10483
|
+
const getDesktopRuntimePaths = (
|
|
10484
|
+
|
|
10485
|
+
|
|
10486
|
+
) => [
|
|
10487
|
+
{
|
|
10488
|
+
path: node_path.join(node_os.homedir(), '.coze', 'desktop', 'runtime.beta.json'),
|
|
10489
|
+
source: 'desktop_beta',
|
|
10490
|
+
},
|
|
10491
|
+
{
|
|
10492
|
+
path: node_path.join(node_os.homedir(), '.coze', 'desktop', 'runtime.json'),
|
|
10493
|
+
source: 'desktop',
|
|
10494
|
+
},
|
|
10327
10495
|
];
|
|
10328
10496
|
|
|
10329
|
-
const
|
|
10330
|
-
|
|
10331
|
-
initSlardar();
|
|
10497
|
+
const isRecord$3 = (value) =>
|
|
10498
|
+
typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
10332
10499
|
|
|
10333
|
-
|
|
10334
|
-
|
|
10335
|
-
|
|
10336
|
-
|
|
10337
|
-
|
|
10500
|
+
const readJson = async (path) => {
|
|
10501
|
+
try {
|
|
10502
|
+
const parsed = safeJsonParse(await promises.readFile(path, 'utf8'), undefined);
|
|
10503
|
+
return isRecord$3(parsed) ? parsed : undefined;
|
|
10504
|
+
} catch (error) {
|
|
10505
|
+
if ((error ).code === 'ENOENT') {
|
|
10506
|
+
return undefined;
|
|
10507
|
+
}
|
|
10508
|
+
throw new CliError(`Unable to read config ${path}: ${String(error)}`, 'CONFIG_INVALID');
|
|
10509
|
+
}
|
|
10510
|
+
};
|
|
10511
|
+
|
|
10512
|
+
const readDesktopAccessTokens = async () => {
|
|
10513
|
+
const candidates = [];
|
|
10514
|
+
for (const { path, source } of getDesktopRuntimePaths()) {
|
|
10515
|
+
try {
|
|
10516
|
+
const runtime = safeJsonParse(await promises.readFile(path, 'utf8'), undefined);
|
|
10517
|
+
if (!isRecord$3(runtime) || !isRecord$3(runtime.patToken)) {
|
|
10518
|
+
continue;
|
|
10519
|
+
}
|
|
10520
|
+
const {accessToken} = runtime.patToken;
|
|
10521
|
+
if (typeof accessToken === 'string' && accessToken.trim()) {
|
|
10522
|
+
candidates.push({ accessToken: accessToken.trim(), source });
|
|
10523
|
+
}
|
|
10524
|
+
} catch (error) {
|
|
10525
|
+
}
|
|
10526
|
+
}
|
|
10527
|
+
return candidates;
|
|
10528
|
+
};
|
|
10529
|
+
|
|
10530
|
+
const configuredPath = (options) =>
|
|
10531
|
+
_optionalChain$c([options, 'optionalAccess', _ => _.config]) || process.env.COZE_CONFIG_FILE;
|
|
10532
|
+
|
|
10533
|
+
const loadConfig = async (options = {}) => {
|
|
10534
|
+
const customPath = configuredPath(options);
|
|
10535
|
+
const globalConfig = customPath
|
|
10536
|
+
? await readJson(node_path.resolve(customPath))
|
|
10537
|
+
: (await readJson(getSharedConfigPath())) || (await readJson(getLegacyConfigPath()));
|
|
10538
|
+
const fixedAccessTokenCandidates = await readDesktopAccessTokens();
|
|
10539
|
+
const environmentAccessToken = _optionalChain$c([process, 'access', _2 => _2.env, 'access', _3 => _3.COZE_API_TOKEN, 'optionalAccess', _4 => _4.trim, 'call', _5 => _5()]);
|
|
10540
|
+
if (environmentAccessToken) {
|
|
10541
|
+
fixedAccessTokenCandidates.push({
|
|
10542
|
+
accessToken: environmentAccessToken,
|
|
10543
|
+
source: 'environment',
|
|
10338
10544
|
});
|
|
10339
|
-
|
|
10340
|
-
|
|
10341
|
-
|
|
10545
|
+
}
|
|
10546
|
+
const fixedAccessToken = _optionalChain$c([fixedAccessTokenCandidates, 'access', _6 => _6[0], 'optionalAccess', _7 => _7.accessToken]);
|
|
10547
|
+
const config = {
|
|
10548
|
+
...DEFAULT_CONFIG,
|
|
10549
|
+
...globalConfig,
|
|
10550
|
+
...(fixedAccessToken
|
|
10551
|
+
? {
|
|
10552
|
+
accessToken: fixedAccessToken,
|
|
10553
|
+
// Desktop PAT and COZE_API_TOKEN are fixed runtime credentials. Never
|
|
10554
|
+
// combine them with refresh metadata from an earlier OAuth login.
|
|
10555
|
+
refreshToken: undefined,
|
|
10556
|
+
tokenExpiresAt: undefined,
|
|
10557
|
+
}
|
|
10558
|
+
: {}),
|
|
10559
|
+
fixedAccessTokenCandidates,
|
|
10560
|
+
oauthAccessToken:
|
|
10561
|
+
typeof _optionalChain$c([globalConfig, 'optionalAccess', _8 => _8.accessToken]) === 'string' ? globalConfig.accessToken : undefined,
|
|
10562
|
+
oauthRefreshToken:
|
|
10563
|
+
typeof _optionalChain$c([globalConfig, 'optionalAccess', _9 => _9.refreshToken]) === 'string' ? globalConfig.refreshToken : undefined,
|
|
10564
|
+
oauthTokenExpiresAt:
|
|
10565
|
+
typeof _optionalChain$c([globalConfig, 'optionalAccess', _10 => _10.tokenExpiresAt]) === 'number' ? globalConfig.tokenExpiresAt : undefined,
|
|
10566
|
+
fixedAccessTokenResolved: fixedAccessTokenCandidates.length === 0,
|
|
10567
|
+
...(process.env.COZE_ORG_ID ? { organizationId: process.env.COZE_ORG_ID } : {}),
|
|
10568
|
+
...(process.env.COZE_ACCOUNT_ID ? { cozeAccountId: process.env.COZE_ACCOUNT_ID } : {}),
|
|
10569
|
+
...(process.env.COZE_SPACE_ID ? { spaceId: process.env.COZE_SPACE_ID } : {}),
|
|
10570
|
+
...(process.env.COZE_PROJECT_ID ? { projectId: process.env.COZE_PROJECT_ID } : {}),
|
|
10571
|
+
...(options.orgId ? { organizationId: options.orgId } : {}),
|
|
10572
|
+
...(options.spaceId ? { spaceId: options.spaceId } : {}),
|
|
10573
|
+
...(options.apiBaseUrl ? { apiBaseUrl: options.apiBaseUrl } : {}),
|
|
10574
|
+
// Runtime-only trust decision: a value persisted in config.json must never enable
|
|
10575
|
+
// project-secret injection for an OAuth access token.
|
|
10576
|
+
injectApiToken: Boolean(fixedAccessToken),
|
|
10577
|
+
};
|
|
10578
|
+
return config;
|
|
10579
|
+
};
|
|
10342
10580
|
|
|
10343
|
-
|
|
10344
|
-
|
|
10345
|
-
|
|
10346
|
-
|
|
10347
|
-
|
|
10348
|
-
|
|
10581
|
+
const saveSharedConfig = async (
|
|
10582
|
+
patch,
|
|
10583
|
+
options = {},
|
|
10584
|
+
) => {
|
|
10585
|
+
const target = node_path.resolve(configuredPath(options) || getSharedConfigPath());
|
|
10586
|
+
const existing = (await readJson(target)) || {};
|
|
10587
|
+
const temp = node_path.join(node_path.dirname(target), `.config-${node_crypto.randomUUID()}.tmp`);
|
|
10588
|
+
await promises.mkdir(node_path.dirname(target), { recursive: true });
|
|
10589
|
+
try {
|
|
10590
|
+
await promises.writeFile(temp, `${JSON.stringify({ ...existing, ...patch }, null, 2)}\n`, {
|
|
10591
|
+
encoding: 'utf8',
|
|
10592
|
+
mode: 0o600,
|
|
10349
10593
|
});
|
|
10350
|
-
await
|
|
10351
|
-
|
|
10594
|
+
await promises.rename(temp, target);
|
|
10595
|
+
} finally {
|
|
10596
|
+
await promises.rm(temp, { force: true });
|
|
10597
|
+
}
|
|
10598
|
+
};
|
|
10599
|
+
|
|
10600
|
+
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; }
|
|
10601
|
+
|
|
10602
|
+
const FIVE_MINUTES = 5 * 60 * 1000;
|
|
10603
|
+
const HTTP_UNAUTHORIZED = 401;
|
|
10604
|
+
|
|
10605
|
+
|
|
10606
|
+
|
|
10607
|
+
|
|
10608
|
+
|
|
10609
|
+
|
|
10610
|
+
|
|
10611
|
+
const resolveExpiry = (expiresIn) =>
|
|
10612
|
+
expiresIn > 946684800 ? expiresIn * 1000 : Date.now() + expiresIn * 1000;
|
|
10613
|
+
|
|
10614
|
+
const parseJson = async (response) => {
|
|
10615
|
+
const text = await response.text();
|
|
10616
|
+
if (!text) {
|
|
10617
|
+
return {};
|
|
10618
|
+
}
|
|
10619
|
+
const parsed = safeJsonParse(text, {});
|
|
10620
|
+
return typeof parsed === 'object' && parsed !== null
|
|
10621
|
+
? (parsed )
|
|
10622
|
+
: {};
|
|
10623
|
+
};
|
|
10624
|
+
|
|
10625
|
+
const isRecord$2 = (value) =>
|
|
10626
|
+
typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
10627
|
+
|
|
10628
|
+
const validateFixedAccessToken = async (
|
|
10629
|
+
accessToken,
|
|
10630
|
+
config,
|
|
10631
|
+
) => {
|
|
10632
|
+
const response = await fetch(new URL('/v1/users/me', config.openApiBaseUrl), {
|
|
10633
|
+
headers: { authorization: `Bearer ${accessToken}` },
|
|
10352
10634
|
});
|
|
10635
|
+
const payload = await parseJson(response);
|
|
10636
|
+
if (response.ok) {
|
|
10637
|
+
return true;
|
|
10638
|
+
}
|
|
10639
|
+
if (response.status === HTTP_UNAUTHORIZED) {
|
|
10640
|
+
return false;
|
|
10641
|
+
}
|
|
10642
|
+
throw new CliError(
|
|
10643
|
+
typeof payload.msg === 'string'
|
|
10644
|
+
? payload.msg
|
|
10645
|
+
: 'Unable to validate the current login.',
|
|
10646
|
+
'AUTH_STATUS_FAILED',
|
|
10647
|
+
{ status: response.status },
|
|
10648
|
+
);
|
|
10649
|
+
};
|
|
10353
10650
|
|
|
10354
|
-
|
|
10651
|
+
const resolveFixedAccessToken = async (config) => {
|
|
10652
|
+
if (
|
|
10653
|
+
config.fixedAccessTokenResolved ||
|
|
10654
|
+
!_optionalChain$b([config, 'access', _ => _.fixedAccessTokenCandidates, 'optionalAccess', _2 => _2.length])
|
|
10655
|
+
) {
|
|
10656
|
+
config.fixedAccessTokenResolved = true;
|
|
10657
|
+
return;
|
|
10658
|
+
}
|
|
10659
|
+
for (const candidate of config.fixedAccessTokenCandidates || []) {
|
|
10660
|
+
if (await validateFixedAccessToken(candidate.accessToken, config)) {
|
|
10661
|
+
config.accessToken = candidate.accessToken;
|
|
10662
|
+
config.refreshToken = undefined;
|
|
10663
|
+
config.tokenExpiresAt = undefined;
|
|
10664
|
+
config.injectApiToken = true;
|
|
10665
|
+
config.fixedAccessTokenResolved = true;
|
|
10666
|
+
return;
|
|
10667
|
+
}
|
|
10668
|
+
}
|
|
10669
|
+
config.accessToken = config.oauthAccessToken;
|
|
10670
|
+
config.refreshToken = config.oauthRefreshToken;
|
|
10671
|
+
config.tokenExpiresAt = config.oauthTokenExpiresAt;
|
|
10672
|
+
config.injectApiToken = false;
|
|
10673
|
+
config.fixedAccessTokenResolved = true;
|
|
10674
|
+
};
|
|
10355
10675
|
|
|
10356
|
-
|
|
10357
|
-
|
|
10358
|
-
|
|
10359
|
-
|
|
10360
|
-
|
|
10361
|
-
|
|
10676
|
+
const getCurrentUser = async (
|
|
10677
|
+
config,
|
|
10678
|
+
options,
|
|
10679
|
+
) => {
|
|
10680
|
+
const token = await getAccessToken(config, options);
|
|
10681
|
+
const response = await fetch(new URL('/v1/users/me', config.openApiBaseUrl), {
|
|
10682
|
+
headers: { authorization: `Bearer ${token}` },
|
|
10683
|
+
});
|
|
10684
|
+
const payload = await parseJson(response);
|
|
10685
|
+
if (!response.ok) {
|
|
10686
|
+
throw new CliError(
|
|
10687
|
+
typeof payload.msg === 'string'
|
|
10688
|
+
? payload.msg
|
|
10689
|
+
: 'Unable to validate the current login. Run `coze-dev deploy auth login` again.',
|
|
10690
|
+
response.status === HTTP_UNAUTHORIZED ? 'AUTH_REQUIRED' : 'AUTH_STATUS_FAILED',
|
|
10691
|
+
{ status: response.status },
|
|
10692
|
+
);
|
|
10693
|
+
}
|
|
10694
|
+
return isRecord$2(payload.data) ? payload.data : payload;
|
|
10695
|
+
};
|
|
10362
10696
|
|
|
10363
|
-
|
|
10697
|
+
const clearAuthPatch = {
|
|
10698
|
+
accessToken: undefined,
|
|
10699
|
+
refreshToken: undefined,
|
|
10700
|
+
tokenExpiresAt: undefined,
|
|
10701
|
+
organizationId: undefined,
|
|
10702
|
+
enterpriseId: undefined,
|
|
10703
|
+
spaceId: undefined,
|
|
10704
|
+
projectId: undefined,
|
|
10705
|
+
};
|
|
10364
10706
|
|
|
10365
|
-
|
|
10366
|
-
|
|
10707
|
+
const getAccessToken = async (
|
|
10708
|
+
config,
|
|
10709
|
+
options,
|
|
10710
|
+
) => {
|
|
10711
|
+
await resolveFixedAccessToken(config);
|
|
10712
|
+
if (!config.accessToken) {
|
|
10713
|
+
throw new CliError(
|
|
10714
|
+
'No shared login found. Run `coze-dev deploy auth login` first.',
|
|
10715
|
+
'AUTH_REQUIRED',
|
|
10716
|
+
);
|
|
10717
|
+
}
|
|
10718
|
+
if (!config.refreshToken || !config.tokenExpiresAt) {
|
|
10719
|
+
return config.accessToken;
|
|
10720
|
+
}
|
|
10721
|
+
if (Date.now() < config.tokenExpiresAt - FIVE_MINUTES) {
|
|
10722
|
+
return config.accessToken;
|
|
10723
|
+
}
|
|
10367
10724
|
|
|
10368
|
-
|
|
10369
|
-
|
|
10725
|
+
const response = await fetch(
|
|
10726
|
+
new URL('/api/permission/oauth2/token', config.openApiBaseUrl),
|
|
10727
|
+
{
|
|
10728
|
+
method: 'POST',
|
|
10729
|
+
headers: { 'content-type': 'application/json' },
|
|
10730
|
+
body: JSON.stringify({
|
|
10731
|
+
grant_type: 'refresh_token',
|
|
10732
|
+
client_id: config.clientId,
|
|
10733
|
+
refresh_token: config.refreshToken,
|
|
10734
|
+
}),
|
|
10735
|
+
},
|
|
10736
|
+
);
|
|
10737
|
+
const payload = await parseJson(response);
|
|
10738
|
+
if (!response.ok || typeof payload.access_token !== 'string') {
|
|
10739
|
+
throw new CliError(
|
|
10740
|
+
typeof payload.error_description === 'string'
|
|
10741
|
+
? payload.error_description
|
|
10742
|
+
: 'Shared login has expired. Run `coze-dev deploy auth login` again.',
|
|
10743
|
+
'AUTH_REFRESH_FAILED',
|
|
10744
|
+
);
|
|
10745
|
+
}
|
|
10746
|
+
const token = payload ;
|
|
10747
|
+
const patch = {
|
|
10748
|
+
accessToken: token.access_token,
|
|
10749
|
+
refreshToken: token.refresh_token || config.refreshToken,
|
|
10750
|
+
tokenExpiresAt: resolveExpiry(token.expires_in),
|
|
10751
|
+
};
|
|
10752
|
+
Object.assign(config, patch);
|
|
10753
|
+
await saveSharedConfig(patch, options);
|
|
10754
|
+
return token.access_token;
|
|
10755
|
+
};
|
|
10756
|
+
|
|
10757
|
+
const saveOAuthToken = async (
|
|
10758
|
+
config,
|
|
10759
|
+
options,
|
|
10760
|
+
token,
|
|
10761
|
+
) => {
|
|
10762
|
+
const patch = {
|
|
10763
|
+
accessToken: token.access_token,
|
|
10764
|
+
refreshToken: token.refresh_token,
|
|
10765
|
+
tokenExpiresAt: resolveExpiry(token.expires_in),
|
|
10766
|
+
organizationId: undefined,
|
|
10767
|
+
enterpriseId: undefined,
|
|
10768
|
+
spaceId: undefined,
|
|
10769
|
+
projectId: undefined,
|
|
10770
|
+
};
|
|
10771
|
+
Object.assign(config, patch);
|
|
10772
|
+
await saveSharedConfig(patch, options);
|
|
10773
|
+
};
|
|
10774
|
+
|
|
10775
|
+
const logout = async (
|
|
10776
|
+
config,
|
|
10777
|
+
options,
|
|
10778
|
+
) => {
|
|
10779
|
+
Object.assign(config, clearAuthPatch);
|
|
10780
|
+
await saveSharedConfig(clearAuthPatch, options);
|
|
10781
|
+
};
|
|
10782
|
+
|
|
10783
|
+
const getAuthStatus = async (
|
|
10784
|
+
config,
|
|
10785
|
+
options,
|
|
10786
|
+
) => {
|
|
10787
|
+
if (!config.accessToken) {
|
|
10788
|
+
return { logged_in: false };
|
|
10789
|
+
}
|
|
10790
|
+
const user = await getCurrentUser(config, options);
|
|
10791
|
+
return {
|
|
10792
|
+
logged_in: true,
|
|
10793
|
+
user,
|
|
10794
|
+
token_expires_at: config.tokenExpiresAt
|
|
10795
|
+
? new Date(config.tokenExpiresAt).toISOString()
|
|
10796
|
+
: 'Never (PAT)',
|
|
10797
|
+
};
|
|
10798
|
+
};
|
|
10799
|
+
|
|
10800
|
+
const DEFAULT_POLL_INTERVAL_MS = 5000;
|
|
10801
|
+
const SLOW_DOWN_INCREMENT_MS = 5000;
|
|
10802
|
+
|
|
10803
|
+
const isRecord$1 = (value) =>
|
|
10804
|
+
typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
10805
|
+
|
|
10806
|
+
const readPayload = async (response) => {
|
|
10807
|
+
const text = await response.text();
|
|
10808
|
+
const payload = safeJsonParse(text, {});
|
|
10809
|
+
return isRecord$1(payload) ? payload : {};
|
|
10810
|
+
};
|
|
10811
|
+
|
|
10812
|
+
const post = async (
|
|
10813
|
+
baseUrl,
|
|
10814
|
+
path,
|
|
10815
|
+
body,
|
|
10816
|
+
) => {
|
|
10817
|
+
const response = await fetch(new URL(path, baseUrl), {
|
|
10818
|
+
method: 'POST',
|
|
10819
|
+
headers: { 'content-type': 'application/json' },
|
|
10820
|
+
body: JSON.stringify(body),
|
|
10821
|
+
});
|
|
10822
|
+
return { payload: await readPayload(response), response };
|
|
10823
|
+
};
|
|
10824
|
+
|
|
10825
|
+
const requireString = (
|
|
10826
|
+
payload,
|
|
10827
|
+
key,
|
|
10828
|
+
) => {
|
|
10829
|
+
const value = payload[key];
|
|
10830
|
+
if (typeof value !== 'string' || !value) {
|
|
10831
|
+
throw new CliError(`OAuth response returned no ${key}.`, 'INVALID_AUTH_RESPONSE');
|
|
10832
|
+
}
|
|
10833
|
+
return value;
|
|
10834
|
+
};
|
|
10835
|
+
|
|
10836
|
+
const requireNumber = (
|
|
10837
|
+
payload,
|
|
10838
|
+
key,
|
|
10839
|
+
) => {
|
|
10840
|
+
const value = Number(payload[key]);
|
|
10841
|
+
if (!Number.isFinite(value) || value <= 0) {
|
|
10842
|
+
throw new CliError(`OAuth response returned no ${key}.`, 'INVALID_AUTH_RESPONSE');
|
|
10843
|
+
}
|
|
10844
|
+
return value;
|
|
10845
|
+
};
|
|
10846
|
+
|
|
10847
|
+
const requestDeviceCode = async (config) => {
|
|
10848
|
+
const { payload, response } = await post(
|
|
10849
|
+
config.openApiBaseUrl,
|
|
10850
|
+
'/api/permission/oauth2/device/code',
|
|
10851
|
+
{ client_id: config.clientId },
|
|
10852
|
+
);
|
|
10853
|
+
if (!response.ok) {
|
|
10854
|
+
throw new CliError(
|
|
10855
|
+
typeof payload.error_description === 'string'
|
|
10856
|
+
? payload.error_description
|
|
10857
|
+
: 'Unable to start OAuth login.',
|
|
10858
|
+
'AUTH_LOGIN_FAILED',
|
|
10859
|
+
{ status: response.status },
|
|
10860
|
+
);
|
|
10861
|
+
}
|
|
10862
|
+
return {
|
|
10863
|
+
device_code: requireString(payload, 'device_code'),
|
|
10864
|
+
user_code: requireString(payload, 'user_code'),
|
|
10865
|
+
verification_uri: requireString(payload, 'verification_uri'),
|
|
10866
|
+
expires_in: requireNumber(payload, 'expires_in'),
|
|
10867
|
+
interval:
|
|
10868
|
+
typeof payload.interval === 'number' && payload.interval > 0
|
|
10869
|
+
? payload.interval
|
|
10870
|
+
: undefined,
|
|
10871
|
+
};
|
|
10872
|
+
};
|
|
10873
|
+
|
|
10874
|
+
const buildVerificationUrl = (deviceCode) => {
|
|
10875
|
+
const url = new URL(deviceCode.verification_uri);
|
|
10876
|
+
url.searchParams.set('user_code', deviceCode.user_code);
|
|
10877
|
+
return url.toString();
|
|
10878
|
+
};
|
|
10879
|
+
|
|
10880
|
+
const openBrowser = (url) => {
|
|
10881
|
+
const command =
|
|
10882
|
+
process.platform === 'darwin'
|
|
10883
|
+
? 'open'
|
|
10884
|
+
: process.platform === 'win32'
|
|
10885
|
+
? 'cmd'
|
|
10886
|
+
: 'xdg-open';
|
|
10887
|
+
const args = process.platform === 'win32' ? ['/c', 'start', '""', url] : [url];
|
|
10888
|
+
try {
|
|
10889
|
+
const child = node_child_process.spawn(command, args, { detached: true, stdio: 'ignore' });
|
|
10890
|
+
child.on('error', () => undefined);
|
|
10891
|
+
child.unref();
|
|
10892
|
+
} catch (error) {
|
|
10893
|
+
}
|
|
10894
|
+
};
|
|
10895
|
+
|
|
10896
|
+
const sleep = async (milliseconds) =>
|
|
10897
|
+
new Promise(resolve => setTimeout(resolve, milliseconds));
|
|
10898
|
+
|
|
10899
|
+
const pollToken = async (
|
|
10900
|
+
config,
|
|
10901
|
+
deviceCode,
|
|
10902
|
+
) => {
|
|
10903
|
+
const expiresAt = Date.now() + deviceCode.expires_in * 1000;
|
|
10904
|
+
let interval = (deviceCode.interval || DEFAULT_POLL_INTERVAL_MS / 1000) * 1000;
|
|
10905
|
+
while (Date.now() < expiresAt) {
|
|
10906
|
+
const { payload, response } = await post(
|
|
10907
|
+
config.openApiBaseUrl,
|
|
10908
|
+
'/api/permission/oauth2/token',
|
|
10909
|
+
{
|
|
10910
|
+
grant_type: 'urn:ietf:params:oauth:grant-type:device_code',
|
|
10911
|
+
client_id: config.clientId,
|
|
10912
|
+
device_code: deviceCode.device_code,
|
|
10913
|
+
},
|
|
10914
|
+
);
|
|
10915
|
+
if (response.ok) {
|
|
10916
|
+
return {
|
|
10917
|
+
access_token: requireString(payload, 'access_token'),
|
|
10918
|
+
refresh_token: requireString(payload, 'refresh_token'),
|
|
10919
|
+
expires_in: requireNumber(payload, 'expires_in'),
|
|
10920
|
+
};
|
|
10921
|
+
}
|
|
10922
|
+
if (payload.error === 'authorization_pending') {
|
|
10923
|
+
await sleep(interval);
|
|
10924
|
+
continue;
|
|
10925
|
+
}
|
|
10926
|
+
if (payload.error === 'slow_down') {
|
|
10927
|
+
interval += SLOW_DOWN_INCREMENT_MS;
|
|
10928
|
+
await sleep(interval);
|
|
10929
|
+
continue;
|
|
10930
|
+
}
|
|
10931
|
+
throw new CliError(
|
|
10932
|
+
typeof payload.error_description === 'string'
|
|
10933
|
+
? payload.error_description
|
|
10934
|
+
: 'OAuth authorization failed.',
|
|
10935
|
+
'AUTH_LOGIN_FAILED',
|
|
10936
|
+
{ oauth_error: payload.error, status: response.status },
|
|
10937
|
+
);
|
|
10938
|
+
}
|
|
10939
|
+
throw new CliError('OAuth authorization expired. Please try again.', 'AUTH_LOGIN_EXPIRED');
|
|
10940
|
+
};
|
|
10941
|
+
|
|
10942
|
+
const loginWithOAuth = async (
|
|
10943
|
+
config,
|
|
10944
|
+
options,
|
|
10945
|
+
callbacks,
|
|
10946
|
+
) => {
|
|
10947
|
+
const deviceCode = await requestDeviceCode(config);
|
|
10948
|
+
const verificationUrl = buildVerificationUrl(deviceCode);
|
|
10949
|
+
callbacks.onVerification(verificationUrl);
|
|
10950
|
+
openBrowser(verificationUrl);
|
|
10951
|
+
await saveOAuthToken(config, options, await pollToken(config, deviceCode));
|
|
10952
|
+
};
|
|
10953
|
+
|
|
10954
|
+
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; }
|
|
10955
|
+
|
|
10956
|
+
|
|
10957
|
+
|
|
10958
|
+
|
|
10959
|
+
|
|
10960
|
+
|
|
10961
|
+
|
|
10962
|
+
|
|
10963
|
+
|
|
10964
|
+
|
|
10965
|
+
|
|
10966
|
+
|
|
10967
|
+
|
|
10968
|
+
|
|
10969
|
+
|
|
10970
|
+
|
|
10971
|
+
|
|
10972
|
+
|
|
10973
|
+
const API_PREFIX = '/api/coding/deployment/v2';
|
|
10974
|
+
const CREATE_PROJECT_PATH = '/api/ideserver_api/project/create_vibe_project';
|
|
10975
|
+
const LIST_SPACES_PATH = '/api/playground_api/space/list';
|
|
10976
|
+
const ENCRYPT_PROJECT_SECRET_PATH =
|
|
10977
|
+
'/api/permission_api/project_secret/encrypt_project_secret';
|
|
10978
|
+
const MAX_MESSAGE_LENGTH = 512;
|
|
10979
|
+
|
|
10980
|
+
const isRecord = (value) =>
|
|
10981
|
+
typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
10982
|
+
|
|
10983
|
+
|
|
10984
|
+
|
|
10985
|
+
|
|
10986
|
+
|
|
10987
|
+
|
|
10988
|
+
|
|
10989
|
+
const parseResponse = async (response) => {
|
|
10990
|
+
const text = await response.text();
|
|
10991
|
+
if (!text) {
|
|
10992
|
+
return { payload: {}, text, validJson: true };
|
|
10993
|
+
}
|
|
10994
|
+
const invalid = Symbol('invalid-json');
|
|
10995
|
+
const parsed = safeJsonParse(text, invalid);
|
|
10996
|
+
return parsed === invalid
|
|
10997
|
+
? { payload: undefined, text, validJson: false }
|
|
10998
|
+
: { payload: parsed, text, validJson: true };
|
|
10999
|
+
};
|
|
11000
|
+
|
|
11001
|
+
|
|
11002
|
+
|
|
11003
|
+
|
|
11004
|
+
|
|
11005
|
+
|
|
11006
|
+
|
|
11007
|
+
|
|
11008
|
+
|
|
11009
|
+
const responseExcerpt = (text) => {
|
|
11010
|
+
const compact = text.replace(/\s+/gu, ' ').trim();
|
|
11011
|
+
return compact ? compact.slice(0, MAX_MESSAGE_LENGTH) : undefined;
|
|
11012
|
+
};
|
|
11013
|
+
|
|
11014
|
+
const unwrap = (
|
|
11015
|
+
payload,
|
|
11016
|
+
expectedKey,
|
|
11017
|
+
responseMetadata,
|
|
11018
|
+
) => {
|
|
11019
|
+
const root = isRecord(payload) ? payload : undefined;
|
|
11020
|
+
const first = isRecord(_optionalChain$a([root, 'optionalAccess', _ => _.data])) ? root.data : undefined;
|
|
11021
|
+
const second = isRecord(_optionalChain$a([first, 'optionalAccess', _2 => _2.data])) ? first.data : undefined;
|
|
11022
|
+
const envelope = [root, first].find(candidate => candidate && 'code' in candidate);
|
|
11023
|
+
if (_optionalChain$a([envelope, 'optionalAccess', _3 => _3.code]) !== undefined && Number(envelope.code) !== 0) {
|
|
11024
|
+
throw new CliError(
|
|
11025
|
+
typeof envelope.msg === 'string'
|
|
11026
|
+
? envelope.msg.slice(0, MAX_MESSAGE_LENGTH)
|
|
11027
|
+
: 'The deployment request was rejected.',
|
|
11028
|
+
'API_REJECTED',
|
|
11029
|
+
{ business_code: envelope.code, ...responseMetadata },
|
|
11030
|
+
);
|
|
11031
|
+
}
|
|
11032
|
+
if (!expectedKey) {
|
|
11033
|
+
return (second || first || root || {}) ;
|
|
11034
|
+
}
|
|
11035
|
+
const matched = [second, first, root].find(
|
|
11036
|
+
candidate => candidate && expectedKey in candidate,
|
|
11037
|
+
);
|
|
11038
|
+
if (!matched) {
|
|
11039
|
+
throw new CliError(
|
|
11040
|
+
`Deployment API returned no ${expectedKey}.`,
|
|
11041
|
+
'INVALID_RESPONSE',
|
|
11042
|
+
);
|
|
11043
|
+
}
|
|
11044
|
+
return matched ;
|
|
11045
|
+
};
|
|
11046
|
+
|
|
11047
|
+
class DeployApiClient {
|
|
11048
|
+
constructor(
|
|
11049
|
+
config,
|
|
11050
|
+
globalOptions,
|
|
11051
|
+
) {this.config = config;this.globalOptions = globalOptions;}
|
|
11052
|
+
|
|
11053
|
+
debug(message) {
|
|
11054
|
+
if (this.globalOptions.debug) {
|
|
11055
|
+
process.stderr.write(`[debug] [api] ${message}\n`);
|
|
11056
|
+
}
|
|
11057
|
+
}
|
|
11058
|
+
|
|
11059
|
+
async post(
|
|
11060
|
+
path,
|
|
11061
|
+
body,
|
|
11062
|
+
expectedKey,
|
|
11063
|
+
useApiPrefix = true,
|
|
11064
|
+
) {
|
|
11065
|
+
const token = await getAccessToken(this.config, this.globalOptions);
|
|
11066
|
+
const headers = {
|
|
11067
|
+
authorization: `Bearer ${token}`,
|
|
11068
|
+
'content-type': 'application/json',
|
|
11069
|
+
'agw-js-conv': 'str',
|
|
11070
|
+
'x-request-from-coze-cli': '1',
|
|
11071
|
+
};
|
|
11072
|
+
// Only a fixed runtime credential (desktop PAT or COZE_API_TOKEN) may become
|
|
11073
|
+
// a project runtime secret. OAuth credentials remain authentication-only.
|
|
11074
|
+
if (
|
|
11075
|
+
this.config.injectApiToken &&
|
|
11076
|
+
path === '/deploy_history/create' &&
|
|
11077
|
+
useApiPrefix
|
|
11078
|
+
) {
|
|
11079
|
+
headers['x-coze-deploy-inject-api-token'] = 'true';
|
|
11080
|
+
}
|
|
11081
|
+
// Coze account id: an explicit COZE_ACCOUNT_ID (config.cozeAccountId) always wins;
|
|
11082
|
+
// otherwise fall back to the organization id resolved from login/config.
|
|
11083
|
+
const cozeAccount = this.config.cozeAccountId || this.config.organizationId;
|
|
11084
|
+
if (cozeAccount) {
|
|
11085
|
+
headers['x-coze-account'] = cozeAccount;
|
|
11086
|
+
}
|
|
11087
|
+
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()]);
|
|
11088
|
+
if (lane) {
|
|
11089
|
+
headers['x-use-ppe'] = '1';
|
|
11090
|
+
headers['x-tt-env'] = lane;
|
|
11091
|
+
}
|
|
11092
|
+
const requestUrl = new URL(
|
|
11093
|
+
`${useApiPrefix ? API_PREFIX : ''}${path}`,
|
|
11094
|
+
this.config.apiBaseUrl,
|
|
11095
|
+
);
|
|
11096
|
+
this.debug(
|
|
11097
|
+
`POST ${requestUrl.toString()}${lane ? ` lane=${lane}` : ''}`,
|
|
11098
|
+
);
|
|
11099
|
+
const response = await fetch(
|
|
11100
|
+
requestUrl,
|
|
11101
|
+
{ method: 'POST', headers, body: JSON.stringify(body) },
|
|
11102
|
+
);
|
|
11103
|
+
const responseMetadata = {
|
|
11104
|
+
status: response.status,
|
|
11105
|
+
status_text: response.statusText,
|
|
11106
|
+
log_id: response.headers.get('x-tt-logid') || undefined,
|
|
11107
|
+
request_path: requestUrl.pathname,
|
|
11108
|
+
content_type: response.headers.get('content-type') || undefined,
|
|
11109
|
+
};
|
|
11110
|
+
this.debug(
|
|
11111
|
+
`${response.status} ${response.statusText} ${requestUrl.pathname}` +
|
|
11112
|
+
`${responseMetadata.log_id ? ` log_id=${responseMetadata.log_id}` : ' log_id=unavailable'}`,
|
|
11113
|
+
);
|
|
11114
|
+
const { payload, text, validJson } = await parseResponse(response);
|
|
11115
|
+
if (!response.ok) {
|
|
11116
|
+
const root = isRecord(payload) ? payload : undefined;
|
|
11117
|
+
throw new CliError(
|
|
11118
|
+
typeof _optionalChain$a([root, 'optionalAccess', _12 => _12.msg]) === 'string'
|
|
11119
|
+
? root.msg.slice(0, MAX_MESSAGE_LENGTH)
|
|
11120
|
+
: `Deployment API failed: ${response.status} ${response.statusText}` +
|
|
11121
|
+
`${validJson ? '' : '; response was not JSON'}`,
|
|
11122
|
+
response.status === 401 ? 'AUTH_REQUIRED' : 'HTTP_ERROR',
|
|
11123
|
+
{
|
|
11124
|
+
...responseMetadata,
|
|
11125
|
+
response_excerpt: responseExcerpt(text),
|
|
11126
|
+
},
|
|
11127
|
+
);
|
|
11128
|
+
}
|
|
11129
|
+
if (!validJson) {
|
|
11130
|
+
throw new CliError(
|
|
11131
|
+
`Deployment API returned invalid JSON (${response.status}).`,
|
|
11132
|
+
'INVALID_RESPONSE',
|
|
11133
|
+
{
|
|
11134
|
+
...responseMetadata,
|
|
11135
|
+
response_excerpt: responseExcerpt(text),
|
|
11136
|
+
},
|
|
11137
|
+
);
|
|
11138
|
+
}
|
|
11139
|
+
return unwrap(payload, expectedKey, responseMetadata);
|
|
11140
|
+
}
|
|
11141
|
+
|
|
11142
|
+
createDeploymentProject(body) {
|
|
11143
|
+
return this.post(
|
|
11144
|
+
CREATE_PROJECT_PATH,
|
|
11145
|
+
body,
|
|
11146
|
+
'project_id',
|
|
11147
|
+
false,
|
|
11148
|
+
);
|
|
11149
|
+
}
|
|
11150
|
+
|
|
11151
|
+
// 回读当前登录态对应的 Coze 账号 id。无入参:账号由服务端从登录态解析(X-Coze-Account →
|
|
11152
|
+
// access token → 兜底登录用户),客户端传什么都只有「等于登录态」一种合法取值。
|
|
11153
|
+
// 只在建 Project 前用一次,用来定这个 Project 下应用的账号归属。
|
|
11154
|
+
getCozeAccount() {
|
|
11155
|
+
return this.post(
|
|
11156
|
+
'/account/get',
|
|
11157
|
+
{},
|
|
11158
|
+
'coze_account_id',
|
|
11159
|
+
);
|
|
11160
|
+
}
|
|
11161
|
+
|
|
11162
|
+
listSpaces(body
|
|
11163
|
+
|
|
11164
|
+
|
|
11165
|
+
|
|
11166
|
+
|
|
11167
|
+
) {
|
|
11168
|
+
return this.post(
|
|
11169
|
+
LIST_SPACES_PATH,
|
|
11170
|
+
body,
|
|
11171
|
+
'bot_space_list',
|
|
11172
|
+
false,
|
|
11173
|
+
);
|
|
11174
|
+
}
|
|
11175
|
+
|
|
11176
|
+
encryptProjectSecret(projectId, secrets) {
|
|
11177
|
+
return this.post(
|
|
11178
|
+
ENCRYPT_PROJECT_SECRET_PATH,
|
|
11179
|
+
{
|
|
11180
|
+
project_id: projectId,
|
|
11181
|
+
encrypt_secrets: {
|
|
11182
|
+
secrets,
|
|
11183
|
+
cred_providers: [],
|
|
11184
|
+
},
|
|
11185
|
+
},
|
|
11186
|
+
'sealed_secrets',
|
|
11187
|
+
false,
|
|
11188
|
+
);
|
|
11189
|
+
}
|
|
11190
|
+
|
|
11191
|
+
// 列当前登录用户名下的 Application,跨 Project。服务端从登录态取 user_id,
|
|
11192
|
+
// 请求体里只有分页参数(deploy_app/list 已去掉 project_id / user_id 两个寻址入参)。
|
|
11193
|
+
listApplications(body) {
|
|
11194
|
+
return this.post(
|
|
11195
|
+
'/deploy_app/list', body, 'items',
|
|
11196
|
+
);
|
|
11197
|
+
}
|
|
11198
|
+
|
|
11199
|
+
getApplication(appId) {
|
|
11200
|
+
return this.post('/deploy_app/get', { app_id: appId }, 'app_id');
|
|
11201
|
+
}
|
|
11202
|
+
|
|
11203
|
+
updateApplication(body) {
|
|
11204
|
+
return this.post('/deploy_app/update', body, 'app_id');
|
|
11205
|
+
}
|
|
11206
|
+
|
|
11207
|
+
// 删除 Application:服务端只接受 **Stopped** 状态,其余状态会带上当前状态报错(先 stop 再 delete)。
|
|
11208
|
+
// 已删除的再删一次是幂等成功。
|
|
11209
|
+
deleteApplication(appId) {
|
|
11210
|
+
return this.post('/deploy_app/delete', { app_id: appId });
|
|
11211
|
+
}
|
|
11212
|
+
|
|
11213
|
+
getDeployConfig(body
|
|
11214
|
+
|
|
11215
|
+
|
|
11216
|
+
|
|
11217
|
+
|
|
11218
|
+
|
|
11219
|
+
) {
|
|
11220
|
+
return this.post('/deploy_config/get', body, 'deploy_config');
|
|
11221
|
+
}
|
|
11222
|
+
|
|
11223
|
+
createDeployHistory(body) {
|
|
11224
|
+
return this.post('/deploy_history/create', body, 'app_id');
|
|
11225
|
+
}
|
|
11226
|
+
|
|
11227
|
+
preDeployUpload(body
|
|
11228
|
+
|
|
11229
|
+
|
|
11230
|
+
) {
|
|
11231
|
+
return this.post('/deploy_history/pre_upload', body, 'upload_url');
|
|
11232
|
+
}
|
|
11233
|
+
|
|
11234
|
+
getDeployHistory(body) {
|
|
11235
|
+
return this.post('/deploy_history/get', body, 'deploy_history_id');
|
|
11236
|
+
}
|
|
11237
|
+
|
|
11238
|
+
listDeployHistory(body) {
|
|
11239
|
+
return this.post
|
|
11240
|
+
|
|
11241
|
+
|
|
11242
|
+
|
|
11243
|
+
('/deploy_history/list', body, 'deploy_history_list');
|
|
11244
|
+
}
|
|
11245
|
+
|
|
11246
|
+
getOnlineDeployHistory(appId) {
|
|
11247
|
+
return this.post(
|
|
11248
|
+
'/deploy_history/get_online', { app_id: appId }, 'deploy_history_list',
|
|
11249
|
+
);
|
|
11250
|
+
}
|
|
11251
|
+
|
|
11252
|
+
getOnlineEnvironment(appId) {
|
|
11253
|
+
return this.post(
|
|
11254
|
+
'/environment/get_online', { app_id: appId }, 'app_id',
|
|
11255
|
+
);
|
|
11256
|
+
}
|
|
11257
|
+
|
|
11258
|
+
checkRollbackDatabase(body) {
|
|
11259
|
+
return this.post(
|
|
11260
|
+
'/deploy_history/check_rollback_database', body, 'is_rollback_possible',
|
|
11261
|
+
);
|
|
11262
|
+
}
|
|
11263
|
+
|
|
11264
|
+
cancelDeployHistory(body) {
|
|
11265
|
+
return this.post('/deploy_history/cancel', body);
|
|
11266
|
+
}
|
|
11267
|
+
|
|
11268
|
+
rollbackDeployHistory(body
|
|
11269
|
+
|
|
11270
|
+
|
|
11271
|
+
|
|
11272
|
+
) {
|
|
11273
|
+
return this.post(
|
|
11274
|
+
'/deploy_history/rollback', body, 'new_deploy_history_id',
|
|
11275
|
+
);
|
|
11276
|
+
}
|
|
11277
|
+
|
|
11278
|
+
stopApplication(appId) {
|
|
11279
|
+
return this.post('/application/stop', { app_id: appId });
|
|
11280
|
+
}
|
|
11281
|
+
|
|
11282
|
+
resumeApplication(appId) {
|
|
11283
|
+
return this.post('/application/resume', { app_id: appId });
|
|
11284
|
+
}
|
|
11285
|
+
|
|
11286
|
+
// 暂停是可逆的:只把线上 Unit 从 Ready 改成 Paused,函数留着,可被 resume 推回 Ready。
|
|
11287
|
+
// stop 会连函数一起删、落到 Stopped,只能靠重新部署恢复 —— resume 配对的是 pause,不是 stop。
|
|
11288
|
+
pauseApplication(appId) {
|
|
11289
|
+
return this.post('/application/pause', { app_id: appId });
|
|
11290
|
+
}
|
|
11291
|
+
|
|
11292
|
+
// PV / UV。入参是 app_id,但服务端反查 project_id 后按 **Project** 聚合 —— 埋点链路只有
|
|
11293
|
+
// project 维度,同一 Project 下多个 Application 拿到的是同一份数据。
|
|
11294
|
+
getUserAnalyticsMetrics(body) {
|
|
11295
|
+
return this.post(
|
|
11296
|
+
'/metrics/user_analytics/get', body, 'charts',
|
|
11297
|
+
);
|
|
11298
|
+
}
|
|
11299
|
+
|
|
11300
|
+
getBuildLog(body) {
|
|
11301
|
+
return this.post('/deploy_history/log', body, 'log');
|
|
11302
|
+
}
|
|
11303
|
+
|
|
11304
|
+
searchRuntimeLog(body) {
|
|
11305
|
+
return this.post(
|
|
11306
|
+
'/runtime_log/search', body, 'logs',
|
|
11307
|
+
);
|
|
11308
|
+
}
|
|
11309
|
+
|
|
11310
|
+
getRuntimeLogCount(appId) {
|
|
11311
|
+
return this.post(
|
|
11312
|
+
'/runtime_log/count', { app_id: appId }, 'limit',
|
|
11313
|
+
);
|
|
11314
|
+
}
|
|
11315
|
+
|
|
11316
|
+
getDeployCount(appId) {
|
|
11317
|
+
return this.post(
|
|
11318
|
+
'/deploy_history/get_count', { app_id: appId }, 'success_count',
|
|
11319
|
+
);
|
|
11320
|
+
}
|
|
11321
|
+
|
|
11322
|
+
getApplicationMetrics(body) {
|
|
11323
|
+
return this.post(
|
|
11324
|
+
'/metrics/get', body, 'charts',
|
|
11325
|
+
);
|
|
11326
|
+
}
|
|
11327
|
+
|
|
11328
|
+
getHostedUsageMonthly(body) {
|
|
11329
|
+
return this.post(
|
|
11330
|
+
'/hosted_usage/monthly', body, 'summary',
|
|
11331
|
+
);
|
|
11332
|
+
}
|
|
11333
|
+
|
|
11334
|
+
authorizeMiniProgram(body
|
|
11335
|
+
|
|
11336
|
+
|
|
11337
|
+
|
|
11338
|
+
|
|
11339
|
+
|
|
11340
|
+
|
|
11341
|
+
) {
|
|
11342
|
+
return this.post
|
|
11343
|
+
|
|
11344
|
+
|
|
11345
|
+
|
|
11346
|
+
('/mini_program/auth', body);
|
|
11347
|
+
}
|
|
11348
|
+
|
|
11349
|
+
createMiniProgramPreview(body
|
|
11350
|
+
|
|
11351
|
+
|
|
11352
|
+
|
|
11353
|
+
|
|
11354
|
+
|
|
11355
|
+
) {
|
|
11356
|
+
return this.post
|
|
11357
|
+
|
|
11358
|
+
|
|
11359
|
+
|
|
11360
|
+
|
|
11361
|
+
('/mini_program/preview', body);
|
|
11362
|
+
}
|
|
11363
|
+
|
|
11364
|
+
listDomains(appId, unitType) {
|
|
11365
|
+
return this.post(
|
|
11366
|
+
'/domain/list', {
|
|
11367
|
+
app_id: appId,
|
|
11368
|
+
...(unitType === undefined ? {} : { unit_type: unitType }),
|
|
11369
|
+
}, 'items',
|
|
11370
|
+
);
|
|
11371
|
+
}
|
|
11372
|
+
|
|
11373
|
+
createDomain(body) {
|
|
11374
|
+
return this.post('/domain/create', body, 'domain');
|
|
11375
|
+
}
|
|
11376
|
+
|
|
11377
|
+
// 改的是系统分配的 <prefix>.coze.site 里的 prefix,不是 createDomain 加进来的自定义域名 ——
|
|
11378
|
+
// 那类域名服务端只提供 create/delete,域名串本身不可改。
|
|
11379
|
+
updateDefaultDomainPrefix(body) {
|
|
11380
|
+
return this.post
|
|
11381
|
+
|
|
11382
|
+
|
|
11383
|
+
|
|
11384
|
+
|
|
11385
|
+
('/domain/update_default_prefix', body, 'new_domain_host_canonical');
|
|
11386
|
+
}
|
|
11387
|
+
|
|
11388
|
+
getMiniProgramAuthStatus(body) {
|
|
11389
|
+
return this.post
|
|
11390
|
+
|
|
11391
|
+
|
|
11392
|
+
|
|
11393
|
+
|
|
11394
|
+
('/api/coding/deployment/auth/status', body, 'is_authorized', false);
|
|
11395
|
+
}
|
|
11396
|
+
|
|
11397
|
+
bindMiniProgramAuth(body
|
|
11398
|
+
|
|
11399
|
+
|
|
11400
|
+
|
|
11401
|
+
|
|
11402
|
+
|
|
11403
|
+
) {
|
|
11404
|
+
return this.post
|
|
11405
|
+
|
|
11406
|
+
|
|
11407
|
+
|
|
11408
|
+
|
|
11409
|
+
|
|
11410
|
+
|
|
11411
|
+
('/api/coding/deployment/auth/bind', body, 'bind_status', false);
|
|
11412
|
+
}
|
|
11413
|
+
|
|
11414
|
+
submitMiniProgramAuthCode(body
|
|
11415
|
+
|
|
11416
|
+
|
|
11417
|
+
|
|
11418
|
+
|
|
11419
|
+
|
|
11420
|
+
) {
|
|
11421
|
+
return this.post(
|
|
11422
|
+
'/api/coding/deployment/auth/submit_code', body, undefined, false,
|
|
11423
|
+
);
|
|
11424
|
+
}
|
|
11425
|
+
|
|
11426
|
+
unbindMiniProgramAuth(body) {
|
|
11427
|
+
return this.post(
|
|
11428
|
+
'/api/coding/deployment/auth/unbind', body, undefined, false,
|
|
11429
|
+
);
|
|
11430
|
+
}
|
|
11431
|
+
}
|
|
11432
|
+
|
|
11433
|
+
const textValue = (value) => {
|
|
11434
|
+
if (typeof value === 'string') {
|
|
11435
|
+
return value;
|
|
11436
|
+
}
|
|
11437
|
+
return JSON.stringify(value, null, 2);
|
|
11438
|
+
};
|
|
11439
|
+
|
|
11440
|
+
class Output {
|
|
11441
|
+
constructor(
|
|
11442
|
+
format,
|
|
11443
|
+
debugEnabled = false,
|
|
11444
|
+
) {this.format = format;this.debugEnabled = debugEnabled;}
|
|
11445
|
+
|
|
11446
|
+
print(value) {
|
|
11447
|
+
process.stdout.write(
|
|
11448
|
+
this.format === 'json'
|
|
11449
|
+
? `${JSON.stringify(value, null, 2)}\n`
|
|
11450
|
+
: `${textValue(value)}\n`,
|
|
11451
|
+
);
|
|
11452
|
+
}
|
|
11453
|
+
|
|
11454
|
+
info(message) {
|
|
11455
|
+
if (this.format === 'text') {
|
|
11456
|
+
process.stderr.write(`${message}\n`);
|
|
11457
|
+
}
|
|
11458
|
+
}
|
|
11459
|
+
|
|
11460
|
+
notice(message) {
|
|
11461
|
+
process.stderr.write(`${message}\n`);
|
|
11462
|
+
}
|
|
11463
|
+
|
|
11464
|
+
warn(message) {
|
|
11465
|
+
process.stderr.write(`Warning: ${message}\n`);
|
|
11466
|
+
}
|
|
11467
|
+
|
|
11468
|
+
debug(message) {
|
|
11469
|
+
if (this.debugEnabled) {
|
|
11470
|
+
process.stderr.write(`[debug] ${message}\n`);
|
|
11471
|
+
}
|
|
11472
|
+
}
|
|
11473
|
+
}
|
|
11474
|
+
|
|
11475
|
+
const runtimes = new WeakMap();
|
|
11476
|
+
|
|
11477
|
+
const getRuntime = async (command) => {
|
|
11478
|
+
const deploy = findDeployCommand(command);
|
|
11479
|
+
let runtime = runtimes.get(deploy);
|
|
11480
|
+
if (!runtime) {
|
|
11481
|
+
runtime = (async () => {
|
|
11482
|
+
const options = deploy.opts();
|
|
11483
|
+
const config = await loadConfig(options);
|
|
11484
|
+
return {
|
|
11485
|
+
client: new DeployApiClient(config, options),
|
|
11486
|
+
config,
|
|
11487
|
+
cwd: process.cwd(),
|
|
11488
|
+
globalOptions: options,
|
|
11489
|
+
output: new Output(options.format || 'json', options.debug),
|
|
11490
|
+
};
|
|
11491
|
+
})();
|
|
11492
|
+
runtimes.set(deploy, runtime);
|
|
11493
|
+
}
|
|
11494
|
+
return runtime;
|
|
11495
|
+
};
|
|
11496
|
+
|
|
11497
|
+
const PRIVACY_POLICY_URL = 'https://docs.coze.cn/guides/privacy';
|
|
11498
|
+
const TERMS_OF_SERVICE_URL = 'https://docs.coze.cn/guides/terms-of-service';
|
|
11499
|
+
|
|
11500
|
+
const registerAuth = (program) => {
|
|
11501
|
+
const auth = program.command('auth').description('Manage deployment CLI authentication');
|
|
11502
|
+
|
|
11503
|
+
auth
|
|
11504
|
+
.command('login')
|
|
11505
|
+
.description('Login with Coze OAuth and save shared credentials')
|
|
11506
|
+
.action(async (_options, command) => {
|
|
11507
|
+
const runtime = await getRuntime(command);
|
|
11508
|
+
await loginWithOAuth(runtime.config, runtime.globalOptions, {
|
|
11509
|
+
onVerification: url => {
|
|
11510
|
+
runtime.output.notice(
|
|
11511
|
+
[
|
|
11512
|
+
'Open this URL to authorize coze-dev deploy:',
|
|
11513
|
+
url,
|
|
11514
|
+
`Privacy Policy: ${PRIVACY_POLICY_URL}`,
|
|
11515
|
+
`Terms of Service: ${TERMS_OF_SERVICE_URL}`,
|
|
11516
|
+
].join('\n'),
|
|
11517
|
+
);
|
|
11518
|
+
},
|
|
11519
|
+
});
|
|
11520
|
+
runtime.output.print({ success: true, logged_in: true, method: 'OAuth' });
|
|
11521
|
+
});
|
|
11522
|
+
|
|
11523
|
+
auth
|
|
11524
|
+
.command('status')
|
|
11525
|
+
.description('Check and refresh the current shared login')
|
|
11526
|
+
.action(async (_options, command) => {
|
|
11527
|
+
const runtime = await getRuntime(command);
|
|
11528
|
+
runtime.output.print(await getAuthStatus(runtime.config, runtime.globalOptions));
|
|
11529
|
+
});
|
|
11530
|
+
|
|
11531
|
+
auth
|
|
11532
|
+
.command('logout')
|
|
11533
|
+
.description('Clear shared credentials and account context')
|
|
11534
|
+
.action(async (_options, command) => {
|
|
11535
|
+
const runtime = await getRuntime(command);
|
|
11536
|
+
await logout(runtime.config, runtime.globalOptions);
|
|
11537
|
+
runtime.output.print({ success: true, logged_out: true });
|
|
11538
|
+
});
|
|
11539
|
+
};
|
|
11540
|
+
|
|
11541
|
+
const execFileAsync = node_util.promisify(node_child_process.execFile);
|
|
11542
|
+
|
|
11543
|
+
const registerContext = (program) => {
|
|
11544
|
+
const context = program.command('context').description('Show or update deployment context');
|
|
11545
|
+
context.command('show').action(async (_options, command) => {
|
|
11546
|
+
const runtime = await getRuntime(command);
|
|
11547
|
+
runtime.output.print({
|
|
11548
|
+
organization_id: runtime.config.organizationId,
|
|
11549
|
+
space_id: runtime.config.spaceId,
|
|
11550
|
+
project_id: runtime.config.projectId,
|
|
11551
|
+
lane: runtime.globalOptions.lane || runtime.config.xTTEnv,
|
|
11552
|
+
config_path: runtime.globalOptions.config || getSharedConfigPath(),
|
|
11553
|
+
});
|
|
11554
|
+
});
|
|
11555
|
+
context
|
|
11556
|
+
.command('use')
|
|
11557
|
+
.option('--space-id <spaceId>', 'Default Space ID')
|
|
11558
|
+
.option('--project-id <projectId>', 'Default Project ID')
|
|
11559
|
+
.action(async (options, command) => {
|
|
11560
|
+
const runtime = await getRuntime(command);
|
|
11561
|
+
await saveSharedConfig(
|
|
11562
|
+
{
|
|
11563
|
+
...(options.spaceId ? { spaceId: options.spaceId } : {}),
|
|
11564
|
+
...(options.projectId ? { projectId: options.projectId } : {}),
|
|
11565
|
+
},
|
|
11566
|
+
runtime.globalOptions,
|
|
11567
|
+
);
|
|
11568
|
+
runtime.output.print({
|
|
11569
|
+
space_id: options.spaceId || runtime.config.spaceId,
|
|
11570
|
+
project_id: options.projectId || runtime.config.projectId,
|
|
11571
|
+
});
|
|
11572
|
+
});
|
|
11573
|
+
};
|
|
11574
|
+
|
|
11575
|
+
const registerDoctor = (program) => {
|
|
11576
|
+
program
|
|
11577
|
+
.command('doctor')
|
|
11578
|
+
.description('Check deployment CLI prerequisites and shared login')
|
|
11579
|
+
.action(async (_options, command) => {
|
|
11580
|
+
const runtime = await getRuntime(command);
|
|
11581
|
+
let gitAvailable = true;
|
|
11582
|
+
try {
|
|
11583
|
+
await execFileAsync('git', ['--version']);
|
|
11584
|
+
} catch (e) {
|
|
11585
|
+
gitAvailable = false;
|
|
11586
|
+
}
|
|
11587
|
+
runtime.output.print({
|
|
11588
|
+
ok: gitAvailable && Boolean(runtime.config.accessToken),
|
|
11589
|
+
git: gitAvailable ? 'ok' : 'missing',
|
|
11590
|
+
login: runtime.config.accessToken ? 'reused' : 'missing',
|
|
11591
|
+
login_config: runtime.globalOptions.config || getSharedConfigPath(),
|
|
11592
|
+
project_id: runtime.config.projectId || 'not configured',
|
|
11593
|
+
});
|
|
11594
|
+
});
|
|
11595
|
+
};
|
|
11596
|
+
|
|
11597
|
+
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; }
|
|
11598
|
+
|
|
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
|
+
const getDeployParentOptions = (command) =>
|
|
11628
|
+
_optionalChain$9([command, 'access', _ => _.parent, 'optionalAccess', _2 => _2.opts, 'call', _3 => _3()]) || {};
|
|
11629
|
+
|
|
11630
|
+
const getDeployAppIdOption = (
|
|
11631
|
+
options,
|
|
11632
|
+
command,
|
|
11633
|
+
) => options.appId || getDeployParentOptions(command).appId;
|
|
11634
|
+
|
|
11635
|
+
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; }
|
|
11636
|
+
|
|
11637
|
+
const isAccountId = (value) => /^[1-9]\d*$/u.test(value);
|
|
11638
|
+
|
|
11639
|
+
/**
|
|
11640
|
+
* 定出这个 Project 下的应用该归属哪个 Coze 账号,写进 project_settings.extra.coze_account_id。
|
|
11641
|
+
*
|
|
11642
|
+
* 优先级(与 api-client 里 x-coze-account 的取值顺序一致,不另立一套口径):
|
|
11643
|
+
* 1. COZE_ACCOUNT_ID(config.cozeAccountId)—— 用户显式指定
|
|
11644
|
+
* 2. COZE_ORG_ID / --org-id(config.organizationId)—— 用户显式指定组织
|
|
11645
|
+
* 3. 登录态回读(deploy v2 account/get)
|
|
11646
|
+
*
|
|
11647
|
+
* ⚠️ 1、2 命中时**不打接口**:本地已经知道账号了,再问一次服务端只是多一个 RTT 和一个失败点。
|
|
11648
|
+
*
|
|
11649
|
+
* 拿不到就返回 undefined(不写 extra),部署照常继续:服务端在 deploy_history/create 里仍会
|
|
11650
|
+
* 按同一条阶梯解析账号,结果与不加这段逻辑时完全一致 —— 只是无登录态的预览初始化那条链路
|
|
11651
|
+
* 少了 Project 上这份归属记录。这是一个辅助接口,不该成为首次部署的单点。
|
|
11652
|
+
*/
|
|
11653
|
+
const resolveCozeAccountId = async (
|
|
11654
|
+
runtime,
|
|
11655
|
+
) => {
|
|
11656
|
+
const configured =
|
|
11657
|
+
_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()]);
|
|
11658
|
+
if (configured) {
|
|
11659
|
+
if (!isAccountId(configured)) {
|
|
11660
|
+
// 不把非法值写进 Project —— 它会被服务端当成「明确但损坏的归属」直接报错。
|
|
11661
|
+
// 该值仍会作为 x-coze-account 发出去,由服务端给出明确的参数错误。
|
|
11662
|
+
runtime.output.debug(
|
|
11663
|
+
`[deploy] Ignoring malformed Coze account id for project settings: ${configured}`,
|
|
11664
|
+
);
|
|
11665
|
+
return undefined;
|
|
11666
|
+
}
|
|
11667
|
+
runtime.output.debug(`[deploy] Using configured Coze account ${configured}`);
|
|
11668
|
+
return configured;
|
|
11669
|
+
}
|
|
11670
|
+
try {
|
|
11671
|
+
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()]);
|
|
11672
|
+
if (!accountId || !isAccountId(accountId)) {
|
|
11673
|
+
runtime.output.debug(
|
|
11674
|
+
`[deploy] Deployment API returned no usable Coze account id: ${String(accountId)}`,
|
|
11675
|
+
);
|
|
11676
|
+
return undefined;
|
|
11677
|
+
}
|
|
11678
|
+
runtime.output.debug(`[deploy] Resolved Coze account ${accountId} from the current login`);
|
|
11679
|
+
return accountId;
|
|
11680
|
+
} catch (error) {
|
|
11681
|
+
runtime.output.warn(
|
|
11682
|
+
`Unable to resolve the Coze account from the current login; the project will be created without an explicit account: ${String(error)}`,
|
|
11683
|
+
);
|
|
11684
|
+
return undefined;
|
|
11685
|
+
}
|
|
11686
|
+
};
|
|
11687
|
+
|
|
11688
|
+
const getCreateDeployConfig = (config) => ({
|
|
11689
|
+
deploy_config: {
|
|
11690
|
+
cpu: config.deploy_config.cpu,
|
|
11691
|
+
memory_mb: config.deploy_config.memory_mb,
|
|
11692
|
+
max_instance: config.deploy_config.max_instance,
|
|
11693
|
+
max_concurrency: config.deploy_config.max_concurrency,
|
|
11694
|
+
},
|
|
11695
|
+
service_type: config.deploy_config.service_type,
|
|
11696
|
+
...(config.deploy_config.computer_id
|
|
11697
|
+
? { computer_id: config.deploy_config.computer_id }
|
|
11698
|
+
: {}),
|
|
11699
|
+
});
|
|
11700
|
+
|
|
11701
|
+
const DEPLOY_STATUS = {
|
|
11702
|
+
pending: 1,
|
|
11703
|
+
running: 2,
|
|
11704
|
+
succeeded: 3,
|
|
11705
|
+
failed: 4,
|
|
11706
|
+
canceled: 5,
|
|
11707
|
+
interrupted: 6,
|
|
11708
|
+
preDeploy: 7,
|
|
11709
|
+
} ;
|
|
11710
|
+
|
|
11711
|
+
const STATUS_NAMES = {
|
|
11712
|
+
[DEPLOY_STATUS.pending]: 'Pending',
|
|
11713
|
+
[DEPLOY_STATUS.running]: 'Running',
|
|
11714
|
+
[DEPLOY_STATUS.succeeded]: 'Succeeded',
|
|
11715
|
+
[DEPLOY_STATUS.failed]: 'Failed',
|
|
11716
|
+
[DEPLOY_STATUS.canceled]: 'Canceled',
|
|
11717
|
+
[DEPLOY_STATUS.interrupted]: 'Interrupted',
|
|
11718
|
+
[DEPLOY_STATUS.preDeploy]: 'WaitingForUpload',
|
|
11719
|
+
};
|
|
11720
|
+
|
|
11721
|
+
/**
|
|
11722
|
+
* 终态 = 不会再变了。
|
|
11723
|
+
*
|
|
11724
|
+
* ⚠️ `interrupted(6)` **不是**终态,别再往这里加。它是过程态:服务端某条流水线自身轮询超时时,
|
|
11725
|
+
* 会把整次部署标成 Interrupted 并安排稍后重新触发(`base_pipe.NewInterruptedResult`),之后仍
|
|
11726
|
+
* 会推进到 Succeeded。安卓构建 10 分钟起步,几乎必然经过至少一次 Interrupted —— 把它当终态会
|
|
11727
|
+
* 让 `deploy --wait` 在构建中途就收工返回,此时 APK 还没产出,`mobile_artifact_list` 是空的。
|
|
11728
|
+
*/
|
|
11729
|
+
const TERMINAL_STATUSES = new Set([
|
|
11730
|
+
DEPLOY_STATUS.succeeded,
|
|
11731
|
+
DEPLOY_STATUS.failed,
|
|
11732
|
+
DEPLOY_STATUS.canceled,
|
|
11733
|
+
]);
|
|
11734
|
+
|
|
11735
|
+
const getDeployStatusText = (status) =>
|
|
11736
|
+
status ? STATUS_NAMES[status] || 'Unknown' : 'Unknown';
|
|
11737
|
+
|
|
11738
|
+
/** 这次部署的结果是否已经定下来了(到了终态就不会再变)。 */
|
|
11739
|
+
const isDeploymentSettled = (status) =>
|
|
11740
|
+
status !== undefined && TERMINAL_STATUSES.has(status);
|
|
11741
|
+
|
|
11742
|
+
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; }
|
|
11743
|
+
|
|
11744
|
+
const formatDeployDetails = (history) =>
|
|
11745
|
+
(_optionalChain$7([history, 'optionalAccess', _ => _.deploy_detail]) || []).map(detail => ({
|
|
11746
|
+
target: detail.target,
|
|
11747
|
+
status: getDeployStatusText(detail.status),
|
|
11748
|
+
deploy_log_key: detail.deploy_log_key,
|
|
11749
|
+
deploy_log_url: detail.deploy_log_url,
|
|
11750
|
+
}));
|
|
11751
|
+
|
|
11752
|
+
const getDeployLogKeys = (history) =>
|
|
11753
|
+
[...new Set(
|
|
11754
|
+
(history.deploy_detail || [])
|
|
11755
|
+
.map(detail => _optionalChain$7([detail, 'access', _2 => _2.deploy_log_key, 'optionalAccess', _3 => _3.trim, 'call', _4 => _4()]))
|
|
11756
|
+
.filter((key) => Boolean(key)),
|
|
11757
|
+
)];
|
|
11758
|
+
|
|
11759
|
+
const normalizePositiveId = (value) => {
|
|
11760
|
+
const normalized = value === undefined ? '' : String(value).trim();
|
|
11761
|
+
return /^[1-9]\d*$/.test(normalized) ? normalized : undefined;
|
|
11762
|
+
};
|
|
11763
|
+
|
|
11764
|
+
const resolveDeployHistoryId = (
|
|
11765
|
+
deployHistoryId,
|
|
11766
|
+
previousDeployHistoryId,
|
|
11767
|
+
) =>
|
|
11768
|
+
normalizePositiveId(deployHistoryId) || normalizePositiveId(previousDeployHistoryId);
|
|
11769
|
+
|
|
11770
|
+
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; }
|
|
11771
|
+
|
|
11772
|
+
const SOURCE_SNAPSHOT_BYTES = 20;
|
|
11773
|
+
const PROJECT_METADATA_FILE_MODE = 0o644;
|
|
11774
|
+
|
|
11775
|
+
const isId = (value) =>
|
|
11776
|
+
typeof value === 'string' && /^\d+$/u.test(value);
|
|
11777
|
+
|
|
11778
|
+
|
|
11779
|
+
const resolveAppId = async (cwd, appId) => {
|
|
11780
|
+
const explicit = _optionalChain$6([appId, 'optionalAccess', _ => _.trim, 'call', _2 => _2()]);
|
|
11781
|
+
if (explicit) {
|
|
11782
|
+
return explicit;
|
|
11783
|
+
}
|
|
11784
|
+
try {
|
|
11785
|
+
return (await readProjectMetadata(node_path.resolve(cwd))).appId;
|
|
11786
|
+
} catch (error) {
|
|
11787
|
+
if ((error ).code === 'COZE_FILE_NOT_FOUND') {
|
|
11788
|
+
return undefined;
|
|
11789
|
+
}
|
|
11790
|
+
throw error;
|
|
11791
|
+
}
|
|
11792
|
+
};
|
|
11793
|
+
|
|
11794
|
+
const requireAppId = async (cwd, appId) => {
|
|
11795
|
+
const resolved = await resolveAppId(cwd, appId);
|
|
11796
|
+
if (!resolved) {
|
|
11797
|
+
throw new CliError(
|
|
11798
|
+
'Application ID is required. Pass --app-id or use a directory whose .coze [project] contains app_id.',
|
|
11799
|
+
'APP_ID_REQUIRED',
|
|
11800
|
+
);
|
|
11801
|
+
}
|
|
11802
|
+
return resolved;
|
|
11803
|
+
};
|
|
11804
|
+
|
|
11805
|
+
const resolveSourceSnapshot = (sourceRootInput) => {
|
|
11806
|
+
const sourceRoot = node_path.resolve(sourceRootInput);
|
|
11807
|
+
const commitHash = node_crypto.randomBytes(SOURCE_SNAPSHOT_BYTES).toString('hex');
|
|
11808
|
+
return { commitHash, sourceRoot };
|
|
11809
|
+
};
|
|
11810
|
+
|
|
11811
|
+
const readProjectMetadata = async (
|
|
11812
|
+
sourceRoot,
|
|
11813
|
+
) => {
|
|
11814
|
+
let cozeFileContent = '';
|
|
11815
|
+
try {
|
|
11816
|
+
cozeFileContent = await promises.readFile(node_path.join(sourceRoot, '.coze'), 'utf8');
|
|
11817
|
+
} catch (error) {
|
|
11818
|
+
if ((error ).code === 'ENOENT') {
|
|
11819
|
+
throw new CliError(
|
|
11820
|
+
`No .coze file found in ${sourceRoot}.`,
|
|
11821
|
+
'COZE_FILE_NOT_FOUND',
|
|
11822
|
+
);
|
|
11823
|
+
}
|
|
11824
|
+
throw error;
|
|
11825
|
+
}
|
|
11826
|
+
const projectSection = _optionalChain$6([cozeFileContent, 'access', _3 => _3.match, 'call', _4 => _4(
|
|
11827
|
+
/^\s*\[project\]\s*(?:#.*)?$([\s\S]*?)(?=^\s*\[[^\]]+\]\s*(?:#.*)?$|(?![\s\S]))/mu,
|
|
11828
|
+
), 'optionalAccess', _5 => _5[1]]);
|
|
11829
|
+
const readProjectString = (key) =>
|
|
11830
|
+
_optionalChain$6([projectSection
|
|
11831
|
+
, 'optionalAccess', _6 => _6.match, 'call', _7 => _7(new RegExp(`^\\s*${key}\\s*=\\s*["']([^"']+)["']`, 'mu')), 'optionalAccess', _8 => _8[1]
|
|
11832
|
+
, 'optionalAccess', _9 => _9.trim, 'call', _10 => _10()]);
|
|
11833
|
+
const name = readProjectString('name');
|
|
11834
|
+
const projectType = readProjectString('project_type');
|
|
11835
|
+
const projectId = readProjectString('project_id');
|
|
11836
|
+
const appId = readProjectString('app_id');
|
|
11837
|
+
const hasUnquotedId = (key) =>
|
|
11838
|
+
Boolean(_optionalChain$6([projectSection, 'optionalAccess', _11 => _11.match, 'call', _12 => _12(new RegExp(`^\\s*${key}\\s*=\\s*(?!["'])\\S+`, 'mu'))]));
|
|
11839
|
+
if (hasUnquotedId('project_id') || hasUnquotedId('app_id')) {
|
|
11840
|
+
throw new CliError(
|
|
11841
|
+
'.coze [project].project_id and app_id must be quoted decimal strings.',
|
|
11842
|
+
'INVALID_COZE_FILE',
|
|
11843
|
+
);
|
|
11844
|
+
}
|
|
11845
|
+
if (projectId && !isId(projectId)) {
|
|
11846
|
+
throw new CliError('.coze [project].project_id must be a quoted decimal string.', 'INVALID_COZE_FILE');
|
|
11847
|
+
}
|
|
11848
|
+
if (appId && !isId(appId)) {
|
|
11849
|
+
throw new CliError('.coze [project].app_id must be a quoted decimal string.', 'INVALID_COZE_FILE');
|
|
11850
|
+
}
|
|
11851
|
+
return { name, projectType, projectId, appId, cozeFileContent };
|
|
11852
|
+
};
|
|
11853
|
+
|
|
11854
|
+
const updateProjectValue = (content, key, value) => {
|
|
11855
|
+
const sectionMatch = /^\s*\[project\]\s*(?:#.*)?$/mu.exec(content);
|
|
11856
|
+
if (!sectionMatch || sectionMatch.index === undefined) {
|
|
11857
|
+
const prefix = `[project]\n${key} = ${JSON.stringify(value)}\n\n`;
|
|
11858
|
+
return `${prefix}${content}`;
|
|
11859
|
+
}
|
|
11860
|
+
const sectionStart = sectionMatch.index + sectionMatch[0].length;
|
|
11861
|
+
const following = content.slice(sectionStart);
|
|
11862
|
+
const nextSection = /^\s*\[[^\]]+\]\s*(?:#.*)?$/mu.exec(following);
|
|
11863
|
+
const sectionEnd = _optionalChain$6([nextSection, 'optionalAccess', _13 => _13.index]) === undefined
|
|
11864
|
+
? content.length
|
|
11865
|
+
: sectionStart + nextSection.index;
|
|
11866
|
+
const before = content.slice(0, sectionStart);
|
|
11867
|
+
let body = content.slice(sectionStart, sectionEnd);
|
|
11868
|
+
const keyPattern = new RegExp(`^(\\s*)${key}\\s*=.*$`, 'mu');
|
|
11869
|
+
if (keyPattern.test(body)) {
|
|
11870
|
+
body = body.replace(keyPattern, `$1${key} = ${JSON.stringify(value)}`);
|
|
11871
|
+
} else {
|
|
11872
|
+
const separator = body.startsWith('\n') || body.startsWith('\r\n') ? '' : '\n';
|
|
11873
|
+
body = `${separator}${body}`;
|
|
11874
|
+
const trailingNewline = body.endsWith('\n') ? '' : '\n';
|
|
11875
|
+
body = `${body}${trailingNewline}${key} = ${JSON.stringify(value)}\n`;
|
|
11876
|
+
}
|
|
11877
|
+
return `${before}${body}${content.slice(sectionEnd)}`;
|
|
11878
|
+
};
|
|
11879
|
+
|
|
11880
|
+
const writeProjectBinding = async (
|
|
11881
|
+
sourceRoot,
|
|
11882
|
+
binding,
|
|
11883
|
+
) => {
|
|
11884
|
+
const path = node_path.join(sourceRoot, '.coze');
|
|
11885
|
+
let content = await promises.readFile(path, 'utf8');
|
|
11886
|
+
if (binding.projectId) {
|
|
11887
|
+
content = updateProjectValue(content, 'project_id', binding.projectId);
|
|
11888
|
+
}
|
|
11889
|
+
if (binding.appId) {
|
|
11890
|
+
content = updateProjectValue(content, 'app_id', binding.appId);
|
|
11891
|
+
}
|
|
11892
|
+
const tempPath = node_path.join(node_path.dirname(path), `.coze-${node_crypto.randomUUID()}.tmp`);
|
|
11893
|
+
try {
|
|
11894
|
+
await promises.writeFile(tempPath, content, {
|
|
11895
|
+
encoding: 'utf8',
|
|
11896
|
+
mode: PROJECT_METADATA_FILE_MODE,
|
|
11897
|
+
});
|
|
11898
|
+
await promises.chmod(tempPath, PROJECT_METADATA_FILE_MODE);
|
|
11899
|
+
await promises.rename(tempPath, path);
|
|
11900
|
+
} finally {
|
|
11901
|
+
await promises.rm(tempPath, { force: true });
|
|
11902
|
+
}
|
|
11903
|
+
return readProjectMetadata(sourceRoot);
|
|
11904
|
+
};
|
|
11905
|
+
|
|
11906
|
+
const ensureProjectMetadata = async (
|
|
11907
|
+
sourceRoot,
|
|
11908
|
+
options,
|
|
11909
|
+
) => {
|
|
11910
|
+
try {
|
|
11911
|
+
return await readProjectMetadata(sourceRoot);
|
|
11912
|
+
} catch (error) {
|
|
11913
|
+
if ((error ).code !== 'COZE_FILE_NOT_FOUND' || !options.allowCreate) {
|
|
11914
|
+
throw error;
|
|
11915
|
+
}
|
|
11916
|
+
}
|
|
11917
|
+
const name = _optionalChain$6([options, 'access', _14 => _14.name, 'optionalAccess', _15 => _15.trim, 'call', _16 => _16()]) || 'Pages application';
|
|
11918
|
+
const projectType = _optionalChain$6([options, 'access', _17 => _17.projectType, 'optionalAccess', _18 => _18.trim, 'call', _19 => _19()]) || 'web';
|
|
11919
|
+
await promises.writeFile(
|
|
11920
|
+
node_path.join(sourceRoot, '.coze'),
|
|
11921
|
+
`[project]\nname = ${JSON.stringify(name)}\nproject_type = ${JSON.stringify(projectType)}\n`,
|
|
11922
|
+
{ encoding: 'utf8', mode: PROJECT_METADATA_FILE_MODE },
|
|
11923
|
+
);
|
|
11924
|
+
await promises.chmod(node_path.join(sourceRoot, '.coze'), PROJECT_METADATA_FILE_MODE);
|
|
11925
|
+
return readProjectMetadata(sourceRoot);
|
|
11926
|
+
};
|
|
11927
|
+
|
|
11928
|
+
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; }
|
|
11929
|
+
const isFile = async (path) => {
|
|
11930
|
+
try {
|
|
11931
|
+
return (await promises.stat(path)).isFile();
|
|
11932
|
+
} catch (error) {
|
|
11933
|
+
if ((error ).code === 'ENOENT') {
|
|
11934
|
+
return false;
|
|
11935
|
+
}
|
|
11936
|
+
throw error;
|
|
11937
|
+
}
|
|
11938
|
+
};
|
|
11939
|
+
|
|
11940
|
+
const validatePagesSource = async (
|
|
11941
|
+
sourceRoot,
|
|
11942
|
+
cozeFileContent,
|
|
11943
|
+
) => {
|
|
11944
|
+
if (await isFile(node_path.join(sourceRoot, 'index.html'))) {
|
|
11945
|
+
return;
|
|
11946
|
+
}
|
|
11947
|
+
|
|
11948
|
+
let config;
|
|
11949
|
+
try {
|
|
11950
|
+
config = TOML.parse(cozeFileContent);
|
|
11951
|
+
} catch (error) {
|
|
11952
|
+
throw new CliError(
|
|
11953
|
+
`Unable to parse .coze: ${error instanceof Error ? error.message : String(error)}`,
|
|
11954
|
+
'INVALID_COZE_FILE',
|
|
11955
|
+
);
|
|
11956
|
+
}
|
|
11957
|
+
const project = config.project ;
|
|
11958
|
+
if (typeof _optionalChain$5([project, 'optionalAccess', _ => _.template]) !== 'string' || project.template.trim().toLowerCase() !== 'nextjs') {
|
|
11959
|
+
throw new CliError(
|
|
11960
|
+
'Pages source contains no index.html; .coze project.template must be "nextjs".',
|
|
11961
|
+
'PAGES_BUILD_CONFIG_REQUIRED',
|
|
11962
|
+
);
|
|
11963
|
+
}
|
|
11964
|
+
const deploy = config.deploy ;
|
|
11965
|
+
const build = _optionalChain$5([deploy, 'optionalAccess', _2 => _2.build]);
|
|
11966
|
+
if (!Array.isArray(build) || build.length === 0 || !build.every(part => typeof part === 'string' && part.length > 0)) {
|
|
11967
|
+
throw new CliError(
|
|
11968
|
+
'Pages source contains no index.html; .coze deploy.build must be a non-empty string array.',
|
|
11969
|
+
'PAGES_BUILD_CONFIG_REQUIRED',
|
|
11970
|
+
);
|
|
11971
|
+
}
|
|
11972
|
+
};
|
|
11973
|
+
|
|
11974
|
+
const readDeployLocalContext = async (
|
|
11975
|
+
sourceRoot,
|
|
11976
|
+
requestedApplicationType,
|
|
11977
|
+
appId,
|
|
11978
|
+
client,
|
|
11979
|
+
) => {
|
|
11980
|
+
const sourceSnapshot = resolveSourceSnapshot(sourceRoot);
|
|
11981
|
+
let applicationTypeHint = requestedApplicationType;
|
|
11982
|
+
let effectiveAppId = appId;
|
|
11983
|
+
if (!effectiveAppId) {
|
|
11984
|
+
try {
|
|
11985
|
+
effectiveAppId = (await ensureProjectMetadata(sourceRoot, { allowCreate: false })).appId;
|
|
11986
|
+
} catch (error) {
|
|
11987
|
+
if ((error ).code !== 'COZE_FILE_NOT_FOUND') {
|
|
11988
|
+
throw error;
|
|
11989
|
+
}
|
|
11990
|
+
}
|
|
11991
|
+
}
|
|
11992
|
+
if (!applicationTypeHint && effectiveAppId) {
|
|
11993
|
+
applicationTypeHint = (await client.getApplication(effectiveAppId)).application_type;
|
|
11994
|
+
}
|
|
11995
|
+
const isPagesDeployment = applicationTypeHint === 'pages';
|
|
11996
|
+
const metadata = await ensureProjectMetadata(sourceRoot, {
|
|
11997
|
+
allowCreate: isPagesDeployment,
|
|
11998
|
+
projectType: isPagesDeployment ? 'web' : undefined,
|
|
11999
|
+
});
|
|
12000
|
+
if (isPagesDeployment) {
|
|
12001
|
+
await validatePagesSource(sourceRoot, metadata.cozeFileContent);
|
|
12002
|
+
}
|
|
12003
|
+
return { ...sourceSnapshot, metadata, isPagesDeployment };
|
|
12004
|
+
};
|
|
12005
|
+
|
|
12006
|
+
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; }
|
|
12007
|
+
|
|
12008
|
+
/**
|
|
12009
|
+
* 把 `mobile_artifact_list` 连同「这个空数组到底什么意思」一起输出。
|
|
12010
|
+
*
|
|
12011
|
+
* 产物是部署过程中逐步落库的:APK 要等安卓构建跑完才写进去,比部署记录本身晚好几分钟。部署没到
|
|
12012
|
+
* 终态时,空的 `mobile_artifact_list` 只代表「还没产出来」,不代表「没有产物」—— 可这两种情况在
|
|
12013
|
+
* 输出里长得一模一样,调用方(尤其是 agent)会把前者读成后者,然后得出「部署成功但系统没返回
|
|
12014
|
+
* APK 下载地址」这种错误结论。线上真发生过。
|
|
12015
|
+
*
|
|
12016
|
+
* 所以未定终态时额外带一个 `artifacts_pending: true`;这个字段不出现,就表示这份列表已经是最终
|
|
12017
|
+
* 结果。`mobile_artifact_list` 本身保持恒存在,避免破坏已有脚本的读法。
|
|
12018
|
+
*/
|
|
12019
|
+
const mobileArtifactsOutput = (
|
|
12020
|
+
history,
|
|
12021
|
+
status = _optionalChain$4([history, 'optionalAccess', _ => _.status]),
|
|
12022
|
+
) => ({
|
|
12023
|
+
mobile_artifact_list: _optionalChain$4([history, 'optionalAccess', _2 => _2.mobile_artifact_list]) || [],
|
|
12024
|
+
...(isDeploymentSettled(status) ? {} : { artifacts_pending: true }),
|
|
12025
|
+
});
|
|
12026
|
+
|
|
12027
|
+
// 服务端 deploy_app/list 的 page_size 上限,超了会被判参数错误。
|
|
12028
|
+
// 客户端先拦一道,是为了把错误说在本地(带上上限值),而不是回一句服务端的通用参数错误。
|
|
12029
|
+
const APP_LIST_MAX_PAGE_SIZE = 100;
|
|
12030
|
+
|
|
12031
|
+
// page_token 是**页码的十进制字符串**(服务端口径,与 deploy_history/list 一致),不是不透明游标。
|
|
12032
|
+
// 所以这里能、也应该在本地校验:`--page-token abc` 早报错,比发出去再被拒强。
|
|
12033
|
+
const parsePositiveInt = (
|
|
12034
|
+
raw,
|
|
12035
|
+
option,
|
|
12036
|
+
code,
|
|
12037
|
+
max,
|
|
12038
|
+
) => {
|
|
12039
|
+
const value = Number(raw);
|
|
12040
|
+
if (!Number.isSafeInteger(value) || value <= 0) {
|
|
12041
|
+
throw new CliError(`${option} must be a positive integer.`, code, { [option]: raw });
|
|
12042
|
+
}
|
|
12043
|
+
if (max !== undefined && value > max) {
|
|
12044
|
+
throw new CliError(`${option} must not exceed ${String(max)}.`, code, { [option]: raw });
|
|
12045
|
+
}
|
|
12046
|
+
return value;
|
|
12047
|
+
};
|
|
12048
|
+
|
|
12049
|
+
// ⛔ 别再用 `Number(options.pageSize || 20)`:`--page-size abc` 会算出 NaN,
|
|
12050
|
+
// JSON.stringify 把它写成 null 发给服务端,最后表现为「参数没生效」而不是「参数写错了」。
|
|
12051
|
+
const parsePageSize = (
|
|
12052
|
+
raw,
|
|
12053
|
+
fallback,
|
|
12054
|
+
max,
|
|
12055
|
+
) => {
|
|
12056
|
+
if (raw === undefined || raw === '') {
|
|
12057
|
+
return fallback;
|
|
12058
|
+
}
|
|
12059
|
+
return parsePositiveInt(raw, '--page-size', 'INVALID_PAGE_SIZE', max);
|
|
12060
|
+
};
|
|
12061
|
+
|
|
12062
|
+
const parsePageToken = (raw) => {
|
|
12063
|
+
if (raw === undefined || raw === '') {
|
|
12064
|
+
return undefined;
|
|
12065
|
+
}
|
|
12066
|
+
parsePositiveInt(raw, '--page-token', 'INVALID_PAGE_TOKEN');
|
|
12067
|
+
return raw;
|
|
12068
|
+
};
|
|
12069
|
+
|
|
12070
|
+
|
|
12071
|
+
|
|
12072
|
+
|
|
12073
|
+
|
|
12074
|
+
|
|
12075
|
+
|
|
12076
|
+
// collectAllPages 顺着 next_page_token 把所有页取回来。
|
|
12077
|
+
//
|
|
12078
|
+
// 服务端从「全量单页」改成真分页之后,`app list` 一次只回一页;想要「我的全部应用」就得翻页。
|
|
12079
|
+
// 与其让每个调用方各写一遍循环,不如给一个 --all。
|
|
12080
|
+
//
|
|
12081
|
+
// ⚠️ 不设页数上限截断:静默截断正是这次要修掉的毛病。只防死循环——服务端如果一直回同一个
|
|
12082
|
+
// token(或说 has_more 却不给 token),直接报错,而不是无限翻。
|
|
12083
|
+
const collectAllPages = async (
|
|
12084
|
+
fetchPage,
|
|
12085
|
+
) => {
|
|
12086
|
+
const items = [];
|
|
12087
|
+
const seen = new Set();
|
|
12088
|
+
let pageToken;
|
|
12089
|
+
let pages = 0;
|
|
12090
|
+
for (;;) {
|
|
12091
|
+
const page = await fetchPage(pageToken);
|
|
12092
|
+
items.push(...(page.items || []));
|
|
12093
|
+
pages += 1;
|
|
12094
|
+
if (!page.has_more) {
|
|
12095
|
+
return { items, pages };
|
|
12096
|
+
}
|
|
12097
|
+
const next = page.next_page_token;
|
|
12098
|
+
if (!next || seen.has(next)) {
|
|
12099
|
+
throw new CliError(
|
|
12100
|
+
'The server reported more pages but returned no usable next_page_token.',
|
|
12101
|
+
'INVALID_PAGE_TOKEN',
|
|
12102
|
+
{ next_page_token: next, pages },
|
|
12103
|
+
);
|
|
12104
|
+
}
|
|
12105
|
+
seen.add(next);
|
|
12106
|
+
pageToken = next;
|
|
12107
|
+
}
|
|
12108
|
+
};
|
|
12109
|
+
|
|
12110
|
+
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; }
|
|
12111
|
+
|
|
12112
|
+
const registerDeployReadCommands = (deploy) => {
|
|
12113
|
+
deploy
|
|
12114
|
+
.command('status')
|
|
12115
|
+
.option('--app-id <appId>', 'Application ID')
|
|
12116
|
+
.option('--deploy-id <deployId>', 'Deployment history ID')
|
|
12117
|
+
.action(async (options, command) => {
|
|
12118
|
+
const runtime = await getRuntime(command);
|
|
12119
|
+
const appId = await requireAppId(runtime.cwd, getDeployAppIdOption(options, command));
|
|
12120
|
+
let deployHistoryId = options.deployId;
|
|
12121
|
+
if (!deployHistoryId) {
|
|
12122
|
+
deployHistoryId = await _asyncOptionalChain([(
|
|
12123
|
+
await runtime.client.listDeployHistory({ app_id: appId, page_size: 1 })
|
|
12124
|
+
), 'access', async _ => _.deploy_history_list, 'optionalAccess', async _2 => _2[0], 'optionalAccess', async _3 => _3.deploy_history_id]);
|
|
12125
|
+
}
|
|
12126
|
+
if (!deployHistoryId) {
|
|
12127
|
+
throw new CliError('No deployment history found.', 'DEPLOYMENT_NOT_FOUND');
|
|
12128
|
+
}
|
|
12129
|
+
const history = await runtime.client.getDeployHistory({
|
|
12130
|
+
app_id: appId,
|
|
12131
|
+
deploy_history_id: deployHistoryId,
|
|
12132
|
+
});
|
|
12133
|
+
runtime.output.print({
|
|
12134
|
+
app_id: appId,
|
|
12135
|
+
deploy_history_id: deployHistoryId,
|
|
12136
|
+
status: getDeployStatusText(history.status),
|
|
12137
|
+
commit_hash: history.commit_hash,
|
|
12138
|
+
commit_message: history.commit_message,
|
|
12139
|
+
domains: history.domain_list || [],
|
|
12140
|
+
error_analysis: history.error_analysis,
|
|
12141
|
+
deploy_detail: formatDeployDetails(history),
|
|
12142
|
+
connector_data_list: history.connector_data_list || [],
|
|
12143
|
+
...mobileArtifactsOutput(history),
|
|
12144
|
+
});
|
|
12145
|
+
});
|
|
12146
|
+
|
|
12147
|
+
deploy
|
|
12148
|
+
.command('list')
|
|
12149
|
+
.option('--app-id <appId>', 'Application ID')
|
|
12150
|
+
.option('--page-size <pageSize>', 'Page size', '10')
|
|
12151
|
+
.option('--page-token <pageToken>', 'Page token (page number)')
|
|
12152
|
+
.action(async (options, command) => {
|
|
12153
|
+
// 先在本地校验:`--page-size abc` 以前算出 NaN 发出去,表现成「参数没生效」。
|
|
12154
|
+
const pageSize = parsePageSize(options.pageSize, 10);
|
|
12155
|
+
const pageToken = parsePageToken(options.pageToken);
|
|
12156
|
+
const runtime = await getRuntime(command);
|
|
12157
|
+
const appId = await requireAppId(runtime.cwd, getDeployAppIdOption(options, command));
|
|
12158
|
+
const data = await runtime.client.listDeployHistory({
|
|
12159
|
+
app_id: appId,
|
|
12160
|
+
page_size: pageSize,
|
|
12161
|
+
page_token: pageToken,
|
|
12162
|
+
});
|
|
12163
|
+
runtime.output.print({
|
|
12164
|
+
items: (data.deploy_history_list || []).map(item => ({
|
|
12165
|
+
deploy_history_id: item.deploy_history_id,
|
|
12166
|
+
status: getDeployStatusText(item.status),
|
|
12167
|
+
commit_hash: item.commit_hash_short || item.commit_hash,
|
|
12168
|
+
commit_message: item.commit_message,
|
|
12169
|
+
created_at: item.created_at,
|
|
12170
|
+
can_rollback: item.can_rollback,
|
|
12171
|
+
deploy_detail: formatDeployDetails(item),
|
|
12172
|
+
connector_data_list: item.connector_data_list || [],
|
|
12173
|
+
...mobileArtifactsOutput(item),
|
|
12174
|
+
})),
|
|
12175
|
+
next_page_token: data.next_page_token,
|
|
12176
|
+
has_more: data.has_more,
|
|
12177
|
+
});
|
|
12178
|
+
});
|
|
12179
|
+
|
|
12180
|
+
deploy
|
|
12181
|
+
.command('online')
|
|
12182
|
+
.description('Show the current online deployment')
|
|
12183
|
+
.option('--app-id <appId>', 'Application ID')
|
|
12184
|
+
.action(async (options, command) => {
|
|
12185
|
+
const runtime = await getRuntime(command);
|
|
12186
|
+
const appId = await requireAppId(runtime.cwd, getDeployAppIdOption(options, command));
|
|
12187
|
+
const data = await runtime.client.getOnlineDeployHistory(appId);
|
|
12188
|
+
runtime.output.print({
|
|
12189
|
+
app_id: appId,
|
|
12190
|
+
items: (data.deploy_history_list || []).map(item => ({
|
|
12191
|
+
deploy_history_id: item.deploy_history_id,
|
|
12192
|
+
status: getDeployStatusText(item.status),
|
|
12193
|
+
commit_hash: item.commit_hash_short || item.commit_hash,
|
|
12194
|
+
commit_message: item.commit_message,
|
|
12195
|
+
created_at: item.created_at,
|
|
12196
|
+
deploy_detail: formatDeployDetails(item),
|
|
12197
|
+
domains: item.domain_list || [],
|
|
12198
|
+
...mobileArtifactsOutput(item),
|
|
12199
|
+
})),
|
|
12200
|
+
});
|
|
12201
|
+
});
|
|
12202
|
+
|
|
12203
|
+
deploy
|
|
12204
|
+
.command('rollback-check')
|
|
12205
|
+
.description('Check whether a deployment supports database rollback')
|
|
12206
|
+
.requiredOption('--deploy-id <deployId>', 'Target deployment history ID')
|
|
12207
|
+
.option('--app-id <appId>', 'Application ID')
|
|
12208
|
+
.action(async (options, command) => {
|
|
12209
|
+
const runtime = await getRuntime(command);
|
|
12210
|
+
const appId = await requireAppId(runtime.cwd, getDeployAppIdOption(options, command));
|
|
12211
|
+
const data = await runtime.client.checkRollbackDatabase({
|
|
12212
|
+
app_id: appId,
|
|
12213
|
+
deploy_history_id: options.deployId || '',
|
|
12214
|
+
});
|
|
12215
|
+
runtime.output.print({ app_id: appId, deploy_history_id: options.deployId, ...data });
|
|
12216
|
+
});
|
|
12217
|
+
|
|
12218
|
+
deploy
|
|
12219
|
+
.command('log-count')
|
|
12220
|
+
.description('Show runtime log count and limit')
|
|
12221
|
+
.option('--app-id <appId>', 'Application ID')
|
|
12222
|
+
.action(async (options, command) => {
|
|
12223
|
+
const runtime = await getRuntime(command);
|
|
12224
|
+
const appId = await requireAppId(runtime.cwd, getDeployAppIdOption(options, command));
|
|
12225
|
+
const data = await runtime.client.getRuntimeLogCount(appId);
|
|
12226
|
+
runtime.output.print({ app_id: appId, ...data });
|
|
12227
|
+
});
|
|
12228
|
+
|
|
12229
|
+
deploy
|
|
12230
|
+
.command('count')
|
|
12231
|
+
.description('Show successful deployment count')
|
|
12232
|
+
.option('--app-id <appId>', 'Application ID')
|
|
12233
|
+
.action(async (options, command) => {
|
|
12234
|
+
const runtime = await getRuntime(command);
|
|
12235
|
+
const appId = await requireAppId(runtime.cwd, getDeployAppIdOption(options, command));
|
|
12236
|
+
const data = await runtime.client.getDeployCount(appId);
|
|
12237
|
+
runtime.output.print({ app_id: appId, ...data });
|
|
12238
|
+
});
|
|
12239
|
+
};
|
|
12240
|
+
|
|
12241
|
+
const registerEnv = (code) => {
|
|
12242
|
+
const env = code
|
|
12243
|
+
.command('env')
|
|
12244
|
+
.description('Inspect the current online environment snapshot');
|
|
12245
|
+
|
|
12246
|
+
env
|
|
12247
|
+
.command('list')
|
|
12248
|
+
.description('List environment variables of the current online deployment')
|
|
12249
|
+
.option('--app-id <appId>', 'Application ID')
|
|
12250
|
+
.action(async (options, command) => {
|
|
12251
|
+
const runtime = await getRuntime(command);
|
|
12252
|
+
const appId = await requireAppId(
|
|
12253
|
+
runtime.cwd,
|
|
12254
|
+
getDeployAppIdOption(options, command),
|
|
12255
|
+
);
|
|
12256
|
+
runtime.output.print(await runtime.client.getOnlineEnvironment(appId));
|
|
12257
|
+
});
|
|
12258
|
+
};
|
|
12259
|
+
|
|
12260
|
+
/* eslint-disable security/detect-non-literal-fs-filename -- validated project-local build output paths */
|
|
12261
|
+
|
|
12262
|
+
const BUILD_OUTPUT_DIRS = new Set(['dist', 'dist-tt']);
|
|
12263
|
+
const EXCLUDED_PARTS = new Set([
|
|
12264
|
+
'.git',
|
|
12265
|
+
'.env',
|
|
12266
|
+
'node_modules',
|
|
12267
|
+
]);
|
|
12268
|
+
const REPRODUCIBLE_ARCHIVE_MTIME = new Date(0);
|
|
12269
|
+
|
|
12270
|
+
const validateBuildOutput = async (
|
|
12271
|
+
sourceRoot,
|
|
12272
|
+
buildOutputDir,
|
|
12273
|
+
) => {
|
|
12274
|
+
if (!BUILD_OUTPUT_DIRS.has(buildOutputDir)) {
|
|
12275
|
+
throw new CliError(
|
|
12276
|
+
`Unsupported Mini-program build output directory: ${buildOutputDir}.`,
|
|
12277
|
+
'SOURCE_PACKAGE_FAILED',
|
|
12278
|
+
);
|
|
12279
|
+
}
|
|
12280
|
+
const buildOutputRoot = node_path.resolve(sourceRoot, buildOutputDir);
|
|
12281
|
+
try {
|
|
12282
|
+
const info = await promises.lstat(buildOutputRoot);
|
|
12283
|
+
if (info.isSymbolicLink() || !info.isDirectory()) {
|
|
12284
|
+
throw new Error('build output must be a regular directory');
|
|
12285
|
+
}
|
|
12286
|
+
const realSourceRoot = await promises.realpath(sourceRoot);
|
|
12287
|
+
const realBuildOutputRoot = await promises.realpath(buildOutputRoot);
|
|
12288
|
+
const relativeOutput = node_path.relative(realSourceRoot, realBuildOutputRoot);
|
|
12289
|
+
if (!relativeOutput || relativeOutput.startsWith('..')) {
|
|
12290
|
+
throw new Error('build output must be inside the source root');
|
|
12291
|
+
}
|
|
12292
|
+
} catch (error) {
|
|
12293
|
+
throw new CliError(
|
|
12294
|
+
`Invalid Mini-program build output ${buildOutputRoot}: ${error instanceof Error ? error.message : String(error)}`,
|
|
12295
|
+
'SOURCE_PACKAGE_FAILED',
|
|
12296
|
+
);
|
|
12297
|
+
}
|
|
12298
|
+
};
|
|
12299
|
+
|
|
12300
|
+
const shouldInclude = (
|
|
12301
|
+
archivePath,
|
|
12302
|
+
entry,
|
|
12303
|
+
) => {
|
|
12304
|
+
if ('isSymbolicLink' in entry && entry.isSymbolicLink()) {
|
|
12305
|
+
return false;
|
|
12306
|
+
}
|
|
12307
|
+
return !archivePath.split(/[\\/]/u).some(part =>
|
|
12308
|
+
EXCLUDED_PARTS.has(part) || part.startsWith('.git'),
|
|
12309
|
+
);
|
|
12310
|
+
};
|
|
12311
|
+
|
|
12312
|
+
const createMiniProgramPackage = async (
|
|
12313
|
+
sourceRoot,
|
|
12314
|
+
buildOutputDir,
|
|
12315
|
+
) => {
|
|
12316
|
+
const resolvedSourceRoot = node_path.resolve(sourceRoot);
|
|
12317
|
+
await validateBuildOutput(resolvedSourceRoot, buildOutputDir);
|
|
12318
|
+
const tempDirectory = await promises.mkdtemp(node_path.join(node_os.tmpdir(), 'coze-mini-program-source-'));
|
|
12319
|
+
const outputPath = node_path.join(tempDirectory, 'source.tar.gz');
|
|
12320
|
+
try {
|
|
12321
|
+
await tar.create(
|
|
12322
|
+
{
|
|
12323
|
+
cwd: resolvedSourceRoot,
|
|
12324
|
+
file: outputPath,
|
|
12325
|
+
filter: shouldInclude,
|
|
12326
|
+
gzip: true,
|
|
12327
|
+
mtime: REPRODUCIBLE_ARCHIVE_MTIME,
|
|
12328
|
+
portable: true,
|
|
12329
|
+
},
|
|
12330
|
+
[buildOutputDir],
|
|
12331
|
+
);
|
|
12332
|
+
const info = await promises.stat(outputPath);
|
|
12333
|
+
if (info.size === 0) {
|
|
12334
|
+
throw new Error('source archive is empty');
|
|
12335
|
+
}
|
|
12336
|
+
return {
|
|
12337
|
+
path: outputPath,
|
|
12338
|
+
sizeBytes: info.size,
|
|
12339
|
+
cleanup: () => promises.rm(tempDirectory, { recursive: true, force: true }),
|
|
12340
|
+
};
|
|
12341
|
+
} catch (error) {
|
|
12342
|
+
await promises.rm(tempDirectory, { recursive: true, force: true });
|
|
12343
|
+
throw new CliError(
|
|
12344
|
+
`Unable to package Mini-program build output: ${error instanceof Error ? error.message : String(error)}`,
|
|
12345
|
+
'SOURCE_PACKAGE_FAILED',
|
|
12346
|
+
);
|
|
12347
|
+
}
|
|
12348
|
+
};
|
|
12349
|
+
|
|
12350
|
+
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; }
|
|
12351
|
+
const CONNECTOR_IDS = {
|
|
12352
|
+
wechat: '10000127',
|
|
12353
|
+
douyin: '10000126',
|
|
12354
|
+
} ;
|
|
12355
|
+
|
|
12356
|
+
const MINI_PROGRAM_BUILD_OUTPUT_DIRS = {
|
|
12357
|
+
wechat: 'dist',
|
|
12358
|
+
douyin: 'dist-tt',
|
|
12359
|
+
} ;
|
|
12360
|
+
|
|
12361
|
+
|
|
12362
|
+
|
|
12363
|
+
|
|
12364
|
+
|
|
12365
|
+
|
|
12366
|
+
|
|
12367
|
+
|
|
12368
|
+
|
|
12369
|
+
|
|
12370
|
+
|
|
12371
|
+
|
|
12372
|
+
|
|
12373
|
+
|
|
12374
|
+
|
|
12375
|
+
const resolveConnectorId = (platform) => {
|
|
12376
|
+
const connectorId = CONNECTOR_IDS[platform ];
|
|
12377
|
+
if (!connectorId) {
|
|
12378
|
+
throw new CliError(
|
|
12379
|
+
`Unsupported Mini-program platform ${String(platform)}; expected wechat or douyin.`,
|
|
12380
|
+
'INVALID_MINIPROGRAM_PLATFORM',
|
|
12381
|
+
);
|
|
12382
|
+
}
|
|
12383
|
+
return connectorId;
|
|
12384
|
+
};
|
|
12385
|
+
|
|
12386
|
+
const resolveBuildOutputDir = (platform) => {
|
|
12387
|
+
const outputDir =
|
|
12388
|
+
MINI_PROGRAM_BUILD_OUTPUT_DIRS[platform ];
|
|
12389
|
+
if (!outputDir) {
|
|
12390
|
+
throw new CliError(
|
|
12391
|
+
`Unsupported Mini-program platform ${String(platform)}; expected wechat or douyin.`,
|
|
12392
|
+
'INVALID_MINIPROGRAM_PLATFORM',
|
|
12393
|
+
);
|
|
12394
|
+
}
|
|
12395
|
+
return outputDir;
|
|
12396
|
+
};
|
|
12397
|
+
|
|
12398
|
+
const resolveProjectId = async (
|
|
12399
|
+
command,
|
|
12400
|
+
options,
|
|
12401
|
+
) => {
|
|
12402
|
+
if (_optionalChain$3([options, 'access', _ => _.projectId, 'optionalAccess', _2 => _2.trim, 'call', _3 => _3()])) {
|
|
12403
|
+
return options.projectId.trim();
|
|
12404
|
+
}
|
|
12405
|
+
const runtime = await getRuntime(command);
|
|
12406
|
+
const sourceRoot = node_path.resolve(runtime.cwd, options.sourceRoot || '.');
|
|
12407
|
+
const metadata = await readProjectMetadata(sourceRoot);
|
|
12408
|
+
if (!metadata.projectId) {
|
|
12409
|
+
throw new CliError(
|
|
12410
|
+
'Project ID is required. Pass --project-id or use a source directory whose .coze [project] contains project_id.',
|
|
12411
|
+
'PROJECT_ID_REQUIRED',
|
|
12412
|
+
);
|
|
12413
|
+
}
|
|
12414
|
+
return metadata.projectId;
|
|
12415
|
+
};
|
|
12416
|
+
|
|
12417
|
+
const MINI_PROGRAM_AUTH_STATUS = {
|
|
12418
|
+
authorized: 1,
|
|
12419
|
+
needAuthorize: 2,
|
|
12420
|
+
boundToOtherUser: 3,
|
|
12421
|
+
} ;
|
|
12422
|
+
|
|
12423
|
+
const getBoundToOtherUserMessage = (platform) => {
|
|
12424
|
+
const platformName = platform === 'wechat' ? 'WeChat' : 'Douyin';
|
|
12425
|
+
const platformConsole =
|
|
12426
|
+
platform === 'wechat' ? 'WeChat Public Platform' : 'Douyin Open Platform';
|
|
12427
|
+
return [
|
|
12428
|
+
`This ${platformName} Mini-program AppID is authorized by another Coze user.`,
|
|
12429
|
+
`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.`,
|
|
12430
|
+
'If this is not your AppID, change --mini-app-id to an AppID for which you have administrator permission, then rerun this auth command.',
|
|
12431
|
+
].join(' ');
|
|
12432
|
+
};
|
|
12433
|
+
|
|
12434
|
+
const getAuthRequiredMessage = () =>
|
|
12435
|
+
'This Mini-program AppID is not authorized for the current Coze user. Run `coze-dev deploy mini-program auth` first.';
|
|
12436
|
+
|
|
12437
|
+
const getPreviewFailureMessage = (data
|
|
12438
|
+
|
|
12439
|
+
|
|
12440
|
+
) =>
|
|
12441
|
+
_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.';
|
|
12442
|
+
|
|
12443
|
+
const registerAuthorizationCommand = (miniProgram) => {
|
|
12444
|
+
miniProgram
|
|
12445
|
+
.command('auth')
|
|
12446
|
+
.description('Authorize a Mini-program AppID for the current Coze user')
|
|
12447
|
+
.requiredOption('--platform <platform>', 'wechat or douyin')
|
|
12448
|
+
.requiredOption('--mini-app-id <miniAppId>', 'Mini-program AppID')
|
|
12449
|
+
.option('--project-id <projectId>', 'Deployment Project ID')
|
|
12450
|
+
.option('--source-root <sourceRoot>', 'Directory containing .coze', '.')
|
|
12451
|
+
.action(async (options, command) => {
|
|
12452
|
+
const runtime = await getRuntime(command);
|
|
12453
|
+
const projectId = await resolveProjectId(command, options);
|
|
12454
|
+
const authorization = await runtime.client.authorizeMiniProgram({
|
|
12455
|
+
project_id: projectId,
|
|
12456
|
+
app_id: options.miniAppId || '',
|
|
12457
|
+
connector_id: resolveConnectorId(options.platform),
|
|
12458
|
+
redirect_url: 'https://code.coze.cn/coding/auth/callback/miniprogram',
|
|
12459
|
+
});
|
|
12460
|
+
if (authorization.status === MINI_PROGRAM_AUTH_STATUS.needAuthorize) {
|
|
12461
|
+
runtime.output.print({
|
|
12462
|
+
project_id: projectId,
|
|
12463
|
+
mini_app_id: options.miniAppId,
|
|
12464
|
+
platform: options.platform,
|
|
12465
|
+
authorization_required: true,
|
|
12466
|
+
auth_url: authorization.auth_url,
|
|
12467
|
+
});
|
|
12468
|
+
return;
|
|
12469
|
+
}
|
|
12470
|
+
if (authorization.status === MINI_PROGRAM_AUTH_STATUS.boundToOtherUser) {
|
|
12471
|
+
throw new CliError(
|
|
12472
|
+
getBoundToOtherUserMessage(options.platform),
|
|
12473
|
+
'MINIPROGRAM_AUTHORIZED_BY_OTHER_USER',
|
|
12474
|
+
);
|
|
12475
|
+
}
|
|
12476
|
+
if (authorization.status !== MINI_PROGRAM_AUTH_STATUS.authorized) {
|
|
12477
|
+
throw new CliError(
|
|
12478
|
+
`Unexpected Mini-program authorization status: ${String(authorization.status)}.`,
|
|
12479
|
+
'INVALID_RESPONSE',
|
|
12480
|
+
);
|
|
12481
|
+
}
|
|
12482
|
+
runtime.output.print({
|
|
12483
|
+
project_id: projectId,
|
|
12484
|
+
mini_app_id: options.miniAppId,
|
|
12485
|
+
platform: options.platform,
|
|
12486
|
+
authorized: true,
|
|
12487
|
+
});
|
|
12488
|
+
});
|
|
12489
|
+
};
|
|
12490
|
+
|
|
12491
|
+
const registerPreviewCommand = (miniProgram) => {
|
|
12492
|
+
miniProgram
|
|
12493
|
+
.command('preview')
|
|
12494
|
+
.description('Create a Mini-program preview QR code from the local build artifact')
|
|
12495
|
+
.requiredOption('--platform <platform>', 'wechat or douyin')
|
|
12496
|
+
.requiredOption('--mini-app-id <miniAppId>', 'Mini-program AppID')
|
|
12497
|
+
.option('--project-id <projectId>', 'Deployment Project ID')
|
|
12498
|
+
.option('--source-root <sourceRoot>', 'Directory containing dist or dist-tt', '.')
|
|
12499
|
+
.option('--server-url <serverUrl>', 'Public HTTPS server URL to whitelist for this preview')
|
|
12500
|
+
.action(async (options, command) => {
|
|
12501
|
+
const runtime = await getRuntime(command);
|
|
12502
|
+
const projectId = await resolveProjectId(command, options);
|
|
12503
|
+
const authorization = await runtime.client.getMiniProgramAuthStatus({
|
|
12504
|
+
project_id: projectId,
|
|
12505
|
+
connector_id: resolveConnectorId(options.platform),
|
|
12506
|
+
});
|
|
12507
|
+
if (
|
|
12508
|
+
!authorization.is_authorized ||
|
|
12509
|
+
authorization.bound_related_id !== options.miniAppId
|
|
12510
|
+
) {
|
|
12511
|
+
throw new CliError(
|
|
12512
|
+
getAuthRequiredMessage(),
|
|
12513
|
+
'MINIPROGRAM_AUTH_REQUIRED',
|
|
12514
|
+
);
|
|
12515
|
+
}
|
|
12516
|
+
const sourceRoot = node_path.resolve(runtime.cwd, options.sourceRoot || '.');
|
|
12517
|
+
const buildOutputDir = resolveBuildOutputDir(options.platform);
|
|
12518
|
+
const sourcePackage = await createMiniProgramPackage(
|
|
12519
|
+
sourceRoot,
|
|
12520
|
+
buildOutputDir,
|
|
12521
|
+
);
|
|
12522
|
+
try {
|
|
12523
|
+
const content = await promises.readFile(sourcePackage.path);
|
|
12524
|
+
const data = await runtime.client.createMiniProgramPreview({
|
|
12525
|
+
project_id: projectId,
|
|
12526
|
+
app_id: options.miniAppId || '',
|
|
12527
|
+
connector_id: resolveConnectorId(options.platform),
|
|
12528
|
+
source_package_base64: content.toString('base64'),
|
|
12529
|
+
...(options.serverUrl ? { server_url: options.serverUrl } : {}),
|
|
12530
|
+
});
|
|
12531
|
+
if (data.failed) {
|
|
12532
|
+
throw new CliError(
|
|
12533
|
+
getPreviewFailureMessage(data),
|
|
12534
|
+
'MINIPROGRAM_PREVIEW_FAILED',
|
|
12535
|
+
);
|
|
12536
|
+
}
|
|
12537
|
+
runtime.output.print({
|
|
12538
|
+
project_id: projectId,
|
|
12539
|
+
mini_app_id: options.miniAppId,
|
|
12540
|
+
platform: options.platform,
|
|
12541
|
+
source_package_size_bytes: sourcePackage.sizeBytes,
|
|
12542
|
+
...data,
|
|
12543
|
+
});
|
|
12544
|
+
} finally {
|
|
12545
|
+
await sourcePackage.cleanup();
|
|
12546
|
+
}
|
|
12547
|
+
});
|
|
12548
|
+
};
|
|
12549
|
+
|
|
12550
|
+
const registerMiniProgram = (code) => {
|
|
12551
|
+
const miniProgram = code
|
|
12552
|
+
.command('mini-program')
|
|
12553
|
+
.alias('miniprogram')
|
|
12554
|
+
.description('Manage WeChat or Douyin Mini-program authorization');
|
|
12555
|
+
|
|
12556
|
+
miniProgram
|
|
12557
|
+
.command('status')
|
|
12558
|
+
.requiredOption('--platform <platform>', 'wechat or douyin')
|
|
12559
|
+
.option('--project-id <projectId>', 'Deployment Project ID')
|
|
12560
|
+
.option('--source-root <sourceRoot>', 'Directory containing .coze', '.')
|
|
12561
|
+
.action(async (options, command) => {
|
|
12562
|
+
const runtime = await getRuntime(command);
|
|
12563
|
+
const projectId = await resolveProjectId(command, options);
|
|
12564
|
+
const connectorId = resolveConnectorId(options.platform);
|
|
12565
|
+
const data = await runtime.client.getMiniProgramAuthStatus({
|
|
12566
|
+
project_id: projectId,
|
|
12567
|
+
connector_id: connectorId,
|
|
12568
|
+
});
|
|
12569
|
+
runtime.output.print({ project_id: projectId, platform: options.platform, ...data });
|
|
12570
|
+
});
|
|
12571
|
+
|
|
12572
|
+
miniProgram
|
|
12573
|
+
.command('bind')
|
|
12574
|
+
.requiredOption('--platform <platform>', 'wechat or douyin')
|
|
12575
|
+
.requiredOption('--mini-app-id <miniAppId>', 'Mini-program AppID')
|
|
12576
|
+
.requiredOption('--redirect-url <redirectUrl>', 'OAuth callback URL')
|
|
12577
|
+
.option('--project-id <projectId>', 'Deployment Project ID')
|
|
12578
|
+
.option('--source-root <sourceRoot>', 'Directory containing .coze', '.')
|
|
12579
|
+
.option('--override', 'Move an AppID already bound to another project owned by you')
|
|
12580
|
+
.action(async (options, command) => {
|
|
12581
|
+
const runtime = await getRuntime(command);
|
|
12582
|
+
const projectId = await resolveProjectId(command, options);
|
|
12583
|
+
const connectorId = resolveConnectorId(options.platform);
|
|
12584
|
+
const data = await runtime.client.bindMiniProgramAuth({
|
|
12585
|
+
project_id: projectId,
|
|
12586
|
+
connector_id: connectorId,
|
|
12587
|
+
redirect_url: options.redirectUrl || '',
|
|
12588
|
+
auth_params: { app_id: options.miniAppId || '' },
|
|
12589
|
+
override: _nullishCoalesce$1(options.override, () => ( false)),
|
|
12590
|
+
});
|
|
12591
|
+
runtime.output.print({
|
|
12592
|
+
project_id: projectId,
|
|
12593
|
+
platform: options.platform,
|
|
12594
|
+
mini_app_id: options.miniAppId,
|
|
12595
|
+
...data,
|
|
12596
|
+
});
|
|
12597
|
+
});
|
|
12598
|
+
|
|
12599
|
+
miniProgram
|
|
12600
|
+
.command('submit-code')
|
|
12601
|
+
.requiredOption('--platform <platform>', 'wechat or douyin')
|
|
12602
|
+
.requiredOption('--mini-app-id <miniAppId>', 'Mini-program AppID')
|
|
12603
|
+
.requiredOption('--code <code>', 'OAuth authorization code')
|
|
12604
|
+
.requiredOption('--verify-state <verifyState>', 'State returned by bind')
|
|
12605
|
+
.option('--project-id <projectId>', 'Deployment Project ID')
|
|
12606
|
+
.option('--source-root <sourceRoot>', 'Directory containing .coze', '.')
|
|
12607
|
+
.action(async (options, command) => {
|
|
12608
|
+
const runtime = await getRuntime(command);
|
|
12609
|
+
const projectId = await resolveProjectId(command, options);
|
|
12610
|
+
await runtime.client.submitMiniProgramAuthCode({
|
|
12611
|
+
project_id: projectId,
|
|
12612
|
+
connector_id: resolveConnectorId(options.platform),
|
|
12613
|
+
code: options.code || '',
|
|
12614
|
+
verify_state: options.verifyState || '',
|
|
12615
|
+
auth_params: { app_id: options.miniAppId || '' },
|
|
12616
|
+
});
|
|
12617
|
+
runtime.output.print({ project_id: projectId, platform: options.platform, bound: true });
|
|
12618
|
+
});
|
|
12619
|
+
|
|
12620
|
+
miniProgram
|
|
12621
|
+
.command('unbind')
|
|
12622
|
+
.requiredOption('--platform <platform>', 'wechat or douyin')
|
|
12623
|
+
.option('--project-id <projectId>', 'Deployment Project ID')
|
|
12624
|
+
.option('--source-root <sourceRoot>', 'Directory containing .coze', '.')
|
|
12625
|
+
.action(async (options, command) => {
|
|
12626
|
+
const runtime = await getRuntime(command);
|
|
12627
|
+
const projectId = await resolveProjectId(command, options);
|
|
12628
|
+
await runtime.client.unbindMiniProgramAuth({
|
|
12629
|
+
project_id: projectId,
|
|
12630
|
+
connector_id: resolveConnectorId(options.platform),
|
|
12631
|
+
});
|
|
12632
|
+
runtime.output.print({ project_id: projectId, platform: options.platform, unbound: true });
|
|
12633
|
+
});
|
|
12634
|
+
|
|
12635
|
+
registerAuthorizationCommand(miniProgram);
|
|
12636
|
+
registerPreviewCommand(miniProgram);
|
|
12637
|
+
};
|
|
12638
|
+
|
|
12639
|
+
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; }
|
|
12640
|
+
|
|
12641
|
+
const POLL_INTERVAL_MS = 3000;
|
|
12642
|
+
const MAX_CONSECUTIVE_RETRIES = 5;
|
|
12643
|
+
const TRANSIENT_RPC_ERROR_CODE = 230000001;
|
|
12644
|
+
/**
|
|
12645
|
+
* `--wait` 的总时长上限。
|
|
12646
|
+
*
|
|
12647
|
+
* Interrupted 不再算终态(见 status.ts),轮询只能靠这个兜底,否则一次卡住的部署会把 CLI
|
|
12648
|
+
* 永远挂在这里。取 60min 是照安卓构建定的:实测 10 分钟起步,中途还会经历若干次
|
|
12649
|
+
* Interrupted → 重新触发。
|
|
12650
|
+
*/
|
|
12651
|
+
const POLL_TIMEOUT_MS = 3600000; // 60min
|
|
12652
|
+
/** 心跳间隔:text 模式下每隔这么久报一次「还在跑」,免得长构建看起来像挂死。 */
|
|
12653
|
+
const HEARTBEAT_MS = 30000;
|
|
12654
|
+
|
|
12655
|
+
const wait = async () =>
|
|
12656
|
+
new Promise(resolve => setTimeout(resolve, POLL_INTERVAL_MS));
|
|
12657
|
+
|
|
12658
|
+
const isRetryablePollError = (error) =>
|
|
12659
|
+
error instanceof CliError &&
|
|
12660
|
+
error.code === 'API_REJECTED' &&
|
|
12661
|
+
Number(_optionalChain$2([error, 'access', _ => _.details, 'optionalAccess', _2 => _2.business_code])) === TRANSIENT_RPC_ERROR_CODE;
|
|
12662
|
+
|
|
12663
|
+
const pollHistory = async (
|
|
12664
|
+
command,
|
|
12665
|
+
appId,
|
|
12666
|
+
deployHistoryId,
|
|
12667
|
+
timeoutMs = POLL_TIMEOUT_MS,
|
|
12668
|
+
) => {
|
|
12669
|
+
const runtime = await getRuntime(command);
|
|
12670
|
+
const startedAt = Date.now();
|
|
12671
|
+
let consecutiveFailures = 0;
|
|
12672
|
+
let lastStatus;
|
|
12673
|
+
let lastBeatAt = startedAt;
|
|
12674
|
+
while (true) {
|
|
12675
|
+
const elapsed = () => Math.floor((Date.now() - startedAt) / 1000);
|
|
12676
|
+
try {
|
|
12677
|
+
const history = await runtime.client.getDeployHistory({
|
|
12678
|
+
app_id: appId,
|
|
12679
|
+
deploy_history_id: deployHistoryId,
|
|
12680
|
+
});
|
|
12681
|
+
consecutiveFailures = 0;
|
|
12682
|
+
const status = getDeployStatusText(history.status);
|
|
12683
|
+
runtime.output.debug(
|
|
12684
|
+
`[deploy] History ${deployHistoryId}: ${status} (${String(elapsed())}s elapsed)`,
|
|
12685
|
+
);
|
|
12686
|
+
if (history.status && TERMINAL_STATUSES.has(history.status)) {
|
|
12687
|
+
return history;
|
|
12688
|
+
}
|
|
12689
|
+
// 长构建(安卓十几分钟)期间给点动静:状态一变就报,否则每 30s 报一次还活着。
|
|
12690
|
+
// output.info 只在 text 模式写 stderr,json 模式是 no-op,不会污染机器可读输出。
|
|
12691
|
+
if (history.status !== lastStatus) {
|
|
12692
|
+
lastStatus = history.status;
|
|
12693
|
+
lastBeatAt = Date.now();
|
|
12694
|
+
runtime.output.info(`[deploy] ${status} (${String(elapsed())}s)`);
|
|
12695
|
+
} else if (Date.now() - lastBeatAt >= HEARTBEAT_MS) {
|
|
12696
|
+
lastBeatAt = Date.now();
|
|
12697
|
+
runtime.output.info(`[deploy] still ${status} (${String(elapsed())}s)`);
|
|
12698
|
+
}
|
|
12699
|
+
} catch (error) {
|
|
12700
|
+
if (!isRetryablePollError(error) || consecutiveFailures >= MAX_CONSECUTIVE_RETRIES) {
|
|
12701
|
+
throw error;
|
|
12702
|
+
}
|
|
12703
|
+
consecutiveFailures += 1;
|
|
12704
|
+
runtime.output.debug(
|
|
12705
|
+
`[deploy] Status check failed transiently; retrying (${String(consecutiveFailures)}/${String(MAX_CONSECUTIVE_RETRIES)}).`,
|
|
12706
|
+
);
|
|
12707
|
+
}
|
|
12708
|
+
if (Date.now() - startedAt >= timeoutMs) {
|
|
12709
|
+
throw new CliError(
|
|
12710
|
+
`Timed out after ${String(elapsed())}s waiting for deployment ${deployHistoryId}; ` +
|
|
12711
|
+
`last status: ${getDeployStatusText(lastStatus)}. The deployment may still be running — ` +
|
|
12712
|
+
'check it with `coze-dev deploy status`.',
|
|
12713
|
+
'DEPLOY_WAIT_TIMEOUT',
|
|
12714
|
+
{ app_id: appId, deploy_history_id: deployHistoryId, last_status: lastStatus },
|
|
12715
|
+
);
|
|
12716
|
+
}
|
|
12717
|
+
await wait();
|
|
12718
|
+
}
|
|
12719
|
+
};
|
|
12720
|
+
|
|
12721
|
+
const GENERAL_PROJECT_TYPE = 9;
|
|
12722
|
+
|
|
12723
|
+
/**
|
|
12724
|
+
* Map `.coze` `[project].project_type` to the VibeProjectType used when creating the
|
|
12725
|
+
* deployment project.
|
|
12726
|
+
*
|
|
12727
|
+
* The values on the left are the ones the deploy server understands (see `cozefileutil`
|
|
12728
|
+
* `ResolveDeployKindByProjectType` / `GeneralProjectTypeByCozeProjectType` in coze-coding);
|
|
12729
|
+
* the numbers on the right are `VibeProjectType` (idl/coze.coding.ide/project.thrift).
|
|
12730
|
+
*
|
|
12731
|
+
* Keeping the two in sync matters beyond project metadata: the created project type decides
|
|
12732
|
+
* the project-scoped `COZE_PROJECT_TYPE` secret injected into the runtime, whether a Postgres
|
|
12733
|
+
* database is provisioned for the project, and whether the traffic gateway enforces inbound
|
|
12734
|
+
* auth. Creating an `agent` project as General(9) therefore deploys successfully but leaves a
|
|
12735
|
+
* dead service: the agent template reads `COZE_PROJECT_TYPE` to pick its graph and needs
|
|
12736
|
+
* `PGDATABASE_URL` on startup.
|
|
12737
|
+
*
|
|
12738
|
+
* VibeProjectType WebApp(3) and AssistantAgent(8) are intentionally absent: no `.coze`
|
|
12739
|
+
* project_type maps to them.
|
|
12740
|
+
*/
|
|
12741
|
+
const resolveCreationProjectType = (
|
|
12742
|
+
projectType,
|
|
12743
|
+
) => {
|
|
12744
|
+
switch (projectType) {
|
|
12745
|
+
case 'agent':
|
|
12746
|
+
return 1;
|
|
12747
|
+
case 'workflow':
|
|
12748
|
+
case 'automation':
|
|
12749
|
+
return 2;
|
|
12750
|
+
case 'app':
|
|
12751
|
+
return 4;
|
|
12752
|
+
case 'skill':
|
|
12753
|
+
return 5;
|
|
12754
|
+
case 'web':
|
|
12755
|
+
case 'backend':
|
|
12756
|
+
return 6;
|
|
12757
|
+
case 'miniapp':
|
|
12758
|
+
case 'miniprogram':
|
|
12759
|
+
return 7;
|
|
12760
|
+
default:
|
|
12761
|
+
return GENERAL_PROJECT_TYPE;
|
|
12762
|
+
}
|
|
12763
|
+
};
|
|
12764
|
+
|
|
12765
|
+
const formatDeployment = (deployment) =>
|
|
12766
|
+
typeof deployment === 'object' && deployment
|
|
12767
|
+
? {
|
|
12768
|
+
...(deployment ),
|
|
12769
|
+
status: getDeployStatusText(
|
|
12770
|
+
Number((deployment ).status),
|
|
12771
|
+
),
|
|
12772
|
+
}
|
|
12773
|
+
: undefined;
|
|
12774
|
+
|
|
12775
|
+
const formatApplication = (application) => ({
|
|
12776
|
+
...application,
|
|
12777
|
+
online_deployment: formatDeployment(application.online_deployment),
|
|
12778
|
+
latest_deployment: formatDeployment(application.latest_deployment),
|
|
12779
|
+
});
|
|
12780
|
+
|
|
12781
|
+
// 对应 IDL 的 MetricTimeRange,数值与 V1 保持一致。
|
|
12782
|
+
const TIME_RANGES = {
|
|
12783
|
+
day: 1,
|
|
12784
|
+
week: 2,
|
|
12785
|
+
month: 3,
|
|
12786
|
+
yesterday: 4,
|
|
12787
|
+
'three-days': 5,
|
|
12788
|
+
};
|
|
12789
|
+
|
|
12790
|
+
const resolveTimeRange = (value) => {
|
|
12791
|
+
const timeRange = TIME_RANGES[value || 'day'];
|
|
12792
|
+
if (!timeRange) {
|
|
12793
|
+
throw new CliError(
|
|
12794
|
+
`Invalid time range; expected one of ${Object.keys(TIME_RANGES).join(', ')}.`,
|
|
12795
|
+
'INVALID_TIME_RANGE',
|
|
12796
|
+
{ time_range: value },
|
|
12797
|
+
);
|
|
12798
|
+
}
|
|
12799
|
+
return timeRange;
|
|
12800
|
+
};
|
|
12801
|
+
|
|
12802
|
+
const UNIT_TYPES = { dev: 1, prod: 2 };
|
|
12803
|
+
|
|
12804
|
+
// 改 Application 本身的两条写操作,都要显式 --yes 才生效。
|
|
12805
|
+
// 单独拎出来是因为它们和 registerApp 里其余只读命令性质不同(会改线上资产),
|
|
12806
|
+
// 顺带让 registerApp 保持在 max-line-per-function 之内。
|
|
12807
|
+
const registerAppMutations = (app) => {
|
|
12808
|
+
app
|
|
12809
|
+
.command('rename <name>')
|
|
12810
|
+
.description('Rename an application')
|
|
12811
|
+
.option('--app-id <appId>', 'Application ID')
|
|
12812
|
+
.option('--yes', 'Confirm rename')
|
|
12813
|
+
.action(async (name, options, command) => {
|
|
12814
|
+
if (!options.yes) {
|
|
12815
|
+
throw new CliError('Pass --yes to rename the application.', 'CONFIRMATION_REQUIRED');
|
|
12816
|
+
}
|
|
12817
|
+
const normalizedName = name.trim();
|
|
12818
|
+
if (!normalizedName || normalizedName.length > 255) {
|
|
12819
|
+
throw new CliError(
|
|
12820
|
+
'Application name must contain 1 to 255 characters.',
|
|
12821
|
+
'INVALID_APPLICATION_NAME',
|
|
12822
|
+
);
|
|
12823
|
+
}
|
|
12824
|
+
const runtime = await getRuntime(command);
|
|
12825
|
+
const appId = await requireAppId(runtime.cwd, options.appId);
|
|
12826
|
+
const application = await runtime.client.updateApplication({
|
|
12827
|
+
app_id: appId,
|
|
12828
|
+
name: normalizedName,
|
|
12829
|
+
});
|
|
12830
|
+
runtime.output.print(
|
|
12831
|
+
formatApplication(application ),
|
|
12832
|
+
);
|
|
12833
|
+
});
|
|
12834
|
+
app
|
|
12835
|
+
// 删除是终态、不可撤销,所以和 rename 一样必须显式 --yes。
|
|
12836
|
+
//
|
|
12837
|
+
// 服务端只接受 **Stopped** 的应用:还在服务的先 `code deploy stop --yes`,否则会拿到一条
|
|
12838
|
+
// 带当前状态的报错。这里刻意不替用户先停 —— 停服会真的把线上服务摘掉,那得是用户自己按的。
|
|
12839
|
+
.command('delete')
|
|
12840
|
+
.description('Delete a stopped application (irreversible)')
|
|
12841
|
+
.option('--app-id <appId>', 'Application ID')
|
|
12842
|
+
.option('--yes', 'Confirm delete')
|
|
12843
|
+
.action(async (options, command) => {
|
|
12844
|
+
if (!options.yes) {
|
|
12845
|
+
throw new CliError('Pass --yes to delete the application.', 'CONFIRMATION_REQUIRED');
|
|
12846
|
+
}
|
|
12847
|
+
const runtime = await getRuntime(command);
|
|
12848
|
+
const appId = await requireAppId(runtime.cwd, options.appId);
|
|
12849
|
+
await runtime.client.deleteApplication(appId);
|
|
12850
|
+
// 本地 .coze 里的 app_id 不动(这条命令可能是在别的目录带 --app-id 跑的),但要说清楚:
|
|
12851
|
+
// 不清掉它,同目录下一次 deploy 会打到一个已删除的应用上、被服务端拒。
|
|
12852
|
+
runtime.output.print({
|
|
12853
|
+
app_id: appId,
|
|
12854
|
+
deleted: true,
|
|
12855
|
+
note: 'Remove app_id from .coze [project] before deploying this directory again.',
|
|
12856
|
+
});
|
|
12857
|
+
});
|
|
12858
|
+
};
|
|
12859
|
+
|
|
12860
|
+
const registerApp = (code) => {
|
|
12861
|
+
const app = code.command('app').description('Manage deployment applications');
|
|
12862
|
+
registerAppMutations(app);
|
|
12863
|
+
app
|
|
12864
|
+
.command('list')
|
|
12865
|
+
// 列的是当前登录用户名下**跨 Project** 的全部 Application。没有 --project-id:
|
|
12866
|
+
// V2 的资产归属是 Owner 而不是 Project,同一个 Project 下的应用可以分属不同用户。
|
|
12867
|
+
// 也不传 user_id:服务端直接从登录态取,客户端传了也只能传自己。
|
|
12868
|
+
//
|
|
12869
|
+
// ⚠️ 服务端是真分页(一页最多 100 条),一次调用只回一页。要「我的全部应用」用 --all,
|
|
12870
|
+
// 它顺着 next_page_token 翻到底 —— 别再默认第一页就是全部。
|
|
12871
|
+
.option('--page-token <pageToken>', 'Pagination token (page number)')
|
|
12872
|
+
.option('--page-size <pageSize>', 'Page size', '20')
|
|
12873
|
+
.option('--all', 'Fetch every page by following next_page_token')
|
|
12874
|
+
.action(async (options, command) => {
|
|
12875
|
+
const pageSize = parsePageSize(options.pageSize, 20, APP_LIST_MAX_PAGE_SIZE);
|
|
12876
|
+
const pageToken = parsePageToken(options.pageToken);
|
|
12877
|
+
if (options.all && pageToken) {
|
|
12878
|
+
throw new CliError(
|
|
12879
|
+
'--all fetches every page and cannot be combined with --page-token.',
|
|
12880
|
+
'INVALID_PAGE_TOKEN',
|
|
12881
|
+
{ page_token: options.pageToken },
|
|
12882
|
+
);
|
|
12883
|
+
}
|
|
12884
|
+
const runtime = await getRuntime(command);
|
|
12885
|
+
const format = (items) =>
|
|
12886
|
+
items.map(item => formatApplication(item ));
|
|
12887
|
+
if (options.all) {
|
|
12888
|
+
const { items, pages } = await collectAllPages(next =>
|
|
12889
|
+
runtime.client.listApplications({ page_token: next, page_size: pageSize }),
|
|
12890
|
+
);
|
|
12891
|
+
runtime.output.print({ items: format(items), pages, has_more: false });
|
|
12892
|
+
return;
|
|
12893
|
+
}
|
|
12894
|
+
const data = await runtime.client.listApplications({
|
|
12895
|
+
page_token: pageToken,
|
|
12896
|
+
page_size: pageSize,
|
|
12897
|
+
});
|
|
12898
|
+
runtime.output.print({
|
|
12899
|
+
items: format(data.items),
|
|
12900
|
+
next_page_token: data.next_page_token,
|
|
12901
|
+
has_more: data.has_more,
|
|
12902
|
+
});
|
|
12903
|
+
});
|
|
12904
|
+
app
|
|
12905
|
+
.command('show')
|
|
12906
|
+
.requiredOption('--app-id <appId>', 'Application ID')
|
|
12907
|
+
.action(async (options, command) => {
|
|
12908
|
+
const runtime = await getRuntime(command);
|
|
12909
|
+
runtime.output.print(
|
|
12910
|
+
formatApplication(
|
|
12911
|
+
(await runtime.client.getApplication(options.appId))
|
|
12912
|
+
|
|
12913
|
+
|
|
12914
|
+
,
|
|
12915
|
+
),
|
|
12916
|
+
);
|
|
12917
|
+
});
|
|
12918
|
+
app
|
|
12919
|
+
.command('analytics')
|
|
12920
|
+
.description('Show PV / UV charts')
|
|
12921
|
+
.option('--app-id <appId>', 'Application ID')
|
|
12922
|
+
.option(
|
|
12923
|
+
'--time-range <timeRange>',
|
|
12924
|
+
`Time range: ${Object.keys(TIME_RANGES).join(', ')}`,
|
|
12925
|
+
'day',
|
|
12926
|
+
)
|
|
12927
|
+
.action(async (options, command) => {
|
|
12928
|
+
const timeRange = resolveTimeRange(options.timeRange);
|
|
12929
|
+
const runtime = await getRuntime(command);
|
|
12930
|
+
const appId = await requireAppId(runtime.cwd, options.appId);
|
|
12931
|
+
const data = await runtime.client.getUserAnalyticsMetrics({
|
|
12932
|
+
app_id: appId,
|
|
12933
|
+
time_range: timeRange,
|
|
12934
|
+
});
|
|
12935
|
+
runtime.output.print({ app_id: appId, charts: data.charts || [] });
|
|
12936
|
+
});
|
|
12937
|
+
app
|
|
12938
|
+
.command('metrics')
|
|
12939
|
+
.description('Show application runtime metrics')
|
|
12940
|
+
.option('--app-id <appId>', 'Application ID')
|
|
12941
|
+
.option(
|
|
12942
|
+
'--time-range <timeRange>',
|
|
12943
|
+
`Time range: ${Object.keys(TIME_RANGES).join(', ')}`,
|
|
12944
|
+
'day',
|
|
12945
|
+
)
|
|
12946
|
+
.action(async (options, command) => {
|
|
12947
|
+
const timeRange = resolveTimeRange(options.timeRange);
|
|
12948
|
+
const runtime = await getRuntime(command);
|
|
12949
|
+
const appId = await requireAppId(runtime.cwd, options.appId);
|
|
12950
|
+
const data = await runtime.client.getApplicationMetrics({
|
|
12951
|
+
app_id: appId,
|
|
12952
|
+
time_range: timeRange,
|
|
12953
|
+
});
|
|
12954
|
+
runtime.output.print({
|
|
12955
|
+
app_id: appId,
|
|
12956
|
+
charts: data.charts || [],
|
|
12957
|
+
stats: data.stats || [],
|
|
12958
|
+
});
|
|
12959
|
+
});
|
|
12960
|
+
app
|
|
12961
|
+
.command('usage')
|
|
12962
|
+
.description('Show monthly hosted usage')
|
|
12963
|
+
.option('--app-id <appId>', 'Application ID')
|
|
12964
|
+
.requiredOption('--bill-month <billMonth>', 'Billing month in YYYY-MM format')
|
|
12965
|
+
.action(async (options, command) => {
|
|
12966
|
+
const billMonth = options.billMonth || '';
|
|
12967
|
+
if (!/^\d{4}-(?:0[1-9]|1[0-2])$/u.test(billMonth)) {
|
|
12968
|
+
throw new CliError(
|
|
12969
|
+
'Invalid billing month; expected YYYY-MM.',
|
|
12970
|
+
'INVALID_BILL_MONTH',
|
|
12971
|
+
{ bill_month: billMonth },
|
|
12972
|
+
);
|
|
12973
|
+
}
|
|
12974
|
+
const runtime = await getRuntime(command);
|
|
12975
|
+
const appId = await requireAppId(runtime.cwd, options.appId);
|
|
12976
|
+
const data = await runtime.client.getHostedUsageMonthly({
|
|
12977
|
+
app_id: appId,
|
|
12978
|
+
bill_month: billMonth,
|
|
12979
|
+
});
|
|
12980
|
+
runtime.output.print({ app_id: appId, summary: data.summary });
|
|
12981
|
+
});
|
|
12982
|
+
};
|
|
12983
|
+
|
|
12984
|
+
const registerDomain = (code) => {
|
|
12985
|
+
const domain = code.command('domain').description('Manage application domains');
|
|
12986
|
+
domain
|
|
12987
|
+
.command('list')
|
|
12988
|
+
.option('--app-id <appId>', 'Application ID')
|
|
12989
|
+
.option('--unit-type <unitType>', 'Unit type: dev or prod', 'prod')
|
|
12990
|
+
.action(async (options, command) => {
|
|
12991
|
+
const unitType = UNIT_TYPES[options.unitType || 'prod'];
|
|
12992
|
+
if (!unitType) {
|
|
12993
|
+
throw new CliError(
|
|
12994
|
+
'Invalid unit type; expected dev or prod.',
|
|
12995
|
+
'INVALID_UNIT_TYPE',
|
|
12996
|
+
{ unit_type: options.unitType },
|
|
12997
|
+
);
|
|
12998
|
+
}
|
|
12999
|
+
const runtime = await getRuntime(command);
|
|
13000
|
+
const appId = await requireAppId(runtime.cwd, options.appId);
|
|
13001
|
+
const data = await runtime.client.listDomains(appId, unitType);
|
|
13002
|
+
runtime.output.print({
|
|
13003
|
+
app_id: appId,
|
|
13004
|
+
unit_type: options.unitType || 'prod',
|
|
13005
|
+
items: (data.items || []).map(item => ({
|
|
13006
|
+
id: item.id,
|
|
13007
|
+
domain_host: item.domain_host,
|
|
13008
|
+
})),
|
|
13009
|
+
});
|
|
13010
|
+
});
|
|
13011
|
+
domain
|
|
13012
|
+
// 改的是系统分配的 <prefix>.coze.site 的 prefix,不是 `domain add` 加进来的自定义域名 ——
|
|
13013
|
+
// 那类域名服务端只有 create/delete,域名串本身改不了。
|
|
13014
|
+
//
|
|
13015
|
+
// 和 rename 一样要 --yes:旧默认域名会立刻停止指向本应用,已经发出去的链接会失效。
|
|
13016
|
+
.command('set-prefix <prefix>')
|
|
13017
|
+
.description('Change the default domain prefix (<prefix>.coze.site)')
|
|
13018
|
+
.option('--app-id <appId>', 'Application ID')
|
|
13019
|
+
.option('--yes', 'Confirm prefix change')
|
|
13020
|
+
.action(async (prefix, options, command) => {
|
|
13021
|
+
if (!options.yes) {
|
|
13022
|
+
throw new CliError(
|
|
13023
|
+
'Pass --yes to change the default domain prefix.',
|
|
13024
|
+
'CONFIRMATION_REQUIRED',
|
|
13025
|
+
);
|
|
13026
|
+
}
|
|
13027
|
+
const normalizedPrefix = prefix.trim();
|
|
13028
|
+
// 只做形态校验:长度、保留词、占用与权益都由服务端判,客户端不复制第二套规则。
|
|
13029
|
+
if (!/^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/u.test(normalizedPrefix)) {
|
|
13030
|
+
throw new CliError(
|
|
13031
|
+
'Invalid prefix; use lowercase letters, digits and hyphens, not starting or ending with a hyphen.',
|
|
13032
|
+
'INVALID_DOMAIN_PREFIX',
|
|
13033
|
+
{ prefix },
|
|
13034
|
+
);
|
|
13035
|
+
}
|
|
13036
|
+
const runtime = await getRuntime(command);
|
|
13037
|
+
const appId = await requireAppId(runtime.cwd, options.appId);
|
|
13038
|
+
const data = await runtime.client.updateDefaultDomainPrefix({
|
|
13039
|
+
app_id: appId,
|
|
13040
|
+
prefix: normalizedPrefix,
|
|
13041
|
+
});
|
|
13042
|
+
runtime.output.print({
|
|
13043
|
+
app_id: appId,
|
|
13044
|
+
prefix: normalizedPrefix,
|
|
13045
|
+
old_domain_host: data.old_domain_host_canonical,
|
|
13046
|
+
new_domain_host: data.new_domain_host_canonical,
|
|
13047
|
+
});
|
|
13048
|
+
});
|
|
13049
|
+
domain
|
|
13050
|
+
.command('add <domain>')
|
|
13051
|
+
.option('--app-id <appId>', 'Application ID')
|
|
13052
|
+
.action(async (domainHost, options, command) => {
|
|
13053
|
+
if (!/^[a-zA-Z0-9](?:[a-zA-Z0-9-]*\.)+[a-zA-Z0-9-]+$/u.test(domainHost)) {
|
|
13054
|
+
throw new CliError('Invalid domain.', 'INVALID_DOMAIN', { domain: domainHost });
|
|
13055
|
+
}
|
|
13056
|
+
const runtime = await getRuntime(command);
|
|
13057
|
+
const appId = await requireAppId(runtime.cwd, options.appId);
|
|
13058
|
+
await runtime.client.createDomain({ app_id: appId, domain: domainHost });
|
|
13059
|
+
runtime.output.print({ app_id: appId, domain: domainHost });
|
|
13060
|
+
});
|
|
13061
|
+
};
|
|
13062
|
+
|
|
13063
|
+
const PACKAGE_SCRIPT_CANDIDATES = [
|
|
13064
|
+
node_path.resolve(__dirname, 'deploy/package-project.js'),
|
|
13065
|
+
node_path.resolve(__dirname, '../../../scripts/deploy/package-project.js'),
|
|
13066
|
+
];
|
|
13067
|
+
|
|
13068
|
+
const packageCommand = (args) => {
|
|
13069
|
+
const packageScript = PACKAGE_SCRIPT_CANDIDATES.find(candidate =>
|
|
13070
|
+
node_fs.existsSync(candidate),
|
|
13071
|
+
);
|
|
13072
|
+
if (!packageScript) {
|
|
13073
|
+
throw new CliError(
|
|
13074
|
+
'The deployment packaging script is missing from this coze-dev installation.',
|
|
13075
|
+
'SOURCE_PACKAGE_FAILED',
|
|
13076
|
+
);
|
|
13077
|
+
}
|
|
13078
|
+
return [packageScript, ...args];
|
|
13079
|
+
};
|
|
13080
|
+
|
|
13081
|
+
const runPackageScript = async (args, debug = false) =>
|
|
13082
|
+
new Promise((resolvePromise, reject) => {
|
|
13083
|
+
const child = node_child_process.spawn(process.execPath, packageCommand(args), {
|
|
13084
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
13085
|
+
});
|
|
13086
|
+
let errorOutput = '';
|
|
13087
|
+
const forward = (chunk) => {
|
|
13088
|
+
const text = chunk.toString();
|
|
13089
|
+
if (debug) {
|
|
13090
|
+
process.stderr.write(text);
|
|
13091
|
+
}
|
|
13092
|
+
errorOutput = `${errorOutput}${text}`.slice(-65536);
|
|
13093
|
+
};
|
|
13094
|
+
child.stdout.on('data', forward);
|
|
13095
|
+
child.stderr.on('data', forward);
|
|
13096
|
+
child.once('error', reject);
|
|
13097
|
+
child.once('close', code => {
|
|
13098
|
+
if (code === 0) {
|
|
13099
|
+
resolvePromise();
|
|
13100
|
+
return;
|
|
13101
|
+
}
|
|
13102
|
+
reject(new Error(
|
|
13103
|
+
`Packaging process exited with code ${String(code)}${errorOutput ? `\n${errorOutput.trim()}` : ''}`,
|
|
13104
|
+
));
|
|
13105
|
+
});
|
|
13106
|
+
});
|
|
13107
|
+
|
|
13108
|
+
|
|
13109
|
+
|
|
13110
|
+
|
|
13111
|
+
|
|
13112
|
+
|
|
13113
|
+
|
|
13114
|
+
|
|
13115
|
+
|
|
13116
|
+
|
|
13117
|
+
|
|
13118
|
+
|
|
13119
|
+
const createSourcePackageArchive = async (
|
|
13120
|
+
sourceRoot,
|
|
13121
|
+
applicationType = 'service',
|
|
13122
|
+
debug = false,
|
|
13123
|
+
) => {
|
|
13124
|
+
const tempDirectory = await promises.mkdtemp(node_path.join(node_os.tmpdir(), 'coze-deploy-source-'));
|
|
13125
|
+
const outputPath = node_path.join(tempDirectory, 'source.tar.gz');
|
|
13126
|
+
try {
|
|
13127
|
+
await runPackageScript(
|
|
13128
|
+
[sourceRoot, outputPath, ...(applicationType === 'pages' ? ['--pages'] : [])],
|
|
13129
|
+
debug,
|
|
13130
|
+
);
|
|
13131
|
+
const info = await promises.stat(outputPath);
|
|
13132
|
+
if (info.size === 0) {
|
|
13133
|
+
throw new CliError('Source package is empty.', 'SOURCE_PACKAGE_FAILED');
|
|
13134
|
+
}
|
|
13135
|
+
return {
|
|
13136
|
+
path: outputPath,
|
|
13137
|
+
sizeBytes: info.size,
|
|
13138
|
+
cleanup: () => promises.rm(tempDirectory, { recursive: true, force: true }),
|
|
13139
|
+
};
|
|
13140
|
+
} catch (error) {
|
|
13141
|
+
await promises.rm(tempDirectory, { recursive: true, force: true });
|
|
13142
|
+
if (error instanceof CliError) {
|
|
13143
|
+
throw error;
|
|
13144
|
+
}
|
|
13145
|
+
throw new CliError(
|
|
13146
|
+
`Unable to package local source: ${error instanceof Error ? error.message : String(error)}`,
|
|
13147
|
+
'SOURCE_PACKAGE_FAILED',
|
|
13148
|
+
);
|
|
13149
|
+
}
|
|
13150
|
+
};
|
|
13151
|
+
|
|
13152
|
+
const UPLOAD_SESSION_FILENAME = '.coze-deploy-upload.json';
|
|
13153
|
+
|
|
13154
|
+
|
|
13155
|
+
|
|
13156
|
+
|
|
13157
|
+
|
|
13158
|
+
|
|
13159
|
+
|
|
13160
|
+
|
|
13161
|
+
|
|
13162
|
+
|
|
13163
|
+
|
|
13164
|
+
const isUploadSession = (value) => {
|
|
13165
|
+
if (!value || typeof value !== 'object') {
|
|
13166
|
+
return false;
|
|
13167
|
+
}
|
|
13168
|
+
const session = value ;
|
|
13169
|
+
return typeof session.idempotencyKey === 'string' &&
|
|
13170
|
+
typeof session.createdAt === 'number' &&
|
|
13171
|
+
typeof session.sourcePackageSizeBytes === 'number' &&
|
|
13172
|
+
Boolean(session.request && typeof session.request === 'object');
|
|
13173
|
+
};
|
|
13174
|
+
|
|
13175
|
+
const readUploadSession = async (sourceRoot) => {
|
|
13176
|
+
try {
|
|
13177
|
+
const parsed = safeJsonParse(
|
|
13178
|
+
await promises.readFile(node_path.join(sourceRoot, UPLOAD_SESSION_FILENAME), 'utf8'),
|
|
13179
|
+
undefined,
|
|
13180
|
+
);
|
|
13181
|
+
return isUploadSession(parsed) ? parsed : undefined;
|
|
13182
|
+
} catch (error) {
|
|
13183
|
+
if ((error ).code === 'ENOENT') {
|
|
13184
|
+
return undefined;
|
|
13185
|
+
}
|
|
13186
|
+
throw error;
|
|
13187
|
+
}
|
|
13188
|
+
};
|
|
13189
|
+
|
|
13190
|
+
const writeUploadSession = async (sourceRoot, session) => {
|
|
13191
|
+
const path = node_path.join(sourceRoot, UPLOAD_SESSION_FILENAME);
|
|
13192
|
+
const tempPath = node_path.join(node_path.dirname(path), `.coze-deploy-upload-${node_crypto.randomUUID()}.tmp`);
|
|
13193
|
+
await promises.mkdir(node_path.dirname(path), { recursive: true });
|
|
13194
|
+
try {
|
|
13195
|
+
await promises.writeFile(tempPath, `${JSON.stringify(session, null, 2)}\n`, { encoding: 'utf8', mode: 0o600 });
|
|
13196
|
+
await promises.rename(tempPath, path);
|
|
13197
|
+
} finally {
|
|
13198
|
+
await promises.rm(tempPath, { force: true });
|
|
13199
|
+
}
|
|
13200
|
+
};
|
|
13201
|
+
|
|
13202
|
+
const removeUploadSession = async (sourceRoot) => {
|
|
13203
|
+
await promises.rm(node_path.join(sourceRoot, UPLOAD_SESSION_FILENAME), { force: true });
|
|
13204
|
+
};
|
|
13205
|
+
|
|
13206
|
+
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; }
|
|
13207
|
+
const INLINE_SOURCE_PACKAGE_MAX_BYTES = 1024 * 1024;
|
|
13208
|
+
const PRE_DEPLOY_SESSION_TTL_MS = 2 * 60 * 60 * 1000;
|
|
13209
|
+
|
|
13210
|
+
const uploadFile = async (
|
|
13211
|
+
uploadUrl,
|
|
13212
|
+
requiredHeaders,
|
|
13213
|
+
archive,
|
|
13214
|
+
) => {
|
|
13215
|
+
const uploadRequest = {
|
|
13216
|
+
method: 'PUT',
|
|
13217
|
+
headers: requiredHeaders,
|
|
13218
|
+
body: node_stream.Readable.toWeb(node_fs.createReadStream(archive.path)) ,
|
|
13219
|
+
duplex: 'half',
|
|
13220
|
+
};
|
|
13221
|
+
const response = await fetch(uploadUrl, uploadRequest);
|
|
13222
|
+
if (!response.ok) {
|
|
13223
|
+
throw new CliError(`Direct artifact upload failed: ${response.status} ${response.statusText}`, 'ARTIFACT_UPLOAD_FAILED');
|
|
13224
|
+
}
|
|
13225
|
+
};
|
|
13226
|
+
|
|
13227
|
+
const createDeploymentWithSourcePackage = async (
|
|
13228
|
+
client,
|
|
13229
|
+
request,
|
|
13230
|
+
archive,
|
|
13231
|
+
sourceRoot,
|
|
13232
|
+
) => {
|
|
13233
|
+
if (archive.sizeBytes <= INLINE_SOURCE_PACKAGE_MAX_BYTES) {
|
|
13234
|
+
const content = await promises.readFile(archive.path);
|
|
13235
|
+
return {
|
|
13236
|
+
uploadMode: 'inline' ,
|
|
13237
|
+
result: await client.createDeployHistory({ ...request, source_package_base64: content.toString('base64') }),
|
|
13238
|
+
};
|
|
13239
|
+
}
|
|
13240
|
+
|
|
13241
|
+
const savedSession = await readUploadSession(sourceRoot);
|
|
13242
|
+
let retryRequest = request;
|
|
13243
|
+
let reconciledSession = savedSession;
|
|
13244
|
+
if (_optionalChain$1([savedSession, 'optionalAccess', _ => _.appId]) && savedSession.deployHistoryId) {
|
|
13245
|
+
const history = await client.getDeployHistory({
|
|
13246
|
+
app_id: savedSession.appId,
|
|
13247
|
+
deploy_history_id: savedSession.deployHistoryId,
|
|
13248
|
+
});
|
|
13249
|
+
switch (history.status) {
|
|
13250
|
+
case DEPLOY_STATUS.preDeploy:
|
|
13251
|
+
// The server is authoritative for the session lifetime. Reuse the
|
|
13252
|
+
// original key even if the local two-hour clock is close to expiry;
|
|
13253
|
+
// pre_upload will either refresh the URL or release an expired slot.
|
|
13254
|
+
break;
|
|
13255
|
+
case DEPLOY_STATUS.pending:
|
|
13256
|
+
case DEPLOY_STATUS.running:
|
|
13257
|
+
case DEPLOY_STATUS.interrupted:
|
|
13258
|
+
case DEPLOY_STATUS.succeeded:
|
|
13259
|
+
// The previous create request was accepted but its response may have
|
|
13260
|
+
// been lost. Do not upload or create another deployment.
|
|
13261
|
+
await removeUploadSession(sourceRoot);
|
|
13262
|
+
return {
|
|
13263
|
+
uploadMode: 'direct' ,
|
|
13264
|
+
result: {
|
|
13265
|
+
app_id: savedSession.appId,
|
|
13266
|
+
deploy_history_id: savedSession.deployHistoryId,
|
|
13267
|
+
status: history.status,
|
|
13268
|
+
version: typeof history.version === 'number' ? history.version : undefined,
|
|
13269
|
+
},
|
|
13270
|
+
};
|
|
13271
|
+
case DEPLOY_STATUS.failed:
|
|
13272
|
+
case DEPLOY_STATUS.canceled:
|
|
13273
|
+
// The reserved history can no longer be claimed. Start a new upload
|
|
13274
|
+
// against the Application that pre_upload already created.
|
|
13275
|
+
await removeUploadSession(sourceRoot);
|
|
13276
|
+
reconciledSession = undefined;
|
|
13277
|
+
retryRequest = {
|
|
13278
|
+
...request,
|
|
13279
|
+
project_id: undefined,
|
|
13280
|
+
app_id: savedSession.appId,
|
|
13281
|
+
};
|
|
13282
|
+
break;
|
|
13283
|
+
default:
|
|
13284
|
+
throw new CliError(
|
|
13285
|
+
`Unable to reconcile pre-deploy history ${savedSession.deployHistoryId}: unknown status ${String(history.status)}.`,
|
|
13286
|
+
'INVALID_RESPONSE',
|
|
13287
|
+
);
|
|
13288
|
+
}
|
|
13289
|
+
}
|
|
13290
|
+
const liveSavedSession = reconciledSession && (
|
|
13291
|
+
reconciledSession.appId && reconciledSession.deployHistoryId ||
|
|
13292
|
+
Date.now() - reconciledSession.createdAt < PRE_DEPLOY_SESSION_TTL_MS
|
|
13293
|
+
)
|
|
13294
|
+
? reconciledSession
|
|
13295
|
+
: undefined;
|
|
13296
|
+
if (liveSavedSession && liveSavedSession.sourcePackageSizeBytes !== archive.sizeBytes) {
|
|
13297
|
+
throw new CliError(
|
|
13298
|
+
'A different source package is waiting for upload. Cancel that deployment or wait for its two-hour session to expire.',
|
|
13299
|
+
'PRE_DEPLOY_SOURCE_CHANGED',
|
|
13300
|
+
);
|
|
13301
|
+
}
|
|
13302
|
+
if (reconciledSession && !liveSavedSession) {
|
|
13303
|
+
await removeUploadSession(sourceRoot);
|
|
13304
|
+
}
|
|
13305
|
+
const resumableSession = liveSavedSession;
|
|
13306
|
+
const session = resumableSession || {
|
|
13307
|
+
idempotencyKey: node_crypto.randomUUID(),
|
|
13308
|
+
createdAt: Date.now(),
|
|
13309
|
+
sourcePackageSizeBytes: archive.sizeBytes,
|
|
13310
|
+
request: retryRequest,
|
|
13311
|
+
};
|
|
13312
|
+
// Persist before preDeployUpload: if the server creates PreDeploy but the response is lost,
|
|
13313
|
+
// the next CLI run must reuse the same idempotency key.
|
|
13314
|
+
await writeUploadSession(sourceRoot, session);
|
|
13315
|
+
const preDeploy = await client.preDeployUpload({
|
|
13316
|
+
...session.request,
|
|
13317
|
+
source_package_size_bytes: String(archive.sizeBytes),
|
|
13318
|
+
idempotency_key: session.idempotencyKey,
|
|
13319
|
+
});
|
|
13320
|
+
await writeUploadSession(sourceRoot, {
|
|
13321
|
+
...session,
|
|
13322
|
+
appId: preDeploy.app_id,
|
|
13323
|
+
deployHistoryId: preDeploy.deploy_history_id,
|
|
13324
|
+
uploadReceipt: preDeploy.upload_receipt,
|
|
13325
|
+
});
|
|
13326
|
+
await uploadFile(preDeploy.upload_url, preDeploy.required_headers || {}, archive);
|
|
13327
|
+
const result = await client.createDeployHistory({
|
|
13328
|
+
...session.request,
|
|
13329
|
+
project_id: undefined,
|
|
13330
|
+
app_id: preDeploy.app_id,
|
|
13331
|
+
pre_deploy_history_id: preDeploy.deploy_history_id,
|
|
13332
|
+
upload_receipt: preDeploy.upload_receipt,
|
|
13333
|
+
source_package_size_bytes: String(archive.sizeBytes),
|
|
13334
|
+
});
|
|
13335
|
+
await removeUploadSession(sourceRoot);
|
|
13336
|
+
return { uploadMode: 'direct' , result };
|
|
13337
|
+
};
|
|
13338
|
+
|
|
13339
|
+
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; }
|
|
13340
|
+
const SUPPORTED_MINIPROGRAM_CONNECTOR_IDS = new Set(['10000127', '10000126']);
|
|
13341
|
+
const collectConnectorId = (value, previous) => [
|
|
13342
|
+
...previous,
|
|
13343
|
+
value,
|
|
13344
|
+
];
|
|
13345
|
+
|
|
13346
|
+
const getConnectorConfigs = (connectorIds) =>
|
|
13347
|
+
(connectorIds || []).map(connectorId => {
|
|
13348
|
+
if (!SUPPORTED_MINIPROGRAM_CONNECTOR_IDS.has(connectorId)) {
|
|
13349
|
+
throw new CliError(
|
|
13350
|
+
`Unsupported connector ID ${connectorId}; expected 10000127 (WeChat) or 10000126 (Douyin).`,
|
|
13351
|
+
'INVALID_CONNECTOR_ID',
|
|
13352
|
+
);
|
|
13353
|
+
}
|
|
13354
|
+
return { connector_id: connectorId };
|
|
13355
|
+
});
|
|
13356
|
+
|
|
13357
|
+
// Keep deployment option and output contracts together for auditing against the V2 IDL.
|
|
13358
|
+
// eslint-disable-next-line @coze-arch/max-line-per-function -- keep V2 deployment contracts together
|
|
13359
|
+
const registerDeploy = (deploy) => {
|
|
13360
|
+
deploy
|
|
13361
|
+
.description('Deploy an application using deployment V2')
|
|
13362
|
+
.option('--source-root <sourceRoot>', 'Local source root', '.')
|
|
13363
|
+
.option('--project-id <projectId>', 'Project ID for the first deployment')
|
|
13364
|
+
.option('--app-id <appId>', 'Application ID')
|
|
13365
|
+
.option(
|
|
13366
|
+
'--application-type <type>',
|
|
13367
|
+
'Deployment application type: service, pages, or mini_program',
|
|
13368
|
+
)
|
|
13369
|
+
.option('-n, --name <name>', 'Application name for the first deployment')
|
|
13370
|
+
.option('--message <message>', 'Deployment message')
|
|
13371
|
+
.option(
|
|
13372
|
+
'--connector-id <connectorId>',
|
|
13373
|
+
'Mini-program channel: 10000127 (WeChat) or 10000126 (Douyin); repeatable',
|
|
13374
|
+
collectConnectorId,
|
|
13375
|
+
[],
|
|
13376
|
+
)
|
|
13377
|
+
.option('--wait', 'Wait for deployment completion')
|
|
13378
|
+
.option('--yes', 'Confirm deployment')
|
|
13379
|
+
// eslint-disable-next-line @coze-arch/max-line-per-function -- deployment orchestration is one auditable flow
|
|
13380
|
+
.action(async (options, command) => {
|
|
13381
|
+
const runtime = await getRuntime(command);
|
|
13382
|
+
const sourceRoot = node_path.resolve(runtime.cwd, options.sourceRoot || '.');
|
|
13383
|
+
const requestedApplicationType = parseApplicationType(options.applicationType);
|
|
13384
|
+
runtime.output.debug(`[deploy] Reading local project: ${sourceRoot}`);
|
|
13385
|
+
const localContext =
|
|
13386
|
+
await readDeployLocalContext(
|
|
13387
|
+
sourceRoot,
|
|
13388
|
+
requestedApplicationType,
|
|
13389
|
+
options.appId,
|
|
13390
|
+
runtime.client,
|
|
13391
|
+
);
|
|
13392
|
+
const { commitHash, isPagesDeployment } = localContext;
|
|
13393
|
+
let { metadata } = localContext;
|
|
13394
|
+
const deploymentName = _nullishCoalesce(options.name, () => ( metadata.name));
|
|
13395
|
+
let projectId = options.projectId || metadata.projectId;
|
|
13396
|
+
let appId = options.appId || metadata.appId;
|
|
13397
|
+
const appIdFromCoze = Boolean(metadata.appId && !options.appId);
|
|
13398
|
+
let projectCreated = false;
|
|
13399
|
+
let linkedApplicationType;
|
|
13400
|
+
if (appId) {
|
|
13401
|
+
const linkedApplication = await runtime.client.getApplication(appId);
|
|
13402
|
+
linkedApplicationType = linkedApplication.application_type;
|
|
13403
|
+
const linkedProjectId = linkedApplication.project_id;
|
|
13404
|
+
if (!options.appId && projectId && linkedProjectId && projectId !== linkedProjectId) {
|
|
13405
|
+
throw new CliError(
|
|
13406
|
+
`Project ${projectId} does not own application ${appId}; it belongs to project ${linkedProjectId}.`,
|
|
13407
|
+
'PROJECT_ID_CONFLICT',
|
|
13408
|
+
);
|
|
13409
|
+
}
|
|
13410
|
+
if (options.appId && linkedProjectId) {
|
|
13411
|
+
projectId = linkedProjectId;
|
|
13412
|
+
} else {
|
|
13413
|
+
projectId ||= linkedProjectId;
|
|
13414
|
+
}
|
|
13415
|
+
if (!projectId) {
|
|
13416
|
+
throw new CliError(
|
|
13417
|
+
`Application ${appId} did not return its associated project_id.`,
|
|
13418
|
+
'INVALID_RESPONSE',
|
|
13419
|
+
);
|
|
13420
|
+
}
|
|
13421
|
+
const inferredApplicationType = linkedApplicationType === 'pages'
|
|
13422
|
+
? 'pages'
|
|
13423
|
+
: inferApplicationTypeFromProjectType(metadata.projectType);
|
|
13424
|
+
const targetApplicationType = requestedApplicationType || inferredApplicationType;
|
|
13425
|
+
if (appIdFromCoze && targetApplicationType && linkedApplicationType !== targetApplicationType) {
|
|
13426
|
+
runtime.output.warn(
|
|
13427
|
+
`The linked application ${appId} is ${linkedApplicationType}, but ${targetApplicationType} is required. A new application will be created and written to .coze.`,
|
|
13428
|
+
);
|
|
13429
|
+
appId = undefined;
|
|
13430
|
+
}
|
|
13431
|
+
}
|
|
13432
|
+
if (!projectId) {
|
|
13433
|
+
runtime.output.debug(
|
|
13434
|
+
'[deploy] Creating a dedicated deployment project in personal space...',
|
|
13435
|
+
);
|
|
13436
|
+
// 账号归属只在建 Project 这一次定死:写进 project_settings.extra 之后,有登录态的首次
|
|
13437
|
+
// 部署和无登录态的预览初始化读到的是同一个账号。本地已经知道账号就不打这次接口。
|
|
13438
|
+
const cozeAccountId = await resolveCozeAccountId(runtime);
|
|
13439
|
+
const project = await runtime.client.createDeploymentProject({
|
|
13440
|
+
space_id: '0',
|
|
13441
|
+
user_query: deploymentName || 'CLI deployment project',
|
|
13442
|
+
project_type: resolveCreationProjectType(metadata.projectType),
|
|
13443
|
+
create_source: 'cli',
|
|
13444
|
+
project_settings: {
|
|
13445
|
+
project_symbol: 'v3.5',
|
|
13446
|
+
...(cozeAccountId ? { extra: { coze_account_id: cozeAccountId } } : {}),
|
|
13447
|
+
},
|
|
13448
|
+
});
|
|
13449
|
+
projectId = project.project_id;
|
|
13450
|
+
projectCreated = true;
|
|
13451
|
+
}
|
|
13452
|
+
if (metadata.projectId !== projectId) {
|
|
13453
|
+
metadata = await writeProjectBinding(sourceRoot, { projectId });
|
|
13454
|
+
}
|
|
13455
|
+
runtime.output.debug(`[deploy] Using project ${projectId} from ${projectCreated ? 'new project' : options.projectId ? '--project-id' : appId ? 'application binding' : '.coze'}`);
|
|
13456
|
+
const cozeFileContent = metadata.cozeFileContent;
|
|
13457
|
+
runtime.output.debug('[deploy] Loading deployment configuration...');
|
|
13458
|
+
const serverConfig = await runtime.client.getDeployConfig({
|
|
13459
|
+
...(appId ? { app_id: appId } : { project_id: projectId }),
|
|
13460
|
+
commit_hash: commitHash,
|
|
13461
|
+
...(isPagesDeployment ? { application_type: 'pages' } : {}),
|
|
13462
|
+
...(cozeFileContent ? { coze_file_content: cozeFileContent } : {}),
|
|
13463
|
+
});
|
|
13464
|
+
const config = withRequestedApplicationType(
|
|
13465
|
+
serverConfig,
|
|
13466
|
+
requestedApplicationType,
|
|
13467
|
+
Boolean(appId),
|
|
13468
|
+
);
|
|
13469
|
+
const applicationType = config.application_type;
|
|
13470
|
+
const connectorConfigs = getConnectorConfigs(options.connectorId);
|
|
13471
|
+
if (!options.yes) {
|
|
13472
|
+
runtime.output.debug('[deploy] Preflight complete; confirmation is required.');
|
|
13473
|
+
runtime.output.print({
|
|
13474
|
+
confirmation_required: true,
|
|
13475
|
+
app_id: appId,
|
|
13476
|
+
project_id: projectId,
|
|
13477
|
+
application_type: applicationType,
|
|
13478
|
+
commit_hash: commitHash,
|
|
13479
|
+
source_root: sourceRoot,
|
|
13480
|
+
deploy_config: config.deploy_config,
|
|
13481
|
+
current_version: config.current_version,
|
|
13482
|
+
next_version: config.next_version,
|
|
13483
|
+
risks: config.risk_list || [],
|
|
13484
|
+
...(!appId && deploymentName ? { name: deploymentName } : {}),
|
|
13485
|
+
message: options.message,
|
|
13486
|
+
lane: runtime.globalOptions.lane || runtime.config.xTTEnv,
|
|
13487
|
+
});
|
|
13488
|
+
return;
|
|
13489
|
+
}
|
|
13490
|
+
let encryptEnvVariable;
|
|
13491
|
+
if (applicationType !== 'pages') {
|
|
13492
|
+
runtime.output.debug('[deploy] Loading and encrypting online environment variables...');
|
|
13493
|
+
const onlineEnvironment = appId
|
|
13494
|
+
? await runtime.client.getOnlineEnvironment(appId)
|
|
13495
|
+
: undefined;
|
|
13496
|
+
if (onlineEnvironment && onlineEnvironment.snapshot_status >= 3) {
|
|
13497
|
+
throw new CliError(
|
|
13498
|
+
onlineEnvironment.status_message ||
|
|
13499
|
+
'The current online environment snapshot is unavailable.',
|
|
13500
|
+
'ONLINE_ENVIRONMENT_UNAVAILABLE',
|
|
13501
|
+
);
|
|
13502
|
+
}
|
|
13503
|
+
const envSecrets = (_optionalChain([onlineEnvironment, 'optionalAccess', _ => _.variables]) || [])
|
|
13504
|
+
.filter(variable => variable.source === 'user')
|
|
13505
|
+
.map(variable => ({
|
|
13506
|
+
secret_id: '',
|
|
13507
|
+
secret_key: variable.key,
|
|
13508
|
+
secret_val: variable.value,
|
|
13509
|
+
secret_type: 'user_custom' ,
|
|
13510
|
+
}));
|
|
13511
|
+
const encrypted = await runtime.client.encryptProjectSecret(projectId, envSecrets);
|
|
13512
|
+
encryptEnvVariable = encrypted.sealed_secrets;
|
|
13513
|
+
if (!encryptEnvVariable) {
|
|
13514
|
+
throw new CliError(
|
|
13515
|
+
'The project secret encryption API returned no sealed_secrets.',
|
|
13516
|
+
'INVALID_RESPONSE',
|
|
13517
|
+
);
|
|
13518
|
+
}
|
|
13519
|
+
}
|
|
13520
|
+
runtime.output.debug(
|
|
13521
|
+
`[deploy] Building and packaging ${applicationType} artifact...`,
|
|
13522
|
+
);
|
|
13523
|
+
const sourcePackage = await createSourcePackageArchive(
|
|
13524
|
+
sourceRoot,
|
|
13525
|
+
applicationType,
|
|
13526
|
+
runtime.globalOptions.debug,
|
|
13527
|
+
);
|
|
13528
|
+
runtime.output.debug(
|
|
13529
|
+
`[deploy] Package ready: ${String(sourcePackage.sizeBytes)} bytes`,
|
|
13530
|
+
);
|
|
13531
|
+
runtime.output.debug('[deploy] Uploading package and creating deployment...');
|
|
13532
|
+
const deploymentRequest = {
|
|
13533
|
+
...(appId ? { app_id: appId } : { project_id: projectId }),
|
|
13534
|
+
application_type: applicationType,
|
|
13535
|
+
commit_hash: commitHash,
|
|
13536
|
+
...(options.message ? { commit_message: options.message } : {}),
|
|
13537
|
+
...(!appId
|
|
13538
|
+
? { name: deploymentName, source_root: sourceRoot }
|
|
13539
|
+
: {}),
|
|
13540
|
+
is_sync_db_to_prod: false,
|
|
13541
|
+
table_sync_configs: [],
|
|
13542
|
+
connector_configs: connectorConfigs,
|
|
13543
|
+
...(cozeFileContent ? { coze_file_content: cozeFileContent } : {}),
|
|
13544
|
+
...(encryptEnvVariable
|
|
13545
|
+
? { encrypt_env_variable: encryptEnvVariable }
|
|
13546
|
+
: {}),
|
|
13547
|
+
...getCreateDeployConfig(config),
|
|
13548
|
+
};
|
|
13549
|
+
let deployment;
|
|
13550
|
+
try {
|
|
13551
|
+
deployment = await createDeploymentWithSourcePackage(runtime.client, deploymentRequest, sourcePackage, sourceRoot);
|
|
13552
|
+
} finally {
|
|
13553
|
+
await sourcePackage.cleanup();
|
|
13554
|
+
}
|
|
13555
|
+
const { result } = deployment;
|
|
13556
|
+
const deployHistoryId = resolveDeployHistoryId(
|
|
13557
|
+
result.deploy_history_id,
|
|
13558
|
+
result.prev_deploy_history_id,
|
|
13559
|
+
);
|
|
13560
|
+
if (!deployHistoryId) {
|
|
13561
|
+
throw new CliError('Deployment response returned no deploy_history_id.', 'INVALID_RESPONSE');
|
|
13562
|
+
}
|
|
13563
|
+
if (metadata.appId !== result.app_id || metadata.projectId !== projectId) {
|
|
13564
|
+
await writeProjectBinding(sourceRoot, {
|
|
13565
|
+
projectId,
|
|
13566
|
+
appId: result.app_id,
|
|
13567
|
+
});
|
|
13568
|
+
if (!appId) {
|
|
13569
|
+
runtime.output.warn(`Created application ${result.app_id} and saved it to .coze.`);
|
|
13570
|
+
}
|
|
13571
|
+
}
|
|
13572
|
+
if (options.wait) {
|
|
13573
|
+
runtime.output.debug('[deploy] Deployment accepted; waiting for completion...');
|
|
13574
|
+
} else {
|
|
13575
|
+
runtime.output.debug('[deploy] Deployment accepted.');
|
|
13576
|
+
}
|
|
13577
|
+
const history = options.wait
|
|
13578
|
+
? await pollHistory(command, result.app_id, deployHistoryId)
|
|
13579
|
+
: undefined;
|
|
13580
|
+
// 不带 --wait 时 history 是 undefined,产物必然还没落库:这里一定会带上
|
|
13581
|
+
// artifacts_pending,而不是甩一个看起来像「查过了,没有」的空数组出去。
|
|
13582
|
+
const effectiveStatus = _nullishCoalesce(_optionalChain([history, 'optionalAccess', _2 => _2.status]), () => ( result.status));
|
|
13583
|
+
runtime.output.print({
|
|
13584
|
+
app_id: result.app_id,
|
|
13585
|
+
deploy_history_id: deployHistoryId,
|
|
13586
|
+
version: result.version,
|
|
13587
|
+
commit_hash: commitHash,
|
|
13588
|
+
status: getDeployStatusText(effectiveStatus),
|
|
13589
|
+
source_package_size_bytes: sourcePackage.sizeBytes,
|
|
13590
|
+
upload_mode: deployment.uploadMode,
|
|
13591
|
+
local_link: appId && !projectCreated ? 'unchanged' : 'written',
|
|
13592
|
+
...mobileArtifactsOutput(history, effectiveStatus),
|
|
13593
|
+
});
|
|
13594
|
+
});
|
|
13595
|
+
|
|
13596
|
+
registerDeployReadCommands(deploy);
|
|
13597
|
+
|
|
13598
|
+
deploy
|
|
13599
|
+
.command('cancel')
|
|
13600
|
+
.requiredOption('--deploy-id <deployId>', 'Deployment history ID')
|
|
13601
|
+
.option('--app-id <appId>', 'Application ID')
|
|
13602
|
+
.option('--yes', 'Confirm cancellation')
|
|
13603
|
+
.action(async (options, command) => {
|
|
13604
|
+
const parentOptions = getDeployParentOptions(command);
|
|
13605
|
+
if (!options.yes && !parentOptions.yes) {
|
|
13606
|
+
throw new CliError('Pass --yes to cancel deployment.', 'CONFIRMATION_REQUIRED');
|
|
13607
|
+
}
|
|
13608
|
+
const runtime = await getRuntime(command);
|
|
13609
|
+
const appId = await requireAppId(runtime.cwd, getDeployAppIdOption(options, command));
|
|
13610
|
+
await runtime.client.cancelDeployHistory({
|
|
13611
|
+
app_id: appId,
|
|
13612
|
+
deploy_history_id: options.deployId || '',
|
|
13613
|
+
});
|
|
13614
|
+
runtime.output.print({ app_id: appId, canceled: true });
|
|
13615
|
+
});
|
|
13616
|
+
|
|
13617
|
+
deploy
|
|
13618
|
+
.command('rollback')
|
|
13619
|
+
.requiredOption('--deploy-id <deployId>', 'Target deployment history ID')
|
|
13620
|
+
.option('--app-id <appId>', 'Application ID')
|
|
13621
|
+
.option('--rollback-database', 'Rollback database')
|
|
13622
|
+
.option('--yes', 'Confirm rollback')
|
|
13623
|
+
.action(async (options, command) => {
|
|
13624
|
+
const parentOptions = getDeployParentOptions(command);
|
|
13625
|
+
if (!options.yes && !parentOptions.yes) {
|
|
13626
|
+
throw new CliError('Pass --yes to rollback.', 'CONFIRMATION_REQUIRED');
|
|
13627
|
+
}
|
|
13628
|
+
const runtime = await getRuntime(command);
|
|
13629
|
+
const appId = await requireAppId(runtime.cwd, getDeployAppIdOption(options, command));
|
|
13630
|
+
const data = await runtime.client.rollbackDeployHistory({
|
|
13631
|
+
app_id: appId,
|
|
13632
|
+
target_deploy_history_id: options.deployId || '',
|
|
13633
|
+
rollback_database: _nullishCoalesce(options.rollbackDatabase, () => ( false)),
|
|
13634
|
+
});
|
|
13635
|
+
runtime.output.print({ app_id: appId, ...data });
|
|
13636
|
+
});
|
|
13637
|
+
|
|
13638
|
+
// stop 不可逆(删函数 → Stopped,只能重新部署),pause 可逆(→ Paused,resume 能推回 Ready)。
|
|
13639
|
+
const applicationActions = {
|
|
13640
|
+
stop: (client, appId) => client.stopApplication(appId),
|
|
13641
|
+
resume: (client, appId) => client.resumeApplication(appId),
|
|
13642
|
+
pause: (client, appId) => client.pauseApplication(appId),
|
|
13643
|
+
} ;
|
|
13644
|
+
|
|
13645
|
+
for (const action of Object.keys(applicationActions) ) {
|
|
13646
|
+
deploy
|
|
13647
|
+
.command(action)
|
|
13648
|
+
.option('--app-id <appId>', 'Application ID')
|
|
13649
|
+
.option('--yes', `Confirm ${action}`)
|
|
13650
|
+
.action(async (options, command) => {
|
|
13651
|
+
const parentOptions = getDeployParentOptions(command);
|
|
13652
|
+
if (!options.yes && !parentOptions.yes) {
|
|
13653
|
+
throw new CliError(`Pass --yes to ${action}.`, 'CONFIRMATION_REQUIRED');
|
|
13654
|
+
}
|
|
13655
|
+
const runtime = await getRuntime(command);
|
|
13656
|
+
const appId = await requireAppId(runtime.cwd, getDeployAppIdOption(options, command));
|
|
13657
|
+
await applicationActions[action](runtime.client, appId);
|
|
13658
|
+
runtime.output.print({ app_id: appId, action, success: true });
|
|
13659
|
+
});
|
|
13660
|
+
}
|
|
13661
|
+
|
|
13662
|
+
deploy
|
|
13663
|
+
.command('logs')
|
|
13664
|
+
.option('--app-id <appId>', 'Application ID')
|
|
13665
|
+
.option('--start-time <startTime>', 'Start time in milliseconds')
|
|
13666
|
+
.option('--end-time <endTime>', 'End time in milliseconds')
|
|
13667
|
+
.option('--limit <limit>', 'Page size')
|
|
13668
|
+
.option('--cursor <cursor>', 'Pagination cursor')
|
|
13669
|
+
.option('--query <query>', 'Log keyword')
|
|
13670
|
+
.option('--level <level>', 'all, info, warn, or error')
|
|
13671
|
+
.action(async (options, command) => {
|
|
13672
|
+
const runtime = await getRuntime(command);
|
|
13673
|
+
const appId = await requireAppId(runtime.cwd, getDeployAppIdOption(options, command));
|
|
13674
|
+
runtime.output.print(
|
|
13675
|
+
await runtime.client.searchRuntimeLog({
|
|
13676
|
+
app_id: appId,
|
|
13677
|
+
start_time: options.startTime,
|
|
13678
|
+
end_time: options.endTime,
|
|
13679
|
+
limit: options.limit,
|
|
13680
|
+
cursor: options.cursor,
|
|
13681
|
+
query: options.query,
|
|
13682
|
+
level: options.level,
|
|
13683
|
+
}),
|
|
13684
|
+
);
|
|
13685
|
+
});
|
|
13686
|
+
|
|
13687
|
+
deploy
|
|
13688
|
+
.command('build-log')
|
|
13689
|
+
.requiredOption('--deploy-id <deployId>', 'Deployment history ID')
|
|
13690
|
+
.option('--key <key>', 'Deployment log key; inferred when the deployment has one log')
|
|
13691
|
+
.option('--app-id <appId>', 'Application ID')
|
|
13692
|
+
.action(async (options, command) => {
|
|
13693
|
+
const runtime = await getRuntime(command);
|
|
13694
|
+
const appId = await requireAppId(runtime.cwd, getDeployAppIdOption(options, command));
|
|
13695
|
+
let key = _optionalChain([options, 'access', _3 => _3.key, 'optionalAccess', _4 => _4.trim, 'call', _5 => _5()]);
|
|
13696
|
+
if (!key) {
|
|
13697
|
+
const history = await runtime.client.getDeployHistory({
|
|
13698
|
+
app_id: appId,
|
|
13699
|
+
deploy_history_id: options.deployId || '',
|
|
13700
|
+
});
|
|
13701
|
+
const keys = getDeployLogKeys(history);
|
|
13702
|
+
if (keys.length === 0) {
|
|
13703
|
+
throw new CliError(
|
|
13704
|
+
'The deployment has no build log key yet. Retry after deployment stages start.',
|
|
13705
|
+
'BUILD_LOG_NOT_READY',
|
|
13706
|
+
);
|
|
13707
|
+
}
|
|
13708
|
+
if (keys.length > 1) {
|
|
13709
|
+
throw new CliError(
|
|
13710
|
+
'The deployment has multiple build logs. Pass --key using deploy status output.',
|
|
13711
|
+
'BUILD_LOG_KEY_REQUIRED',
|
|
13712
|
+
{ available_keys: keys },
|
|
13713
|
+
);
|
|
13714
|
+
}
|
|
13715
|
+
key = keys[0];
|
|
13716
|
+
}
|
|
13717
|
+
if (!key) {
|
|
13718
|
+
throw new CliError('Deployment log key is empty.', 'BUILD_LOG_NOT_READY');
|
|
13719
|
+
}
|
|
13720
|
+
runtime.output.print(
|
|
13721
|
+
await runtime.client.getBuildLog({
|
|
13722
|
+
app_id: appId,
|
|
13723
|
+
deploy_history_id: options.deployId || '',
|
|
13724
|
+
key,
|
|
13725
|
+
}),
|
|
13726
|
+
);
|
|
13727
|
+
});
|
|
13728
|
+
|
|
13729
|
+
deploy
|
|
13730
|
+
.command('config')
|
|
13731
|
+
.option('--app-id <appId>', 'Application ID')
|
|
13732
|
+
.option('--commit-id <commitId>', 'Commit hash')
|
|
13733
|
+
.action(async (options, command) => {
|
|
13734
|
+
const runtime = await getRuntime(command);
|
|
13735
|
+
const appId = await requireAppId(runtime.cwd, getDeployAppIdOption(options, command));
|
|
13736
|
+
const application = await runtime.client.getApplication(appId);
|
|
13737
|
+
const commitHash = options.commitId || _optionalChain([application, 'access', _6 => _6.latest_deployment, 'optionalAccess', _7 => _7.commit_hash]);
|
|
13738
|
+
if (!commitHash) {
|
|
13739
|
+
throw new CliError('No deployment commit is available.', 'DEPLOYMENT_NOT_FOUND');
|
|
13740
|
+
}
|
|
13741
|
+
const applicationType = application.application_type;
|
|
13742
|
+
const cozeFileContent = applicationType === 'pages'
|
|
13743
|
+
? undefined
|
|
13744
|
+
: (await readProjectMetadata(node_path.resolve(runtime.cwd))).cozeFileContent;
|
|
13745
|
+
runtime.output.print(
|
|
13746
|
+
await runtime.client.getDeployConfig({
|
|
13747
|
+
app_id: appId,
|
|
13748
|
+
commit_hash: commitHash,
|
|
13749
|
+
...(applicationType === 'pages' ? { application_type: 'pages' } : {}),
|
|
13750
|
+
...(cozeFileContent ? { coze_file_content: cozeFileContent } : {}),
|
|
13751
|
+
}),
|
|
13752
|
+
);
|
|
13753
|
+
});
|
|
13754
|
+
};
|
|
13755
|
+
|
|
13756
|
+
const registerCommands = (program) => {
|
|
13757
|
+
registerAuth(program);
|
|
13758
|
+
registerContext(program);
|
|
13759
|
+
registerDoctor(program);
|
|
13760
|
+
|
|
13761
|
+
// Keep deployment operations directly under `coze-dev deploy` so the common
|
|
13762
|
+
// path is concise: `coze-dev deploy`, `coze-dev deploy status`, etc.
|
|
13763
|
+
registerDeploy(program);
|
|
13764
|
+
registerApp(program);
|
|
13765
|
+
registerDomain(program);
|
|
13766
|
+
registerEnv(program);
|
|
13767
|
+
registerMiniProgram(program);
|
|
13768
|
+
|
|
13769
|
+
// Preserve the original `coze-dev deploy code ...` hierarchy for scripts and
|
|
13770
|
+
// older plugin versions that still rely on it.
|
|
13771
|
+
const code = program.command('code', { hidden: true }).description('Legacy deployment operations');
|
|
13772
|
+
registerApp(code);
|
|
13773
|
+
registerDeploy(code.command('deploy'));
|
|
13774
|
+
registerDomain(code);
|
|
13775
|
+
registerEnv(code);
|
|
13776
|
+
registerMiniProgram(code);
|
|
13777
|
+
};
|
|
13778
|
+
|
|
13779
|
+
const configureDeployCommand = (command) => {
|
|
13780
|
+
markDeployCommand(command)
|
|
13781
|
+
.description('Deploy and manage Coze applications')
|
|
13782
|
+
.enablePositionalOptions()
|
|
13783
|
+
.option('--format <format>', 'Output format: json or text', 'json')
|
|
13784
|
+
.option('--config <path>', 'Shared Coze CLI config path')
|
|
13785
|
+
.option('--org-id <id>', 'Override organization ID')
|
|
13786
|
+
.option('--space-id <id>', 'Override space ID')
|
|
13787
|
+
.option('--lane <name>', 'Route API requests to the specified PPE lane')
|
|
13788
|
+
.option('--api-base-url <url>', 'Override API base URL')
|
|
13789
|
+
.option('--debug', 'Print debug diagnostics')
|
|
13790
|
+
.showHelpAfterError()
|
|
13791
|
+
.exitOverride();
|
|
13792
|
+
registerCommands(command);
|
|
13793
|
+
return command;
|
|
13794
|
+
};
|
|
13795
|
+
|
|
13796
|
+
const registerCommand = (program) => {
|
|
13797
|
+
configureDeployCommand(program.command('deploy'));
|
|
13798
|
+
};
|
|
13799
|
+
|
|
13800
|
+
const readFormat = (argv) => {
|
|
13801
|
+
const index = argv.indexOf('--format');
|
|
13802
|
+
return index >= 0 && argv[index + 1] === 'text' ? 'text' : 'json';
|
|
13803
|
+
};
|
|
13804
|
+
|
|
13805
|
+
const handleDeployError = (error, argv = process.argv) => {
|
|
13806
|
+
if (
|
|
13807
|
+
error instanceof commander.CommanderError &&
|
|
13808
|
+
['commander.helpDisplayed', 'commander.version'].includes(error.code)
|
|
13809
|
+
) {
|
|
13810
|
+
return;
|
|
13811
|
+
}
|
|
13812
|
+
const output = new Output(readFormat(argv), argv.includes('--debug'));
|
|
13813
|
+
output.print({ error: toErrorPayload(error) });
|
|
13814
|
+
process.exitCode = error instanceof commander.CommanderError ? 4 : 1;
|
|
13815
|
+
};
|
|
13816
|
+
|
|
13817
|
+
const commands = [
|
|
13818
|
+
registerCommand$1,
|
|
13819
|
+
registerCommand$4,
|
|
13820
|
+
registerCommand$7,
|
|
13821
|
+
registerCommand$5,
|
|
13822
|
+
registerCommand$6,
|
|
13823
|
+
registerCommand$3,
|
|
13824
|
+
registerCommand$2,
|
|
13825
|
+
registerCommand,
|
|
13826
|
+
];
|
|
13827
|
+
|
|
13828
|
+
const main = async () => {
|
|
13829
|
+
// 初始化 Slardar 监控
|
|
13830
|
+
initSlardar();
|
|
13831
|
+
|
|
13832
|
+
// 监听未捕获的异常
|
|
13833
|
+
process.on('uncaughtException', async (error) => {
|
|
13834
|
+
reportError(error, {
|
|
13835
|
+
type: 'uncaughtException',
|
|
13836
|
+
context: 'global',
|
|
13837
|
+
});
|
|
13838
|
+
await flushSlardar();
|
|
13839
|
+
process.exit(1);
|
|
13840
|
+
});
|
|
13841
|
+
|
|
13842
|
+
// 监听未处理的 Promise rejection
|
|
13843
|
+
process.on('unhandledRejection', async (reason) => {
|
|
13844
|
+
const error = reason instanceof Error ? reason : new Error(String(reason));
|
|
13845
|
+
reportError(error, {
|
|
13846
|
+
type: 'unhandledRejection',
|
|
13847
|
+
context: 'global',
|
|
13848
|
+
});
|
|
13849
|
+
await flushSlardar();
|
|
13850
|
+
process.exit(1);
|
|
13851
|
+
});
|
|
13852
|
+
|
|
13853
|
+
const program = new commander.Command();
|
|
13854
|
+
|
|
13855
|
+
program
|
|
13856
|
+
.name('coze-dev')
|
|
13857
|
+
.description(
|
|
13858
|
+
'Coze Coding CLI - Project template engine for frontend stacks',
|
|
13859
|
+
)
|
|
13860
|
+
.version(packageJson.version);
|
|
13861
|
+
|
|
13862
|
+
commands.forEach(initCmd => initCmd(program));
|
|
13863
|
+
|
|
13864
|
+
// 在 help 输出中添加模板信息
|
|
13865
|
+
program.addHelpText('after', generateTemplatesHelpText());
|
|
13866
|
+
|
|
13867
|
+
// 使用 parseAsync 等待命令执行完成
|
|
13868
|
+
try {
|
|
13869
|
+
await program.parseAsync(process.argv);
|
|
13870
|
+
} catch (error) {
|
|
13871
|
+
if (process.argv[2] === 'deploy') {
|
|
13872
|
+
handleDeployError(error);
|
|
13873
|
+
} else {
|
|
13874
|
+
throw error;
|
|
13875
|
+
}
|
|
13876
|
+
}
|
|
10370
13877
|
|
|
10371
13878
|
// 统一在命令执行完成后 flush
|
|
10372
13879
|
// 注意:如果命令中调用了 process.exit(),不会执行到这里
|