@ttmg/cli 0.4.6-vibe-beta.8 → 0.4.6-vibe-beta.10
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 +4 -8
- package/dist/index.js +54 -33
- package/dist/index.js.map +1 -1
- package/dist/package.json +1 -1
- package/dist/scripts/verify-agent-contract.js +2 -0
- package/dist/scripts/vibe-ppe-test-preload.cjs +16 -2
- package/dist/scripts/vibe-upload-smoke.js +78 -11
- package/package.json +1 -1
- package/vibe-upload.md +24 -47
package/README.md
CHANGED
|
@@ -1,12 +1,8 @@
|
|
|
1
1
|
### @ttmg/cli
|
|
2
2
|
|
|
3
|
-
Vibe
|
|
3
|
+
Vibe 真实网页授权与上传:`ttmg upload --vibe --web --dir ./game --title "My game" --icon ./avatar.png --format ndjson`。只向用户收集标题和本地头像,并使用游戏目录或代码包;其他应用资料由平台默认处理,不需要用户填写。网页授权后,CLI 自动继续上传。见 [Vibe 接入说明](vibe-upload.md)。
|
|
4
4
|
|
|
5
|
-
Vibe
|
|
6
|
-
|
|
7
|
-
Vibe 真实网页授权:`ttmg upload --vibe --web --dir ./game --title "My game" --icon ./avatar.png --format ndjson`。内置 PPE 创建任务后打开系统浏览器,持续查询真实绑定状态,不模拟授权;当前真实素材上传仍受限制。`--web` 不能与 `--mock` 或 `--no-open` 同用,原 `--mock` 链路不变。详见 [Vibe 接入说明](vibe-upload.md)。
|
|
8
|
-
|
|
9
|
-
Vibe real web authorization: use `--web` without `--mock`. It creates a PPE task, opens the system browser and polls real binding status; real material upload remains gated. It conflicts with `--mock` and `--no-open`. The original Mock workflow is unchanged. See [Vibe integration](vibe-upload.md).
|
|
5
|
+
Vibe real web authorization and upload: use `--web` with the title, local icon and game directory or ZIP. Collect only the title and icon from the user; the platform defaults all other app metadata. Upload continues after browser authorization. See [Vibe integration](vibe-upload.md).
|
|
10
6
|
|
|
11
7
|
`ttmg` is a command-line tool designed for managing and developing mini-game projects. It supports initialization, development, debugging, and packaging for both H5 and native mini-games.
|
|
12
8
|
`ttmg` 是一款专为小游戏项目管理与开发设计的命令行工具,支持 H5 小游戏和原生小游戏的初始化、开发调试及打包构建。
|
|
@@ -73,8 +69,8 @@ simulated. See [Vibe binding/upload](vibe-upload.md) for schema-v2 results.
|
|
|
73
69
|
`--mock` now creates real PPE tasks, not a fully offline run. Real request failures
|
|
74
70
|
still fail. Production routing is a future CLI release change, not Skill configuration.
|
|
75
71
|
|
|
76
|
-
|
|
77
|
-
|
|
72
|
+
当前上传只需要标题、头像和游戏目录或代码包,其他应用资料由平台默认处理。Skill 读取 `inputRequirements`,不向用户索要额外资料;本地预检使用 `--dry-run`。
|
|
73
|
+
Current uploads need only the title, icon and game directory or ZIP. The platform defaults other metadata. Read `inputRequirements` and do not request extra fields. Use `--dry-run` for local preparation.
|
|
78
74
|
|
|
79
75
|
For the existing authenticated platform workflow, log in first; this does not apply to the local Vibe prototype above.
|
|
80
76
|
原有需要平台鉴权的流程仍先登录;上述 Vibe 本地原型不需要此步骤。
|
package/dist/index.js
CHANGED
|
@@ -21,6 +21,7 @@ var express = require('express');
|
|
|
21
21
|
var cheerio = require('cheerio');
|
|
22
22
|
var archiver = require('archiver');
|
|
23
23
|
var FormData$1 = require('form-data');
|
|
24
|
+
var https = require('https');
|
|
24
25
|
var promises = require('timers/promises');
|
|
25
26
|
var chokidar = require('chokidar');
|
|
26
27
|
var WebSocket = require('ws');
|
|
@@ -34,7 +35,6 @@ var require$$0 = require('util');
|
|
|
34
35
|
var require$$0$1 = require('events');
|
|
35
36
|
var require$$0$2 = require('buffer');
|
|
36
37
|
var require$$1$2 = require('stream');
|
|
37
|
-
var https = require('https');
|
|
38
38
|
var dns = require('dns');
|
|
39
39
|
var boxen = require('boxen');
|
|
40
40
|
var semver = require('semver');
|
|
@@ -7232,7 +7232,7 @@ const messages = {
|
|
|
7232
7232
|
'cli.command.logout.desc': 'Logout and clear local user data',
|
|
7233
7233
|
'cli.command.auth.desc': 'Inspect local authentication state',
|
|
7234
7234
|
'cli.command.auth.open.desc': 'Open an existing Vibe task authorization page in the system browser',
|
|
7235
|
-
'cli.command.upload.vibeWeb': '
|
|
7235
|
+
'cli.command.upload.vibeWeb': 'Authorize in the browser, then upload to PPE (--vibe; no Mock or --no-open)',
|
|
7236
7236
|
'cli.command.auth.open.pageUrl': 'Local pageUrl returned by the running Vibe upload command',
|
|
7237
7237
|
'cli.command.auth.open.requested': 'Browser open requested. Complete authorization there; the existing upload process continues polling.',
|
|
7238
7238
|
'cli.command.auth.open.invalidPage': 'Pass the local pageUrl from the running Vibe upload command, not the platform URL.',
|
|
@@ -7435,9 +7435,9 @@ const messages = {
|
|
|
7435
7435
|
'cli.command.upload.servePreviewPage': 'Serve a temporary local preview page with test-account and preview QR codes',
|
|
7436
7436
|
'cli.command.upload.noOpen': 'Do not open the local preview page in the default browser',
|
|
7437
7437
|
'cli.command.upload.format': 'Output format: text | json | ndjson',
|
|
7438
|
-
'cli.command.upload.vibe': '
|
|
7438
|
+
'cli.command.upload.vibe': 'Binding and upload: collect only title and icon; other app metadata uses platform defaults (schema v2)',
|
|
7439
7439
|
'cli.command.upload.vibeTitle': 'Game title supplied by the Skill (--vibe)',
|
|
7440
|
-
'cli.command.upload.vibeAppInfo': '
|
|
7440
|
+
'cli.command.upload.vibeAppInfo': 'Legacy metadata file compatibility; not needed for current uploads and must not be requested from users',
|
|
7441
7441
|
'cli.command.upload.vibeIcon': 'Local PNG/JPEG/WebP selected by the user (--vibe)',
|
|
7442
7442
|
'cli.command.upload.vibePackage': 'Prepared ZIP instead of --dir (--vibe)',
|
|
7443
7443
|
'cli.command.upload.vibeDryRun': 'Validate and package locally without authorization or upload (--vibe)',
|
|
@@ -7645,7 +7645,7 @@ const messages = {
|
|
|
7645
7645
|
'cli.command.logout.desc': '退出登录并清除本地用户信息',
|
|
7646
7646
|
'cli.command.auth.desc': '查看本地登录状态',
|
|
7647
7647
|
'cli.command.auth.open.desc': '在系统浏览器打开已有 Vibe 任务的授权页',
|
|
7648
|
-
'cli.command.upload.vibeWeb': '
|
|
7648
|
+
'cli.command.upload.vibeWeb': '网页授权就绪后自动上传到 PPE(--vibe;不能与 Mock 或 --no-open 同用)',
|
|
7649
7649
|
'cli.command.auth.open.pageUrl': '正在运行的 Vibe 上传命令返回的本地 pageUrl',
|
|
7650
7650
|
'cli.command.auth.open.requested': '已请求浏览器打开授权页。请在页面完成授权,原上传进程继续轮询。',
|
|
7651
7651
|
'cli.command.auth.open.invalidPage': '请传入正在运行的 Vibe 上传命令返回的本地 pageUrl,不是平台授权链接。',
|
|
@@ -7848,8 +7848,8 @@ const messages = {
|
|
|
7848
7848
|
'cli.command.upload.servePreviewPage': '启动包含测试账号与预览二维码的临时本地页面',
|
|
7849
7849
|
'cli.command.upload.noOpen': '不使用默认浏览器打开本地预览页面',
|
|
7850
7850
|
'cli.command.upload.format': '输出格式:text | json | ndjson',
|
|
7851
|
-
'cli.command.upload.vibe': '
|
|
7852
|
-
'cli.command.upload.vibeAppInfo': '
|
|
7851
|
+
'cli.command.upload.vibe': '绑定上传:只收集标题和头像,其他应用资料由平台默认处理(schema v2)',
|
|
7852
|
+
'cli.command.upload.vibeAppInfo': '仅兼容旧资料文件;当前上传无需此参数,不应向用户索要',
|
|
7853
7853
|
'cli.command.upload.vibeTitle': 'Skill 提供的游戏标题(--vibe)',
|
|
7854
7854
|
'cli.command.upload.vibeIcon': '用户指定的本地 PNG/JPEG/WebP 图片(--vibe)',
|
|
7855
7855
|
'cli.command.upload.vibePackage': '已准备的 ZIP,与 --dir 二选一(--vibe)',
|
|
@@ -16308,7 +16308,7 @@ async function authStatus(options = {}) {
|
|
|
16308
16308
|
return result;
|
|
16309
16309
|
}
|
|
16310
16310
|
|
|
16311
|
-
var version = "0.4.6-vibe-beta.
|
|
16311
|
+
var version = "0.4.6-vibe-beta.10";
|
|
16312
16312
|
var engines = {
|
|
16313
16313
|
node: ">=20.19.1 <21 || >=22"
|
|
16314
16314
|
};
|
|
@@ -16317,6 +16317,20 @@ var pkg = {
|
|
|
16317
16317
|
engines: engines
|
|
16318
16318
|
};
|
|
16319
16319
|
|
|
16320
|
+
// Skill-facing v2 contract. Backend credentials never cross this boundary.
|
|
16321
|
+
const VIBE_INPUT_REQUIREMENTS = {
|
|
16322
|
+
requiredUserInputs: ['title', 'icon'],
|
|
16323
|
+
codeSource: ['dir', 'package'],
|
|
16324
|
+
additionalMetadataSource: 'platform-defaults',
|
|
16325
|
+
requestAdditionalMetadata: false,
|
|
16326
|
+
};
|
|
16327
|
+
class VibeError extends Error {
|
|
16328
|
+
constructor(code) {
|
|
16329
|
+
super(code);
|
|
16330
|
+
this.code = code;
|
|
16331
|
+
}
|
|
16332
|
+
}
|
|
16333
|
+
|
|
16320
16334
|
function getCapabilities() {
|
|
16321
16335
|
return {
|
|
16322
16336
|
schemaVersion: '1',
|
|
@@ -16351,20 +16365,24 @@ function getCapabilities() {
|
|
|
16351
16365
|
taskCreation: true,
|
|
16352
16366
|
statusPolling: true,
|
|
16353
16367
|
authorizationScheme: 'aweme://webview?url=<encoded landing_url>',
|
|
16354
|
-
uploadEnabled:
|
|
16355
|
-
uploadBlockedError: 'VIBE_REAL_UPLOAD_NOT_READY',
|
|
16368
|
+
uploadEnabled: true,
|
|
16356
16369
|
},
|
|
16357
16370
|
terminalSuccess: 'uploaded',
|
|
16358
16371
|
stages: ['precheck', 'packaging', 'prepared', 'creating_task', 'waiting_authorization', 'uploading', 'uploaded', 'failed', 'cancelled'],
|
|
16359
16372
|
uploadSteps: ['avatar', 'app_info', 'package'],
|
|
16360
16373
|
sourceProjectIdentity: '.ttmg/vibe-project.json',
|
|
16361
16374
|
metadataInputs: ['title', 'icon', 'dir|package'],
|
|
16362
|
-
|
|
16375
|
+
inputRequirements: VIBE_INPUT_REQUIREMENTS,
|
|
16376
|
+
webAuthorization: { option: '--web', backend: 'ppe', defaultLane: 'ppe_op_vc', simulation: false, opensSystemBrowser: true, continuesPolling: true, formatIndependent: true, conflictsWith: ['--mock', '--mock-scenario', '--vibe-api', '--no-open'], mockBehaviorUnchanged: true, materialUploadEnabled: true },
|
|
16363
16377
|
optionalMetadataFile: '--app-info',
|
|
16364
16378
|
appInfoFields: {
|
|
16365
|
-
required: [
|
|
16366
|
-
optional: [
|
|
16379
|
+
required: [],
|
|
16380
|
+
optional: [],
|
|
16367
16381
|
suppliedByCli: ['app_name', 'icon_uri'],
|
|
16382
|
+
additionalMetadataSource: 'platform-defaults',
|
|
16383
|
+
requestFromUser: false,
|
|
16384
|
+
legacyFileOption: '--app-info',
|
|
16385
|
+
legacyFileOptionRecommended: false,
|
|
16368
16386
|
},
|
|
16369
16387
|
appInfoPreflight: {
|
|
16370
16388
|
titleMaxCharacters: 30,
|
|
@@ -17126,7 +17144,7 @@ withVerboseOption(program
|
|
|
17126
17144
|
// Vibe v2 backend selection (including opt-in ppe-mock) stays outside the Skill workflow.
|
|
17127
17145
|
.option('--title <title>', t('cli.command.upload.vibeTitle'))
|
|
17128
17146
|
.option('--icon <path>', t('cli.command.upload.vibeIcon'))
|
|
17129
|
-
.
|
|
17147
|
+
.addOption(new commander.Option('--app-info <path>', t('cli.command.upload.vibeAppInfo')).hideHelp())
|
|
17130
17148
|
.option('--package <path>', t('cli.command.upload.vibePackage'))
|
|
17131
17149
|
.option('--dry-run', t('cli.command.upload.vibeDryRun'))
|
|
17132
17150
|
.option('--mock', t('cli.command.upload.vibeMock'))
|
|
@@ -17576,13 +17594,6 @@ else {
|
|
|
17576
17594
|
program.parse(process.argv);
|
|
17577
17595
|
}
|
|
17578
17596
|
|
|
17579
|
-
class VibeError extends Error {
|
|
17580
|
-
constructor(code) {
|
|
17581
|
-
super(code);
|
|
17582
|
-
this.code = code;
|
|
17583
|
-
}
|
|
17584
|
-
}
|
|
17585
|
-
|
|
17586
17597
|
// Only the backend-owned authorization page can be a browser redirect target.
|
|
17587
17598
|
// Never return its import_token to Skill stdout or put it in a CLI argument.
|
|
17588
17599
|
function browserLandingUrl(value) {
|
|
@@ -17694,7 +17705,7 @@ var authOpen = /*#__PURE__*/Object.freeze({
|
|
|
17694
17705
|
vibeAuthOpen: vibeAuthOpen
|
|
17695
17706
|
});
|
|
17696
17707
|
|
|
17697
|
-
// BFF IDL: feat-minis-import. PPE
|
|
17708
|
+
// BFF IDL: feat-minis-import. PPE import flow; no production adapter.
|
|
17698
17709
|
const prefix = '/bff/app_info/minis_import/';
|
|
17699
17710
|
const MINIS_IMPORT_PATHS = {
|
|
17700
17711
|
create: `${prefix}create_minis_import_task_for_agent/`,
|
|
@@ -17862,15 +17873,9 @@ function createPpeBackend(lane, adapter) {
|
|
|
17862
17873
|
'x-use-ppe': '1',
|
|
17863
17874
|
'x-tt-env': lane,
|
|
17864
17875
|
}, adapter);
|
|
17865
|
-
const uploadUnavailable = async () => {
|
|
17866
|
-
throw new VibeError('VIBE_REAL_UPLOAD_NOT_READY');
|
|
17867
|
-
};
|
|
17868
17876
|
return {
|
|
17869
17877
|
...backend,
|
|
17870
|
-
uploadAvailable:
|
|
17871
|
-
uploadIcon: uploadUnavailable,
|
|
17872
|
-
submitInfo: uploadUnavailable,
|
|
17873
|
-
uploadPackage: uploadUnavailable,
|
|
17878
|
+
uploadAvailable: true,
|
|
17874
17879
|
};
|
|
17875
17880
|
}
|
|
17876
17881
|
/** Opt-in integration demo: only creation and polling can reach PPE. */
|
|
@@ -17894,6 +17899,7 @@ function createPpeMockBackend(lane, adapter, scenario = 'success') {
|
|
|
17894
17899
|
return {
|
|
17895
17900
|
mode: 'ppe-mock',
|
|
17896
17901
|
uploadAvailable: true,
|
|
17902
|
+
dispose: () => real.dispose?.(),
|
|
17897
17903
|
async createTask(input, signal) {
|
|
17898
17904
|
if (realTask)
|
|
17899
17905
|
throw new VibeError('VIBE_TASK_NOT_ACCEPTING_INPUT');
|
|
@@ -17925,14 +17931,20 @@ function createPpeMockBackend(lane, adapter, scenario = 'success') {
|
|
|
17925
17931
|
};
|
|
17926
17932
|
}
|
|
17927
17933
|
function createHttpBackend(mode, baseURL, environmentHeaders = {}, adapter) {
|
|
17934
|
+
// Own the agents so an early multipart response cannot leave upload sockets
|
|
17935
|
+
// keeping the CLI alive after its terminal result. Never destroy global agents.
|
|
17936
|
+
const httpAgent = new http.Agent();
|
|
17937
|
+
const httpsAgent = new https.Agent();
|
|
17928
17938
|
const client = axios.create({
|
|
17929
17939
|
baseURL,
|
|
17930
17940
|
timeout: 30000,
|
|
17931
17941
|
maxRedirects: 0,
|
|
17932
17942
|
proxy: false,
|
|
17933
17943
|
adapter,
|
|
17944
|
+
httpAgent,
|
|
17945
|
+
httpsAgent,
|
|
17934
17946
|
});
|
|
17935
|
-
|
|
17947
|
+
const backend = createBackend(mode, async (request) => {
|
|
17936
17948
|
try {
|
|
17937
17949
|
let body;
|
|
17938
17950
|
let headers = {};
|
|
@@ -17971,6 +17983,13 @@ function createHttpBackend(mode, baseURL, environmentHeaders = {}, adapter) {
|
|
|
17971
17983
|
: 'VIBE_BACKEND_REQUEST_FAILED');
|
|
17972
17984
|
}
|
|
17973
17985
|
});
|
|
17986
|
+
return {
|
|
17987
|
+
...backend,
|
|
17988
|
+
dispose() {
|
|
17989
|
+
httpAgent.destroy();
|
|
17990
|
+
httpsAgent.destroy();
|
|
17991
|
+
},
|
|
17992
|
+
};
|
|
17974
17993
|
}
|
|
17975
17994
|
const MOCK_SCENARIOS = [
|
|
17976
17995
|
'success',
|
|
@@ -18837,6 +18856,7 @@ async function executeVibeUpload(options, onEvent = () => { }, dependencies = {}
|
|
|
18837
18856
|
let timeout;
|
|
18838
18857
|
let timedOut = false;
|
|
18839
18858
|
let page;
|
|
18859
|
+
let backend = deps.backend;
|
|
18840
18860
|
let detached = false;
|
|
18841
18861
|
let progressUpdates = Promise.resolve();
|
|
18842
18862
|
let ppeLane;
|
|
@@ -18846,6 +18866,7 @@ async function executeVibeUpload(options, onEvent = () => { }, dependencies = {}
|
|
|
18846
18866
|
schemaVersion: '2',
|
|
18847
18867
|
command: 'upload',
|
|
18848
18868
|
mode: 'vibe',
|
|
18869
|
+
inputRequirements: VIBE_INPUT_REQUIREMENTS,
|
|
18849
18870
|
operationId: `vibe_${crypto.randomUUID()}`,
|
|
18850
18871
|
ts: Date.now(),
|
|
18851
18872
|
status: 'precheck',
|
|
@@ -18926,7 +18947,6 @@ async function executeVibeUpload(options, onEvent = () => { }, dependencies = {}
|
|
|
18926
18947
|
timedOut = true;
|
|
18927
18948
|
controller.abort();
|
|
18928
18949
|
}, timeoutMs);
|
|
18929
|
-
let backend = deps.backend;
|
|
18930
18950
|
if (!options.dryRun && !backend) {
|
|
18931
18951
|
if (options.mock)
|
|
18932
18952
|
backend = deps.createTrialBackend(options.mockScenario);
|
|
@@ -19159,8 +19179,8 @@ async function executeVibeUpload(options, onEvent = () => { }, dependencies = {}
|
|
|
19159
19179
|
VIBE_TITLE_REQUIRED: ['请提供游戏名称。', 'Provide a game title.'],
|
|
19160
19180
|
VIBE_TITLE_TOO_LONG: ['游戏名称不能超过 30 个字符。', 'The game title must not exceed 30 characters.'],
|
|
19161
19181
|
VIBE_INVALID_APP_INFO: [
|
|
19162
|
-
'
|
|
19163
|
-
'
|
|
19182
|
+
'旧 --app-info 文件无效。当前上传只需标题和头像,其他资料由平台默认处理;移除 --app-info 后重试,不要向用户索要额外资料。',
|
|
19183
|
+
'Invalid legacy --app-info file. Current uploads need only title and icon; the platform defaults other metadata. Remove --app-info and retry without requesting extra fields from the user.',
|
|
19164
19184
|
],
|
|
19165
19185
|
VIBE_PLATFORM_ICON_INVALID: [
|
|
19166
19186
|
'平台头像要求 PNG/JPEG、1024×1024,且不超过 5 MiB,请重新选择本地图片。',
|
|
@@ -19265,6 +19285,7 @@ async function executeVibeUpload(options, onEvent = () => { }, dependencies = {}
|
|
|
19265
19285
|
finally {
|
|
19266
19286
|
clearTimeout(timeout);
|
|
19267
19287
|
externalSignal?.removeEventListener('abort', cancel);
|
|
19288
|
+
backend?.dispose?.();
|
|
19268
19289
|
if (page && !detached)
|
|
19269
19290
|
page.close();
|
|
19270
19291
|
}
|