@ttmg/cli 0.4.6-vibe-beta.16 → 0.4.6-vibe-beta.18
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 +6 -12
- package/dist/index.js +172 -47
- package/dist/index.js.map +1 -1
- package/dist/package.json +2 -2
- package/dist/scripts/vibe-ppe-test-preload.cjs +1 -1
- package/dist/scripts/vibe-upload-smoke.js +21 -7
- package/package.json +2 -2
- package/vibe-upload.md +23 -12
package/dist/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ttmg/cli",
|
|
3
|
-
"version": "0.4.6-vibe-beta.
|
|
3
|
+
"version": "0.4.6-vibe-beta.18",
|
|
4
4
|
"description": "TikTok Mini Game Command Line Tool",
|
|
5
5
|
"license": "ISC",
|
|
6
6
|
"bin": {
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"scripts": {
|
|
18
18
|
"demo:vibe": "npm run build && node scripts/vibe-upload-demo.js",
|
|
19
19
|
"test:game-categories": "node scripts/run-ts-test.js src/commands/common/game/categories.test.ts",
|
|
20
|
-
"test:vibe": "npm run test:game-categories && node scripts/run-ts-test.js src/commands/common/vibe/vibe.test.ts",
|
|
20
|
+
"test:vibe": "npm run test:game-categories && node scripts/run-ts-test.js src/commands/common/vibe/vibe.test.ts && node scripts/run-ts-test.js src/commands/common/vibe/preview.test.ts",
|
|
21
21
|
"test:vibe-process": "node scripts/vibe-upload-smoke.js",
|
|
22
22
|
"prepack": "npm run build && npm run verify:dist-version && npm run verify:agent-contract",
|
|
23
23
|
"build": "node scripts/build.js",
|
|
@@ -10,7 +10,7 @@ https.request = (options, callback) => {
|
|
|
10
10
|
assert.equal(typeof options, 'object');
|
|
11
11
|
assert.equal(options.hostname, 'developers.tiktok.com');
|
|
12
12
|
assert.equal(options.protocol, 'https:');
|
|
13
|
-
assert.match(options.path, /^\/bff\/app_info\/minis_import\/(create_minis_import_task_for_agent|
|
|
13
|
+
assert.match(options.path, /^\/bff\/app_info\/minis_import\/(create_minis_import_task_for_agent|get_minis_import_task_detail_for_agent|upload_minis_import_app_icon_for_agent|submit_minis_import_info_for_agent|upload_minis_import_package_for_agent)\//);
|
|
14
14
|
const request = http.request({
|
|
15
15
|
...options,
|
|
16
16
|
protocol: 'http:', hostname: '127.0.0.1', host: undefined, port,
|
|
@@ -171,7 +171,7 @@ async function main() {
|
|
|
171
171
|
for await (const chunk of req) chunks.push(chunk);
|
|
172
172
|
const body = Buffer.concat(chunks);
|
|
173
173
|
const create = url.pathname.endsWith('/create_minis_import_task_for_agent/');
|
|
174
|
-
const status = url.pathname.endsWith('/
|
|
174
|
+
const status = url.pathname.endsWith('/get_minis_import_task_detail_for_agent/');
|
|
175
175
|
const iconUpload = url.pathname.endsWith('/upload_minis_import_app_icon_for_agent/');
|
|
176
176
|
const infoUpload = url.pathname.endsWith('/submit_minis_import_info_for_agent/');
|
|
177
177
|
const packageUpload = url.pathname.endsWith('/upload_minis_import_package_for_agent/');
|
|
@@ -217,7 +217,11 @@ async function main() {
|
|
|
217
217
|
} : iconUpload ? {icon_uri: 'web-icon-receipt'}
|
|
218
218
|
: infoUpload ? {}
|
|
219
219
|
: packageUpload ? {status: 3, package_uri: 'web-package-receipt'}
|
|
220
|
-
: { status: webMode && webPolls
|
|
220
|
+
: { status: webMode && webPolls > 5 ? 6 : webMode && webPolls === 5 ? 2 : 1,
|
|
221
|
+
ready_for_input: webMode && webPolls === 5,
|
|
222
|
+
...(webMode && webPolls >= 7 ? { preview_url: 'https://www.tiktok.com/minis/process-preview',
|
|
223
|
+
app_id: '7686101169281894417', code_asset_id: '7686101169281894418',
|
|
224
|
+
client_key: 'process-client', minis_center_history_id: '7686101169281894419' } : {}) };
|
|
221
225
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
222
226
|
res.end(JSON.stringify({ ...data, error_info: { code: (failStatus && status) || url.pathname === webFailureEndpoint ? 420500 : 0 } }));
|
|
223
227
|
});
|
|
@@ -306,7 +310,7 @@ async function main() {
|
|
|
306
310
|
task_id: '7684370037737619477', import_token: 'receipt-test-secret',
|
|
307
311
|
landing_url: 'https://example.invalid/auth', poll_interval_seconds: 0.01,
|
|
308
312
|
},
|
|
309
|
-
|
|
313
|
+
get_minis_import_task_detail_for_agent: { status: 2, ready_for_input: true, preview_url: 'https://www.tiktok.com/minis/receipt-preview' },
|
|
310
314
|
upload_minis_import_app_icon_for_agent: { icon_uri: 'test-icon' },
|
|
311
315
|
submit_minis_import_info_for_agent: {},
|
|
312
316
|
upload_minis_import_package_for_agent: { status: 2, package_uri: 'test-package' },
|
|
@@ -328,9 +332,10 @@ async function main() {
|
|
|
328
332
|
assert.equal(savedFinal.taskStatusRaw, 2);
|
|
329
333
|
assert.equal(savedEvents.filter(e => e.terminal).length, 1);
|
|
330
334
|
assert.deepEqual(uploadPaths, [
|
|
331
|
-
'create_minis_import_task_for_agent', '
|
|
335
|
+
'create_minis_import_task_for_agent', 'get_minis_import_task_detail_for_agent',
|
|
332
336
|
'upload_minis_import_app_icon_for_agent', 'submit_minis_import_info_for_agent',
|
|
333
337
|
'upload_minis_import_package_for_agent',
|
|
338
|
+
'get_minis_import_task_detail_for_agent',
|
|
334
339
|
]);
|
|
335
340
|
assert.doesNotMatch(saved.stdout + saved.stderr, /receipt-test-secret|test-package/);
|
|
336
341
|
} finally {
|
|
@@ -468,12 +473,21 @@ async function main() {
|
|
|
468
473
|
assert.equal(output.at(-1).classification.source, format === 'json' ? 'defaults' : 'arguments');
|
|
469
474
|
assert.equal(output.at(-1).description, expectedWebDescription);
|
|
470
475
|
assert.equal(output.at(-1).descriptionSource, format === 'json' ? 'defaults' : 'arguments');
|
|
471
|
-
assert.equal(output.at(-1).taskStatusRaw,
|
|
476
|
+
assert.equal(output.at(-1).taskStatusRaw, 6);
|
|
477
|
+
assert.equal(output.at(-1).previewReady, true);
|
|
478
|
+
assert.equal(output.at(-1).previewUrl, 'https://www.tiktok.com/minis/process-preview');
|
|
479
|
+
assert.equal(output.at(-1).codeAssetId, '7686101169281894418');
|
|
480
|
+
assert.equal(output.at(-1).qrPurpose, 'authorization_binding');
|
|
481
|
+
const readyPage = await (await fetch(output.at(-1).pageUrl)).text();
|
|
482
|
+
assert.match(readyPage, /Authorization QR/);
|
|
483
|
+
assert.doesNotMatch(readyPage, /Game preview QR/);
|
|
484
|
+
assert.match(readyPage, /data-phase="preview"/);
|
|
472
485
|
assert.equal(output.filter(e => e.terminal).length, 1);
|
|
473
|
-
assert.equal(webPolls,
|
|
486
|
+
assert.equal(webPolls, 7, 'Keep polling the same task until preview URL is available');
|
|
474
487
|
assert.deepEqual(requests.slice(requestStart).map(r => r.path.split('/').filter(Boolean).at(-1)), [
|
|
475
|
-
'create_minis_import_task_for_agent', ...Array(5).fill('
|
|
488
|
+
'create_minis_import_task_for_agent', ...Array(5).fill('get_minis_import_task_detail_for_agent'),
|
|
476
489
|
'upload_minis_import_app_icon_for_agent', 'submit_minis_import_info_for_agent', 'upload_minis_import_package_for_agent',
|
|
490
|
+
'get_minis_import_task_detail_for_agent', 'get_minis_import_task_detail_for_agent',
|
|
477
491
|
]);
|
|
478
492
|
if (format === 'json') assert.equal(output.length, 1);
|
|
479
493
|
const opens = fs.readFileSync(receipt, 'utf8').trim().split('\n').map(line => JSON.parse(line));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ttmg/cli",
|
|
3
|
-
"version": "0.4.6-vibe-beta.
|
|
3
|
+
"version": "0.4.6-vibe-beta.18",
|
|
4
4
|
"description": "TikTok Mini Game Command Line Tool",
|
|
5
5
|
"license": "ISC",
|
|
6
6
|
"bin": {
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"scripts": {
|
|
18
18
|
"demo:vibe": "npm run build && node scripts/vibe-upload-demo.js",
|
|
19
19
|
"test:game-categories": "node scripts/run-ts-test.js src/commands/common/game/categories.test.ts",
|
|
20
|
-
"test:vibe": "npm run test:game-categories && node scripts/run-ts-test.js src/commands/common/vibe/vibe.test.ts",
|
|
20
|
+
"test:vibe": "npm run test:game-categories && node scripts/run-ts-test.js src/commands/common/vibe/vibe.test.ts && node scripts/run-ts-test.js src/commands/common/vibe/preview.test.ts",
|
|
21
21
|
"test:vibe-process": "node scripts/vibe-upload-smoke.js",
|
|
22
22
|
"prepack": "npm run build && npm run verify:dist-version && npm run verify:agent-contract",
|
|
23
23
|
"build": "node scripts/build.js",
|
package/vibe-upload.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
`ttmg upload --vibe` 将本地小游戏上传到 TikTok Mini Games。用户提供游戏标题和头像,在手机 TikTok 扫码授权后,CLI 自动完成头像、应用资料和代码包上传。Skill 负责准备工程、调用命令和读取结果;CLI 负责素材校验、打包、授权轮询及上传。
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
`0.4.6-vibe-beta.18` 支持手机授权、上传后持续轮询和返回原绑定二维码。Snow Crew 已在 PPE 完成真实绑定上传,本次返回原绑定码的页面体验已由用户验证。预览链接的完整链路此前已在 beta.17 验证。正式环境未开放,上传完成不代表审核通过或正式发布。
|
|
7
7
|
|
|
8
8
|
## Quick Start
|
|
9
9
|
|
|
@@ -18,18 +18,23 @@ ttmg upload --vibe --dir ./game --title "星环守卫" --icon ./avatar.png --for
|
|
|
18
18
|
```
|
|
19
19
|
|
|
20
20
|
1. 启动命令,CLI 检查素材并自动打开电脑上的二维码页。
|
|
21
|
+
|
|
21
22
|
2. 用户使用手机 TikTok 扫码授权,保持原命令运行。
|
|
23
|
+
|
|
22
24
|
3. CLI 自动上传头像、应用资料和代码包,页面展示进度与结果。
|
|
23
|
-
|
|
25
|
+
|
|
26
|
+
4. 上传成功后,原页面先短暂显示成功提示,再返回扫码界面,保留最初的绑定二维码。CLI 仍查询同一任务并返回 `previewUrl`。页面提示本次已上传,再次扫描此码可打开手机端绑定页面,无需重复上传。
|
|
27
|
+
|
|
28
|
+
5. Skill 收到 `terminal=true`、`status=uploaded`、`uploaded=true`、`previewReady=true`、`simulation=false` 且退出码为 0 后,报告上传完成及预览链接已返回。不要把电脑页保留的绑定码说成试玩码。
|
|
24
29
|
|
|
25
30
|
已有 ZIP 时,用 `--package ./game.zip` 替换 `--dir ./game`。无需预先执行 `ttmg login` 或配置 PPE 环境。描述和分类可省略,CLI 使用默认资料;完整参数见下文。
|
|
26
31
|
|
|
27
32
|
## 安装与本地预检
|
|
28
33
|
|
|
29
|
-
安装后确认版本为 `0.4.6-vibe-beta.
|
|
34
|
+
安装后确认版本为 `0.4.6-vibe-beta.18`,能力查询中 `authorizationMode` 为 `qr`、`previewQr` 为 `false`,`preview.qrPurpose` 为 `authorization_binding`。支持 Node.js 20.19.1–20.x 或 22 及以上版本。
|
|
30
35
|
|
|
31
36
|
```sh
|
|
32
|
-
npm install -g @ttmg/cli@0.4.6-vibe-beta.
|
|
37
|
+
npm install -g @ttmg/cli@0.4.6-vibe-beta.18
|
|
33
38
|
ttmg --version
|
|
34
39
|
ttmg capabilities --format json
|
|
35
40
|
```
|
|
@@ -113,7 +118,8 @@ ttmg upload --vibe --dir ./game --title "星环守卫" --icon ./avatar.png --cat
|
|
|
113
118
|
|
|
114
119
|
3. 收到 `uploading`,按 `uploadStep` 展示 `avatar`、`app_info`、`package` 进度。授权轮询和上传由 CLI 完成。
|
|
115
120
|
|
|
116
|
-
4. 收到 `
|
|
121
|
+
4. 收到 `waiting_preview` 时,素材已上传,保持原进程运行。CLI 使用同一任务继续查询;状态已完成但尚无预览链接时也继续等待。
|
|
122
|
+
5. 终态仍为 `status=uploaded`。`previewReady=true` 表示后端预览链接已返回;`qrPurpose=authorization_binding` 表示 `pageUrl` 保留原绑定码,`previewUrl` 不作为该页面的二维码内容。等待失败时保留 `uploaded=true`,同时返回错误和 `nextAction=check_task`,不要重新上传。
|
|
117
123
|
|
|
118
124
|
## 扫码授权与自动上传
|
|
119
125
|
|
|
@@ -147,7 +153,8 @@ ttmg auth open --page-url <pageUrl> --format json
|
|
|
147
153
|
|
|
148
154
|
- `uploading`:根据 uploadStep 显示 avatar、app_info、package 的进度,不再询问授权。
|
|
149
155
|
|
|
150
|
-
- `
|
|
156
|
+
- `waiting_preview`:uploaded=true、terminal=false,正在查询后端处理结果,等待预览链接。
|
|
157
|
+
- `uploaded`:terminal=true、uploaded=true、simulation=false 且退出码 0:上传完成,previewReady=true 时已取得预览链接;电脑页保留原绑定码,不是审核通过或正式发布。
|
|
151
158
|
|
|
152
159
|
- `failed / cancelled`:根据 errorCode、message 和 nextAction 提示处理,不自动重传。
|
|
153
160
|
|
|
@@ -158,15 +165,17 @@ ttmg auth open --page-url <pageUrl> --format json
|
|
|
158
165
|
|
|
159
166
|
按阶段补充:`taskId`(字符串,禁止转成 JS Number)、`pollIntervalSeconds`、`readyForInput`、`taskStatusRaw`(仅诊断)、`uploadStep`、`loadedBytes`、`totalBytes`、`pageUrl`、`qrPurpose=authorization_binding`、素材大小和包 SHA256。代码包字节进度达到 100% 不代表成功,必须等待最终上传回执。
|
|
160
167
|
|
|
161
|
-
`nextAction` 取值:`wait`、`scan_qr`、`fix_input`、`restart_authorization`、`check_task`、`none`。已开始上传后发生失败/超时,先检查 task
|
|
168
|
+
`nextAction` 取值:`wait`、`scan_qr`、`fix_input`、`restart_authorization`、`check_task`、`none`。已开始上传后发生失败/超时,先检查 task,不能直接再次创建并重传。预览等待超时返回 `VIBE_PREVIEW_TIMEOUT`;查询失败、取消或页面失败均保留 `uploaded=true`,并返回错误及 `nextAction=check_task`。
|
|
169
|
+
|
|
170
|
+
新结果字段:`previewUrl`、`previewReady`、`clientKey`、`appId`、`codeAssetId`、`minisCenterHistoryId`。业务 ID 使用字符串,后端尚未返回时省略;只有有效的非空 preview_url 才触发预览就绪。Mock 保持模拟上传终态,不返回真实预览二维码。
|
|
162
171
|
|
|
163
172
|
退出码:成功/dry-run 为 0,失败为 1,Ctrl+C 为 130。进程或宿主意外终止导致没有终态时,不得认定上传成功。
|
|
164
173
|
|
|
165
|
-
轮询间隔使用创建任务返回的 `poll_interval_seconds`。`--timeout`
|
|
174
|
+
轮询间隔使用创建任务返回的 `poll_interval_seconds`。`--timeout` 是包括授权、上传和等待预览的整体超时,默认 300 秒。不自动重试写接口、不实现跨进程续传。
|
|
166
175
|
|
|
167
176
|
## 页面与素材
|
|
168
177
|
|
|
169
|
-
|
|
178
|
+
本地页在扫码、上传、等待预览、成功或失败时均展示本次资料。后台查询状态,只更新变化内容,不整页刷新;预览就绪或终态失败后停止查询。授权后上传期间移除绑定码;素材上传成功后先展示成功提示约 1.2 秒,再平滑返回最初扫码布局,使用原始 landing_url 生成同一个绑定码,文案明确本次已上传。preview_url 返回后也不替换二维码。Skill 可用 `pageUrl` 重新打开同一页面,重新打开时直接显示保留的绑定码。绑定链接仍受后端任务有效期约束,页面不会创建新任务或重新上传。
|
|
170
179
|
|
|
171
180
|
页面只监听 127.0.0.1,二维码才由手机扫描,手机不访问 pageUrl。默认 15 分钟后关闭,内容驻留内存;测试可设置 `TTMG_VIBE_PAGE_TTL_MS`(1—900000)。取消进程会关闭页面;成功与可显示的失败页面保留至到期。不要分享本地页面地址。
|
|
172
181
|
|
|
@@ -182,7 +191,7 @@ CLI 在工程目录的 `.ttmg/vibe-project.json` 保存并复用非敏感 source
|
|
|
182
191
|
|
|
183
192
|
- `POST create_minis_import_task_for_agent/`:请求 source_type=1、source_project_id、task_idempotency_id、minis_type=MINI_GAME。响应 task_id、import_token、landing_url、poll_interval_seconds。
|
|
184
193
|
|
|
185
|
-
- `GET
|
|
194
|
+
- `GET get_minis_import_task_detail_for_agent/`:请求 Query:task_id、import_token。响应 status、ready_for_input,以及可选的 client_key、app_id、code_asset_id、minis_center_history_id、preview_url;授权和上传后的轮询均使用此接口。
|
|
186
195
|
|
|
187
196
|
- `POST upload_minis_import_app_icon_for_agent/`:请求 Multipart:task_id、import_token、file。响应 icon_uri。
|
|
188
197
|
|
|
@@ -191,7 +200,7 @@ CLI 在工程目录的 `.ttmg/vibe-project.json` 保存并复用非敏感 source
|
|
|
191
200
|
- `POST upload_minis_import_package_for_agent/`:请求 Multipart:task_id、import_token、asset_type=2、file。响应 package_uri、status。
|
|
192
201
|
|
|
193
202
|
|
|
194
|
-
所有响应必须业务 `error_info.code=0
|
|
203
|
+
所有响应必须业务 `error_info.code=0`。上传回执还要求非空 package_uri 和合法非失败状态;收到回执后继续查询 Detail,直到拿到有效 preview_url。HTTP 200、进度100% 都不能单独作为成功判定。19位 task_id 在 CLI 内保留字符串,提交 i64 JSON 时无损编码。任务凭据只在当前进程内保留,终态后清除。
|
|
195
204
|
|
|
196
205
|
```sh
|
|
197
206
|
TTMG_VIBE_BACKEND=local-http TTMG_VIBE_API=http://127.0.0.1:3100 ttmg upload --vibe --package ./game.zip --title "测试游戏" --icon ./avatar.png --format ndjson
|
|
@@ -199,7 +208,9 @@ TTMG_VIBE_BACKEND=local-http TTMG_VIBE_API=http://127.0.0.1:3100 ttmg upload --v
|
|
|
199
208
|
|
|
200
209
|
维护者可使用 `--vibe-api http://127.0.0.1:3100` 验证本机 HTTP 合同,只接受回环 IP,不跟随重定向、不读取 Cookie;本地服务需实现上表协议。Skill 使用 `--vibe`,PPE 路由由 CLI 内置。正式环境未开放。
|
|
201
210
|
|
|
202
|
-
**v1 → v2 兼容性变化**:旧 UUID 换 Token 的三接口协议废弃,`--vibe-authorize-url` 返回明确错误;授权地址来自 landing_url
|
|
211
|
+
**v1 → v2 兼容性变化**:旧 UUID 换 Token 的三接口协议废弃,`--vibe-authorize-url` 返回明确错误;授权地址来自 landing_url。不再输出旧 preview_ready 状态、uploadId、reviewStatus。
|
|
212
|
+
|
|
213
|
+
beta.18 保留 waiting_preview 状态和 uploaded 终态;与 beta.17 相比,成功页改回原绑定码,终态 qrPurpose 改为已有枚举 authorization_binding,previewQr 能力设为 false。previewUrl / previewReady 的含义不变,schemaVersion 仍为 2;Skill 需按 qrPurpose 判断页面二维码用途,不再把 previewReady 等同于页面显示试玩码。普通不带 --vibe 的 upload 不变。
|
|
203
214
|
|
|
204
215
|
2026-09-14 已核对 BFF 源码:头像 PNG/JPEG、1024×1024、5 MiB;Native ZIP 和解压总大小上限 100 MiB。本地暂未实现完整 ZIP 内容及解压总大小校验。2026-09-16 本地构建使用自有测试素材跑通真实 PPE 手机扫码授权、头像、默认资料和代码包上传。该验证不覆盖全部游戏或正式环境。后端接口调整留在适配层处理;若用户动作或成功语义改变,应协商升级 CLI schema。
|
|
205
216
|
|