@ttmg/cli 0.3.2-beta.9 → 0.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. package/CHANGELOG.md +4 -1
  2. package/dist/index.js +166 -23
  3. package/dist/index.js.map +1 -1
  4. package/dist/package.json +2 -2
  5. package/dist/public/assets/{index-DCvzzS3c.js → index-BBJshfB_.js} +1 -1
  6. package/dist/public/assets/index-BBJshfB_.js.br +0 -0
  7. package/dist/public/assets/{index-CZeMe3yb.js → index-Bxrlcdy9.js} +1 -1
  8. package/dist/public/assets/index-Bxrlcdy9.js.br +0 -0
  9. package/dist/public/assets/{index-BGB_3rmy.js → index-CgXh9-IR.js} +2 -2
  10. package/dist/public/assets/index-CgXh9-IR.js.br +0 -0
  11. package/dist/public/assets/{index-B7gDE9jg.js → index-CnpdpEXV.js} +1 -1
  12. package/dist/public/assets/{index-BGxy8aq-.js → index-DZ4Lot5a.js} +1 -1
  13. package/dist/public/assets/index-DZ4Lot5a.js.br +0 -0
  14. package/dist/public/assets/index-DZSJz0Hu.js +1 -0
  15. package/dist/public/assets/{index-DZh72DCT.js → index-D_UafQRj.js} +1 -1
  16. package/dist/public/assets/{index-dPxUjVAV.js → index-DqhIu6n9.js} +1 -1
  17. package/dist/public/assets/{index-C-hKdJe4.js → index-Dwl4ZYBR.js} +1 -1
  18. package/dist/public/assets/{index-Be7GH3NR.js → index-IjT-c81T.js} +1 -1
  19. package/dist/public/assets/{index-NjsKimh-.js → index-liPKaTSM.js} +1 -1
  20. package/dist/public/assets/{index-DTYGiGBE.js → index-maYHtPXK.js} +1 -1
  21. package/dist/public/index.html +1 -1
  22. package/package.json +2 -2
  23. package/dist/public/assets/index-BGB_3rmy.js.br +0 -0
  24. package/dist/public/assets/index-BGxy8aq-.js.br +0 -0
  25. package/dist/public/assets/index-CZeMe3yb.js.br +0 -0
  26. package/dist/public/assets/index-DCvzzS3c.js.br +0 -0
  27. package/dist/public/assets/index-sz2rmYug.js +0 -1
package/CHANGELOG.md CHANGED
@@ -198,4 +198,7 @@ API 预检建议文案统一收敛,避免重复提示,阅读更清晰
198
198
  顶部区域透出项目预检错误与警告信息,便于开发者及时发现问题并修复
199
199
  语言选择策略优化:优先使用 CLI 本地设置,未设置时自动回退浏览器语言
200
200
  启动校验增强:检查是否在小游戏根目录执行,对于分包配置 subPackages 给出明确报错,引导开发者修改为 subpackages
201
- 修复项目详情中展示的主包大小限制和代码预检不一致的情况
201
+ 修复项目详情中展示的主包大小限制和代码预检不一致的情况
202
+
203
+ ## 0.3.3
204
+ 升级 ttmg-pack 到 0.4.5,解决安卓无法调试 unity 项目问题
package/dist/index.js CHANGED
@@ -6507,7 +6507,14 @@ const getCurrentUser = () => {
6507
6507
  // ppe_dev_tool
6508
6508
  function getAxiosProxyConfig() {
6509
6509
  const config = getTTMGRC();
6510
- const proxyUrl = config?.proxy;
6510
+ // 优先级: http-proxy > socks-proxy > proxy (老字段兼容)
6511
+ let proxyUrl = config?.['http-proxy'];
6512
+ if (!proxyUrl) {
6513
+ proxyUrl = config?.['socks-proxy'];
6514
+ }
6515
+ if (!proxyUrl) {
6516
+ proxyUrl = config?.proxy;
6517
+ }
6511
6518
  if (proxyUrl) {
6512
6519
  let agent;
6513
6520
  if (proxyUrl.startsWith('socks')) {
@@ -6779,6 +6786,7 @@ const messages = {
6779
6786
  'cli.option.dev.h5': 'Debug TikTok Mini Games for Web',
6780
6787
  'cli.command.login.desc': 'Login with developer account',
6781
6788
  'cli.command.login.verbose': 'Print verbose logs for debugging',
6789
+ 'cli.command.logout.desc': 'Logout and clear local user data',
6782
6790
  'cli.command.setup.desc': 'Initialize ttmg environment',
6783
6791
  'cli.command.setup.lang': 'Language (only supports): en-US | zh-CN',
6784
6792
  'cli.command.reset.desc': 'Reset local CLI state',
@@ -6789,6 +6797,10 @@ const messages = {
6789
6797
  'cli.command.config.set.desc': 'Set a configuration value',
6790
6798
  'cli.command.config.get.desc': 'Get a configuration value',
6791
6799
  'cli.command.config.delete.desc': 'Delete a configuration value',
6800
+ 'cli.command.upload.desc': 'Upload Mini Game to Developer Platform',
6801
+ 'cli.command.upload.clientKey': 'Client Key of the Mini Game',
6802
+ 'cli.command.upload.note': 'Note for the upload',
6803
+ 'cli.command.upload.dir': 'Game project directory (default: current directory)',
6792
6804
  'cli.option.h5': 'H5 Mini Game',
6793
6805
  'cli.native.init.placeholder': 'Native Mini Game initialize',
6794
6806
  'cli.native.build.placeholder': 'Native Mini Game bundle',
@@ -6830,9 +6842,12 @@ const messages = {
6830
6842
  'login.error.withCode': 'Login failed: {message}, error_code: {code}',
6831
6843
  'login.error.withMessage': 'Login failed: {message}',
6832
6844
  'login.error.noUserId': 'Login failed. No user_id in response.',
6833
- 'login.warning.proxyIssue': 'The response does not look like the login API (e.g. proxy returned "Connection established" instead of forwarding the real response).\n\nThe API is not reachable from mainland without proxy. Please ensure your proxy correctly forwards HTTPS to developers.tiktok.com: try another proxy node, or check that the proxy is in global/tunnel mode and not intercepting HTTPS.\n\nProxy troubleshooting doc:\nhttps://bytedance.larkoffice.com/wiki/ZblJwT0ZNil9jJkS8EgcFlcQnFc',
6845
+ 'login.warning.proxyIssue': 'The response does not look like the login API (e.g. proxy returned "Connection established" instead of forwarding the real response).\n\nThe API is not reachable from mainland without proxy. Please ensure your proxy correctly forwards HTTPS to developers.tiktok.com: try another proxy node, or configure the CLI internal proxy using `ttmg config set proxy socks5://...`.\n\nProxy troubleshooting doc:\nhttps://bytedance.larkoffice.com/wiki/PeIawT4M4ia9R8kYyLMcjwHknOg',
6834
6846
  'login.error.connectService': 'Failed to connect to login service',
6835
- 'login.error.networkBlocked': "Detected that the current terminal's network proxy settings are preventing external network access.\n\nPlease check your local terminal proxy configuration. You can follow this doc to modify your terminal network settings:\nhttps://bytedance.larkoffice.com/wiki/ZblJwT0ZNil9jJkS8EgcFlcQnFc",
6847
+ 'login.error.networkBlocked': "Network connection failed. This is usually caused by advanced proxy settings (e.g., fake-ip mode) or incorrect terminal proxy environment variables.\n\nWe strongly recommend turning off global proxy mode and configuring the CLI internal proxy using:\n ttmg config set proxy socks5://127.0.0.1:<your_socks_port>\n\nFor detailed solutions, please refer to the proxy troubleshooting doc:\nhttps://bytedance.larkoffice.com/wiki/PeIawT4M4ia9R8kYyLMcjwHknOg",
6848
+ 'logout.spinner.loggingOut': 'Logging out...',
6849
+ 'logout.success': 'Logged out successfully!',
6850
+ 'logout.fail': 'Logout failed: {error}',
6836
6851
  'h5.dev.configMissing': '{file} is not exist, please run minis game init first',
6837
6852
  'h5.dev.precheckTips': '⚠️ Before dev, please ensure:\n 1. The account used to login www.tiktok.com is in the sandbox target user range of Minis developer platform, otherwise login authorization will throw an error.\n 2. The browser allows www.tiktok.com <popup and redirect>, because the authorization login linkage needs to open a new tab popup for operation, otherwise the authorization login linkage will not be able to debug normally.',
6838
6853
  'h5.dev.startingBanner': '\n \n============== start dev your game, it will take a few seconds ============ \n \n',
@@ -6884,8 +6899,16 @@ const messages = {
6884
6899
  'native.tips.3': ' After scanning the QR code with your phone for Test User authentication,',
6885
6900
  'native.tips.3.sub1': ' the compiled code package will be uploaded to the client automatically.',
6886
6901
  'native.tips.3.sub2': ' Game debugging will start right away.',
6887
- 'native.tips.4': ' Before scanning with TikTok, make sure your phone and computer are on the same Wi-Fi.',
6888
- 'native.tips.4.sub1': ' This is required for stable local connection and debugging.',
6902
+ 'native.tips.4': ' How to ensure a smooth connection?',
6903
+ 'native.tips.4.sub1': ' https://bytedance.larkoffice.com/wiki/WvifwWjGri7bTzkPbqKcqVi5ntc',
6904
+ 'upload.spinner.fetchInfo': 'Fetching game info for client key {clientKey} ...',
6905
+ 'upload.spinner.zipping': 'Zipping game assets in directory: {dir} ...',
6906
+ 'upload.spinner.uploading': 'Uploading game to platform (size: {size} MB)...',
6907
+ 'upload.success': 'Upload success! View version at: {url}',
6908
+ 'upload.fail': 'Upload failed: {error}',
6909
+ 'upload.error.noClientKey': 'Client Key is required for upload. Use --client-key <key>',
6910
+ 'upload.error.notLoggedIn': 'Not logged in. Please run `ttmg login` first.',
6911
+ 'upload.error.dirNotExist': 'The specified directory does not exist: {dir}',
6889
6912
  },
6890
6913
  'zh-CN': {
6891
6914
  'cli.description': 'TikTok 小游戏命令行工具',
@@ -6894,6 +6917,7 @@ const messages = {
6894
6917
  'cli.option.dev.h5': 'Web 调试 TikTok 小游戏',
6895
6918
  'cli.command.login.desc': '使用开发者账号登录',
6896
6919
  'cli.command.login.verbose': '输出调试用详细日志',
6920
+ 'cli.command.logout.desc': '退出登录并清除本地用户信息',
6897
6921
  'cli.command.setup.desc': '初始化 ttmg 环境',
6898
6922
  'cli.command.setup.lang': '语言(仅支持):en-US | zh-CN',
6899
6923
  'cli.command.reset.desc': '重置本地 CLI 状态',
@@ -6904,6 +6928,10 @@ const messages = {
6904
6928
  'cli.command.config.set.desc': '设置配置项',
6905
6929
  'cli.command.config.get.desc': '获取配置项',
6906
6930
  'cli.command.config.delete.desc': '删除配置项',
6931
+ 'cli.command.upload.desc': '上传小游戏到开发者平台',
6932
+ 'cli.command.upload.clientKey': '小游戏的 Client Key',
6933
+ 'cli.command.upload.note': '上传备注',
6934
+ 'cli.command.upload.dir': '小游戏项目根目录(默认为当前目录)',
6907
6935
  'cli.option.h5': 'H5 小游戏',
6908
6936
  'cli.native.init.placeholder': 'Native 小游戏初始化',
6909
6937
  'cli.native.build.placeholder': 'Native 小游戏打包',
@@ -6945,9 +6973,12 @@ const messages = {
6945
6973
  'login.error.withCode': '登录失败:{message},错误码:{code}',
6946
6974
  'login.error.withMessage': '登录失败:{message}',
6947
6975
  'login.error.noUserId': '登录失败,响应中未返回 user_id。',
6948
- 'login.warning.proxyIssue': '当前响应看起来不是登录接口返回(例如代理返回了 "Connection established",而不是转发真实响应)。\n\n该接口在大陆网络通常需要代理。请确认代理可正确转发 developers.tiktok.com 的 HTTPS 请求:尝试切换节点,或检查代理是否为全局/隧道模式且未拦截 HTTPS。\n\n代理排查文档:\nhttps://bytedance.larkoffice.com/wiki/ZblJwT0ZNil9jJkS8EgcFlcQnFc',
6976
+ 'login.warning.proxyIssue': '当前响应看起来不是登录接口返回(例如代理返回了 "Connection established",而不是转发真实响应)。\n\n该接口在大陆网络通常需要代理。请确认代理可正确转发 developers.tiktok.com 的 HTTPS 请求:尝试切换节点,或者使用 `ttmg config set proxy socks5://...` 配置 CLI 内置代理。\n\n代理排查文档:\nhttps://bytedance.larkoffice.com/wiki/PeIawT4M4ia9R8kYyLMcjwHknOg',
6949
6977
  'login.error.connectService': '连接登录服务失败',
6950
- 'login.error.networkBlocked': '检测到当前终端代理设置导致无法访问外网。\n\n请检查本地终端代理配置,可参考以下文档修改:\nhttps://bytedance.larkoffice.com/wiki/ZblJwT0ZNil9jJkS8EgcFlcQnFc',
6978
+ 'login.error.networkBlocked': '网络连接失败。这通常是由于代理软件的高级设置(如 fake-ip 模式)或终端残留了错误的代理环境变量导致的。\n\n我们强烈建议你关闭全局代理,并为 CLI 配置内置 SOCKS5 代理:\n ttmg config set proxy socks5://127.0.0.1:<你的socks端口>\n\n详细排查方案请参考最新代理设置文档:\nhttps://bytedance.larkoffice.com/wiki/PeIawT4M4ia9R8kYyLMcjwHknOg',
6979
+ 'logout.spinner.loggingOut': '正在退出登录...',
6980
+ 'logout.success': '退出登录成功!',
6981
+ 'logout.fail': '退出登录失败:{error}',
6951
6982
  'h5.dev.configMissing': '{file} 不存在,请先执行 minis game init',
6952
6983
  'h5.dev.precheckTips': '⚠️ 开始调试前请确认:\n 1. 当前登录 www.tiktok.com 的账号在小程序开发者平台沙盒目标用户范围内,否则登录授权会报错。\n 2. 浏览器允许 www.tiktok.com 弹窗与重定向,授权登录链路需要新开标签页进行操作,否则无法正常调试。',
6953
6984
  'h5.dev.startingBanner': '\n \n============== 已开始调试你的游戏,通常需要几秒钟 ============ \n \n',
@@ -6999,8 +7030,16 @@ const messages = {
6999
7030
  'native.tips.3': ' 手机扫码通过 Test User 认证后,',
7000
7031
  'native.tips.3.sub1': ' 编译后的代码包会自动上传到客户端。',
7001
7032
  'native.tips.3.sub2': ' 随即开始游戏调试。',
7002
- 'native.tips.4': ' 在使用 TikTok 扫码前,请确保手机和电脑处于同一个 Wi-Fi。',
7003
- 'native.tips.4.sub1': ' 这是本地连接与正常调试的前提条件。',
7033
+ 'native.tips.4': ' 如何保证可以顺利连接?',
7034
+ 'native.tips.4.sub1': ' https://bytedance.larkoffice.com/wiki/WvifwWjGri7bTzkPbqKcqVi5ntc',
7035
+ 'upload.spinner.fetchInfo': '正在获取游戏信息 (client key: {clientKey}) ...',
7036
+ 'upload.spinner.zipping': '正在压缩游戏资源目录: {dir} ...',
7037
+ 'upload.spinner.uploading': '正在上传游戏到平台 (大小: {size} MB) ...',
7038
+ 'upload.success': '上传成功!可在以下地址查看版本:{url}',
7039
+ 'upload.fail': '上传失败:{error}',
7040
+ 'upload.error.noClientKey': '上传必须提供 Client Key,请使用 --client-key <key> 参数',
7041
+ 'upload.error.notLoggedIn': '未登录,请先执行 `ttmg login` 登录开发者平台账号。',
7042
+ 'upload.error.dirNotExist': '指定的项目目录不存在:{dir}',
7004
7043
  },
7005
7044
  };
7006
7045
 
@@ -8458,15 +8497,16 @@ function showTips(context) {
8458
8497
  console.log('');
8459
8498
  console.log(chalk.red.bold('4. ⚠️') +
8460
8499
  t('native.tips.4'));
8461
- console.log(t('native.tips.4.sub1'));
8500
+ console.log(chalk.cyan.underline(t('native.tips.4.sub1')));
8462
8501
  console.log(chalk.gray('─────────────────────────────────────────────'));
8463
8502
  }
8464
8503
 
8465
8504
  /**
8466
- * 辅助函数:将当前工作目录打包为 Buffer
8505
+ * 辅助函数:将指定目录(默认为当前工作目录)打包为 Buffer
8467
8506
  * @param customIgnores - 可选的自定义忽略规则数组 (支持 glob 模式,如 ['dist/**', '*.log'])
8507
+ * @param targetDir - 可选的目标目录,默认为 process.cwd()
8468
8508
  */
8469
- const zipCwdToBuffer = (customIgnores = []) => {
8509
+ const zipCwdToBuffer = (customIgnores = [], targetDir = process.cwd()) => {
8470
8510
  return new Promise((resolve, reject) => {
8471
8511
  const chunks = [];
8472
8512
  const output = new require$$2$1.Writable({
@@ -8483,7 +8523,6 @@ const zipCwdToBuffer = (customIgnores = []) => {
8483
8523
  reject(err);
8484
8524
  });
8485
8525
  archive.pipe(output);
8486
- const cwd = process.cwd();
8487
8526
  // 1. 基础忽略列表 (建议保留这些基础规则,防止包过大)
8488
8527
  const defaultIgnores = [
8489
8528
  'node_modules/**',
@@ -8498,7 +8537,7 @@ const zipCwdToBuffer = (customIgnores = []) => {
8498
8537
  // 3. 执行打包
8499
8538
  // 注意:ignore 规则必须使用正斜杠 /,即使在 Windows 下
8500
8539
  archive.glob('**/*', {
8501
- cwd: cwd,
8540
+ cwd: targetDir,
8502
8541
  ignore: finalIgnores,
8503
8542
  dot: true, // 包含 .env 等点文件
8504
8543
  });
@@ -10281,6 +10320,7 @@ async function login(options) {
10281
10320
  headers,
10282
10321
  maxRedirects: 20,
10283
10322
  timeout: 30000,
10323
+ ...getAxiosProxyConfig(),
10284
10324
  });
10285
10325
  log('Response status', response.status);
10286
10326
  log('Response data', response?.data);
@@ -10345,6 +10385,30 @@ async function login(options) {
10345
10385
  }
10346
10386
  }
10347
10387
 
10388
+ async function logout() {
10389
+ const ora = await import('ora');
10390
+ const spinner = ora.default({
10391
+ text: chalk.cyan.bold(t('logout.spinner.loggingOut')),
10392
+ spinner: 'dots',
10393
+ }).start();
10394
+ try {
10395
+ const config = getTTMGRC();
10396
+ if (config) {
10397
+ // Remove sensitive user info
10398
+ delete config.email;
10399
+ delete config.user_id;
10400
+ delete config.cookie;
10401
+ resetTTMGRC(config);
10402
+ }
10403
+ spinner.succeed(chalk.green.bold(t('logout.success')));
10404
+ process.exit(0);
10405
+ }
10406
+ catch (err) {
10407
+ spinner.fail(chalk.red.bold(t('logout.fail', { error: err.message || String(err) })));
10408
+ process.exit(1);
10409
+ }
10410
+ }
10411
+
10348
10412
  const supportedLangs$1 = ['en-US', 'zh-CN'];
10349
10413
  function isSupportedLang$1(lang) {
10350
10414
  return supportedLangs$1.includes(lang);
@@ -10448,9 +10512,9 @@ const config = {
10448
10512
  spinner.fail(chalk.red(`Value is required for config key: ${key}`));
10449
10513
  process.exit(1);
10450
10514
  }
10451
- if (key === 'proxy') {
10452
- setTTMGRC({ proxy: value });
10453
- spinner.succeed(chalk.green(`Set proxy to ${value}`));
10515
+ if (key === 'proxy' || key === 'http-proxy' || key === 'socks-proxy') {
10516
+ setTTMGRC({ [key]: value });
10517
+ spinner.succeed(chalk.green(`Set ${key} to ${value}`));
10454
10518
  }
10455
10519
  else if (key === 'lang') {
10456
10520
  if (!isSupportedLang(value)) {
@@ -10476,8 +10540,8 @@ const config = {
10476
10540
  const spinner = ora(`Getting ${key}...`).start();
10477
10541
  try {
10478
10542
  const rc = getTTMGRC();
10479
- if (key === 'proxy') {
10480
- spinner.succeed(chalk.green(`proxy=${rc?.proxy || ''}`));
10543
+ if (key === 'proxy' || key === 'http-proxy' || key === 'socks-proxy') {
10544
+ spinner.succeed(chalk.green(`${key}=${rc?.[key] || ''}`));
10481
10545
  }
10482
10546
  else if (key === 'lang') {
10483
10547
  spinner.succeed(chalk.green(`lang=${rc?.lang || ''}`));
@@ -10496,9 +10560,9 @@ const config = {
10496
10560
  const ora = (oraModule.default || oraModule);
10497
10561
  const spinner = ora(`Deleting ${key}...`).start();
10498
10562
  try {
10499
- if (key === 'proxy') {
10500
- setTTMGRC({ proxy: undefined });
10501
- spinner.succeed(chalk.green(`Deleted proxy config`));
10563
+ if (key === 'proxy' || key === 'http-proxy' || key === 'socks-proxy') {
10564
+ setTTMGRC({ [key]: undefined });
10565
+ spinner.succeed(chalk.green(`Deleted ${key} config`));
10502
10566
  }
10503
10567
  else if (key === 'lang') {
10504
10568
  setTTMGRC({ lang: undefined });
@@ -10515,7 +10579,71 @@ const config = {
10515
10579
  }
10516
10580
  };
10517
10581
 
10518
- var version = "0.3.2-beta.9";
10582
+ async function upload({ clientKey, note = '--', dir, }) {
10583
+ const ora = await import('ora');
10584
+ const spinner = ora.default({
10585
+ text: chalk.cyan.bold(t('upload.spinner.fetchInfo', { clientKey: clientKey || 'unknown' })),
10586
+ spinner: 'dots',
10587
+ }).start();
10588
+ try {
10589
+ console.log(chalk.gray(`[upload] Start uploading process...`));
10590
+ console.log(chalk.gray(`[upload] Parameters: clientKey=${clientKey}, note=${note}, dir=${dir || process.cwd()}`));
10591
+ const user = getCurrentUser();
10592
+ if (!user || !user.cookie) {
10593
+ throw new Error(t('upload.error.notLoggedIn'));
10594
+ }
10595
+ if (!clientKey) {
10596
+ throw new Error(t('upload.error.noClientKey'));
10597
+ }
10598
+ // 1. 获取游戏信息,主要是为了拿 appId
10599
+ console.log(chalk.gray(`[upload] Step 1: Fetching game info for clientKey ${clientKey}`));
10600
+ const infoRes = await fetchGameInfo(clientKey);
10601
+ console.log(chalk.gray(`[upload] Game info response: ${JSON.stringify(infoRes)}`));
10602
+ if (infoRes.error) {
10603
+ throw new Error(infoRes.error.errorMsg || 'Failed to fetch game info');
10604
+ }
10605
+ const appId = infoRes.data?.app_id;
10606
+ const name = infoRes.data?.name || 'game';
10607
+ if (!appId) {
10608
+ throw new Error('No appId found for this client key');
10609
+ }
10610
+ // 2. 打包指定或当前目录
10611
+ const targetDir = dir ? path.resolve(process.cwd(), dir) : process.cwd();
10612
+ // 检查目录是否存在
10613
+ if (!fs.existsSync(targetDir)) {
10614
+ throw new Error(t('upload.error.dirNotExist', { dir: targetDir }));
10615
+ }
10616
+ console.log(chalk.gray(`[upload] Step 2: Zipping directory ${targetDir}`));
10617
+ spinner.text = chalk.cyan.bold(t('upload.spinner.zipping', { dir: targetDir }));
10618
+ const zipBuffer = await zipCwdToBuffer([], targetDir);
10619
+ // 计算文件大小 (MB)
10620
+ const fileSizeMB = (zipBuffer.length / (1024 * 1024)).toFixed(2);
10621
+ console.log(chalk.gray(`[upload] Zipping completed. File size: ${fileSizeMB} MB`));
10622
+ // 3. 上传到平台
10623
+ console.log(chalk.gray(`[upload] Step 3: Uploading to platform...`));
10624
+ spinner.text = chalk.cyan.bold(t('upload.spinner.uploading', { size: fileSizeMB }));
10625
+ const uploadRes = await uploadGameToPlatform({
10626
+ data: zipBuffer.buffer.slice(zipBuffer.byteOffset, zipBuffer.byteOffset + zipBuffer.byteLength),
10627
+ name,
10628
+ clientKey,
10629
+ note,
10630
+ appId,
10631
+ });
10632
+ console.log(chalk.gray(`[upload] Upload response: ${JSON.stringify({ ...uploadRes, data: uploadRes.data ? { ...uploadRes.data, detail: uploadRes.data.detail } : null })}`));
10633
+ if (uploadRes.error) {
10634
+ throw new Error(uploadRes.error.message || 'Upload failed');
10635
+ }
10636
+ console.log(chalk.gray(`[upload] Upload finished successfully.`));
10637
+ spinner.succeed(chalk.green.bold(t('upload.success', { url: uploadRes.data?.detail || '' })));
10638
+ process.exit(0);
10639
+ }
10640
+ catch (error) {
10641
+ spinner.fail(chalk.red.bold(t('upload.fail', { error: error.message || String(error) })));
10642
+ process.exit(1);
10643
+ }
10644
+ }
10645
+
10646
+ var version = "0.3.3";
10519
10647
  var pkg = {
10520
10648
  version: version};
10521
10649
 
@@ -10534,6 +10662,21 @@ program
10534
10662
  .action(async (cmd) => {
10535
10663
  await login({ verbose: cmd.verbose });
10536
10664
  });
10665
+ program
10666
+ .command('logout')
10667
+ .description(t('cli.command.logout.desc'))
10668
+ .action(async () => {
10669
+ await logout();
10670
+ });
10671
+ program
10672
+ .command('upload')
10673
+ .description(t('cli.command.upload.desc'))
10674
+ .option('-ck, --client-key <clientKey>', t('cli.command.upload.clientKey'))
10675
+ .option('-n, --note <note>', t('cli.command.upload.note'))
10676
+ .option('-d, --dir <dir>', t('cli.command.upload.dir'))
10677
+ .action(async (cmd) => {
10678
+ await upload({ clientKey: cmd.clientKey, note: cmd.note, dir: cmd.dir });
10679
+ });
10537
10680
  program
10538
10681
  .command('setup')
10539
10682
  .description(t('cli.command.setup.desc'))