@ttmg/cli 0.4.6-vibe-beta.18 → 0.4.6-vibe-beta.20

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/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ttmg/cli",
3
- "version": "0.4.6-vibe-beta.18",
3
+ "version": "0.4.6-vibe-beta.20",
4
4
  "description": "TikTok Mini Game Command Line Tool",
5
5
  "license": "ISC",
6
6
  "bin": {
@@ -115,7 +115,7 @@ function events(result) {
115
115
  async function main() {
116
116
  // Exercise the built worker IPC and new command without creating a platform task.
117
117
  const authWorker = spawn(process.execPath, [entry, '__vibe-page-server'], {
118
- env: {...env, TTMG_VIBE_PAGE_TTL_MS: '30000'}, stdio: ['ignore', 'ignore', 'ignore', 'ipc'],
118
+ env: {...env, TTMG_VIBE_PAGE_TTL_MS: '500'}, stdio: ['ignore', 'ignore', 'ignore', 'ipc'],
119
119
  });
120
120
  children.add(authWorker);
121
121
  const workerMessage = predicate => new Promise((resolve, reject) => {
@@ -130,6 +130,9 @@ async function main() {
130
130
  let rendered = workerMessage(message => message.type === 'rendered' && message.id === 1);
131
131
  authWorker.send({type: 'render', id: 1, html: '<h1>Waiting</h1>', browserLandingUrl: landing});
132
132
  await rendered;
133
+ await new Promise(resolve => setTimeout(resolve, 700));
134
+ assert.equal(await (await fetch(ready.url)).text(), '<h1>Waiting</h1>',
135
+ 'Retention TTL must not close the page while the CLI is still polling');
133
136
  const browserReceipt = path.join(temp, 'browser-open.ndjson');
134
137
  const browserEnv = {
135
138
  NODE_OPTIONS: `--require=${path.join(__dirname, 'vibe-auth-open-test-preload.cjs')}`,
@@ -162,7 +165,15 @@ async function main() {
162
165
  assert.doesNotMatch(invalid.stdout + invalid.stderr, /process-private-token/);
163
166
  }
164
167
  assert.equal(fs.readFileSync(browserReceipt, 'utf8').trim().split('\n').length, 2);
165
- authWorker.kill();
168
+ const workerExited = new Promise((resolve, reject) => {
169
+ const timer = setTimeout(() => reject(new Error('Detached worker did not expire')), 4000);
170
+ authWorker.once('exit', code => { clearTimeout(timer); resolve(code); });
171
+ });
172
+ authWorker.disconnect();
173
+ assert.equal(await (await fetch(ready.url)).text(), '<h1>Complete</h1>',
174
+ 'A completed page remains readable after CLI detaches');
175
+ assert.equal(await workerExited, 0);
176
+ await assert.rejects(fetch(ready.url), 'Detached page must close when retention expires');
166
177
  children.delete(authWorker);
167
178
  fixtureServer = http.createServer(async (req, res) => {
168
179
  const url = new URL(req.url, 'http://127.0.0.1');
@@ -390,7 +401,10 @@ async function main() {
390
401
  const previewHtml = await (await fetch(final.pageUrl)).text();
391
402
  assert.match(previewHtml, /Simulated upload complete/);
392
403
  assert.match(previewHtml, /data-phase="complete"/);
393
- assert.doesNotMatch(previewHtml, /QR|preview|review|Publish to TikTok/);
404
+ assert.doesNotMatch(previewHtml.split('<body>')[1], /QR|preview|review|Publish to TikTok/);
405
+ const localizedPage = await fetch(final.pageUrl, {headers: {'Accept-Language': 'zh-CN'}});
406
+ assert.equal(localizedPage.headers.get('vary'), 'Accept-Language');
407
+ assert.match(await localizedPage.text(), /<html lang="zh-CN">[\s\S]*模拟上传完成/);
394
408
 
395
409
  const beforeWeb = requests.length;
396
410
  const webConflict = await run([...input, '--web', '--mock', '--format', 'json']);
@@ -477,10 +491,11 @@ async function main() {
477
491
  assert.equal(output.at(-1).previewReady, true);
478
492
  assert.equal(output.at(-1).previewUrl, 'https://www.tiktok.com/minis/process-preview');
479
493
  assert.equal(output.at(-1).codeAssetId, '7686101169281894418');
480
- assert.equal(output.at(-1).qrPurpose, 'authorization_binding');
494
+ assert.equal(output.at(-1).qrPurpose, 'game_preview');
481
495
  const readyPage = await (await fetch(output.at(-1).pageUrl)).text();
482
- assert.match(readyPage, /Authorization QR/);
483
- assert.doesNotMatch(readyPage, /Game preview QR/);
496
+ assert.match(readyPage, /Progress QR/);
497
+ assert.match(readyPage, /Game preview QR/);
498
+ assert.ok(readyPage.indexOf('alt="Progress QR"') < readyPage.indexOf('alt="Game preview QR"'));
484
499
  assert.match(readyPage, /data-phase="preview"/);
485
500
  assert.equal(output.filter(e => e.terminal).length, 1);
486
501
  assert.equal(webPolls, 7, 'Keep polling the same task until preview URL is available');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ttmg/cli",
3
- "version": "0.4.6-vibe-beta.18",
3
+ "version": "0.4.6-vibe-beta.20",
4
4
  "description": "TikTok Mini Game Command Line Tool",
5
5
  "license": "ISC",
6
6
  "bin": {
package/vibe-upload.md CHANGED
@@ -1,9 +1,10 @@
1
- # Vibe 扫码授权与上传
2
-
1
+ # Vibe Upload and Preview
3
2
 
4
3
  `ttmg upload --vibe` 将本地小游戏上传到 TikTok Mini Games。用户提供游戏标题和头像,在手机 TikTok 扫码授权后,CLI 自动完成头像、应用资料和代码包上传。Skill 负责准备工程、调用命令和读取结果;CLI 负责素材校验、打包、授权轮询及上传。
5
4
 
6
- `0.4.6-vibe-beta.18` 支持手机授权、上传后持续轮询和返回原绑定二维码。Snow Crew 已在 PPE 完成真实绑定上传,本次返回原绑定码的页面体验已由用户验证。预览链接的完整链路此前已在 beta.17 验证。正式环境未开放,上传完成不代表审核通过或正式发布。
5
+ `0.4.6-vibe-beta.20` 支持手机授权、自动上传、同任务轮询和双二维码预览。左侧保留原码用于「查看进度」,右侧从加载态切换为「扫码预览」。页面按浏览器语言显示中英文,两个二维码的图案尺寸和白边一致,头像与整块应用信息垂直居中。当前为 PPE 测试链路,上传完成不代表审核通过或正式发布。
6
+
7
+ Version `0.4.6-vibe-beta.20` supports phone authorization, automatic upload, same-task polling and two QR codes: Check progress on the left, and the preview loader or QR on the right. Page language follows the browser, both QR codes use equal visible dimensions, and the icon is vertically centered beside the app details. This is a PPE trial; upload success is not review approval or production release.
7
8
 
8
9
  ## Quick Start
9
10
 
@@ -23,18 +24,24 @@ ttmg upload --vibe --dir ./game --title "星环守卫" --icon ./avatar.png --for
23
24
 
24
25
  3. CLI 自动上传头像、应用资料和代码包,页面展示进度与结果。
25
26
 
26
- 4. 上传成功后,原页面先短暂显示成功提示,再返回扫码界面,保留最初的绑定二维码。CLI 仍查询同一任务并返回 `previewUrl`。页面提示本次已上传,再次扫描此码可打开手机端绑定页面,无需重复上传。
27
+ 4. 上传成功后短暂显示成功提示,随后左侧保留原二维码、右侧展示预览加载态;CLI 持续查询同一任务,兼容状态 9(等待提交代码审核)。拿到有效 `previewUrl` 后,右侧加载态切换为预览码,左侧原码保留为「查看进度」,无需重复上传。
27
28
 
28
- 5. Skill 收到 `terminal=true`、`status=uploaded`、`uploaded=true`、`previewReady=true`、`simulation=false` 且退出码为 0 后,报告上传完成及预览链接已返回。不要把电脑页保留的绑定码说成试玩码。
29
+ 5. Skill 收到 `terminal=true`、`status=uploaded`、`uploaded=true`、`previewReady=true`、`simulation=false` 且退出码为 0 后,提示用户扫码预览。主码的 `qrPurpose` 为 `game_preview` 或 `tool_preview`。
29
30
 
30
31
  已有 ZIP 时,用 `--package ./game.zip` 替换 `--dir ./game`。无需预先执行 `ttmg login` 或配置 PPE 环境。描述和分类可省略,CLI 使用默认资料;完整参数见下文。
31
32
 
32
33
  ## 安装与本地预检
33
34
 
34
- 安装后确认版本为 `0.4.6-vibe-beta.18`,能力查询中 `authorizationMode` 为 `qr`、`previewQr` 为 `false`,`preview.qrPurpose` 为 `authorization_binding`。支持 Node.js 20.19.1–20.x 或 22 及以上版本。
35
+ ### Tool PPE 试用
36
+
37
+ 使用 `--minis-type MINI_TOOL`,省略时仍上传小游戏。首轮使用 Native 工程或 ZIP,固定 `EFFICIENCY_AND_OFFICE` 分类、`region=US` 和 `min_sdk_version=1.0.0`,不传游戏子类型。暂不接受分类和旧 `--app-info` 覆盖;描述仍可用 `--description` 设置。此试用尚未代表真机预览或审核通过,也不包含 H5 包支持。
38
+
39
+ 在独立 Tool 工程目录调用:`ttmg upload --vibe --minis-type MINI_TOOL --dir ./tool --title "Focus Timer" --icon ./icon.png --format ndjson`。工程身份首次创建后固定类型,不要复用小游戏的 `.ttmg/vibe-project.json`。
40
+
41
+ 安装后确认版本为 `0.4.6-vibe-beta.20`。能力声明中 `authorizationMode=qr`、`previewQr=true`,预览主码用途为 `game_preview`(Tool 为 `tool_preview`),原码仍保留。支持 Node.js 20.19.1–20.x 或 22 及以上版本。
35
42
 
36
43
  ```sh
37
- npm install -g @ttmg/cli@0.4.6-vibe-beta.18
44
+ npm install -g @ttmg/cli@0.4.6-vibe-beta.20
38
45
  ttmg --version
39
46
  ttmg capabilities --format json
40
47
  ```
@@ -119,7 +126,7 @@ ttmg upload --vibe --dir ./game --title "星环守卫" --icon ./avatar.png --cat
119
126
  3. 收到 `uploading`,按 `uploadStep` 展示 `avatar`、`app_info`、`package` 进度。授权轮询和上传由 CLI 完成。
120
127
 
121
128
  4. 收到 `waiting_preview` 时,素材已上传,保持原进程运行。CLI 使用同一任务继续查询;状态已完成但尚无预览链接时也继续等待。
122
- 5. 终态仍为 `status=uploaded`。`previewReady=true` 表示后端预览链接已返回;`qrPurpose=authorization_binding` 表示 `pageUrl` 保留原绑定码,`previewUrl` 不作为该页面的二维码内容。等待失败时保留 `uploaded=true`,同时返回错误和 `nextAction=check_task`,不要重新上传。
129
+ 5. 终态仍为 `status=uploaded`。`previewReady=true` 表示后端预览链接已返回,主码使用该地址,`qrPurpose` 为 `game_preview` 或 `tool_preview`。等待失败时保留 `uploaded=true`,同时返回错误和 `nextAction=check_task`,不要重新上传。
123
130
 
124
131
  ## 扫码授权与自动上传
125
132
 
@@ -154,7 +161,7 @@ ttmg auth open --page-url <pageUrl> --format json
154
161
  - `uploading`:根据 uploadStep 显示 avatar、app_info、package 的进度,不再询问授权。
155
162
 
156
163
  - `waiting_preview`:uploaded=true、terminal=false,正在查询后端处理结果,等待预览链接。
157
- - `uploaded`:terminal=true、uploaded=true、simulation=false 且退出码 0:上传完成,previewReady=true 时已取得预览链接;电脑页保留原绑定码,不是审核通过或正式发布。
164
+ - `uploaded`:terminal=true、uploaded=true、simulation=false 且退出码 0 表示上传完成;previewReady=true 时页面展示预览码并保留进度码,不代表审核通过或正式发布。
158
165
 
159
166
  - `failed / cancelled`:根据 errorCode、message 和 nextAction 提示处理,不自动重传。
160
167
 
@@ -163,7 +170,7 @@ ttmg auth open --page-url <pageUrl> --format json
163
170
 
164
171
  从真实创建任务请求发起前开始 `platformWrite=true`,表示已尝试平台写入,不代表创建或上传成功。只有内部离线测试、本机 HTTP 和 dry-run 保持 `platformWrite=false`。
165
172
 
166
- 按阶段补充:`taskId`(字符串,禁止转成 JS Number)、`pollIntervalSeconds`、`readyForInput`、`taskStatusRaw`(仅诊断)、`uploadStep`、`loadedBytes`、`totalBytes`、`pageUrl`、`qrPurpose=authorization_binding`、素材大小和包 SHA256。代码包字节进度达到 100% 不代表成功,必须等待最终上传回执。
173
+ 按阶段补充:`taskId`(字符串,禁止转成 JS Number)、`pollIntervalSeconds`、`readyForInput`、`taskStatusRaw`(仅诊断)、`uploadStep`、`loadedBytes`、`totalBytes`、`pageUrl`、`qrPurpose`(授权/等待时为 authorization_binding,预览时为 game_preview 或 tool_preview)、素材大小和包 SHA256。代码包字节进度达到 100% 不代表成功,必须等待最终上传回执。
167
174
 
168
175
  `nextAction` 取值:`wait`、`scan_qr`、`fix_input`、`restart_authorization`、`check_task`、`none`。已开始上传后发生失败/超时,先检查 task,不能直接再次创建并重传。预览等待超时返回 `VIBE_PREVIEW_TIMEOUT`;查询失败、取消或页面失败均保留 `uploaded=true`,并返回错误及 `nextAction=check_task`。
169
176
 
@@ -171,13 +178,17 @@ ttmg auth open --page-url <pageUrl> --format json
171
178
 
172
179
  退出码:成功/dry-run 为 0,失败为 1,Ctrl+C 为 130。进程或宿主意外终止导致没有终态时,不得认定上传成功。
173
180
 
174
- 轮询间隔使用创建任务返回的 `poll_interval_seconds`。`--timeout` 是包括授权、上传和等待预览的整体超时,默认 300 秒。不自动重试写接口、不实现跨进程续传。
181
+ 轮询间隔使用创建任务返回的 `poll_interval_seconds`。本版本将 `--timeout`(包括授权、上传和等待预览的整体超时)延长为默认 1800 秒,最大 3600 秒。不自动重试写接口、不实现跨进程续传。
182
+
183
+ `--timeout` covers authorization, upload and preview polling. It defaults to 1800 seconds and supports up to 3600 seconds. Write requests are not automatically retried; cross-process resume is not supported.
175
184
 
176
185
  ## 页面与素材
177
186
 
178
- 本地页在扫码、上传、等待预览、成功或失败时均展示本次资料。后台查询状态,只更新变化内容,不整页刷新;预览就绪或终态失败后停止查询。授权后上传期间移除绑定码;素材上传成功后先展示成功提示约 1.2 秒,再平滑返回最初扫码布局,使用原始 landing_url 生成同一个绑定码,文案明确本次已上传。preview_url 返回后也不替换二维码。Skill 可用 `pageUrl` 重新打开同一页面,重新打开时直接显示保留的绑定码。绑定链接仍受后端任务有效期约束,页面不会创建新任务或重新上传。
187
+ 页面展示本次标题、头像、描述及分类,按浏览器语言显示中英文。后台更新变化内容,不整页刷新;上传期间保留原二维码,上传成功后短暂提示,再显示预览加载态。返回有效 preview_url 后,以真实预览码替换占位,原码保留为「查看进度」;双码实际图案均为 160×160,外部白边一致。预览就绪或查询结束后停止等待动画。重新打开 pageUrl 直接显示当前状态,不会创建新任务或重新上传。
188
+
189
+ 页面只监听 127.0.0.1,二维码才由手机扫描,手机不访问 pageUrl。本版本在任务进行中保持页面可用,CLI 结束或意外退出后再保留 30 分钟,内容驻留内存;测试可设置 `TTMG_VIBE_PAGE_TTL_MS`(1—1800000)。上传前主动取消会立即关闭页面;成功、上传后取消及可显示的失败页面保留至到期。页面保留时间不会延长后端二维码的有效期。不要分享本地页面地址。
179
190
 
180
- 页面只监听 127.0.0.1,二维码才由手机扫描,手机不访问 pageUrl。默认 15 分钟后关闭,内容驻留内存;测试可设置 `TTMG_VIBE_PAGE_TTL_MS`(1—900000)。取消进程会关闭页面;成功与可显示的失败页面保留至到期。不要分享本地页面地址。
191
+ the page listens only on 127.0.0.1 and stays available while the CLI is running, then for 30 minutes after it finishes or exits unexpectedly. Cancelling before upload closes the page immediately. The retention window does not extend backend QR validity.
181
192
 
182
193
  CLI 执行本地项目检查和 ZIP 打包,并按 PNG/JPEG、1024×1024、5 MiB 校验上传头像。文件头检查不等于完整图像解码;ZIP 非空、大小和文件头检查不等于完整内容、解压总大小校验或平台审核。
183
194
 
@@ -210,7 +221,7 @@ TTMG_VIBE_BACKEND=local-http TTMG_VIBE_API=http://127.0.0.1:3100 ttmg upload --v
210
221
 
211
222
  **v1 → v2 兼容性变化**:旧 UUID 换 Token 的三接口协议废弃,`--vibe-authorize-url` 返回明确错误;授权地址来自 landing_url。不再输出旧 preview_ready 状态、uploadId、reviewStatus。
212
223
 
213
- beta.18 保留 waiting_preview 状态和 uploaded 终态;与 beta.17 相比,成功页改回原绑定码,终态 qrPurpose 改为已有枚举 authorization_binding,previewQr 能力设为 false。previewUrl / previewReady 的含义不变,schemaVersion 仍为 2;Skill 需按 qrPurpose 判断页面二维码用途,不再把 previewReady 等同于页面显示试玩码。普通不带 --vibe 的 upload 不变。
224
+ beta.19 保留 waiting_preview 状态、uploaded 终态和 schemaVersion=2,兼容状态 9。与 beta.18 相比,previewQr=true,主码使用 previewUrl,qrPurpose 为 game_preview 或 tool_preview,原码以「查看进度」保留。Skill 应按 qrPurpose 判断用途。普通不带 --vibe 的 upload 不变。
214
225
 
215
226
  2026-09-14 已核对 BFF 源码:头像 PNG/JPEG、1024×1024、5 MiB;Native ZIP 和解压总大小上限 100 MiB。本地暂未实现完整 ZIP 内容及解压总大小校验。2026-09-16 本地构建使用自有测试素材跑通真实 PPE 手机扫码授权、头像、默认资料和代码包上传。该验证不覆盖全部游戏或正式环境。后端接口调整留在适配层处理;若用户动作或成功语义改变,应协商升级 CLI schema。
216
227