@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/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.22";
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
- if (cmd.vibe) {
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(cmd);
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
- return (await client.request({
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: { ...environmentHeaders, ...headers },
19013
+ headers: requestHeaders,
18959
19014
  signal: request.signal,
18960
19015
  maxBodyLength: Infinity,
18961
19016
  onUploadProgress: p => request.onProgress?.(p.loaded, p.total),
18962
- })).data;
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: result.operationId,
20381
+ task_idempotency_id: taskIdempotencyId,
20296
20382
  minis_type: minisType,
20297
20383
  }, controller.signal);
20298
20384
  ensureActive();