@ttmg/cli 0.4.6-vibe-beta.22 → 0.4.6-vibe-beta.24
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/CHANGELOG.md +556 -0
- package/README.md +3 -3
- package/dist/index.js +108 -22
- package/dist/index.js.map +1 -1
- package/dist/package.json +1 -1
- package/dist/scripts/vibe-upload-smoke.js +26 -4
- package/package.json +1 -1
- package/src/commands/common/game/categories.test.ts +38 -0
- package/src/commands/common/game/categories.ts +48 -0
- package/src/commands/common/game/categoryCatalog.json +522 -0
- package/vibe-upload.md +7 -5
package/dist/index.js
CHANGED
|
@@ -16386,7 +16386,7 @@ async function authStatus(options = {}) {
|
|
|
16386
16386
|
return result;
|
|
16387
16387
|
}
|
|
16388
16388
|
|
|
16389
|
-
var version = "0.4.6-vibe-beta.
|
|
16389
|
+
var version = "0.4.6-vibe-beta.24";
|
|
16390
16390
|
var engines = {
|
|
16391
16391
|
node: ">=20.19.1 <21 || >=22"
|
|
16392
16392
|
};
|
|
@@ -18084,10 +18084,11 @@ withVerboseOption(program
|
|
|
18084
18084
|
.option('--poll-interval <seconds>', t('cli.command.upload.vibePollInterval'))
|
|
18085
18085
|
.option('--timeout <seconds>', t('cli.command.upload.vibeTimeout'))
|
|
18086
18086
|
.option('--format <format>', t('cli.command.upload.format'), 'text')
|
|
18087
|
-
.addHelpText('after', t('cli.command.upload.vibeWebGuide'))).action(async (cmd) => {
|
|
18088
|
-
|
|
18087
|
+
.addHelpText('after', t('cli.command.upload.vibeWebGuide'))).action(async (cmd, command) => {
|
|
18088
|
+
const uploadOptions = { ...command.optsWithGlobals(), ...cmd };
|
|
18089
|
+
if (uploadOptions.vibe) {
|
|
18089
18090
|
const { vibeUpload } = await Promise.resolve().then(function () { return index$1; });
|
|
18090
|
-
await vibeUpload(
|
|
18091
|
+
await vibeUpload(uploadOptions);
|
|
18091
18092
|
return;
|
|
18092
18093
|
}
|
|
18093
18094
|
if ([
|
|
@@ -18668,6 +18669,50 @@ const MINIS_IMPORT_PATHS = {
|
|
|
18668
18669
|
info: `${prefix}submit_minis_import_info_for_agent/`,
|
|
18669
18670
|
package: `${prefix}upload_minis_import_package_for_agent/`,
|
|
18670
18671
|
};
|
|
18672
|
+
const sensitiveKey = /authorization|cookie|password|secret|token|email/i;
|
|
18673
|
+
function safeTraceUrl(value) {
|
|
18674
|
+
try {
|
|
18675
|
+
const url = new URL(value);
|
|
18676
|
+
for (const key of url.searchParams.keys()) {
|
|
18677
|
+
if (sensitiveKey.test(key))
|
|
18678
|
+
url.searchParams.set(key, '[REDACTED]');
|
|
18679
|
+
}
|
|
18680
|
+
return url.toString();
|
|
18681
|
+
}
|
|
18682
|
+
catch {
|
|
18683
|
+
return value;
|
|
18684
|
+
}
|
|
18685
|
+
}
|
|
18686
|
+
function safeTraceError(value) {
|
|
18687
|
+
return String(value ?? '')
|
|
18688
|
+
.replace(/([?&](?:import_token|access_token|token)=)[^&#\s]*/gi, '$1[REDACTED]')
|
|
18689
|
+
.replace(/((?:import_token|access_token|token)[=:]\s*)[^,;\s]*/gi, '$1[REDACTED]');
|
|
18690
|
+
}
|
|
18691
|
+
function safeTraceValue(value, key = '', seen = new WeakSet()) {
|
|
18692
|
+
if (sensitiveKey.test(key))
|
|
18693
|
+
return '[REDACTED]';
|
|
18694
|
+
if (Buffer.isBuffer(value))
|
|
18695
|
+
return { type: 'Buffer', sizeBytes: value.length };
|
|
18696
|
+
if (typeof value === 'string')
|
|
18697
|
+
return /url$/i.test(key) || /^https?:\/\//i.test(value) ? safeTraceUrl(value) : value;
|
|
18698
|
+
if (!value || typeof value !== 'object')
|
|
18699
|
+
return value;
|
|
18700
|
+
if (seen.has(value))
|
|
18701
|
+
return '[Circular]';
|
|
18702
|
+
seen.add(value);
|
|
18703
|
+
if (Array.isArray(value))
|
|
18704
|
+
return value.map(item => safeTraceValue(item, '', seen));
|
|
18705
|
+
return Object.fromEntries(Object.entries(value).map(([childKey, childValue]) => [
|
|
18706
|
+
childKey,
|
|
18707
|
+
safeTraceValue(childValue, childKey, seen),
|
|
18708
|
+
]));
|
|
18709
|
+
}
|
|
18710
|
+
function emitTrace(sink, trace) {
|
|
18711
|
+
try {
|
|
18712
|
+
sink?.(trace);
|
|
18713
|
+
}
|
|
18714
|
+
catch { /* Diagnostics must never affect uploads. */ }
|
|
18715
|
+
}
|
|
18671
18716
|
function safeWebUrl(value) {
|
|
18672
18717
|
if (typeof value !== 'string')
|
|
18673
18718
|
throw new VibeError('VIBE_INVALID_RESPONSE');
|
|
@@ -18833,7 +18878,7 @@ function createBackend(mode, transport) {
|
|
|
18833
18878
|
},
|
|
18834
18879
|
};
|
|
18835
18880
|
}
|
|
18836
|
-
function createLocalHttpBackend(baseUrl) {
|
|
18881
|
+
function createLocalHttpBackend(baseUrl, adapter, trace) {
|
|
18837
18882
|
let base;
|
|
18838
18883
|
try {
|
|
18839
18884
|
base = new URL(safeWebUrl(baseUrl));
|
|
@@ -18846,16 +18891,16 @@ function createLocalHttpBackend(baseUrl) {
|
|
|
18846
18891
|
base.search ||
|
|
18847
18892
|
base.hash)
|
|
18848
18893
|
throw new VibeError('VIBE_INVALID_LOCAL_ENDPOINT');
|
|
18849
|
-
return createHttpBackend('local-http', base.origin);
|
|
18894
|
+
return createHttpBackend('local-http', base.origin, {}, adapter, trace);
|
|
18850
18895
|
}
|
|
18851
|
-
function createPpeBackend(lane, adapter) {
|
|
18896
|
+
function createPpeBackend(lane, adapter, trace) {
|
|
18852
18897
|
// No default lane and no production fallback. Keep PPE requests on the known host.
|
|
18853
18898
|
if (!lane || !/^ppe_[a-zA-Z0-9_-]{1,64}$/.test(lane))
|
|
18854
18899
|
throw new VibeError('VIBE_INVALID_PPE_ENV');
|
|
18855
18900
|
const backend = createHttpBackend('ppe', 'https://developers.tiktok.com', {
|
|
18856
18901
|
'x-use-ppe': '1',
|
|
18857
18902
|
'x-tt-env': lane,
|
|
18858
|
-
}, adapter);
|
|
18903
|
+
}, adapter, trace);
|
|
18859
18904
|
return {
|
|
18860
18905
|
...backend,
|
|
18861
18906
|
uploadAvailable: true,
|
|
@@ -18864,11 +18909,11 @@ function createPpeBackend(lane, adapter) {
|
|
|
18864
18909
|
/** Opt-in integration demo: only creation and polling can reach PPE. */
|
|
18865
18910
|
// Release-owned configuration, not a developer setup step. Remove PPE routing
|
|
18866
18911
|
// here when the production chain is ready; do not change the Skill command.
|
|
18867
|
-
function createVibeTrialBackend(scenario, adapter) {
|
|
18868
|
-
return createPpeMockBackend('ppe_op_vc', adapter, scenario);
|
|
18912
|
+
function createVibeTrialBackend(scenario, adapter, trace) {
|
|
18913
|
+
return createPpeMockBackend('ppe_op_vc', adapter, scenario, trace);
|
|
18869
18914
|
}
|
|
18870
|
-
function createPpeMockBackend(lane, adapter, scenario = 'success') {
|
|
18871
|
-
const real = createPpeBackend(lane, adapter);
|
|
18915
|
+
function createPpeMockBackend(lane, adapter, scenario = 'success', trace) {
|
|
18916
|
+
const real = createPpeBackend(lane, adapter, trace);
|
|
18872
18917
|
const mock = createMockBackend(scenario);
|
|
18873
18918
|
let realTask;
|
|
18874
18919
|
let mockTask;
|
|
@@ -18914,7 +18959,7 @@ function createPpeMockBackend(lane, adapter, scenario = 'success') {
|
|
|
18914
18959
|
uploadPackage: async (task, input, signal, onProgress) => mock.uploadPackage(uploadTask(task), input, signal, onProgress),
|
|
18915
18960
|
};
|
|
18916
18961
|
}
|
|
18917
|
-
function createHttpBackend(mode, baseURL, environmentHeaders = {}, adapter) {
|
|
18962
|
+
function createHttpBackend(mode, baseURL, environmentHeaders = {}, adapter, trace) {
|
|
18918
18963
|
// Own the agents so an early multipart response cannot leave upload sockets
|
|
18919
18964
|
// keeping the CLI alive after its terminal result. Never destroy global agents.
|
|
18920
18965
|
const httpAgent = new http.Agent();
|
|
@@ -18928,7 +18973,11 @@ function createHttpBackend(mode, baseURL, environmentHeaders = {}, adapter) {
|
|
|
18928
18973
|
httpAgent,
|
|
18929
18974
|
httpsAgent,
|
|
18930
18975
|
});
|
|
18976
|
+
let requestSequence = 0;
|
|
18931
18977
|
const backend = createBackend(mode, async (request) => {
|
|
18978
|
+
const requestId = ++requestSequence;
|
|
18979
|
+
const startedAt = Date.now();
|
|
18980
|
+
const url = new URL(request.path, baseURL).toString();
|
|
18932
18981
|
try {
|
|
18933
18982
|
let body;
|
|
18934
18983
|
let headers = {};
|
|
@@ -18950,18 +18999,42 @@ function createHttpBackend(mode, baseURL, environmentHeaders = {}, adapter) {
|
|
|
18950
18999
|
body = JSON.stringify(request.data).replace(/"task_id":"([1-9]\d*)"/, '"task_id":$1');
|
|
18951
19000
|
headers = { 'Content-Type': 'application/json' };
|
|
18952
19001
|
}
|
|
18953
|
-
|
|
19002
|
+
const requestHeaders = { ...environmentHeaders, ...headers };
|
|
19003
|
+
emitTrace(trace, {
|
|
19004
|
+
event: 'http_request', requestId, method: request.method, url,
|
|
19005
|
+
headers: safeTraceValue(requestHeaders),
|
|
19006
|
+
request: safeTraceValue(request.data),
|
|
19007
|
+
});
|
|
19008
|
+
const response = await client.request({
|
|
18954
19009
|
method: request.method,
|
|
18955
19010
|
url: request.path,
|
|
18956
19011
|
params: request.method === 'GET' ? request.data : undefined,
|
|
18957
19012
|
data: body,
|
|
18958
|
-
headers:
|
|
19013
|
+
headers: requestHeaders,
|
|
18959
19014
|
signal: request.signal,
|
|
18960
19015
|
maxBodyLength: Infinity,
|
|
18961
19016
|
onUploadProgress: p => request.onProgress?.(p.loaded, p.total),
|
|
18962
|
-
})
|
|
19017
|
+
});
|
|
19018
|
+
emitTrace(trace, {
|
|
19019
|
+
event: 'http_response', requestId, method: request.method, url,
|
|
19020
|
+
statusCode: response.status,
|
|
19021
|
+
headers: safeTraceValue(response.headers),
|
|
19022
|
+
response: safeTraceValue(response.data),
|
|
19023
|
+
elapsedMs: Date.now() - startedAt,
|
|
19024
|
+
});
|
|
19025
|
+
return response.data;
|
|
18963
19026
|
}
|
|
18964
|
-
catch {
|
|
19027
|
+
catch (error) {
|
|
19028
|
+
emitTrace(trace, {
|
|
19029
|
+
event: 'http_error', requestId, method: request.method, url,
|
|
19030
|
+
statusCode: error?.response?.status,
|
|
19031
|
+
headers: safeTraceValue(error?.response?.headers),
|
|
19032
|
+
response: safeTraceValue(error?.response?.data),
|
|
19033
|
+
elapsedMs: Date.now() - startedAt,
|
|
19034
|
+
error: request.signal.aborted
|
|
19035
|
+
? 'Request cancelled'
|
|
19036
|
+
: safeTraceError(error?.message || error),
|
|
19037
|
+
});
|
|
18965
19038
|
throw new VibeError(request.signal.aborted
|
|
18966
19039
|
? 'VIBE_CANCELLED'
|
|
18967
19040
|
: 'VIBE_BACKEND_REQUEST_FAILED');
|
|
@@ -20166,6 +20239,16 @@ async function executeVibeUpload(options, onEvent = () => { }, dependencies = {}
|
|
|
20166
20239
|
errorCode: null,
|
|
20167
20240
|
error: null,
|
|
20168
20241
|
};
|
|
20242
|
+
const httpTrace = options.verbose
|
|
20243
|
+
? trace => console.error(JSON.stringify({
|
|
20244
|
+
schemaVersion: '1',
|
|
20245
|
+
command: 'upload',
|
|
20246
|
+
mode: 'vibe',
|
|
20247
|
+
operationId: result.operationId,
|
|
20248
|
+
ts: Date.now(),
|
|
20249
|
+
...trace,
|
|
20250
|
+
}))
|
|
20251
|
+
: undefined;
|
|
20169
20252
|
const emit = (status, fields = {}) => {
|
|
20170
20253
|
result = {
|
|
20171
20254
|
...result,
|
|
@@ -20235,13 +20318,13 @@ async function executeVibeUpload(options, onEvent = () => { }, dependencies = {}
|
|
|
20235
20318
|
}, timeoutMs);
|
|
20236
20319
|
if (!options.dryRun && !backend) {
|
|
20237
20320
|
if (options.mock)
|
|
20238
|
-
backend = deps.createTrialBackend(options.mockScenario);
|
|
20321
|
+
backend = deps.createTrialBackend(options.mockScenario, undefined, httpTrace);
|
|
20239
20322
|
else if (hybridSelected)
|
|
20240
|
-
backend = createPpeMockBackend(ppeLane, undefined, options.mockScenario);
|
|
20323
|
+
backend = createPpeMockBackend(ppeLane, undefined, options.mockScenario, httpTrace);
|
|
20241
20324
|
else if (ppeSelected)
|
|
20242
|
-
backend = createPpeBackend(ppeLane);
|
|
20325
|
+
backend = createPpeBackend(ppeLane, undefined, httpTrace);
|
|
20243
20326
|
else if (options.vibeApi)
|
|
20244
|
-
backend = createLocalHttpBackend(options.vibeApi);
|
|
20327
|
+
backend = createLocalHttpBackend(options.vibeApi, undefined, httpTrace);
|
|
20245
20328
|
else
|
|
20246
20329
|
throw new VibeError('VIBE_BACKEND_NOT_CONFIGURED');
|
|
20247
20330
|
}
|
|
@@ -20288,11 +20371,14 @@ async function executeVibeUpload(options, onEvent = () => { }, dependencies = {}
|
|
|
20288
20371
|
hybrid: backend.mode === 'ppe-mock',
|
|
20289
20372
|
};
|
|
20290
20373
|
const sourceProjectId = deps.projectId(options);
|
|
20374
|
+
// The project ID identifies the game; the task request ID is new for each upload.
|
|
20375
|
+
// Keep it separate from the operation ID used in progress events.
|
|
20376
|
+
const taskIdempotencyId = crypto.randomUUID();
|
|
20291
20377
|
emit('creating_task', { platformWrite: backend.mode === 'ppe' || backend.mode === 'ppe-mock' });
|
|
20292
20378
|
task = await backend.createTask({
|
|
20293
20379
|
source_type: 1,
|
|
20294
20380
|
source_project_id: sourceProjectId,
|
|
20295
|
-
task_idempotency_id:
|
|
20381
|
+
task_idempotency_id: taskIdempotencyId,
|
|
20296
20382
|
minis_type: minisType,
|
|
20297
20383
|
}, controller.signal);
|
|
20298
20384
|
ensureActive();
|