@contentful/experience-design-system-cli 2.23.2-dev-build-09d87bb.0 → 2.23.2-dev-build-753ceef.0

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.
Files changed (69) hide show
  1. package/README.md +24 -2
  2. package/dist/package.json +2 -1
  3. package/dist/src/analytics/apply.d.ts +6 -0
  4. package/dist/src/analytics/apply.js +30 -0
  5. package/dist/src/analytics/client.d.ts +7 -0
  6. package/dist/src/analytics/client.js +68 -0
  7. package/dist/src/analytics/constants.d.ts +4 -0
  8. package/dist/src/analytics/constants.js +4 -0
  9. package/dist/src/analytics/env.d.ts +4 -0
  10. package/dist/src/analytics/env.js +14 -0
  11. package/dist/src/analytics/exit.d.ts +5 -0
  12. package/dist/src/analytics/exit.js +24 -0
  13. package/dist/src/analytics/index.d.ts +10 -0
  14. package/dist/src/analytics/index.js +9 -0
  15. package/dist/src/analytics/normalize.d.ts +3 -0
  16. package/dist/src/analytics/normalize.js +18 -0
  17. package/dist/src/analytics/os.d.ts +2 -0
  18. package/dist/src/analytics/os.js +13 -0
  19. package/dist/src/analytics/session.d.ts +3 -0
  20. package/dist/src/analytics/session.js +15 -0
  21. package/dist/src/analytics/tracker.d.ts +17 -0
  22. package/dist/src/analytics/tracker.js +126 -0
  23. package/dist/src/analytics/types.d.ts +28 -0
  24. package/dist/src/analytics/types.js +1 -0
  25. package/dist/src/analyze/command.js +8 -2
  26. package/dist/src/analyze/select/command.js +13 -9
  27. package/dist/src/analyze/select/tui/App.js +1 -4
  28. package/dist/src/analyze/select-agent/command.js +14 -11
  29. package/dist/src/apply/api-client.d.ts +5 -5
  30. package/dist/src/apply/api-client.js +18 -8
  31. package/dist/src/apply/command.d.ts +1 -1
  32. package/dist/src/apply/command.js +81 -77
  33. package/dist/src/apply/preview-utils.d.ts +1 -5
  34. package/dist/src/apply/preview-utils.js +1 -5
  35. package/dist/src/apply/tui/ServerApplyView.d.ts +3 -6
  36. package/dist/src/apply/tui/ServerApplyView.js +6 -15
  37. package/dist/src/apply/tui/ServerPreviewView.d.ts +1 -2
  38. package/dist/src/apply/tui/ServerPreviewView.js +3 -3
  39. package/dist/src/generate/command.js +15 -9
  40. package/dist/src/generate/edit/command.js +1 -0
  41. package/dist/src/import/command.js +1 -6
  42. package/dist/src/import/orchestrator.d.ts +0 -1
  43. package/dist/src/import/orchestrator.js +18 -14
  44. package/dist/src/import/tui/WizardApp.d.ts +1 -2
  45. package/dist/src/import/tui/WizardApp.js +8 -8
  46. package/dist/src/import/tui/final-review-host.d.ts +1 -2
  47. package/dist/src/import/tui/final-review-host.js +2 -2
  48. package/dist/src/import/tui/runLivePreview.d.ts +0 -3
  49. package/dist/src/import/tui/runLivePreview.js +1 -4
  50. package/dist/src/import/tui/steps/GenerateReviewStep.d.ts +1 -2
  51. package/dist/src/import/tui/steps/GenerateReviewStep.js +3 -3
  52. package/dist/src/import/tui/steps/WizardPreviewStep.d.ts +2 -6
  53. package/dist/src/import/tui/steps/WizardPreviewStep.js +3 -12
  54. package/dist/src/import/tui/useFinalizePreview.d.ts +0 -2
  55. package/dist/src/import/tui/useFinalizePreview.js +0 -0
  56. package/dist/src/import/tui/useLivePreview.d.ts +0 -2
  57. package/dist/src/import/tui/useLivePreview.js +0 -1
  58. package/dist/src/index.js +6 -1
  59. package/dist/src/lib/command-options.d.ts +0 -1
  60. package/dist/src/lib/command-options.js +0 -3
  61. package/dist/src/print/command.js +16 -13
  62. package/dist/src/program.js +8 -1
  63. package/dist/src/runs/modify-launcher.d.ts +0 -2
  64. package/dist/src/runs/modify-launcher.js +0 -2
  65. package/dist/src/runs/push-helpers.d.ts +0 -1
  66. package/dist/src/runs/push-helpers.js +0 -3
  67. package/dist/src/runs/replay-helpers.d.ts +0 -4
  68. package/dist/src/runs/replay-helpers.js +0 -3
  69. package/package.json +6 -5
@@ -14,6 +14,7 @@ import { hashPromptForSkill } from '../session/cache-keys.js';
14
14
  import { getRefineArtifactsRoot, getRefineSessionPaths } from '../analyze/select/persistence.js';
15
15
  import { readExperiencesCredentials } from '../credentials-store.js';
16
16
  import { addAgentModelOptions } from '../lib/agent-model-options.js';
17
+ import { bindAnalyticsSessionId, exitWithAnalytics } from '../analytics/index.js';
17
18
  const execFileAsync = promisify(execFile);
18
19
  const DEFAULT_TIMEOUT_MS = Number(process.env.EDS_AGENT_TIMEOUT_MS ?? 3 * 60 * 1000);
19
20
  const DEFAULT_COMPONENT_CONCURRENCY = 10;
@@ -23,7 +24,8 @@ const invoker = createLocalCliAgentInvoker({
23
24
  });
24
25
  function die(message) {
25
26
  process.stderr.write(`${message}\n`);
26
- process.exit(1);
27
+ void exitWithAnalytics(1);
28
+ throw new Error('exit');
27
29
  }
28
30
  async function pathExists(p) {
29
31
  return access(p)
@@ -276,7 +278,8 @@ function resolveSessionId(sessionFlag) {
276
278
  .get();
277
279
  if (!row) {
278
280
  process.stderr.write('Error: no completed analyze extract session found. Run analyze extract first, or pass --session <id>.\n');
279
- process.exit(1);
281
+ void exitWithAnalytics(1);
282
+ throw new Error('exit');
280
283
  }
281
284
  return row.id;
282
285
  }
@@ -340,6 +343,7 @@ async function runGenerateSkill(skill, opts, verbose = false) {
340
343
  let allComponents;
341
344
  if (skill === 'components') {
342
345
  sessionId = resolveSessionId(opts.session);
346
+ await bindAnalyticsSessionId(sessionId);
343
347
  const acceptedNames = await loadAcceptedNames(sessionId);
344
348
  const db = openPipelineDb();
345
349
  try {
@@ -396,7 +400,7 @@ async function runGenerateSkill(skill, opts, verbose = false) {
396
400
  skillPathOverride: generatePromptPath,
397
401
  });
398
402
  process.stdout.write(prompt + '\n');
399
- process.exit(0);
403
+ await exitWithAnalytics(0);
400
404
  }
401
405
  const binary = resolveBinary(agent);
402
406
  if (!(await assertBinaryInPath(binary))) {
@@ -405,7 +409,7 @@ async function runGenerateSkill(skill, opts, verbose = false) {
405
409
  skill,
406
410
  sessionId: sessionId ?? '',
407
411
  });
408
- process.exit(1);
412
+ await exitWithAnalytics(1);
409
413
  }
410
414
  if (skill === 'components' && allComponents && sessionId) {
411
415
  const db = openPipelineDb();
@@ -471,6 +475,8 @@ async function runGenerateSkill(skill, opts, verbose = false) {
471
475
  resolvedSessionId = newId;
472
476
  }
473
477
  }
478
+ sessionId = resolvedSessionId;
479
+ await bindAnalyticsSessionId(resolvedSessionId);
474
480
  const tokenPromptHash = await hashPromptForSkill('tokens');
475
481
  // Check cache before invoking agent
476
482
  if (!noCache) {
@@ -483,12 +489,12 @@ async function runGenerateSkill(skill, opts, verbose = false) {
483
489
  // Skip agent invocation — jump to view
484
490
  const viewResult = { skill, agent, sessionId: sessionId ?? '' };
485
491
  if (process.stdout.isTTY) {
486
- const { waitUntilExit } = render(createElement(GenerateView, { result: viewResult, onExit: () => process.exit(0) }));
492
+ const { waitUntilExit } = render(createElement(GenerateView, { result: viewResult, onExit: () => void exitWithAnalytics(0) }));
487
493
  await waitUntilExit();
488
494
  }
489
495
  else {
490
496
  process.stdout.write(`generate complete\nskill: ${skill}\nagent: ${agent}\nsession=${sessionId ?? ''}\n`);
491
- process.exit(0);
497
+ await exitWithAnalytics(0);
492
498
  }
493
499
  return;
494
500
  }
@@ -523,7 +529,7 @@ async function runGenerateSkill(skill, opts, verbose = false) {
523
529
  process.stderr.write(`Error: agent produced no set_token calls.\n` +
524
530
  `Run with --dry-run to inspect the prompt.\n\n` +
525
531
  `Agent output:\n${result.stdout}\n`);
526
- process.exit(1);
532
+ await exitWithAnalytics(1);
527
533
  }
528
534
  if (tokenWarnings.length > 0) {
529
535
  process.stderr.write(`Warnings:\n${tokenWarnings.map((w) => ` ${w}`).join('\n')}\n`);
@@ -548,13 +554,13 @@ async function runGenerateSkill(skill, opts, verbose = false) {
548
554
  if (process.stdout.isTTY) {
549
555
  const { waitUntilExit } = render(createElement(GenerateView, {
550
556
  result: viewResult,
551
- onExit: () => process.exit(0),
557
+ onExit: () => void exitWithAnalytics(0),
552
558
  }));
553
559
  await waitUntilExit();
554
560
  }
555
561
  else {
556
562
  process.stdout.write(`generate complete\nskill: ${skill}\nagent: ${agent}\nsession=${sessionId ?? ''}\n`);
557
- process.exit(0);
563
+ await exitWithAnalytics(0);
558
564
  }
559
565
  }
560
566
  function addAgentFlags(cmd) {
@@ -99,6 +99,7 @@ async function runNonInteractive(opts, skill) {
99
99
  process.stderr.write(`Accepted: ${accepted.length} Rejected: ${rejected.length}\n`);
100
100
  }
101
101
  export function registerGenerateEditCommand(parent, skill) {
102
+ // TODO(analytics): bindAnalyticsSessionId when generate edit ships — tracked in schema as generate_edit.
102
103
  parent
103
104
  .command('edit')
104
105
  .description(`Review and correct generate ${skill} output before pushing`)
@@ -4,7 +4,7 @@ import { resolveAutoFilter } from './auto-filter-resolve.js';
4
4
  import { resolveAgent, resolveModel } from './agent-model-resolve.js';
5
5
  import { addAgentModelOptions } from '../lib/agent-model-options.js';
6
6
  import { resolveCompositionMode } from '../lib/composition-mode.js';
7
- import { addAllowDeletionsOption, addCompositionOptions } from '../lib/command-options.js';
7
+ import { addCompositionOptions } from '../lib/command-options.js';
8
8
  import { isConflictMode } from '../runs/save-path-resolver.js';
9
9
  import { readExperiencesCredentials } from '../credentials-store.js';
10
10
  import { DEFAULT_CONFIGURED_HOST, toConfiguredHost } from '../host-utils.js';
@@ -46,7 +46,6 @@ export function registerImportCommand(program) {
46
46
  .option('--print-prompt', 'Print the generate components prompt without invoking the agent. Replaces the legacy --dry-run prompt-print behaviour on this command.')
47
47
  .option('--auto-accept-scope', 'Accept all extracted components without prompting (for scripted/non-TTY callers)');
48
48
  addCompositionOptions(cmd);
49
- addAllowDeletionsOption(cmd);
50
49
  cmd
51
50
  .option('--composition-map <path>', 'Consume a hand-authored parent→children interchange map (implies --composite)')
52
51
  .option('--composition-agent', 'Opt into agentic mapping resolution when deterministic sources find no groups (implies --composite)')
@@ -137,7 +136,6 @@ export function registerImportCommand(program) {
137
136
  ...(opts.host ? { host: opts.host } : {}),
138
137
  interactive: interactiveTerminalSupported,
139
138
  ...(opts.force ? { force: true } : {}),
140
- ...(opts.allowDeletions ? { allowDeletions: true } : {}),
141
139
  });
142
140
  return;
143
141
  }
@@ -168,7 +166,6 @@ export function registerImportCommand(program) {
168
166
  ...(opts.saveAsNew ? { saveAsNew: true } : {}),
169
167
  ...(opts.outDir ? { outDir: opts.outDir } : {}),
170
168
  ...(opts.force ? { force: true } : {}),
171
- ...(opts.allowDeletions ? { allowDeletions: true } : {}),
172
169
  });
173
170
  return;
174
171
  }
@@ -300,7 +297,6 @@ export function registerImportCommand(program) {
300
297
  selectPromptPath: opts.selectPromptPath ?? creds.selectPromptPath,
301
298
  generatePromptPath: opts.generatePromptPath ?? creds.generatePromptPath,
302
299
  ...(opts.rawTokens ? { initialRawTokensPath: resolve(opts.rawTokens) } : {}),
303
- allowDeletions: opts.allowDeletions === true,
304
300
  ...pickerProps,
305
301
  }));
306
302
  unmountInk = unmount;
@@ -361,7 +357,6 @@ export function registerImportCommand(program) {
361
357
  dryRun: dryRunForward,
362
358
  selectPromptPath: opts.selectPromptPath,
363
359
  autoRejectCycles: opts.autoRejectCycles ?? false,
364
- allowDeletions: opts.allowDeletions ?? false,
365
360
  compositionMode: headlessCompositionMode,
366
361
  ...(opts.compositionMap ? { compositionMap: opts.compositionMap } : {}),
367
362
  ...(opts.compositionAgent ? { compositionAgent: true } : {}),
@@ -26,7 +26,6 @@ export interface PipelineOptions {
26
26
  selectPromptPath?: string;
27
27
  /** When true, auto-reject cycle participants and retry push instead of surfacing an error. */
28
28
  autoRejectCycles?: boolean;
29
- allowDeletions?: boolean;
30
29
  compositionMode?: CompositionMode;
31
30
  compositionMap?: string;
32
31
  compositionAgent?: boolean;
@@ -6,17 +6,19 @@ import { openPipelineDb, getOrCreateSession, createStep, updateStep, findLatestS
6
6
  import { detectSlotCycles, formatSlotCycleReport } from '../apply/command.js';
7
7
  import { PREVIEW_ERROR_PREFIX, VALIDATION_FAILED_CODE, parsePreviewValidationErrors } from '../apply/api-client.js';
8
8
  import { buildPostPushUrl } from '../lib/contentful-urls.js';
9
- import { getDebugLogger, debugEnvForSubprocess } from '../lib/debug-logger.js';
9
+ import { getDebugLogger } from '../lib/debug-logger.js';
10
+ import { bindAnalyticsSession, emitSessionStarted } from '../analytics/index.js';
11
+ import { pipelineSubprocessEnv } from '../analytics/env.js';
10
12
  function findCliPath() {
11
13
  return join(fileURLToPath(import.meta.url), '..', '..', '..', '..', 'bin', 'cli.js');
12
14
  }
13
- async function runStep(args, cliPath, env = {}, streamStderr = false) {
15
+ async function runStep(args, cliPath, analyticsSessionId, env = {}, streamStderr = false) {
14
16
  const debug = getDebugLogger();
15
17
  const startedAt = Date.now();
16
18
  debug.event('import', 'subprocess.spawn', { cliPath, args });
17
19
  return new Promise((res) => {
18
20
  const child = execFile('node', [cliPath, ...args], {
19
- env: debugEnvForSubprocess({ ...process.env, ...env }),
21
+ env: pipelineSubprocessEnv({ ...process.env, ...env }, analyticsSessionId),
20
22
  });
21
23
  let stdout = '';
22
24
  let stderr = '';
@@ -108,6 +110,10 @@ export async function runPipeline(opts, progressWriter, cliPathOverride) {
108
110
  inputPath: projectRoot,
109
111
  outDir,
110
112
  });
113
+ await bindAnalyticsSession(sessionId, {
114
+ ...(opts.spaceId ? { space_key: opts.spaceId, environment_key: opts.environmentId } : {}),
115
+ });
116
+ await emitSessionStarted('import');
111
117
  progressWriter(`Experience Design System CLI — Pipeline Import`);
112
118
  progressWriter(`Project: ${projectRoot}`);
113
119
  progressWriter(`Output: ${outDir}`);
@@ -159,7 +165,7 @@ export async function runPipeline(opts, progressWriter, cliPathOverride) {
159
165
  if (opts.agent)
160
166
  analyzeArgs.push('--agent', opts.agent);
161
167
  }
162
- const r = await runStep(analyzeArgs, cliPath);
168
+ const r = await runStep(analyzeArgs, cliPath, sessionId);
163
169
  const durationMs = Date.now() - t0;
164
170
  if (r.exitCode !== 0) {
165
171
  if (r.stderr)
@@ -231,7 +237,7 @@ export async function runPipeline(opts, progressWriter, cliPathOverride) {
231
237
  editArgs.push('--select-all');
232
238
  }
233
239
  }
234
- const rEdit = await runStep(editArgs, cliPath, { FORCE_COLOR: '1' }, useAgentSelect);
240
+ const rEdit = await runStep(editArgs, cliPath, sessionId, { FORCE_COLOR: '1' }, useAgentSelect);
235
241
  const editDurationMs = Date.now() - t0Edit;
236
242
  if (rEdit.exitCode !== 0) {
237
243
  if (rEdit.stderr && !useAgentSelect)
@@ -292,7 +298,7 @@ export async function runPipeline(opts, progressWriter, cliPathOverride) {
292
298
  extractSession: extractSessionId ?? '',
293
299
  });
294
300
  const t0 = Date.now();
295
- const r = await runStep(generateArgs, cliPath, { FORCE_COLOR: '1' }, true);
301
+ const r = await runStep(generateArgs, cliPath, sessionId, { FORCE_COLOR: '1' }, true);
296
302
  const durationMs = Date.now() - t0;
297
303
  if (r.exitCode !== 0) {
298
304
  updateStep(db, stepId, 'failed', {}, r.stderr);
@@ -355,7 +361,7 @@ export async function runPipeline(opts, progressWriter, cliPathOverride) {
355
361
  out: componentsPath,
356
362
  });
357
363
  const t0 = Date.now();
358
- const r = await runStep(printArgs, cliPath);
364
+ const r = await runStep(printArgs, cliPath, sessionId);
359
365
  const durationMs = Date.now() - t0;
360
366
  if (r.exitCode !== 0) {
361
367
  if (r.stderr)
@@ -418,14 +424,12 @@ export async function runPipeline(opts, progressWriter, cliPathOverride) {
418
424
  pushArgs.push('--host', opts.host);
419
425
  if (opts.verbose)
420
426
  pushArgs.push('--verbose');
421
- if (opts.allowDeletions)
422
- pushArgs.push('--allow-deletions');
423
427
  pushArgs.push('--yes');
424
428
  const pushStepId = createStep(db, sessionId, 'apply push', {
425
429
  components: componentsPath,
426
430
  });
427
431
  const t0 = Date.now();
428
- let r = await runStep(pushArgs, cliPath, { FORCE_COLOR: '1' }, true);
432
+ let r = await runStep(pushArgs, cliPath, sessionId, { FORCE_COLOR: '1' }, true);
429
433
  const excludedByRetry = [];
430
434
  let validationRetryCount = 0;
431
435
  while (validationRetryCount < MAX_VALIDATION_RETRIES && isPreviewValidationError(r) && extractSessionId) {
@@ -442,10 +446,10 @@ export async function runPipeline(opts, progressWriter, cliPathOverride) {
442
446
  '--exclude-components',
443
447
  offenders.join(','),
444
448
  ];
445
- const rejectResult = await runStep(rejectArgs, cliPath);
449
+ const rejectResult = await runStep(rejectArgs, cliPath, sessionId);
446
450
  if (rejectResult.exitCode !== 0)
447
451
  break;
448
- r = await runStep(pushArgs, cliPath, { FORCE_COLOR: '1' }, true);
452
+ r = await runStep(pushArgs, cliPath, sessionId, { FORCE_COLOR: '1' }, true);
449
453
  validationRetryCount++;
450
454
  }
451
455
  const durationMs = Date.now() - t0;
@@ -480,10 +484,10 @@ export async function runPipeline(opts, progressWriter, cliPathOverride) {
480
484
  '--exclude-components',
481
485
  cycleNames.join(','),
482
486
  ];
483
- const rejectResult = await runStep(rejectArgs, cliPath);
487
+ const rejectResult = await runStep(rejectArgs, cliPath, sessionId);
484
488
  if (rejectResult.exitCode === 0) {
485
489
  const retryT0 = Date.now();
486
- const retryR = await runStep(pushArgs, cliPath, { FORCE_COLOR: '1' }, true);
490
+ const retryR = await runStep(pushArgs, cliPath, sessionId, { FORCE_COLOR: '1' }, true);
487
491
  const retryDurationMs = Date.now() - t0 + (Date.now() - retryT0);
488
492
  if (isSlotCycleError(retryR)) {
489
493
  const retryReport = extractCycleReport(retryR.stderr);
@@ -66,6 +66,5 @@ export type WizardAppProps = {
66
66
  initialRawTokensPath?: string;
67
67
  initialRuns?: RunRecord[];
68
68
  onRunPicked?: (selection: RunPickerSelection) => void;
69
- allowDeletions?: boolean;
70
69
  };
71
- export declare function WizardApp({ initialSpaceId, initialEnvironmentId, initialCmaToken, initialHost, initialAgent, initialModel, initialProjectPath, host, autoAcceptScope, autoRejectCycles, compositionMode, compositionMap, compositionAgent, compositionAgentMode, compositionRefresh, generateMap, promptOverrides, noCache, autoFilter, livePreview, noPush, noSave, outDirOverride, onConflictMode, selectPromptPath, generatePromptPath, seedExtractSessionId, seedGenerateSessionId, seedTokenSessionId, seedTokensPath, initialStep, initialRawTokensPath, initialRuns, onRunPicked, allowDeletions, }?: WizardAppProps): React.ReactElement;
70
+ export declare function WizardApp({ initialSpaceId, initialEnvironmentId, initialCmaToken, initialHost, initialAgent, initialModel, initialProjectPath, host, autoAcceptScope, autoRejectCycles, compositionMode, compositionMap, compositionAgent, compositionAgentMode, compositionRefresh, generateMap, promptOverrides, noCache, autoFilter, livePreview, noPush, noSave, outDirOverride, onConflictMode, selectPromptPath, generatePromptPath, seedExtractSessionId, seedGenerateSessionId, seedTokenSessionId, seedTokensPath, initialStep, initialRawTokensPath, initialRuns, onRunPicked, }?: WizardAppProps): React.ReactElement;
@@ -138,7 +138,7 @@ function logStep(entry) {
138
138
  appendFileSync(WIZARD_LOG, line);
139
139
  getDebugLogger().event('wizard', 'step', entry);
140
140
  }
141
- export function WizardApp({ initialSpaceId = '', initialEnvironmentId = 'master', initialCmaToken = '', initialHost, initialAgent, initialModel, initialProjectPath, host, autoAcceptScope = false, autoRejectCycles = false, compositionMode = 'atomic', compositionMap, compositionAgent = false, compositionAgentMode, compositionRefresh = false, generateMap, promptOverrides, noCache = false, autoFilter = true, livePreview = true, noPush = false, noSave = false, outDirOverride, onConflictMode, selectPromptPath, generatePromptPath, seedExtractSessionId, seedGenerateSessionId, seedTokenSessionId, seedTokensPath, initialStep, initialRawTokensPath, initialRuns, onRunPicked, allowDeletions = false, } = {}) {
141
+ export function WizardApp({ initialSpaceId = '', initialEnvironmentId = 'master', initialCmaToken = '', initialHost, initialAgent, initialModel, initialProjectPath, host, autoAcceptScope = false, autoRejectCycles = false, compositionMode = 'atomic', compositionMap, compositionAgent = false, compositionAgentMode, compositionRefresh = false, generateMap, promptOverrides, noCache = false, autoFilter = true, livePreview = true, noPush = false, noSave = false, outDirOverride, onConflictMode, selectPromptPath, generatePromptPath, seedExtractSessionId, seedGenerateSessionId, seedTokenSessionId, seedTokensPath, initialStep, initialRawTokensPath, initialRuns, onRunPicked, } = {}) {
142
142
  const defaultConfiguredHost = toConfiguredHost(host || process.env['EDS_HOST']) ?? DEFAULT_CONFIGURED_HOST;
143
143
  const resolveWizardHost = (hostValue) => hostValue || defaultConfiguredHost;
144
144
  const { stdout } = useStdout();
@@ -830,7 +830,7 @@ export function WizardApp({ initialSpaceId = '', initialEnvironmentId = 'master'
830
830
  tokens = await readTokensFromPath('tokens', tokensPath);
831
831
  }
832
832
  let manifest = buildManifest(components, tokens, { deleteAllComponents: allowEmptyDeleteAllRef.current });
833
- let preview = await client.previewImport(manifest, allowDeletions);
833
+ let preview = await client.previewImport(manifest);
834
834
  if (extractSessionId) {
835
835
  let needsRepreview = false;
836
836
  const db = openPipelineDb();
@@ -852,7 +852,7 @@ export function WizardApp({ initialSpaceId = '', initialEnvironmentId = 'master'
852
852
  if (needsRepreview) {
853
853
  components = loadCDFComponents(db, extractSessionId);
854
854
  manifest = buildManifest(components, tokens, { deleteAllComponents: allowEmptyDeleteAllRef.current });
855
- preview = await client.previewImport(manifest, allowDeletions);
855
+ preview = await client.previewImport(manifest);
856
856
  }
857
857
  }
858
858
  finally {
@@ -946,7 +946,7 @@ export function WizardApp({ initialSpaceId = '', initialEnvironmentId = 'master'
946
946
  });
947
947
  }
948
948
  };
949
- const runPush = async (manifest, spaceId, environmentId, cmaToken, host, acknowledgeBreakingChanges, allowDeletions, preview) => {
949
+ const runPush = async (manifest, spaceId, environmentId, cmaToken, host, acknowledgeBreakingChanges, preview) => {
950
950
  if (shouldRefusePush(state)) {
951
951
  update(buildSkippedPushTransition());
952
952
  return;
@@ -986,7 +986,7 @@ export function WizardApp({ initialSpaceId = '', initialEnvironmentId = 'master'
986
986
  environmentId,
987
987
  host: resolvedHost,
988
988
  });
989
- let operation = await client.applyImport(manifest, { acknowledgeBreakingChanges, allowDeletions });
989
+ let operation = await client.applyImport(manifest, acknowledgeBreakingChanges);
990
990
  try {
991
991
  logStep({
992
992
  applyResponse: {
@@ -1437,7 +1437,7 @@ export function WizardApp({ initialSpaceId = '', initialEnvironmentId = 'master'
1437
1437
  return (_jsx(RunningStep, { stepNumber: stepNum, totalSteps: totalSteps, title: "Generating definitions", description: `${formatAcceptanceSummary({ accepted: state.acceptedCount, autoRejected: state.autoRejectedCount })} ${state.agent} is mapping your TypeScript types to Contentful's CDF format.${hasTokens ? ' Using your design tokens for prop resolution.' : ''}`, detail: progressDetail }));
1438
1438
  }
1439
1439
  case 'final-review': {
1440
- return (_jsx(FinalReviewHost, { extractSessionId: state.extractSessionId, generatedCount: state.generatedCount, autoAccept: autoAcceptScope, compositionMode: compositionMode, livePreview: livePreview, spaceId: state.spaceId, environmentId: state.environmentId, cmaToken: state.cmaToken, host: state.host, tokensPath: state.tokensPath, initialFinalizeError: state.finalizeErrorBanner, allowDeletions: allowDeletions, onFinalize: (accepted, rejected, unresolved) => {
1440
+ return (_jsx(FinalReviewHost, { extractSessionId: state.extractSessionId, generatedCount: state.generatedCount, autoAccept: autoAcceptScope, compositionMode: compositionMode, livePreview: livePreview, spaceId: state.spaceId, environmentId: state.environmentId, cmaToken: state.cmaToken, host: state.host, tokensPath: state.tokensPath, initialFinalizeError: state.finalizeErrorBanner, onFinalize: (accepted, rejected, unresolved) => {
1441
1441
  process.stderr.write(`Accepted: ${accepted} Rejected: ${rejected} Unresolved: ${unresolved}\n`);
1442
1442
  let acceptedCount = accepted;
1443
1443
  const detectAcceptedCycles = () => {
@@ -1605,8 +1605,8 @@ export function WizardApp({ initialSpaceId = '', initialEnvironmentId = 'master'
1605
1605
  // present-but-empty (only $schema), so editing would dead-end on the
1606
1606
  // "No generated definitions found" screen.
1607
1607
  const editableComponentCount = Object.keys(state.manifest?.componentsManifest ?? {}).filter((k) => k !== '$schema').length;
1608
- return (_jsx(WizardPreviewStep, { preview: state.serverPreview, spaceId: state.spaceId, environmentId: state.environmentId, stepNumber: totalSteps, totalSteps: totalSteps, allowDeletions: allowDeletions, onConfirm: (acknowledge, deleteMissing) => {
1609
- void runPush(state.manifest, state.spaceId, state.environmentId, state.cmaToken, state.host, acknowledge, deleteMissing, state.serverPreview);
1608
+ return (_jsx(WizardPreviewStep, { preview: state.serverPreview, spaceId: state.spaceId, environmentId: state.environmentId, stepNumber: totalSteps, totalSteps: totalSteps, onConfirm: (acknowledge) => {
1609
+ void runPush(state.manifest, state.spaceId, state.environmentId, state.cmaToken, state.host, acknowledge, state.serverPreview);
1610
1610
  }, ...(editableComponentCount > 0 ? { onEdit: () => void runEditFromPreview() } : {}), onSaveFiles: () => {
1611
1611
  void startSaveFlow();
1612
1612
  }, onQuit: () => process.exit(0) }));
@@ -14,6 +14,5 @@ export type FinalReviewHostProps = {
14
14
  host?: string;
15
15
  tokensPath?: string;
16
16
  initialFinalizeError?: string | null;
17
- allowDeletions?: boolean;
18
17
  };
19
- export declare function FinalReviewHost({ extractSessionId, generatedCount, autoAccept, compositionMode, onFinalize, onQuit, livePreview, spaceId, environmentId, cmaToken, host, tokensPath, initialFinalizeError, allowDeletions, }: FinalReviewHostProps): React.ReactElement;
18
+ export declare function FinalReviewHost({ extractSessionId, generatedCount, autoAccept, compositionMode, onFinalize, onQuit, livePreview, spaceId, environmentId, cmaToken, host, tokensPath, initialFinalizeError, }: FinalReviewHostProps): React.ReactElement;
@@ -4,7 +4,7 @@ import { PALETTE } from '../../analyze/select/tui/theme.js';
4
4
  import React from 'react';
5
5
  import { GenerateReviewStep } from './steps/GenerateReviewStep.js';
6
6
  import { AtomicGenerateReviewStep } from './steps/AtomicGenerateReviewStep.js';
7
- export function FinalReviewHost({ extractSessionId, generatedCount, autoAccept, compositionMode = 'atomic', onFinalize, onQuit, livePreview, spaceId, environmentId, cmaToken, host, tokensPath, initialFinalizeError, allowDeletions, }) {
7
+ export function FinalReviewHost({ extractSessionId, generatedCount, autoAccept, compositionMode = 'atomic', onFinalize, onQuit, livePreview, spaceId, environmentId, cmaToken, host, tokensPath, initialFinalizeError, }) {
8
8
  if (!extractSessionId) {
9
9
  return (_jsx(Box, { paddingX: 2, paddingY: 1, children: _jsx(Text, { color: PALETTE.error, children: "Error: no session ID \u2014 cannot load generated definitions." }) }));
10
10
  }
@@ -15,7 +15,7 @@ export function FinalReviewHost({ extractSessionId, generatedCount, autoAccept,
15
15
  // passes projectSlotGraph to FieldEditor and never walks closures/cycles, so
16
16
  // slot-composition editing and every hierarchy affordance stay absent.
17
17
  const StepComponent = compositionMode === 'atomic' ? AtomicGenerateReviewStep : GenerateReviewStep;
18
- return (_jsx(StepComponent, { extractSessionId: extractSessionId, onFinalize: onFinalize, onQuit: onQuit, livePreview: livePreview, spaceId: spaceId, environmentId: environmentId, cmaToken: cmaToken, host: host, tokensPath: tokensPath, initialFinalizeError: initialFinalizeError, ...(compositionMode !== 'atomic' ? { allowDeletions } : {}) }));
18
+ return (_jsx(StepComponent, { extractSessionId: extractSessionId, onFinalize: onFinalize, onQuit: onQuit, livePreview: livePreview, spaceId: spaceId, environmentId: environmentId, cmaToken: cmaToken, host: host, tokensPath: tokensPath, initialFinalizeError: initialFinalizeError }));
19
19
  }
20
20
  function FinalReviewAutoAccept({ generatedCount, onFinalize, }) {
21
21
  React.useEffect(() => {
@@ -26,9 +26,6 @@ export type RunLivePreviewOptions = {
26
26
  * full delete. Lets the Finalize dialog show exactly what the accepted push
27
27
  * would delete, independent of the session's on-disk generated rows. */
28
28
  acceptedKeys?: ReadonlySet<string>;
29
- /** Forwarded verbatim to `previewImport`. Governs whether the response
30
- * includes removed entities or a suppressed-count summary instead. */
31
- allowDeletions?: boolean;
32
29
  };
33
30
  /**
34
31
  * Pure async helper used by `useLivePreview` to re-fire `previewImport` after a
@@ -60,10 +60,7 @@ export async function runLivePreview(opts) {
60
60
  timeoutHandle = setTimeout(() => reject(new TimeoutError()), timeoutMs);
61
61
  });
62
62
  try {
63
- const response = (await Promise.race([
64
- client.previewImport(manifest, opts.allowDeletions === true),
65
- timeoutPromise,
66
- ]));
63
+ const response = (await Promise.race([client.previewImport(manifest), timeoutPromise]));
67
64
  if (process.env['EDS_VERBOSE']) {
68
65
  const durationMs = Date.now() - startedAt;
69
66
  try {
@@ -11,7 +11,6 @@ type GenerateReviewStepProps = {
11
11
  host?: string;
12
12
  tokensPath?: string;
13
13
  initialFinalizeError?: string | null;
14
- allowDeletions?: boolean;
15
14
  };
16
15
  export declare function sortComponentsForSidebar<T extends {
17
16
  key: string;
@@ -34,4 +33,4 @@ export interface BreakingRow {
34
33
  }
35
34
  export declare function buildBreakingRows(breakingChanges: BreakingComponent[]): BreakingRow[];
36
35
  export declare function deriveBreakingChanges(response: ServerPreviewResponse): BreakingComponent[];
37
- export declare function GenerateReviewStep({ extractSessionId, onFinalize, onQuit, livePreview, spaceId, environmentId, cmaToken, host, tokensPath, initialFinalizeError, allowDeletions, }: GenerateReviewStepProps): React.ReactElement;
36
+ export declare function GenerateReviewStep({ extractSessionId, onFinalize, onQuit, livePreview, spaceId, environmentId, cmaToken, host, tokensPath, initialFinalizeError, }: GenerateReviewStepProps): React.ReactElement;
@@ -174,7 +174,7 @@ export function deriveBreakingChanges(response) {
174
174
  }
175
175
  return out;
176
176
  }
177
- export function GenerateReviewStep({ extractSessionId, onFinalize, onQuit, livePreview = true, spaceId = '', environmentId = '', cmaToken = '', host = '', tokensPath = '', initialFinalizeError = null, allowDeletions = false, }) {
177
+ export function GenerateReviewStep({ extractSessionId, onFinalize, onQuit, livePreview = true, spaceId = '', environmentId = '', cmaToken = '', host = '', tokensPath = '', initialFinalizeError = null, }) {
178
178
  const { stdout } = useStdout();
179
179
  const terminalWidth = stdout?.columns ?? 80;
180
180
  const [components, setComponents] = useState([]);
@@ -271,8 +271,9 @@ export function GenerateReviewStep({ extractSessionId, onFinalize, onQuit, liveP
271
271
  cmaToken,
272
272
  host,
273
273
  onResult: handleLivePreviewResult,
274
+ // With nothing accepted, preview the delete-all diff so the review UI shows
275
+ // which existing components a push would remove (instead of an empty preview).
274
276
  deleteAllComponents: acceptedCountForPreview === 0,
275
- allowDeletions,
276
277
  });
277
278
  const SPINNER_FRAMES = '⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏';
278
279
  const [spinnerTick, setSpinnerTick] = useState(0);
@@ -351,7 +352,6 @@ export function GenerateReviewStep({ extractSessionId, onFinalize, onQuit, liveP
351
352
  cmaToken,
352
353
  host,
353
354
  acceptedKeys: new Set(components.filter((c) => c.status === 'accepted').map((c) => c.key)),
354
- allowDeletions,
355
355
  });
356
356
  const handleFinalizeConfirm = () => {
357
357
  const acceptedCount = components.filter((c) => c.status === 'accepted').length;
@@ -12,14 +12,10 @@ type WizardPreviewStepProps = {
12
12
  environmentId: string;
13
13
  stepNumber: number;
14
14
  totalSteps: number;
15
- /** The value the preview was actually fetched with — not a hint. When
16
- * `false`, the server never returned removed entities, so there is
17
- * nothing to render item-by-item or toggle over. */
18
- allowDeletions?: boolean;
19
- onConfirm: (acknowledge: boolean, allowDeletions: boolean) => void;
15
+ onConfirm: (acknowledge: boolean) => void;
20
16
  onEdit?: () => void;
21
17
  onSaveFiles?: () => void;
22
18
  onQuit: () => void;
23
19
  };
24
- export declare function WizardPreviewStep({ preview, spaceId, environmentId, stepNumber, totalSteps, allowDeletions: fetchedAllowDeletions, onConfirm, onEdit, onSaveFiles, onQuit, }: WizardPreviewStepProps): React.ReactElement;
20
+ export declare function WizardPreviewStep({ preview, spaceId, environmentId, stepNumber, totalSteps, onConfirm, onEdit, onSaveFiles, onQuit, }: WizardPreviewStepProps): React.ReactElement;
25
21
  export {};
@@ -89,14 +89,10 @@ export function buildPreviewDiffLines(preview) {
89
89
  }
90
90
  return lines;
91
91
  }
92
- export function WizardPreviewStep({ preview, spaceId, environmentId, stepNumber, totalSteps, allowDeletions: fetchedAllowDeletions = false, onConfirm, onEdit, onSaveFiles, onQuit, }) {
92
+ export function WizardPreviewStep({ preview, spaceId, environmentId, stepNumber, totalSteps, onConfirm, onEdit, onSaveFiles, onQuit, }) {
93
93
  const breakingWithImpact = hasBreakingChangesWithImpact(preview);
94
94
  const [diffExpanded, setDiffExpanded] = useState(false);
95
95
  const [scrollOffset, setScrollOffset] = useState(0);
96
- // Local state exists only to let the user opt OUT of a deletion the fetch
97
- // already surfaced — it can never turn true when the fetch used false,
98
- // because there's nothing in `preview` to reveal in that case.
99
- const [allowDeletions, setAllowDeletions] = useState(fetchedAllowDeletions);
100
96
  const { stdout } = useStdout();
101
97
  const terminalRows = stdout?.rows ?? 40;
102
98
  const viewportHeight = Math.max(terminalRows - 14, 10);
@@ -109,14 +105,9 @@ export function WizardPreviewStep({ preview, spaceId, environmentId, stepNumber,
109
105
  }));
110
106
  }, [diffExpanded, preview]);
111
107
  const maxScroll = Math.max(0, allDiffLines.length - viewportHeight);
112
- const removedCount = preview.components.removed.length + preview.tokens.removed.length;
113
108
  useImmediateInput((input, key) => {
114
109
  if (key.return) {
115
- onConfirm(breakingWithImpact, allowDeletions);
116
- return;
117
- }
118
- if ((input === 'x' || input === 'X') && fetchedAllowDeletions && removedCount > 0) {
119
- setAllowDeletions((prev) => !prev);
110
+ onConfirm(breakingWithImpact);
120
111
  return;
121
112
  }
122
113
  if (input === 'd' || input === 'D') {
@@ -165,5 +156,5 @@ export function WizardPreviewStep({ preview, spaceId, environmentId, stepNumber,
165
156
  })] })), components.changed.length > 0 && (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { gap: 1, children: [_jsx(Text, { color: PALETTE.warning, children: " \uFF5E" }), _jsxs(Text, { children: [components.changed.length, " will be updated"] })] }), components.changed.map((item, i) => {
166
157
  const isBreaking = item.changeClassification?.classification === 'breaking';
167
158
  return (_jsxs(Text, { color: isBreaking ? PALETTE.error : PALETTE.warning, children: [' ', isBreaking ? '⚠' : '~', " ", item.current.name] }, `chg-${i}`));
168
- })] })), components.removed.length > 0 && (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { gap: 1, children: [_jsx(Text, { color: allowDeletions ? PALETTE.error : PALETTE.warning, children: allowDeletions ? ' ✗' : ' ⊘' }), _jsxs(Text, { children: [components.removed.length, " will be ", allowDeletions ? 'deleted' : 'skipped'] })] }), components.removed.map((item, i) => (_jsxs(Text, { color: allowDeletions ? PALETTE.error : PALETTE.warning, dimColor: !allowDeletions, children: [' ', allowDeletions ? '✗' : '⊘', " ", item.name] }, `rm-${i}`)))] })), components.unchanged.length > 0 && (_jsxs(Box, { gap: 1, children: [_jsx(Text, { dimColor: true, children: " \u00B7" }), _jsxs(Text, { dimColor: true, children: [components.unchanged.length, " unchanged"] })] }))] })), hasTokens && (_jsxs(Box, { flexDirection: "column", gap: 0, children: [_jsx(Box, { gap: 1, marginTop: 1, children: _jsx(Text, { bold: true, dimColor: true, children: "Design Tokens" }) }), tokens.new.length > 0 && (_jsxs(Box, { gap: 1, children: [_jsx(Text, { color: PALETTE.success, children: " \uFF0B" }), _jsxs(Text, { children: [tokens.new.length, " will be created"] })] })), tokens.changed.length > 0 && (_jsxs(Box, { gap: 1, children: [_jsx(Text, { color: PALETTE.warning, children: " \uFF5E" }), _jsxs(Text, { children: [tokens.changed.length, " will be updated"] })] })), tokens.removed.length > 0 && (_jsxs(Box, { gap: 1, children: [_jsx(Text, { color: allowDeletions ? PALETTE.error : PALETTE.warning, children: allowDeletions ? ' ✗' : ' ⊘' }), _jsxs(Text, { children: [tokens.removed.length, " will be ", allowDeletions ? 'deleted' : 'skipped'] })] })), tokens.unchanged.length > 0 && (_jsxs(Box, { gap: 1, children: [_jsx(Text, { dimColor: true, children: " \u00B7" }), _jsxs(Text, { dimColor: true, children: [tokens.unchanged.length, " unchanged"] })] }))] })), diffExpanded && allDiffLines.length > 0 && (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(Text, { dimColor: true, children: '─'.repeat(40) }), _jsxs(Text, { dimColor: true, children: [' ', "Diff (", allDiffLines.length, " lines) \u2014 line ", scrollOffset + 1, "\u2013", Math.min(scrollOffset + viewportHeight, allDiffLines.length), " of ", allDiffLines.length] }), _jsx(Box, { flexDirection: "column", children: allDiffLines.slice(scrollOffset, scrollOffset + viewportHeight).map((line) => (_jsx(Box, { children: line.element }, line.key))) }), maxScroll > 0 && _jsx(Text, { dimColor: true, children: " \u2195 j/k to scroll, f/b to page" })] }))] })) : (_jsx(Text, { dimColor: true, children: "Nothing to push \u2014 everything is already up to date." })), !fetchedAllowDeletions && (_jsxs(Box, { gap: 1, children: [_jsx(Text, { color: PALETTE.warning, children: " \u2298" }), _jsx(Text, { children: "Deletions are hidden by default \u2014 rerun with --allow-deletions to see them." })] })), _jsxs(Box, { gap: 1, marginTop: 1, children: [_jsx(Text, { dimColor: true, children: "Space:" }), _jsx(Text, { children: spaceId }), _jsx(Text, { dimColor: true, children: "/" }), _jsx(Text, { dimColor: true, children: "Environment:" }), _jsx(Text, { children: environmentId })] }), breakingWithImpact && (_jsx(Box, { marginTop: 1, children: _jsx(Text, { color: PALETTE.error, bold: true, children: "\u26A0 Breaking changes will affect downstream entities. Press Enter to acknowledge and apply." }) })), allowDeletions && removedCount > 0 && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: PALETTE.error, bold: true, children: ["\u26A0 ", removedCount, " missing ", removedCount === 1 ? 'entity' : 'entities', " will be permanently deleted. Press Enter to confirm."] }) })), _jsxs(Box, { gap: 3, marginTop: 1, children: [_jsx(Text, { dimColor: true, children: "[Enter] Push to Contentful" }), _jsxs(Text, { dimColor: true, children: ["[d] ", diffExpanded ? 'Hide' : 'Show', " diff"] }), diffExpanded && _jsx(Text, { dimColor: true, children: "[j/k] Scroll [f/b] Page" }), onEdit && _jsx(Text, { dimColor: true, children: "[e] Edit definitions" }), onSaveFiles && _jsx(Text, { dimColor: true, children: "[s] Save files instead" }), fetchedAllowDeletions && removedCount > 0 && (_jsxs(Text, { dimColor: true, children: ["[x] ", allowDeletions ? '[✓]' : '[ ]', " Allow deletions"] })), _jsx(Text, { dimColor: true, children: "[q] Cancel" })] })] }));
159
+ })] })), components.removed.length > 0 && (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { gap: 1, children: [_jsx(Text, { color: PALETTE.error, children: " \u2717" }), _jsxs(Text, { children: [components.removed.length, " will be removed"] })] }), components.removed.map((item, i) => (_jsxs(Text, { color: PALETTE.error, children: [' ', "\u2717 ", item.name] }, `rm-${i}`)))] })), components.unchanged.length > 0 && (_jsxs(Box, { gap: 1, children: [_jsx(Text, { dimColor: true, children: " \u00B7" }), _jsxs(Text, { dimColor: true, children: [components.unchanged.length, " unchanged"] })] }))] })), hasTokens && (_jsxs(Box, { flexDirection: "column", gap: 0, children: [_jsx(Box, { gap: 1, marginTop: 1, children: _jsx(Text, { bold: true, dimColor: true, children: "Design Tokens" }) }), tokens.new.length > 0 && (_jsxs(Box, { gap: 1, children: [_jsx(Text, { color: PALETTE.success, children: " \uFF0B" }), _jsxs(Text, { children: [tokens.new.length, " will be created"] })] })), tokens.changed.length > 0 && (_jsxs(Box, { gap: 1, children: [_jsx(Text, { color: PALETTE.warning, children: " \uFF5E" }), _jsxs(Text, { children: [tokens.changed.length, " will be updated"] })] })), tokens.removed.length > 0 && (_jsxs(Box, { gap: 1, children: [_jsx(Text, { color: PALETTE.error, children: " \u2717" }), _jsxs(Text, { children: [tokens.removed.length, " will be removed"] })] })), tokens.unchanged.length > 0 && (_jsxs(Box, { gap: 1, children: [_jsx(Text, { dimColor: true, children: " \u00B7" }), _jsxs(Text, { dimColor: true, children: [tokens.unchanged.length, " unchanged"] })] }))] })), diffExpanded && allDiffLines.length > 0 && (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(Text, { dimColor: true, children: '─'.repeat(40) }), _jsxs(Text, { dimColor: true, children: [' ', "Diff (", allDiffLines.length, " lines) \u2014 line ", scrollOffset + 1, "\u2013", Math.min(scrollOffset + viewportHeight, allDiffLines.length), " of ", allDiffLines.length] }), _jsx(Box, { flexDirection: "column", children: allDiffLines.slice(scrollOffset, scrollOffset + viewportHeight).map((line) => (_jsx(Box, { children: line.element }, line.key))) }), maxScroll > 0 && _jsx(Text, { dimColor: true, children: " \u2195 j/k to scroll, f/b to page" })] }))] })) : (_jsx(Text, { dimColor: true, children: "Nothing to push \u2014 everything is already up to date." })), _jsxs(Box, { gap: 1, marginTop: 1, children: [_jsx(Text, { dimColor: true, children: "Space:" }), _jsx(Text, { children: spaceId }), _jsx(Text, { dimColor: true, children: "/" }), _jsx(Text, { dimColor: true, children: "Environment:" }), _jsx(Text, { children: environmentId })] }), breakingWithImpact && (_jsx(Box, { marginTop: 1, children: _jsx(Text, { color: PALETTE.error, bold: true, children: "\u26A0 Breaking changes will affect downstream entities. Press Enter to acknowledge and apply." }) })), _jsxs(Box, { gap: 3, marginTop: 1, children: [_jsx(Text, { dimColor: true, children: "[Enter] Push to Contentful" }), _jsxs(Text, { dimColor: true, children: ["[d] ", diffExpanded ? 'Hide' : 'Show', " diff"] }), diffExpanded && _jsx(Text, { dimColor: true, children: "[j/k] Scroll [f/b] Page" }), onEdit && _jsx(Text, { dimColor: true, children: "[e] Edit definitions" }), onSaveFiles && _jsx(Text, { dimColor: true, children: "[s] Save files instead" }), _jsx(Text, { dimColor: true, children: "[q] Cancel" })] })] }));
169
160
  }
@@ -11,8 +11,6 @@ export type UseFinalizePreviewOptions = {
11
11
  host: string;
12
12
  /** Component keys the operator has accepted; drives the scoped preview. */
13
13
  acceptedKeys: ReadonlySet<string>;
14
- /** Forwarded verbatim to `runLivePreview`/`previewImport`. */
15
- allowDeletions?: boolean;
16
14
  };
17
15
  export type UseFinalizePreviewReturn = {
18
16
  status: FinalizePreviewStatus;
@@ -12,8 +12,6 @@ export type UseLivePreviewOptions = {
12
12
  /** Preview an empty-but-present manifest (delete-all diff) when nothing is
13
13
  * accepted, so the final-review UI can show what a push would delete. */
14
14
  deleteAllComponents?: boolean;
15
- /** Forwarded verbatim to `runLivePreview`/`previewImport`. */
16
- allowDeletions?: boolean;
17
15
  };
18
16
  export type LivePreviewStatus = 'idle' | 'running';
19
17
  export type UseLivePreviewReturn = {
@@ -82,7 +82,6 @@ export function useLivePreview(opts) {
82
82
  host: current.host,
83
83
  generation,
84
84
  deleteAllComponents: current.deleteAllComponents === true,
85
- allowDeletions: current.allowDeletions === true,
86
85
  });
87
86
  // Discard stale responses (generation tag).
88
87
  if (result.generation !== latestRef.current)
package/dist/src/index.js CHANGED
@@ -1,7 +1,12 @@
1
1
  import { createProgram } from './program.js';
2
+ import { failActiveCommand, flushAnalytics } from './analytics/index.js';
2
3
  createProgram()
3
4
  .parseAsync()
4
- .catch((err) => {
5
+ .catch(async (err) => {
6
+ await failActiveCommand({
7
+ error_name: err instanceof Error ? err.name : 'Error',
8
+ });
9
+ await flushAnalytics();
5
10
  process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}\n`);
6
11
  process.exit(1);
7
12
  });
@@ -3,4 +3,3 @@ export declare function addArtifactInputOptions(cmd: Command): Command;
3
3
  export declare function addContentfulTargetOptions(cmd: Command): Command;
4
4
  export declare function addCompositionOptions(cmd: Command): Command;
5
5
  export declare function addSelectionOptions(cmd: Command): Command;
6
- export declare function addAllowDeletionsOption(cmd: Command): Command;
@@ -25,6 +25,3 @@ export function addSelectionOptions(cmd) {
25
25
  .option('--select <pattern>', 'Select entities by ID pattern (repeatable)', collectOptionValue, [])
26
26
  .option('--deselect <pattern>', 'Deselect entities by ID pattern (repeatable)', collectOptionValue, []);
27
27
  }
28
- export function addAllowDeletionsOption(cmd) {
29
- return cmd.option('--allow-deletions', 'Allow the push to delete remote ComponentTypes/DesignTokens missing from the manifest (default: skip them)');
30
- }