@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
package/README.md
CHANGED
|
@@ -214,6 +214,7 @@ Pass `--select-prompt-path <path>` and/or `--generate-prompt-path <path>` to swa
|
|
|
214
214
|
| `--host <url>` | `https://api.contentful.com` | Override API base URL |
|
|
215
215
|
| `--on-conflict <mode>` | _(prompt via `<SaveConflictGate>`)_ | Headless conflict resolution when a file already exists at the save path: `overwrite`, `skip`, or `fail`. Bypasses the wizard's interactive save-conflict gate. Mutex with `--no-save`. |
|
|
216
216
|
| `--print-prompt` | — | Print the generate prompt to stdout and exit. Replaces the prompt-print semantics of `--dry-run`. |
|
|
217
|
+
| `--allow-deletions` | off (non-destructive) | Allow the push to delete remote ComponentTypes/DesignTokens missing from the manifest. Default skips them instead of deleting. Without this flag, preview responses suppress the removed-entity list and return a count instead; interactive confirm screens show an opt-out toggle (never opt-in) only when the flag is passed. Forwarded to headless subprocess pushes and `--push-from-run`. |
|
|
217
218
|
| `--dry-run` | _(deprecated)_ | Deprecated alias for `--print-prompt`. Emits a stderr deprecation notice; prompt-print semantics will be removed in a future release. |
|
|
218
219
|
|
|
219
220
|
### Run-picker at wizard start
|
|
@@ -418,7 +419,7 @@ experiences apply select --space-id <id> --environment-id <env> --session <id>
|
|
|
418
419
|
experiences apply push --space-id <id> --environment-id <env> --session <id> [--yes]
|
|
419
420
|
```
|
|
420
421
|
|
|
421
|
-
Shared flags: `--components`, `--tokens`, `--session`, `--space-id`, `--environment-id`, `--cma-token`, `--host`, `--viewports`. `apply preview` adds `--include-unchanged`. `apply select` adds `--select-all`, `--select`, `--deselect`, `--force`. `apply push` adds `--yes`, `--verbose`, `--force`, `--dry-run`.
|
|
422
|
+
Shared flags: `--components`, `--tokens`, `--session`, `--space-id`, `--environment-id`, `--cma-token`, `--host`, `--viewports`. `apply preview` adds `--include-unchanged`. `apply select` adds `--select-all`, `--select`, `--deselect`, `--force`, `--allow-deletions`. `apply push` adds `--yes`, `--verbose`, `--force`, `--dry-run`, `--allow-deletions`. By default, remote ComponentTypes and DesignTokens missing from the pushed manifest are skipped, not deleted; pass `--allow-deletions` to restore the prior delete behavior.
|
|
422
423
|
|
|
423
424
|
Design tokens are written first (component types may reference token kinds). Each entity write is recorded in the session database atomically — interrupted pushes resume from where they left off.
|
|
424
425
|
|
|
@@ -450,29 +451,6 @@ Wizard run history is separate: `~/.config/experiences/runs.json`.
|
|
|
450
451
|
|
|
451
452
|
---
|
|
452
453
|
|
|
453
|
-
## Usage data
|
|
454
|
-
|
|
455
|
-
The CLI collects **anonymous usage data** to help us understand which commands are used and where the import workflow succeeds or fails. This data does **not** include your source code, file paths, credentials, prompts, or any content you author.
|
|
456
|
-
|
|
457
|
-
What may be included:
|
|
458
|
-
|
|
459
|
-
- Command name and duration
|
|
460
|
-
- CLI, Node.js, and operating-system version
|
|
461
|
-
- Anonymous session identifiers that link steps within a single import run
|
|
462
|
-
- Structural counts (for example, how many components were extracted or accepted)
|
|
463
|
-
- Space and environment IDs you pass on the command line
|
|
464
|
-
- Contentful request IDs from API responses (to correlate failures with server logs)
|
|
465
|
-
|
|
466
|
-
You can turn this off at any time:
|
|
467
|
-
|
|
468
|
-
```bash
|
|
469
|
-
DISABLE_ANALYTICS=1 experiences import --project ./my-app
|
|
470
|
-
```
|
|
471
|
-
|
|
472
|
-
Setting `DISABLE_ANALYTICS` to any value disables collection for that invocation.
|
|
473
|
-
|
|
474
|
-
---
|
|
475
|
-
|
|
476
454
|
## Development
|
|
477
455
|
|
|
478
456
|
```bash
|
package/dist/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contentful/experience-design-system-cli",
|
|
3
|
-
"version": "2.23.2-dev-build-
|
|
3
|
+
"version": "2.23.2-dev-build-e996ffb.0",
|
|
4
4
|
"description": "Contentful Experiences design system import CLI",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -41,7 +41,6 @@
|
|
|
41
41
|
"@contentful/experience-design-system-extraction": "workspace:*",
|
|
42
42
|
"@contentful/experience-design-system-generation": "workspace:*",
|
|
43
43
|
"@contentful/experience-design-system-types": "workspace:*",
|
|
44
|
-
"@segment/analytics-node": "^3.0.0",
|
|
45
44
|
"commander": "^13.1.0",
|
|
46
45
|
"ink": "^4.4.1",
|
|
47
46
|
"react": "^18.3.1",
|
|
@@ -24,7 +24,6 @@ import { DEFAULT_AGENT_NAME, isAgentName, runAgent, } from '@contentful/experien
|
|
|
24
24
|
import { readExperiencesCredentials } from '../credentials-store.js';
|
|
25
25
|
import { buildAnalyzeViewRows, partitionGlobalWarnings } from './build-analyze-view-rows.js';
|
|
26
26
|
import { getInteractiveTerminalSupport } from '../lib/terminal-capabilities.js';
|
|
27
|
-
import { bindAnalyticsSessionId, emitSessionStarted, enrichCommandResult, exitWithAnalytics, isPipelineAnalyticsChild, } from '../analytics/index.js';
|
|
28
27
|
import { getDebugLogger } from '../lib/debug-logger.js';
|
|
29
28
|
const SCANNED_FILE_EXTENSIONS = new Set(['.astro', '.js', '.jsx', '.svelte', '.ts', '.tsx', '.vue']);
|
|
30
29
|
/**
|
|
@@ -265,10 +264,6 @@ export function registerAnalyzeCommand(program) {
|
|
|
265
264
|
inputPath: projectRoot,
|
|
266
265
|
outDir,
|
|
267
266
|
});
|
|
268
|
-
await bindAnalyticsSessionId(sessionId);
|
|
269
|
-
if (!isPipelineAnalyticsChild()) {
|
|
270
|
-
await emitSessionStarted('analyze_extract');
|
|
271
|
-
}
|
|
272
267
|
const stepId = createStep(db, sessionId, 'analyze extract', {
|
|
273
268
|
project: projectRoot,
|
|
274
269
|
});
|
|
@@ -542,7 +537,6 @@ export function registerAnalyzeCommand(program) {
|
|
|
542
537
|
storeSlotCycles(db, sessionId, withBreaks);
|
|
543
538
|
storeScannedFiles(db, sessionId, sourceFiles.map((f) => relative(projectRoot, f)));
|
|
544
539
|
updateStep(db, stepId, 'complete', { sessionId });
|
|
545
|
-
enrichCommandResult({ extracted_component_count: validatedComponents.length });
|
|
546
540
|
db.close();
|
|
547
541
|
const allWarnings = [...extraction.warnings, ...filterWarnings];
|
|
548
542
|
const { rows: componentRows, totalErrors } = buildAnalyzeViewRows(filteredComponents, validatedComponents, allWarnings);
|
|
@@ -564,7 +558,7 @@ export function registerAnalyzeCommand(program) {
|
|
|
564
558
|
if (getInteractiveTerminalSupport().supported) {
|
|
565
559
|
const { waitUntilExit } = render(createElement(AnalyzeView, {
|
|
566
560
|
result: analyzeResult,
|
|
567
|
-
onExit: () =>
|
|
561
|
+
onExit: () => process.exit(0),
|
|
568
562
|
}));
|
|
569
563
|
await waitUntilExit();
|
|
570
564
|
}
|
|
@@ -591,7 +585,7 @@ export function registerAnalyzeCommand(program) {
|
|
|
591
585
|
summaryLines.push('Warnings: none');
|
|
592
586
|
}
|
|
593
587
|
process.stderr.write(summaryLines.join('\n') + '\n');
|
|
594
|
-
|
|
588
|
+
process.exit(0);
|
|
595
589
|
}
|
|
596
590
|
});
|
|
597
591
|
registerAnalyzeEditCommand(analyze);
|
|
@@ -8,7 +8,6 @@ import { loadReviewInput } from './parser.js';
|
|
|
8
8
|
import { App } from './tui/App.js';
|
|
9
9
|
import { openPipelineDb, loadRawComponents, storeRawComponents, createStep, updateStep } from '../../session/db.js';
|
|
10
10
|
import { validateExtractedComponents, shouldExcludeDueToValidation, formatExclusionWarning, } from '@contentful/experience-design-system-extraction';
|
|
11
|
-
import { bindAnalyticsSessionId, enrichCommandResult, exitWithAnalytics } from '../../analytics/index.js';
|
|
12
11
|
const SAFE_PATH_RE = /^[a-zA-Z0-9_.$[\]=]+$/;
|
|
13
12
|
const PROTO_KEYS = new Set(['__proto__', 'constructor', 'prototype']);
|
|
14
13
|
function applyDotPath(obj, path, value) {
|
|
@@ -103,7 +102,6 @@ async function runNonInteractive(snapshot, opts, paths, sessionId) {
|
|
|
103
102
|
}
|
|
104
103
|
const accepted = snapshot.components.filter((c) => c.status === 'accepted').length;
|
|
105
104
|
const rejected = snapshot.components.filter((c) => c.status === 'rejected').length + (names.length || 0);
|
|
106
|
-
enrichCommandResult({ accepted_component_count: accepted });
|
|
107
105
|
process.stderr.write(`Accepted: ${accepted} Rejected: ${rejected}\n`);
|
|
108
106
|
return;
|
|
109
107
|
}
|
|
@@ -132,7 +130,7 @@ async function runNonInteractive(snapshot, opts, paths, sessionId) {
|
|
|
132
130
|
lines.push('');
|
|
133
131
|
lines.push('Re-run with --exclude-invalid to auto-reject these components, or run analyze select interactively to fix them.');
|
|
134
132
|
process.stderr.write(lines.join('\n') + '\n');
|
|
135
|
-
|
|
133
|
+
process.exit(1);
|
|
136
134
|
return;
|
|
137
135
|
}
|
|
138
136
|
}
|
|
@@ -177,14 +175,14 @@ async function runNonInteractive(snapshot, opts, paths, sessionId) {
|
|
|
177
175
|
const parsed = JSON.parse(raw);
|
|
178
176
|
if (!Array.isArray(parsed)) {
|
|
179
177
|
process.stderr.write(`Error: --patch file must be a JSON array of patch operations: ${opts.patch}\n`);
|
|
180
|
-
|
|
178
|
+
process.exit(1);
|
|
181
179
|
return;
|
|
182
180
|
}
|
|
183
181
|
patchOps = parsed;
|
|
184
182
|
}
|
|
185
183
|
catch {
|
|
186
184
|
process.stderr.write(`Error: cannot read or parse --patch file: ${opts.patch}\n`);
|
|
187
|
-
|
|
185
|
+
process.exit(1);
|
|
188
186
|
return;
|
|
189
187
|
}
|
|
190
188
|
// Warn on unknown component names
|
|
@@ -231,7 +229,6 @@ async function runNonInteractive(snapshot, opts, paths, sessionId) {
|
|
|
231
229
|
db.close();
|
|
232
230
|
}
|
|
233
231
|
}
|
|
234
|
-
enrichCommandResult({ accepted_component_count: accepted.length });
|
|
235
232
|
process.stderr.write(`Accepted: ${accepted.length} Rejected: ${rejected.length}\n`);
|
|
236
233
|
}
|
|
237
234
|
/**
|
|
@@ -348,7 +345,7 @@ export async function rejectComponentsByName(sessionId, names, opts = {}) {
|
|
|
348
345
|
const components = snapshot.components.map((c) => (nameSet.has(c.name) ? { ...c, status: 'rejected' } : c));
|
|
349
346
|
await saveReviewState(paths.statePath, { ...snapshot, components });
|
|
350
347
|
}
|
|
351
|
-
|
|
348
|
+
function resolveSessionId(sessionFlag) {
|
|
352
349
|
if (sessionFlag)
|
|
353
350
|
return sessionFlag;
|
|
354
351
|
const db = openPipelineDb();
|
|
@@ -363,7 +360,7 @@ async function resolveSessionId(sessionFlag) {
|
|
|
363
360
|
.get();
|
|
364
361
|
if (!row) {
|
|
365
362
|
process.stderr.write('Error: no completed analyze extract session found. Run analyze extract first, or pass --session <id>.\n');
|
|
366
|
-
|
|
363
|
+
process.exit(1);
|
|
367
364
|
}
|
|
368
365
|
return row.id;
|
|
369
366
|
}
|
|
@@ -387,8 +384,7 @@ export function registerAnalyzeEditCommand(program) {
|
|
|
387
384
|
.option('--exclude-invalid', 'With --select-all: auto-reject components with validation errors instead of failing loud (opt-in bypass for the gate)')
|
|
388
385
|
.option('--exclude-components <names>', 'Comma-separated component names to force-reject, regardless of other selection flags')
|
|
389
386
|
.action(async ({ session: sessionFlag, projectRoot, acceptAll, selectAll, reject, deselect, select, patch, excludeInvalid, excludeComponents, }) => {
|
|
390
|
-
const sessionId =
|
|
391
|
-
await bindAnalyticsSessionId(sessionId);
|
|
387
|
+
const sessionId = resolveSessionId(sessionFlag);
|
|
392
388
|
const db = openPipelineDb();
|
|
393
389
|
let rawComponentCount = 0;
|
|
394
390
|
try {
|
|
@@ -399,7 +395,7 @@ export function registerAnalyzeEditCommand(program) {
|
|
|
399
395
|
}
|
|
400
396
|
if (rawComponentCount === 0) {
|
|
401
397
|
process.stderr.write(`Error: session '${sessionId}' has no raw components. Run analyze extract first.\n`);
|
|
402
|
-
|
|
398
|
+
process.exit(1);
|
|
403
399
|
return;
|
|
404
400
|
}
|
|
405
401
|
const artifactsRoot = getRefineArtifactsRoot();
|
|
@@ -424,7 +420,7 @@ export function registerAnalyzeEditCommand(program) {
|
|
|
424
420
|
}
|
|
425
421
|
catch (error) {
|
|
426
422
|
process.stderr.write(`Error: unable to initialize refine session.\n${error instanceof Error ? error.message : String(error)}\n`);
|
|
427
|
-
|
|
423
|
+
process.exit(1);
|
|
428
424
|
return;
|
|
429
425
|
}
|
|
430
426
|
// Non-interactive path
|
|
@@ -469,7 +465,7 @@ export function registerAnalyzeEditCommand(program) {
|
|
|
469
465
|
});
|
|
470
466
|
if (process.stdout.columns !== undefined && process.stdout.columns < 60) {
|
|
471
467
|
process.stderr.write(`Error: terminal too narrow (${process.stdout.columns} cols). Resize to 60+ columns.\n`);
|
|
472
|
-
|
|
468
|
+
process.exit(1);
|
|
473
469
|
}
|
|
474
470
|
const { waitUntilExit } = render(createElement(App, {
|
|
475
471
|
sessionId,
|
|
@@ -80,7 +80,10 @@ export function App({ sessionId, artifactsRoot, reviewRoot }) {
|
|
|
80
80
|
if (!manifest.componentsManifest)
|
|
81
81
|
manifest.componentsManifest = {};
|
|
82
82
|
const client = new ImportApiClient({ cmaToken, spaceId, environmentId });
|
|
83
|
-
|
|
83
|
+
// This preview is display-only (component-picker annotations); it never
|
|
84
|
+
// triggers an apply, so always request the full diff to keep the
|
|
85
|
+
// existing "removed" annotation working.
|
|
86
|
+
const preview = await client.previewImport(manifest, true);
|
|
84
87
|
const annotations = {};
|
|
85
88
|
for (const item of preview.components.new) {
|
|
86
89
|
const name = item.name ?? '';
|
|
@@ -11,7 +11,6 @@ import { buildRepoContextIndex, buildSelectionContext } from './context-builder.
|
|
|
11
11
|
import { runShowRationale } from './show-rationale.js';
|
|
12
12
|
import { isAbsolute, resolve } from 'node:path';
|
|
13
13
|
import { getDebugLogger } from '../../lib/debug-logger.js';
|
|
14
|
-
import { bindAnalyticsSessionId, enrichCommandResult, exitWithAnalytics } from '../../analytics/index.js';
|
|
15
14
|
import { validateExtractedComponents, shouldExcludeDueToValidation, formatExclusionWarning, } from '@contentful/experience-design-system-extraction';
|
|
16
15
|
const DEFAULT_TIMEOUT_MS = Number(process.env.EDS_AGENT_TIMEOUT_MS ?? 3 * 60 * 1000);
|
|
17
16
|
export const DEFAULT_CONCURRENCY = 10;
|
|
@@ -28,7 +27,7 @@ function resolveBatchSize() {
|
|
|
28
27
|
return DEFAULT_BATCH_SIZE;
|
|
29
28
|
return Math.floor(n);
|
|
30
29
|
}
|
|
31
|
-
|
|
30
|
+
function resolveSessionId(sessionFlag) {
|
|
32
31
|
if (sessionFlag)
|
|
33
32
|
return sessionFlag;
|
|
34
33
|
const db = openPipelineDb();
|
|
@@ -43,7 +42,7 @@ async function resolveSessionId(sessionFlag) {
|
|
|
43
42
|
.get();
|
|
44
43
|
if (!row) {
|
|
45
44
|
process.stderr.write('Error: no completed analyze extract session found. Run analyze extract first, or pass --session <id>.\n');
|
|
46
|
-
|
|
45
|
+
process.exit(1);
|
|
47
46
|
}
|
|
48
47
|
return row.id;
|
|
49
48
|
}
|
|
@@ -330,7 +329,7 @@ export function registerAnalyzeSelectAgentCommand(program) {
|
|
|
330
329
|
catch (err) {
|
|
331
330
|
const message = err instanceof Error ? err.message : String(err);
|
|
332
331
|
process.stderr.write(`Error: ${message}\n`);
|
|
333
|
-
|
|
332
|
+
process.exit(1);
|
|
334
333
|
return;
|
|
335
334
|
}
|
|
336
335
|
}
|
|
@@ -339,7 +338,7 @@ export function registerAnalyzeSelectAgentCommand(program) {
|
|
|
339
338
|
const model = opts.model ?? savedCreds.agentModel;
|
|
340
339
|
if (!agentName || !isAgentName(agentName)) {
|
|
341
340
|
process.stderr.write(`Error: no agent configured. Pass --agent <name> or run experiences setup. Accepted values: ${AGENT_NAMES.join(', ')}\n`);
|
|
342
|
-
|
|
341
|
+
process.exit(1);
|
|
343
342
|
return;
|
|
344
343
|
}
|
|
345
344
|
const agent = agentName;
|
|
@@ -353,7 +352,7 @@ export function registerAnalyzeSelectAgentCommand(program) {
|
|
|
353
352
|
.catch(() => false);
|
|
354
353
|
if (!exists) {
|
|
355
354
|
process.stderr.write(`Error: custom prompt path not found: ${resolvedPath}\n`);
|
|
356
|
-
|
|
355
|
+
process.exit(1);
|
|
357
356
|
return;
|
|
358
357
|
}
|
|
359
358
|
if (!selectPromptPath.toLowerCase().endsWith('.md')) {
|
|
@@ -361,8 +360,7 @@ export function registerAnalyzeSelectAgentCommand(program) {
|
|
|
361
360
|
}
|
|
362
361
|
process.stderr.write(formatCustomPromptBanner('select', resolvedPath));
|
|
363
362
|
}
|
|
364
|
-
const sessionId =
|
|
365
|
-
await bindAnalyticsSessionId(sessionId);
|
|
363
|
+
const sessionId = resolveSessionId(opts.session);
|
|
366
364
|
const selectionRoot = resolveProjectRoot(sessionId, opts.projectRoot);
|
|
367
365
|
const db = openPipelineDb();
|
|
368
366
|
let rawComponents;
|
|
@@ -376,7 +374,7 @@ export function registerAnalyzeSelectAgentCommand(program) {
|
|
|
376
374
|
}
|
|
377
375
|
if (rawComponents.length === 0) {
|
|
378
376
|
process.stderr.write(`Error: session '${sessionId}' has no raw components. Run analyze extract first.\n`);
|
|
379
|
-
|
|
377
|
+
process.exit(1);
|
|
380
378
|
return;
|
|
381
379
|
}
|
|
382
380
|
// Re-run validation (not persisted to DB, so always recompute).
|
|
@@ -401,7 +399,7 @@ export function registerAnalyzeSelectAgentCommand(program) {
|
|
|
401
399
|
lines.push('');
|
|
402
400
|
lines.push('Re-run with --exclude-invalid to auto-reject these components, or fix them in source first.');
|
|
403
401
|
process.stderr.write(lines.join('\n') + '\n');
|
|
404
|
-
|
|
402
|
+
process.exit(1);
|
|
405
403
|
return;
|
|
406
404
|
}
|
|
407
405
|
const componentsForAgent = validatedComponents.filter((comp) => !shouldExcludeDueToValidation(comp));
|
|
@@ -428,7 +426,7 @@ export function registerAnalyzeSelectAgentCommand(program) {
|
|
|
428
426
|
if (opts.dryRun) {
|
|
429
427
|
if (selectionCandidates.length === 0) {
|
|
430
428
|
process.stderr.write('No valid components to preview — all components were excluded due to validation errors.\n');
|
|
431
|
-
|
|
429
|
+
process.exit(0);
|
|
432
430
|
return;
|
|
433
431
|
}
|
|
434
432
|
const first = selectionCandidates[0];
|
|
@@ -440,7 +438,7 @@ export function registerAnalyzeSelectAgentCommand(program) {
|
|
|
440
438
|
skillPathOverride: selectPromptPath ? resolve(selectPromptPath) : undefined,
|
|
441
439
|
});
|
|
442
440
|
process.stdout.write(prompt + '\n');
|
|
443
|
-
|
|
441
|
+
process.exit(0);
|
|
444
442
|
return;
|
|
445
443
|
}
|
|
446
444
|
// --no-cache is the global kill-switch; --no-select-cache is the stage-
|
|
@@ -506,7 +504,7 @@ export function registerAnalyzeSelectAgentCommand(program) {
|
|
|
506
504
|
}
|
|
507
505
|
catch (error) {
|
|
508
506
|
process.stderr.write(`Error: unable to initialize select session.\n${error instanceof Error ? error.message : String(error)}\n`);
|
|
509
|
-
|
|
507
|
+
process.exit(1);
|
|
510
508
|
return;
|
|
511
509
|
}
|
|
512
510
|
const paths = await getRefineSessionPaths(sessionId, artifactsRoot);
|
|
@@ -552,7 +550,6 @@ export function registerAnalyzeSelectAgentCommand(program) {
|
|
|
552
550
|
finally {
|
|
553
551
|
stepDb.close();
|
|
554
552
|
}
|
|
555
|
-
enrichCommandResult({ accepted_component_count: accepted.length });
|
|
556
553
|
process.stderr.write(`Accepted: ${accepted.length} Rejected: ${rejected.length} Needs review: ${unresolved.length}\n`);
|
|
557
554
|
});
|
|
558
555
|
}
|
|
@@ -45,17 +45,17 @@ export declare class ImportApiClient {
|
|
|
45
45
|
private spaceId;
|
|
46
46
|
private environmentId;
|
|
47
47
|
private retry;
|
|
48
|
-
private lastRequestId?;
|
|
49
|
-
getLastRequestId(): string | undefined;
|
|
50
|
-
private noteRequestId;
|
|
51
48
|
constructor(opts: ApiClientOptions);
|
|
52
49
|
private base;
|
|
53
50
|
private headers;
|
|
54
51
|
private requestWithRetry;
|
|
55
52
|
validateToken(): Promise<void>;
|
|
56
53
|
checkPreflight(): Promise<void>;
|
|
57
|
-
previewImport(manifest: ManifestPayload): Promise<ServerPreviewResponse>;
|
|
58
|
-
applyImport(manifest: ManifestPayload,
|
|
54
|
+
previewImport(manifest: ManifestPayload, allowDeletions?: boolean): Promise<ServerPreviewResponse>;
|
|
55
|
+
applyImport(manifest: ManifestPayload, options: {
|
|
56
|
+
acknowledgeBreakingChanges: boolean;
|
|
57
|
+
allowDeletions?: boolean;
|
|
58
|
+
}): Promise<ApplyOperationResponse>;
|
|
59
59
|
pollOperation(operationId: string, opts?: {
|
|
60
60
|
intervalMs?: number;
|
|
61
61
|
maxIntervalMs?: number;
|
|
@@ -180,15 +180,6 @@ export class ImportApiClient {
|
|
|
180
180
|
spaceId;
|
|
181
181
|
environmentId;
|
|
182
182
|
retry;
|
|
183
|
-
lastRequestId;
|
|
184
|
-
getLastRequestId() {
|
|
185
|
-
return this.lastRequestId;
|
|
186
|
-
}
|
|
187
|
-
noteRequestId(response) {
|
|
188
|
-
const requestId = response.headers.get('x-contentful-request-id');
|
|
189
|
-
if (requestId)
|
|
190
|
-
this.lastRequestId = requestId;
|
|
191
|
-
}
|
|
192
183
|
constructor(opts) {
|
|
193
184
|
this.host = toApiHost(opts.host);
|
|
194
185
|
this.token = opts.cmaToken;
|
|
@@ -246,10 +237,8 @@ export class ImportApiClient {
|
|
|
246
237
|
await this.retry.sleep(delayMs);
|
|
247
238
|
continue;
|
|
248
239
|
}
|
|
249
|
-
if (!isTransientStatus(result.response.status))
|
|
250
|
-
this.noteRequestId(result.response);
|
|
240
|
+
if (!isTransientStatus(result.response.status))
|
|
251
241
|
return result;
|
|
252
|
-
}
|
|
253
242
|
if (attempt === this.retry.maxAttempts) {
|
|
254
243
|
const body = stringifyError(result.error);
|
|
255
244
|
const guidance = `The ${phase} request failed after ${attempt} attempts because the service remained unavailable. ` +
|
|
@@ -284,7 +273,6 @@ export class ImportApiClient {
|
|
|
284
273
|
// false positives that don't apply to the design-systems API authorization path.
|
|
285
274
|
const url = `${this.host}/users/me`;
|
|
286
275
|
const res = await request(url, { token: this.token });
|
|
287
|
-
this.noteRequestId(res);
|
|
288
276
|
if (res.status === 401) {
|
|
289
277
|
throw new ApiError('CMA token is invalid or revoked', res.status, await res.text());
|
|
290
278
|
}
|
|
@@ -310,7 +298,6 @@ export class ImportApiClient {
|
|
|
310
298
|
catch {
|
|
311
299
|
return; // network error — don't block; the real call will surface it
|
|
312
300
|
}
|
|
313
|
-
this.noteRequestId(res);
|
|
314
301
|
if (res.ok)
|
|
315
302
|
return;
|
|
316
303
|
if (res.status >= 500)
|
|
@@ -320,19 +307,20 @@ export class ImportApiClient {
|
|
|
320
307
|
return; // legacy backend without the endpoint
|
|
321
308
|
throw new ApiError(`preflight failed: ${res.status}`, res.status, body);
|
|
322
309
|
}
|
|
323
|
-
async previewImport(manifest) {
|
|
310
|
+
async previewImport(manifest, allowDeletions = false) {
|
|
324
311
|
const debug = getDebugLogger();
|
|
325
312
|
const startedAt = Date.now();
|
|
326
313
|
debug.event('apply', 'preview.request', {
|
|
327
314
|
url: `${this.base()}/design_systems/imports/preview`,
|
|
328
315
|
componentCount: manifest.components?.length ?? 0,
|
|
329
316
|
tokenCount: manifest.designTokens?.length ?? 0,
|
|
317
|
+
allowDeletions,
|
|
330
318
|
});
|
|
331
319
|
const result = await this.requestWithRetry('preview', PREVIEW_ERROR_PREFIX, () => designSystemImportSourcelessPreview({
|
|
332
320
|
baseUrl: this.host,
|
|
333
321
|
headers: this.headers(),
|
|
334
322
|
path: { spaceId: this.spaceId, environmentId: this.environmentId },
|
|
335
|
-
body: manifest,
|
|
323
|
+
body: { ...manifest, allowDeletions },
|
|
336
324
|
parseAs: 'json',
|
|
337
325
|
}));
|
|
338
326
|
if (!result.response.ok) {
|
|
@@ -348,12 +336,14 @@ export class ImportApiClient {
|
|
|
348
336
|
debug.event('apply', 'preview.ok', { status: result.response.status, durationMs: Date.now() - startedAt });
|
|
349
337
|
return sanitizePreviewResponse(parsed);
|
|
350
338
|
}
|
|
351
|
-
async applyImport(manifest,
|
|
339
|
+
async applyImport(manifest, options) {
|
|
340
|
+
const { acknowledgeBreakingChanges, allowDeletions = false } = options;
|
|
352
341
|
const debug = getDebugLogger();
|
|
353
342
|
const startedAt = Date.now();
|
|
354
343
|
debug.event('apply', 'apply.request', {
|
|
355
344
|
url: `${this.base()}/design_systems/imports/apply`,
|
|
356
345
|
acknowledgeBreakingChanges,
|
|
346
|
+
allowDeletions,
|
|
357
347
|
});
|
|
358
348
|
let result;
|
|
359
349
|
try {
|
|
@@ -361,7 +351,7 @@ export class ImportApiClient {
|
|
|
361
351
|
baseUrl: this.host,
|
|
362
352
|
headers: this.headers(),
|
|
363
353
|
path: { spaceId: this.spaceId, environmentId: this.environmentId },
|
|
364
|
-
body: { ...manifest, acknowledgeBreakingChanges },
|
|
354
|
+
body: { ...manifest, acknowledgeBreakingChanges, allowDeletions },
|
|
365
355
|
parseAs: 'json',
|
|
366
356
|
});
|
|
367
357
|
}
|
|
@@ -11,7 +11,7 @@ export declare function formatSlotCycleReport(cycles: ReturnType<typeof findSlot
|
|
|
11
11
|
export declare function assertNoSlotCycles(components: Array<{
|
|
12
12
|
key: string;
|
|
13
13
|
entry: CDFComponentEntry;
|
|
14
|
-
}>):
|
|
14
|
+
}>): void;
|
|
15
15
|
export declare function extractComponentsFromManifest(manifest: {
|
|
16
16
|
componentsManifest?: Record<string, unknown>;
|
|
17
17
|
} | null | undefined): Array<{
|