@contentful/experience-design-system-cli 2.23.2-dev-build-753ceef.0 → 2.23.2-dev-build-e996ffb.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.
- package/README.md +2 -24
- package/dist/package.json +1 -2
- package/dist/src/analyze/command.js +2 -8
- package/dist/src/analyze/select/command.js +9 -13
- package/dist/src/analyze/select/tui/App.js +4 -1
- package/dist/src/analyze/select-agent/command.js +11 -14
- package/dist/src/apply/api-client.d.ts +5 -5
- package/dist/src/apply/api-client.js +8 -18
- package/dist/src/apply/command.d.ts +1 -1
- package/dist/src/apply/command.js +77 -81
- package/dist/src/apply/preview-utils.d.ts +5 -1
- package/dist/src/apply/preview-utils.js +5 -1
- package/dist/src/apply/tui/ServerApplyView.d.ts +6 -3
- package/dist/src/apply/tui/ServerApplyView.js +15 -6
- package/dist/src/apply/tui/ServerPreviewView.d.ts +2 -1
- package/dist/src/apply/tui/ServerPreviewView.js +3 -3
- package/dist/src/generate/command.js +9 -15
- package/dist/src/generate/edit/command.js +0 -1
- package/dist/src/import/command.js +6 -1
- package/dist/src/import/orchestrator.d.ts +1 -0
- package/dist/src/import/orchestrator.js +14 -18
- package/dist/src/import/tui/WizardApp.d.ts +2 -1
- package/dist/src/import/tui/WizardApp.js +8 -8
- package/dist/src/import/tui/final-review-host.d.ts +2 -1
- package/dist/src/import/tui/final-review-host.js +2 -2
- package/dist/src/import/tui/runLivePreview.d.ts +3 -0
- package/dist/src/import/tui/runLivePreview.js +4 -1
- package/dist/src/import/tui/steps/GenerateReviewStep.d.ts +2 -1
- package/dist/src/import/tui/steps/GenerateReviewStep.js +3 -3
- package/dist/src/import/tui/steps/WizardPreviewStep.d.ts +6 -2
- package/dist/src/import/tui/steps/WizardPreviewStep.js +12 -3
- package/dist/src/import/tui/useFinalizePreview.d.ts +2 -0
- package/dist/src/import/tui/useFinalizePreview.js +0 -0
- package/dist/src/import/tui/useLivePreview.d.ts +2 -0
- package/dist/src/import/tui/useLivePreview.js +1 -0
- package/dist/src/index.js +1 -6
- package/dist/src/lib/command-options.d.ts +1 -0
- package/dist/src/lib/command-options.js +3 -0
- package/dist/src/print/command.js +13 -16
- package/dist/src/program.js +1 -8
- package/dist/src/runs/modify-launcher.d.ts +2 -0
- package/dist/src/runs/modify-launcher.js +2 -0
- package/dist/src/runs/push-helpers.d.ts +1 -0
- package/dist/src/runs/push-helpers.js +3 -0
- package/dist/src/runs/replay-helpers.d.ts +4 -0
- package/dist/src/runs/replay-helpers.js +3 -0
- package/package.json +5 -6
- package/dist/src/analytics/apply.d.ts +0 -6
- package/dist/src/analytics/apply.js +0 -30
- package/dist/src/analytics/client.d.ts +0 -7
- package/dist/src/analytics/client.js +0 -68
- package/dist/src/analytics/constants.d.ts +0 -4
- package/dist/src/analytics/constants.js +0 -4
- package/dist/src/analytics/env.d.ts +0 -4
- package/dist/src/analytics/env.js +0 -14
- package/dist/src/analytics/exit.d.ts +0 -5
- package/dist/src/analytics/exit.js +0 -24
- package/dist/src/analytics/index.d.ts +0 -10
- package/dist/src/analytics/index.js +0 -9
- package/dist/src/analytics/normalize.d.ts +0 -3
- package/dist/src/analytics/normalize.js +0 -18
- package/dist/src/analytics/os.d.ts +0 -2
- package/dist/src/analytics/os.js +0 -13
- package/dist/src/analytics/session.d.ts +0 -3
- package/dist/src/analytics/session.js +0 -15
- package/dist/src/analytics/tracker.d.ts +0 -17
- package/dist/src/analytics/tracker.js +0 -126
- package/dist/src/analytics/types.d.ts +0 -28
- package/dist/src/analytics/types.js +0 -1
|
@@ -14,7 +14,6 @@ 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';
|
|
18
17
|
const execFileAsync = promisify(execFile);
|
|
19
18
|
const DEFAULT_TIMEOUT_MS = Number(process.env.EDS_AGENT_TIMEOUT_MS ?? 3 * 60 * 1000);
|
|
20
19
|
const DEFAULT_COMPONENT_CONCURRENCY = 10;
|
|
@@ -24,8 +23,7 @@ const invoker = createLocalCliAgentInvoker({
|
|
|
24
23
|
});
|
|
25
24
|
function die(message) {
|
|
26
25
|
process.stderr.write(`${message}\n`);
|
|
27
|
-
|
|
28
|
-
throw new Error('exit');
|
|
26
|
+
process.exit(1);
|
|
29
27
|
}
|
|
30
28
|
async function pathExists(p) {
|
|
31
29
|
return access(p)
|
|
@@ -278,8 +276,7 @@ function resolveSessionId(sessionFlag) {
|
|
|
278
276
|
.get();
|
|
279
277
|
if (!row) {
|
|
280
278
|
process.stderr.write('Error: no completed analyze extract session found. Run analyze extract first, or pass --session <id>.\n');
|
|
281
|
-
|
|
282
|
-
throw new Error('exit');
|
|
279
|
+
process.exit(1);
|
|
283
280
|
}
|
|
284
281
|
return row.id;
|
|
285
282
|
}
|
|
@@ -343,7 +340,6 @@ async function runGenerateSkill(skill, opts, verbose = false) {
|
|
|
343
340
|
let allComponents;
|
|
344
341
|
if (skill === 'components') {
|
|
345
342
|
sessionId = resolveSessionId(opts.session);
|
|
346
|
-
await bindAnalyticsSessionId(sessionId);
|
|
347
343
|
const acceptedNames = await loadAcceptedNames(sessionId);
|
|
348
344
|
const db = openPipelineDb();
|
|
349
345
|
try {
|
|
@@ -400,7 +396,7 @@ async function runGenerateSkill(skill, opts, verbose = false) {
|
|
|
400
396
|
skillPathOverride: generatePromptPath,
|
|
401
397
|
});
|
|
402
398
|
process.stdout.write(prompt + '\n');
|
|
403
|
-
|
|
399
|
+
process.exit(0);
|
|
404
400
|
}
|
|
405
401
|
const binary = resolveBinary(agent);
|
|
406
402
|
if (!(await assertBinaryInPath(binary))) {
|
|
@@ -409,7 +405,7 @@ async function runGenerateSkill(skill, opts, verbose = false) {
|
|
|
409
405
|
skill,
|
|
410
406
|
sessionId: sessionId ?? '',
|
|
411
407
|
});
|
|
412
|
-
|
|
408
|
+
process.exit(1);
|
|
413
409
|
}
|
|
414
410
|
if (skill === 'components' && allComponents && sessionId) {
|
|
415
411
|
const db = openPipelineDb();
|
|
@@ -475,8 +471,6 @@ async function runGenerateSkill(skill, opts, verbose = false) {
|
|
|
475
471
|
resolvedSessionId = newId;
|
|
476
472
|
}
|
|
477
473
|
}
|
|
478
|
-
sessionId = resolvedSessionId;
|
|
479
|
-
await bindAnalyticsSessionId(resolvedSessionId);
|
|
480
474
|
const tokenPromptHash = await hashPromptForSkill('tokens');
|
|
481
475
|
// Check cache before invoking agent
|
|
482
476
|
if (!noCache) {
|
|
@@ -489,12 +483,12 @@ async function runGenerateSkill(skill, opts, verbose = false) {
|
|
|
489
483
|
// Skip agent invocation — jump to view
|
|
490
484
|
const viewResult = { skill, agent, sessionId: sessionId ?? '' };
|
|
491
485
|
if (process.stdout.isTTY) {
|
|
492
|
-
const { waitUntilExit } = render(createElement(GenerateView, { result: viewResult, onExit: () =>
|
|
486
|
+
const { waitUntilExit } = render(createElement(GenerateView, { result: viewResult, onExit: () => process.exit(0) }));
|
|
493
487
|
await waitUntilExit();
|
|
494
488
|
}
|
|
495
489
|
else {
|
|
496
490
|
process.stdout.write(`generate complete\nskill: ${skill}\nagent: ${agent}\nsession=${sessionId ?? ''}\n`);
|
|
497
|
-
|
|
491
|
+
process.exit(0);
|
|
498
492
|
}
|
|
499
493
|
return;
|
|
500
494
|
}
|
|
@@ -529,7 +523,7 @@ async function runGenerateSkill(skill, opts, verbose = false) {
|
|
|
529
523
|
process.stderr.write(`Error: agent produced no set_token calls.\n` +
|
|
530
524
|
`Run with --dry-run to inspect the prompt.\n\n` +
|
|
531
525
|
`Agent output:\n${result.stdout}\n`);
|
|
532
|
-
|
|
526
|
+
process.exit(1);
|
|
533
527
|
}
|
|
534
528
|
if (tokenWarnings.length > 0) {
|
|
535
529
|
process.stderr.write(`Warnings:\n${tokenWarnings.map((w) => ` ${w}`).join('\n')}\n`);
|
|
@@ -554,13 +548,13 @@ async function runGenerateSkill(skill, opts, verbose = false) {
|
|
|
554
548
|
if (process.stdout.isTTY) {
|
|
555
549
|
const { waitUntilExit } = render(createElement(GenerateView, {
|
|
556
550
|
result: viewResult,
|
|
557
|
-
onExit: () =>
|
|
551
|
+
onExit: () => process.exit(0),
|
|
558
552
|
}));
|
|
559
553
|
await waitUntilExit();
|
|
560
554
|
}
|
|
561
555
|
else {
|
|
562
556
|
process.stdout.write(`generate complete\nskill: ${skill}\nagent: ${agent}\nsession=${sessionId ?? ''}\n`);
|
|
563
|
-
|
|
557
|
+
process.exit(0);
|
|
564
558
|
}
|
|
565
559
|
}
|
|
566
560
|
function addAgentFlags(cmd) {
|
|
@@ -99,7 +99,6 @@ 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.
|
|
103
102
|
parent
|
|
104
103
|
.command('edit')
|
|
105
104
|
.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 { addCompositionOptions } from '../lib/command-options.js';
|
|
7
|
+
import { addAllowDeletionsOption, 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,6 +46,7 @@ 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);
|
|
49
50
|
cmd
|
|
50
51
|
.option('--composition-map <path>', 'Consume a hand-authored parent→children interchange map (implies --composite)')
|
|
51
52
|
.option('--composition-agent', 'Opt into agentic mapping resolution when deterministic sources find no groups (implies --composite)')
|
|
@@ -136,6 +137,7 @@ export function registerImportCommand(program) {
|
|
|
136
137
|
...(opts.host ? { host: opts.host } : {}),
|
|
137
138
|
interactive: interactiveTerminalSupported,
|
|
138
139
|
...(opts.force ? { force: true } : {}),
|
|
140
|
+
...(opts.allowDeletions ? { allowDeletions: true } : {}),
|
|
139
141
|
});
|
|
140
142
|
return;
|
|
141
143
|
}
|
|
@@ -166,6 +168,7 @@ export function registerImportCommand(program) {
|
|
|
166
168
|
...(opts.saveAsNew ? { saveAsNew: true } : {}),
|
|
167
169
|
...(opts.outDir ? { outDir: opts.outDir } : {}),
|
|
168
170
|
...(opts.force ? { force: true } : {}),
|
|
171
|
+
...(opts.allowDeletions ? { allowDeletions: true } : {}),
|
|
169
172
|
});
|
|
170
173
|
return;
|
|
171
174
|
}
|
|
@@ -297,6 +300,7 @@ export function registerImportCommand(program) {
|
|
|
297
300
|
selectPromptPath: opts.selectPromptPath ?? creds.selectPromptPath,
|
|
298
301
|
generatePromptPath: opts.generatePromptPath ?? creds.generatePromptPath,
|
|
299
302
|
...(opts.rawTokens ? { initialRawTokensPath: resolve(opts.rawTokens) } : {}),
|
|
303
|
+
allowDeletions: opts.allowDeletions === true,
|
|
300
304
|
...pickerProps,
|
|
301
305
|
}));
|
|
302
306
|
unmountInk = unmount;
|
|
@@ -357,6 +361,7 @@ export function registerImportCommand(program) {
|
|
|
357
361
|
dryRun: dryRunForward,
|
|
358
362
|
selectPromptPath: opts.selectPromptPath,
|
|
359
363
|
autoRejectCycles: opts.autoRejectCycles ?? false,
|
|
364
|
+
allowDeletions: opts.allowDeletions ?? false,
|
|
360
365
|
compositionMode: headlessCompositionMode,
|
|
361
366
|
...(opts.compositionMap ? { compositionMap: opts.compositionMap } : {}),
|
|
362
367
|
...(opts.compositionAgent ? { compositionAgent: true } : {}),
|
|
@@ -26,6 +26,7 @@ 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;
|
|
29
30
|
compositionMode?: CompositionMode;
|
|
30
31
|
compositionMap?: string;
|
|
31
32
|
compositionAgent?: boolean;
|
|
@@ -6,19 +6,17 @@ 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 } from '../lib/debug-logger.js';
|
|
10
|
-
import { bindAnalyticsSession, emitSessionStarted } from '../analytics/index.js';
|
|
11
|
-
import { pipelineSubprocessEnv } from '../analytics/env.js';
|
|
9
|
+
import { getDebugLogger, debugEnvForSubprocess } from '../lib/debug-logger.js';
|
|
12
10
|
function findCliPath() {
|
|
13
11
|
return join(fileURLToPath(import.meta.url), '..', '..', '..', '..', 'bin', 'cli.js');
|
|
14
12
|
}
|
|
15
|
-
async function runStep(args, cliPath,
|
|
13
|
+
async function runStep(args, cliPath, env = {}, streamStderr = false) {
|
|
16
14
|
const debug = getDebugLogger();
|
|
17
15
|
const startedAt = Date.now();
|
|
18
16
|
debug.event('import', 'subprocess.spawn', { cliPath, args });
|
|
19
17
|
return new Promise((res) => {
|
|
20
18
|
const child = execFile('node', [cliPath, ...args], {
|
|
21
|
-
env:
|
|
19
|
+
env: debugEnvForSubprocess({ ...process.env, ...env }),
|
|
22
20
|
});
|
|
23
21
|
let stdout = '';
|
|
24
22
|
let stderr = '';
|
|
@@ -110,10 +108,6 @@ export async function runPipeline(opts, progressWriter, cliPathOverride) {
|
|
|
110
108
|
inputPath: projectRoot,
|
|
111
109
|
outDir,
|
|
112
110
|
});
|
|
113
|
-
await bindAnalyticsSession(sessionId, {
|
|
114
|
-
...(opts.spaceId ? { space_key: opts.spaceId, environment_key: opts.environmentId } : {}),
|
|
115
|
-
});
|
|
116
|
-
await emitSessionStarted('import');
|
|
117
111
|
progressWriter(`Experience Design System CLI — Pipeline Import`);
|
|
118
112
|
progressWriter(`Project: ${projectRoot}`);
|
|
119
113
|
progressWriter(`Output: ${outDir}`);
|
|
@@ -165,7 +159,7 @@ export async function runPipeline(opts, progressWriter, cliPathOverride) {
|
|
|
165
159
|
if (opts.agent)
|
|
166
160
|
analyzeArgs.push('--agent', opts.agent);
|
|
167
161
|
}
|
|
168
|
-
const r = await runStep(analyzeArgs, cliPath
|
|
162
|
+
const r = await runStep(analyzeArgs, cliPath);
|
|
169
163
|
const durationMs = Date.now() - t0;
|
|
170
164
|
if (r.exitCode !== 0) {
|
|
171
165
|
if (r.stderr)
|
|
@@ -237,7 +231,7 @@ export async function runPipeline(opts, progressWriter, cliPathOverride) {
|
|
|
237
231
|
editArgs.push('--select-all');
|
|
238
232
|
}
|
|
239
233
|
}
|
|
240
|
-
const rEdit = await runStep(editArgs, cliPath,
|
|
234
|
+
const rEdit = await runStep(editArgs, cliPath, { FORCE_COLOR: '1' }, useAgentSelect);
|
|
241
235
|
const editDurationMs = Date.now() - t0Edit;
|
|
242
236
|
if (rEdit.exitCode !== 0) {
|
|
243
237
|
if (rEdit.stderr && !useAgentSelect)
|
|
@@ -298,7 +292,7 @@ export async function runPipeline(opts, progressWriter, cliPathOverride) {
|
|
|
298
292
|
extractSession: extractSessionId ?? '',
|
|
299
293
|
});
|
|
300
294
|
const t0 = Date.now();
|
|
301
|
-
const r = await runStep(generateArgs, cliPath,
|
|
295
|
+
const r = await runStep(generateArgs, cliPath, { FORCE_COLOR: '1' }, true);
|
|
302
296
|
const durationMs = Date.now() - t0;
|
|
303
297
|
if (r.exitCode !== 0) {
|
|
304
298
|
updateStep(db, stepId, 'failed', {}, r.stderr);
|
|
@@ -361,7 +355,7 @@ export async function runPipeline(opts, progressWriter, cliPathOverride) {
|
|
|
361
355
|
out: componentsPath,
|
|
362
356
|
});
|
|
363
357
|
const t0 = Date.now();
|
|
364
|
-
const r = await runStep(printArgs, cliPath
|
|
358
|
+
const r = await runStep(printArgs, cliPath);
|
|
365
359
|
const durationMs = Date.now() - t0;
|
|
366
360
|
if (r.exitCode !== 0) {
|
|
367
361
|
if (r.stderr)
|
|
@@ -424,12 +418,14 @@ export async function runPipeline(opts, progressWriter, cliPathOverride) {
|
|
|
424
418
|
pushArgs.push('--host', opts.host);
|
|
425
419
|
if (opts.verbose)
|
|
426
420
|
pushArgs.push('--verbose');
|
|
421
|
+
if (opts.allowDeletions)
|
|
422
|
+
pushArgs.push('--allow-deletions');
|
|
427
423
|
pushArgs.push('--yes');
|
|
428
424
|
const pushStepId = createStep(db, sessionId, 'apply push', {
|
|
429
425
|
components: componentsPath,
|
|
430
426
|
});
|
|
431
427
|
const t0 = Date.now();
|
|
432
|
-
let r = await runStep(pushArgs, cliPath,
|
|
428
|
+
let r = await runStep(pushArgs, cliPath, { FORCE_COLOR: '1' }, true);
|
|
433
429
|
const excludedByRetry = [];
|
|
434
430
|
let validationRetryCount = 0;
|
|
435
431
|
while (validationRetryCount < MAX_VALIDATION_RETRIES && isPreviewValidationError(r) && extractSessionId) {
|
|
@@ -446,10 +442,10 @@ export async function runPipeline(opts, progressWriter, cliPathOverride) {
|
|
|
446
442
|
'--exclude-components',
|
|
447
443
|
offenders.join(','),
|
|
448
444
|
];
|
|
449
|
-
const rejectResult = await runStep(rejectArgs, cliPath
|
|
445
|
+
const rejectResult = await runStep(rejectArgs, cliPath);
|
|
450
446
|
if (rejectResult.exitCode !== 0)
|
|
451
447
|
break;
|
|
452
|
-
r = await runStep(pushArgs, cliPath,
|
|
448
|
+
r = await runStep(pushArgs, cliPath, { FORCE_COLOR: '1' }, true);
|
|
453
449
|
validationRetryCount++;
|
|
454
450
|
}
|
|
455
451
|
const durationMs = Date.now() - t0;
|
|
@@ -484,10 +480,10 @@ export async function runPipeline(opts, progressWriter, cliPathOverride) {
|
|
|
484
480
|
'--exclude-components',
|
|
485
481
|
cycleNames.join(','),
|
|
486
482
|
];
|
|
487
|
-
const rejectResult = await runStep(rejectArgs, cliPath
|
|
483
|
+
const rejectResult = await runStep(rejectArgs, cliPath);
|
|
488
484
|
if (rejectResult.exitCode === 0) {
|
|
489
485
|
const retryT0 = Date.now();
|
|
490
|
-
const retryR = await runStep(pushArgs, cliPath,
|
|
486
|
+
const retryR = await runStep(pushArgs, cliPath, { FORCE_COLOR: '1' }, true);
|
|
491
487
|
const retryDurationMs = Date.now() - t0 + (Date.now() - retryT0);
|
|
492
488
|
if (isSlotCycleError(retryR)) {
|
|
493
489
|
const retryReport = extractCycleReport(retryR.stderr);
|
|
@@ -66,5 +66,6 @@ export type WizardAppProps = {
|
|
|
66
66
|
initialRawTokensPath?: string;
|
|
67
67
|
initialRuns?: RunRecord[];
|
|
68
68
|
onRunPicked?: (selection: RunPickerSelection) => void;
|
|
69
|
+
allowDeletions?: boolean;
|
|
69
70
|
};
|
|
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;
|
|
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;
|
|
@@ -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, } = {}) {
|
|
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, } = {}) {
|
|
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);
|
|
833
|
+
let preview = await client.previewImport(manifest, allowDeletions);
|
|
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);
|
|
855
|
+
preview = await client.previewImport(manifest, allowDeletions);
|
|
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, preview) => {
|
|
949
|
+
const runPush = async (manifest, spaceId, environmentId, cmaToken, host, acknowledgeBreakingChanges, allowDeletions, 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);
|
|
989
|
+
let operation = await client.applyImport(manifest, { acknowledgeBreakingChanges, allowDeletions });
|
|
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, 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, allowDeletions: allowDeletions, 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, onConfirm: (acknowledge) => {
|
|
1609
|
-
void runPush(state.manifest, state.spaceId, state.environmentId, state.cmaToken, state.host, acknowledge, state.serverPreview);
|
|
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);
|
|
1610
1610
|
}, ...(editableComponentCount > 0 ? { onEdit: () => void runEditFromPreview() } : {}), onSaveFiles: () => {
|
|
1611
1611
|
void startSaveFlow();
|
|
1612
1612
|
}, onQuit: () => process.exit(0) }));
|
|
@@ -14,5 +14,6 @@ export type FinalReviewHostProps = {
|
|
|
14
14
|
host?: string;
|
|
15
15
|
tokensPath?: string;
|
|
16
16
|
initialFinalizeError?: string | null;
|
|
17
|
+
allowDeletions?: boolean;
|
|
17
18
|
};
|
|
18
|
-
export declare function FinalReviewHost({ extractSessionId, generatedCount, autoAccept, compositionMode, onFinalize, onQuit, livePreview, spaceId, environmentId, cmaToken, host, tokensPath, initialFinalizeError, }: FinalReviewHostProps): React.ReactElement;
|
|
19
|
+
export declare function FinalReviewHost({ extractSessionId, generatedCount, autoAccept, compositionMode, onFinalize, onQuit, livePreview, spaceId, environmentId, cmaToken, host, tokensPath, initialFinalizeError, allowDeletions, }: 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, }) {
|
|
7
|
+
export function FinalReviewHost({ extractSessionId, generatedCount, autoAccept, compositionMode = 'atomic', onFinalize, onQuit, livePreview, spaceId, environmentId, cmaToken, host, tokensPath, initialFinalizeError, allowDeletions, }) {
|
|
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 }));
|
|
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 } : {}) }));
|
|
19
19
|
}
|
|
20
20
|
function FinalReviewAutoAccept({ generatedCount, onFinalize, }) {
|
|
21
21
|
React.useEffect(() => {
|
|
@@ -26,6 +26,9 @@ 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;
|
|
29
32
|
};
|
|
30
33
|
/**
|
|
31
34
|
* Pure async helper used by `useLivePreview` to re-fire `previewImport` after a
|
|
@@ -60,7 +60,10 @@ export async function runLivePreview(opts) {
|
|
|
60
60
|
timeoutHandle = setTimeout(() => reject(new TimeoutError()), timeoutMs);
|
|
61
61
|
});
|
|
62
62
|
try {
|
|
63
|
-
const response = (await Promise.race([
|
|
63
|
+
const response = (await Promise.race([
|
|
64
|
+
client.previewImport(manifest, opts.allowDeletions === true),
|
|
65
|
+
timeoutPromise,
|
|
66
|
+
]));
|
|
64
67
|
if (process.env['EDS_VERBOSE']) {
|
|
65
68
|
const durationMs = Date.now() - startedAt;
|
|
66
69
|
try {
|
|
@@ -11,6 +11,7 @@ type GenerateReviewStepProps = {
|
|
|
11
11
|
host?: string;
|
|
12
12
|
tokensPath?: string;
|
|
13
13
|
initialFinalizeError?: string | null;
|
|
14
|
+
allowDeletions?: boolean;
|
|
14
15
|
};
|
|
15
16
|
export declare function sortComponentsForSidebar<T extends {
|
|
16
17
|
key: string;
|
|
@@ -33,4 +34,4 @@ export interface BreakingRow {
|
|
|
33
34
|
}
|
|
34
35
|
export declare function buildBreakingRows(breakingChanges: BreakingComponent[]): BreakingRow[];
|
|
35
36
|
export declare function deriveBreakingChanges(response: ServerPreviewResponse): BreakingComponent[];
|
|
36
|
-
export declare function GenerateReviewStep({ extractSessionId, onFinalize, onQuit, livePreview, spaceId, environmentId, cmaToken, host, tokensPath, initialFinalizeError, }: GenerateReviewStepProps): React.ReactElement;
|
|
37
|
+
export declare function GenerateReviewStep({ extractSessionId, onFinalize, onQuit, livePreview, spaceId, environmentId, cmaToken, host, tokensPath, initialFinalizeError, allowDeletions, }: 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, }) {
|
|
177
|
+
export function GenerateReviewStep({ extractSessionId, onFinalize, onQuit, livePreview = true, spaceId = '', environmentId = '', cmaToken = '', host = '', tokensPath = '', initialFinalizeError = null, allowDeletions = false, }) {
|
|
178
178
|
const { stdout } = useStdout();
|
|
179
179
|
const terminalWidth = stdout?.columns ?? 80;
|
|
180
180
|
const [components, setComponents] = useState([]);
|
|
@@ -271,9 +271,8 @@ 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).
|
|
276
274
|
deleteAllComponents: acceptedCountForPreview === 0,
|
|
275
|
+
allowDeletions,
|
|
277
276
|
});
|
|
278
277
|
const SPINNER_FRAMES = '⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏';
|
|
279
278
|
const [spinnerTick, setSpinnerTick] = useState(0);
|
|
@@ -352,6 +351,7 @@ export function GenerateReviewStep({ extractSessionId, onFinalize, onQuit, liveP
|
|
|
352
351
|
cmaToken,
|
|
353
352
|
host,
|
|
354
353
|
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,10 +12,14 @@ type WizardPreviewStepProps = {
|
|
|
12
12
|
environmentId: string;
|
|
13
13
|
stepNumber: number;
|
|
14
14
|
totalSteps: number;
|
|
15
|
-
|
|
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;
|
|
16
20
|
onEdit?: () => void;
|
|
17
21
|
onSaveFiles?: () => void;
|
|
18
22
|
onQuit: () => void;
|
|
19
23
|
};
|
|
20
|
-
export declare function WizardPreviewStep({ preview, spaceId, environmentId, stepNumber, totalSteps, onConfirm, onEdit, onSaveFiles, onQuit, }: WizardPreviewStepProps): React.ReactElement;
|
|
24
|
+
export declare function WizardPreviewStep({ preview, spaceId, environmentId, stepNumber, totalSteps, allowDeletions: fetchedAllowDeletions, onConfirm, onEdit, onSaveFiles, onQuit, }: WizardPreviewStepProps): React.ReactElement;
|
|
21
25
|
export {};
|
|
@@ -89,10 +89,14 @@ export function buildPreviewDiffLines(preview) {
|
|
|
89
89
|
}
|
|
90
90
|
return lines;
|
|
91
91
|
}
|
|
92
|
-
export function WizardPreviewStep({ preview, spaceId, environmentId, stepNumber, totalSteps, onConfirm, onEdit, onSaveFiles, onQuit, }) {
|
|
92
|
+
export function WizardPreviewStep({ preview, spaceId, environmentId, stepNumber, totalSteps, allowDeletions: fetchedAllowDeletions = false, 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);
|
|
96
100
|
const { stdout } = useStdout();
|
|
97
101
|
const terminalRows = stdout?.rows ?? 40;
|
|
98
102
|
const viewportHeight = Math.max(terminalRows - 14, 10);
|
|
@@ -105,9 +109,14 @@ export function WizardPreviewStep({ preview, spaceId, environmentId, stepNumber,
|
|
|
105
109
|
}));
|
|
106
110
|
}, [diffExpanded, preview]);
|
|
107
111
|
const maxScroll = Math.max(0, allDiffLines.length - viewportHeight);
|
|
112
|
+
const removedCount = preview.components.removed.length + preview.tokens.removed.length;
|
|
108
113
|
useImmediateInput((input, key) => {
|
|
109
114
|
if (key.return) {
|
|
110
|
-
onConfirm(breakingWithImpact);
|
|
115
|
+
onConfirm(breakingWithImpact, allowDeletions);
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
if ((input === 'x' || input === 'X') && fetchedAllowDeletions && removedCount > 0) {
|
|
119
|
+
setAllowDeletions((prev) => !prev);
|
|
111
120
|
return;
|
|
112
121
|
}
|
|
113
122
|
if (input === 'd' || input === 'D') {
|
|
@@ -156,5 +165,5 @@ export function WizardPreviewStep({ preview, spaceId, environmentId, stepNumber,
|
|
|
156
165
|
})] })), 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) => {
|
|
157
166
|
const isBreaking = item.changeClassification?.classification === 'breaking';
|
|
158
167
|
return (_jsxs(Text, { color: isBreaking ? PALETTE.error : PALETTE.warning, children: [' ', isBreaking ? '⚠' : '~', " ", item.current.name] }, `chg-${i}`));
|
|
159
|
-
})] })), components.removed.length > 0 && (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { gap: 1, children: [_jsx(Text, { color: PALETTE.error, children:
|
|
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" })] })] }));
|
|
160
169
|
}
|
|
@@ -11,6 +11,8 @@ 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;
|
|
14
16
|
};
|
|
15
17
|
export type UseFinalizePreviewReturn = {
|
|
16
18
|
status: FinalizePreviewStatus;
|
|
Binary file
|
|
@@ -12,6 +12,8 @@ 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;
|
|
15
17
|
};
|
|
16
18
|
export type LivePreviewStatus = 'idle' | 'running';
|
|
17
19
|
export type UseLivePreviewReturn = {
|
|
@@ -82,6 +82,7 @@ export function useLivePreview(opts) {
|
|
|
82
82
|
host: current.host,
|
|
83
83
|
generation,
|
|
84
84
|
deleteAllComponents: current.deleteAllComponents === true,
|
|
85
|
+
allowDeletions: current.allowDeletions === true,
|
|
85
86
|
});
|
|
86
87
|
// Discard stale responses (generation tag).
|
|
87
88
|
if (result.generation !== latestRef.current)
|
package/dist/src/index.js
CHANGED
|
@@ -1,12 +1,7 @@
|
|
|
1
1
|
import { createProgram } from './program.js';
|
|
2
|
-
import { failActiveCommand, flushAnalytics } from './analytics/index.js';
|
|
3
2
|
createProgram()
|
|
4
3
|
.parseAsync()
|
|
5
|
-
.catch(
|
|
6
|
-
await failActiveCommand({
|
|
7
|
-
error_name: err instanceof Error ? err.name : 'Error',
|
|
8
|
-
});
|
|
9
|
-
await flushAnalytics();
|
|
4
|
+
.catch((err) => {
|
|
10
5
|
process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
11
6
|
process.exit(1);
|
|
12
7
|
});
|
|
@@ -3,3 +3,4 @@ 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,3 +25,6 @@ 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
|
+
}
|