@contentful/experience-design-system-cli 2.18.1-dev-build-55a7404.0 → 2.18.1-dev-build-b4ecc99.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 +1 -2
- package/dist/package.json +4 -4
- package/dist/src/analyze/select/tui/App.js +1 -4
- package/dist/src/apply/api-client.d.ts +2 -5
- package/dist/src/apply/api-client.js +3 -11
- package/dist/src/apply/command.js +10 -27
- package/dist/src/apply/preview-utils.d.ts +2 -4
- package/dist/src/apply/preview-utils.js +4 -8
- package/dist/src/apply/tui/ServerApplyView.d.ts +3 -6
- package/dist/src/apply/tui/ServerApplyView.js +6 -15
- package/dist/src/apply/tui/ServerPreviewView.d.ts +1 -2
- package/dist/src/apply/tui/ServerPreviewView.js +3 -6
- package/dist/src/import/command.js +1 -6
- package/dist/src/import/orchestrator.d.ts +0 -1
- package/dist/src/import/orchestrator.js +0 -2
- package/dist/src/import/tui/WizardApp.d.ts +1 -2
- package/dist/src/import/tui/WizardApp.js +8 -8
- package/dist/src/import/tui/final-review-host.d.ts +1 -2
- package/dist/src/import/tui/final-review-host.js +2 -2
- package/dist/src/import/tui/runLivePreview.d.ts +0 -3
- package/dist/src/import/tui/runLivePreview.js +1 -4
- package/dist/src/import/tui/steps/GenerateReviewStep.d.ts +1 -2
- package/dist/src/import/tui/steps/GenerateReviewStep.js +3 -3
- package/dist/src/import/tui/steps/WizardPreviewStep.d.ts +2 -6
- package/dist/src/import/tui/steps/WizardPreviewStep.js +4 -14
- package/dist/src/import/tui/useFinalizePreview.d.ts +0 -2
- package/dist/src/import/tui/useFinalizePreview.js +0 -0
- package/dist/src/import/tui/useLivePreview.d.ts +0 -2
- package/dist/src/import/tui/useLivePreview.js +0 -1
- package/dist/src/lib/command-options.d.ts +0 -1
- package/dist/src/lib/command-options.js +0 -3
- package/dist/src/runs/modify-launcher.d.ts +0 -2
- package/dist/src/runs/modify-launcher.js +0 -2
- package/dist/src/runs/push-helpers.d.ts +0 -1
- package/dist/src/runs/push-helpers.js +0 -3
- package/dist/src/runs/replay-helpers.d.ts +0 -4
- package/dist/src/runs/replay-helpers.js +0 -3
- package/package.json +7 -7
package/README.md
CHANGED
|
@@ -214,7 +214,6 @@ 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`. |
|
|
218
217
|
| `--dry-run` | _(deprecated)_ | Deprecated alias for `--print-prompt`. Emits a stderr deprecation notice; prompt-print semantics will be removed in a future release. |
|
|
219
218
|
|
|
220
219
|
### Run-picker at wizard start
|
|
@@ -419,7 +418,7 @@ experiences apply select --space-id <id> --environment-id <env> --session <id>
|
|
|
419
418
|
experiences apply push --space-id <id> --environment-id <env> --session <id> [--yes]
|
|
420
419
|
```
|
|
421
420
|
|
|
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
|
|
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`.
|
|
423
422
|
|
|
424
423
|
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.
|
|
425
424
|
|
package/dist/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contentful/experience-design-system-cli",
|
|
3
|
-
"version": "2.18.1-dev-build-
|
|
3
|
+
"version": "2.18.1-dev-build-b4ecc99.0",
|
|
4
4
|
"description": "Contentful Experiences design system import CLI",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -51,11 +51,11 @@
|
|
|
51
51
|
"@tsconfig/node24": "^24.0.3",
|
|
52
52
|
"@types/node": "^24.0.3",
|
|
53
53
|
"@types/react": "^18.3.24",
|
|
54
|
-
"eslint": "^9.39.
|
|
54
|
+
"eslint": "^9.39.5",
|
|
55
55
|
"eslint-config-prettier": "^10.1.8",
|
|
56
|
-
"eslint-plugin-prettier": "^5.5.
|
|
56
|
+
"eslint-plugin-prettier": "^5.5.6",
|
|
57
57
|
"ink-testing-library": "^4.0.0",
|
|
58
|
-
"typescript-eslint": "^8.
|
|
58
|
+
"typescript-eslint": "^8.66.0",
|
|
59
59
|
"vitest": "^4.0.16"
|
|
60
60
|
},
|
|
61
61
|
"repository": {
|
|
@@ -80,10 +80,7 @@ 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
|
-
|
|
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);
|
|
83
|
+
const preview = await client.previewImport(manifest);
|
|
87
84
|
const annotations = {};
|
|
88
85
|
for (const item of preview.components.new) {
|
|
89
86
|
const name = item.name ?? '';
|
|
@@ -50,11 +50,8 @@ export declare class ImportApiClient {
|
|
|
50
50
|
private headers;
|
|
51
51
|
private requestWithRetry;
|
|
52
52
|
validateToken(): Promise<void>;
|
|
53
|
-
previewImport(manifest: ManifestPayload
|
|
54
|
-
applyImport(manifest: ManifestPayload,
|
|
55
|
-
acknowledgeBreakingChanges: boolean;
|
|
56
|
-
allowDeletions?: boolean;
|
|
57
|
-
}): Promise<ApplyOperationResponse>;
|
|
53
|
+
previewImport(manifest: ManifestPayload): Promise<ServerPreviewResponse>;
|
|
54
|
+
applyImport(manifest: ManifestPayload, acknowledgeBreakingChanges: boolean): Promise<ApplyOperationResponse>;
|
|
58
55
|
pollOperation(operationId: string, opts?: {
|
|
59
56
|
intervalMs?: number;
|
|
60
57
|
maxIntervalMs?: number;
|
|
@@ -268,25 +268,19 @@ export class ImportApiClient {
|
|
|
268
268
|
throw new ApiError(`unexpected error validating token: ${res.status}`, res.status, await res.text());
|
|
269
269
|
}
|
|
270
270
|
}
|
|
271
|
-
async previewImport(manifest
|
|
271
|
+
async previewImport(manifest) {
|
|
272
272
|
const debug = getDebugLogger();
|
|
273
273
|
const startedAt = Date.now();
|
|
274
274
|
debug.event('apply', 'preview.request', {
|
|
275
275
|
url: `${this.base()}/design_systems/imports/preview`,
|
|
276
276
|
componentCount: manifest.components?.length ?? 0,
|
|
277
277
|
tokenCount: manifest.designTokens?.length ?? 0,
|
|
278
|
-
allowDeletions,
|
|
279
278
|
});
|
|
280
279
|
const result = await this.requestWithRetry('preview', PREVIEW_ERROR_PREFIX, () => designSystemImportSourcelessPreview({
|
|
281
280
|
baseUrl: this.host,
|
|
282
281
|
headers: this.headers(),
|
|
283
282
|
path: { spaceId: this.spaceId, environmentId: this.environmentId },
|
|
284
283
|
body: manifest,
|
|
285
|
-
// The generated query type only declares `access_token` — the backend
|
|
286
|
-
// reads `allowDeletions` off the raw query string with no OpenAPI
|
|
287
|
-
// parameter declared for it. Cast narrowly here rather than widening
|
|
288
|
-
// the generated type for an undocumented param.
|
|
289
|
-
query: { allowDeletions: String(allowDeletions) },
|
|
290
284
|
parseAs: 'json',
|
|
291
285
|
}));
|
|
292
286
|
if (!result.response.ok) {
|
|
@@ -302,14 +296,12 @@ export class ImportApiClient {
|
|
|
302
296
|
debug.event('apply', 'preview.ok', { status: result.response.status, durationMs: Date.now() - startedAt });
|
|
303
297
|
return sanitizePreviewResponse(parsed);
|
|
304
298
|
}
|
|
305
|
-
async applyImport(manifest,
|
|
306
|
-
const { acknowledgeBreakingChanges, allowDeletions = false } = options;
|
|
299
|
+
async applyImport(manifest, acknowledgeBreakingChanges) {
|
|
307
300
|
const debug = getDebugLogger();
|
|
308
301
|
const startedAt = Date.now();
|
|
309
302
|
debug.event('apply', 'apply.request', {
|
|
310
303
|
url: `${this.base()}/design_systems/imports/apply`,
|
|
311
304
|
acknowledgeBreakingChanges,
|
|
312
|
-
allowDeletions,
|
|
313
305
|
});
|
|
314
306
|
let result;
|
|
315
307
|
try {
|
|
@@ -317,7 +309,7 @@ export class ImportApiClient {
|
|
|
317
309
|
baseUrl: this.host,
|
|
318
310
|
headers: this.headers(),
|
|
319
311
|
path: { spaceId: this.spaceId, environmentId: this.environmentId },
|
|
320
|
-
body: { ...manifest, acknowledgeBreakingChanges
|
|
312
|
+
body: { ...manifest, acknowledgeBreakingChanges },
|
|
321
313
|
parseAs: 'json',
|
|
322
314
|
});
|
|
323
315
|
}
|
|
@@ -12,7 +12,7 @@ import { ServerPreviewApp, ServerPreviewConfirm, ServerApplyProgress, ServerAppl
|
|
|
12
12
|
import { SelectView, makeSelectKey } from './tui/SelectView.js';
|
|
13
13
|
import { buildPostPushUrl } from '../lib/contentful-urls.js';
|
|
14
14
|
import { resolveCompositionMode } from '../lib/composition-mode.js';
|
|
15
|
-
import {
|
|
15
|
+
import { addArtifactInputOptions, addCompositionOptions, addContentfulTargetOptions, addSelectionOptions, } from '../lib/command-options.js';
|
|
16
16
|
import { stripAllowedComponents } from '../import/strip-allowed-components.js';
|
|
17
17
|
import { readExperiencesCredentials } from '../credentials-store.js';
|
|
18
18
|
import { getInteractiveTerminalSupport, requireInteractiveTerminal } from '../lib/terminal-capabilities.js';
|
|
@@ -457,7 +457,6 @@ export function registerApplyCommand(program) {
|
|
|
457
457
|
preview,
|
|
458
458
|
spaceId,
|
|
459
459
|
environmentId,
|
|
460
|
-
allowDeletions: false,
|
|
461
460
|
}));
|
|
462
461
|
await waitUntilExit();
|
|
463
462
|
}
|
|
@@ -470,7 +469,6 @@ export function registerApplyCommand(program) {
|
|
|
470
469
|
addArtifactInputOptions(pushCmd);
|
|
471
470
|
addContentfulTargetOptions(pushCmd);
|
|
472
471
|
addCompositionOptions(pushCmd);
|
|
473
|
-
addAllowDeletionsOption(pushCmd);
|
|
474
472
|
pushCmd
|
|
475
473
|
.option('--yes', 'Skip interactive confirmation')
|
|
476
474
|
.option('--verbose', 'Show all entity progress including skipped/unchanged')
|
|
@@ -504,7 +502,7 @@ export function registerApplyCommand(program) {
|
|
|
504
502
|
const manifest = buildManifest(components, tokens);
|
|
505
503
|
let preview;
|
|
506
504
|
try {
|
|
507
|
-
preview = await client.previewImport(manifest
|
|
505
|
+
preview = await client.previewImport(manifest);
|
|
508
506
|
}
|
|
509
507
|
catch (e) {
|
|
510
508
|
if (e instanceof ApiError)
|
|
@@ -519,7 +517,6 @@ export function registerApplyCommand(program) {
|
|
|
519
517
|
preview,
|
|
520
518
|
spaceId,
|
|
521
519
|
environmentId,
|
|
522
|
-
allowDeletions: opts.allowDeletions === true,
|
|
523
520
|
}));
|
|
524
521
|
await waitUntilExit();
|
|
525
522
|
}
|
|
@@ -550,10 +547,7 @@ export function registerApplyCommand(program) {
|
|
|
550
547
|
}
|
|
551
548
|
let operation;
|
|
552
549
|
try {
|
|
553
|
-
operation = await client.applyImport(manifest,
|
|
554
|
-
acknowledgeBreakingChanges: breakingWithImpact || opts.force === true,
|
|
555
|
-
allowDeletions: opts.allowDeletions === true,
|
|
556
|
-
});
|
|
550
|
+
operation = await client.applyImport(manifest, breakingWithImpact || opts.force === true);
|
|
557
551
|
}
|
|
558
552
|
catch (e) {
|
|
559
553
|
if (e instanceof ApiError)
|
|
@@ -575,7 +569,7 @@ export function registerApplyCommand(program) {
|
|
|
575
569
|
return;
|
|
576
570
|
}
|
|
577
571
|
await new Promise((resolvePromise) => {
|
|
578
|
-
const runApply = async (acknowledge
|
|
572
|
+
const runApply = async (acknowledge) => {
|
|
579
573
|
instance.rerender(createElement(ServerApplyProgress, {
|
|
580
574
|
spaceId,
|
|
581
575
|
environmentId,
|
|
@@ -583,10 +577,7 @@ export function registerApplyCommand(program) {
|
|
|
583
577
|
}));
|
|
584
578
|
let operation;
|
|
585
579
|
try {
|
|
586
|
-
operation = await client.applyImport(manifest,
|
|
587
|
-
acknowledgeBreakingChanges: acknowledge,
|
|
588
|
-
allowDeletions: applyDeletions,
|
|
589
|
-
});
|
|
580
|
+
operation = await client.applyImport(manifest, acknowledge);
|
|
590
581
|
}
|
|
591
582
|
catch (e) {
|
|
592
583
|
if (e instanceof ApiError) {
|
|
@@ -634,9 +625,8 @@ export function registerApplyCommand(program) {
|
|
|
634
625
|
spaceId,
|
|
635
626
|
environmentId,
|
|
636
627
|
breakingWithImpact,
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
void runApply(acknowledge, applyDeletions);
|
|
628
|
+
onConfirm: (acknowledge) => {
|
|
629
|
+
void runApply(acknowledge);
|
|
640
630
|
},
|
|
641
631
|
onCancel: () => {
|
|
642
632
|
process.exit(0);
|
|
@@ -650,7 +640,6 @@ export function registerApplyCommand(program) {
|
|
|
650
640
|
addContentfulTargetOptions(selectCmd);
|
|
651
641
|
addCompositionOptions(selectCmd);
|
|
652
642
|
addSelectionOptions(selectCmd);
|
|
653
|
-
addAllowDeletionsOption(selectCmd);
|
|
654
643
|
selectCmd.option('--force', 'Skip confirmation for breaking changes').action(async (opts) => {
|
|
655
644
|
const nonInteractive = opts.selectAll || (opts.select ?? []).length > 0 || (opts.deselect ?? []).length > 0;
|
|
656
645
|
if (!nonInteractive) {
|
|
@@ -680,7 +669,7 @@ export function registerApplyCommand(program) {
|
|
|
680
669
|
const fullManifest = buildManifest(components, tokens);
|
|
681
670
|
let preview;
|
|
682
671
|
try {
|
|
683
|
-
preview = await client.previewImport(fullManifest
|
|
672
|
+
preview = await client.previewImport(fullManifest);
|
|
684
673
|
}
|
|
685
674
|
catch (e) {
|
|
686
675
|
if (e instanceof ApiError)
|
|
@@ -718,10 +707,7 @@ export function registerApplyCommand(program) {
|
|
|
718
707
|
}
|
|
719
708
|
let operation;
|
|
720
709
|
try {
|
|
721
|
-
operation = await client.applyImport(filteredManifest,
|
|
722
|
-
acknowledgeBreakingChanges: hasBreaking || opts.force === true,
|
|
723
|
-
allowDeletions: opts.allowDeletions === true,
|
|
724
|
-
});
|
|
710
|
+
operation = await client.applyImport(filteredManifest, hasBreaking || opts.force === true);
|
|
725
711
|
}
|
|
726
712
|
catch (e) {
|
|
727
713
|
if (e instanceof ApiError)
|
|
@@ -763,10 +749,7 @@ export function registerApplyCommand(program) {
|
|
|
763
749
|
}));
|
|
764
750
|
let operation;
|
|
765
751
|
try {
|
|
766
|
-
operation = await client.applyImport(filteredManifest,
|
|
767
|
-
acknowledgeBreakingChanges: hasBreaking,
|
|
768
|
-
allowDeletions: opts.allowDeletions === true,
|
|
769
|
-
});
|
|
752
|
+
operation = await client.applyImport(filteredManifest, hasBreaking);
|
|
770
753
|
}
|
|
771
754
|
catch (e) {
|
|
772
755
|
if (e instanceof ApiError) {
|
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
import type { ServerPreviewResponse } from '@contentful/experience-design-system-types';
|
|
2
2
|
/**
|
|
3
3
|
* True when a preview response describes zero server-side changes across
|
|
4
|
-
* every diff bucket (components, tokens, taxonomies)
|
|
5
|
-
* Used by:
|
|
4
|
+
* every diff bucket (components, tokens, taxonomies). Used by:
|
|
6
5
|
* - `experiences apply` (CLI): short-circuit the confirm-and-push step.
|
|
7
6
|
* - `experiences import` wizard: block finalize when the resulting push
|
|
8
7
|
* would be a pure no-op (INTEG-4411 refined guard).
|
|
9
8
|
*
|
|
10
9
|
* A push that produces ANY entry in ANY bucket — including a rejection that
|
|
11
|
-
* removes a server-side component — is NOT empty.
|
|
12
|
-
* ANY suppressedDeletions (when fetched with allowDeletions: false) is NOT empty.
|
|
10
|
+
* removes a server-side component — is NOT empty.
|
|
13
11
|
*/
|
|
14
12
|
export declare function isEmptyPreview(preview: ServerPreviewResponse): boolean;
|
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* True when a preview response describes zero server-side changes across
|
|
3
|
-
* every diff bucket (components, tokens, taxonomies)
|
|
4
|
-
* Used by:
|
|
3
|
+
* every diff bucket (components, tokens, taxonomies). Used by:
|
|
5
4
|
* - `experiences apply` (CLI): short-circuit the confirm-and-push step.
|
|
6
5
|
* - `experiences import` wizard: block finalize when the resulting push
|
|
7
6
|
* would be a pure no-op (INTEG-4411 refined guard).
|
|
8
7
|
*
|
|
9
8
|
* A push that produces ANY entry in ANY bucket — including a rejection that
|
|
10
|
-
* removes a server-side component — is NOT empty.
|
|
11
|
-
* ANY suppressedDeletions (when fetched with allowDeletions: false) is NOT empty.
|
|
9
|
+
* removes a server-side component — is NOT empty.
|
|
12
10
|
*/
|
|
13
11
|
export function isEmptyPreview(preview) {
|
|
14
|
-
const { components, tokens, taxonomies
|
|
12
|
+
const { components, tokens, taxonomies } = preview;
|
|
15
13
|
return (components.new.length === 0 &&
|
|
16
14
|
components.changed.length === 0 &&
|
|
17
15
|
components.removed.length === 0 &&
|
|
@@ -20,7 +18,5 @@ export function isEmptyPreview(preview) {
|
|
|
20
18
|
tokens.removed.length === 0 &&
|
|
21
19
|
taxonomies.new.length === 0 &&
|
|
22
20
|
taxonomies.changed.length === 0 &&
|
|
23
|
-
taxonomies.removed.length === 0
|
|
24
|
-
(suppressedDeletions?.components ?? 0) === 0 &&
|
|
25
|
-
(suppressedDeletions?.tokens ?? 0) === 0);
|
|
21
|
+
taxonomies.removed.length === 0);
|
|
26
22
|
}
|
|
@@ -5,19 +5,16 @@ interface ServerPreviewConfirmProps {
|
|
|
5
5
|
spaceId: string;
|
|
6
6
|
environmentId: string;
|
|
7
7
|
breakingWithImpact: boolean;
|
|
8
|
-
|
|
9
|
-
allowDeletions: boolean;
|
|
10
|
-
onConfirm: (acknowledge: boolean, allowDeletions: boolean) => void;
|
|
8
|
+
onConfirm: (acknowledge: boolean) => void;
|
|
11
9
|
onCancel: () => void;
|
|
12
10
|
}
|
|
13
|
-
export declare function ServerPreviewConfirm({ preview, spaceId, environmentId, breakingWithImpact,
|
|
11
|
+
export declare function ServerPreviewConfirm({ preview, spaceId, environmentId, breakingWithImpact, onConfirm, onCancel, }: ServerPreviewConfirmProps): React.ReactElement;
|
|
14
12
|
interface ServerPreviewAppProps {
|
|
15
13
|
preview: ServerPreviewResponse;
|
|
16
14
|
spaceId: string;
|
|
17
15
|
environmentId: string;
|
|
18
|
-
allowDeletions: boolean;
|
|
19
16
|
}
|
|
20
|
-
export declare function ServerPreviewApp({ preview, spaceId, environmentId
|
|
17
|
+
export declare function ServerPreviewApp({ preview, spaceId, environmentId }: ServerPreviewAppProps): React.ReactElement;
|
|
21
18
|
interface ServerApplyProgressProps {
|
|
22
19
|
spaceId: string;
|
|
23
20
|
environmentId: string;
|
|
@@ -1,32 +1,23 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useState } from 'react';
|
|
3
2
|
import { Box, Text, useInput } from 'ink';
|
|
4
3
|
import { ServerPreviewView } from './ServerPreviewView.js';
|
|
5
4
|
import { buildPostPushUrl } from '../../lib/contentful-urls.js';
|
|
6
5
|
import { formatEdsiError } from '../../lib/error-parser.js';
|
|
7
|
-
export function ServerPreviewConfirm({ preview, spaceId, environmentId, breakingWithImpact,
|
|
8
|
-
const [allowDeletions, setAllowDeletions] = useState(fetchedAllowDeletions);
|
|
9
|
-
const removedCount = preview.components.removed.length + preview.tokens.removed.length;
|
|
6
|
+
export function ServerPreviewConfirm({ preview, spaceId, environmentId, breakingWithImpact, onConfirm, onCancel, }) {
|
|
10
7
|
useInput((input, key) => {
|
|
11
|
-
if (key.return)
|
|
12
|
-
onConfirm(breakingWithImpact
|
|
13
|
-
return;
|
|
14
|
-
}
|
|
15
|
-
if ((input === 'x' || input === 'X') && fetchedAllowDeletions && removedCount > 0) {
|
|
16
|
-
setAllowDeletions((prev) => !prev);
|
|
17
|
-
return;
|
|
18
|
-
}
|
|
8
|
+
if (key.return)
|
|
9
|
+
onConfirm(breakingWithImpact);
|
|
19
10
|
if (key.escape || input === 'q')
|
|
20
11
|
onCancel();
|
|
21
12
|
});
|
|
22
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(ServerPreviewView, { preview: preview, spaceId: spaceId, environmentId: environmentId
|
|
13
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(ServerPreviewView, { preview: preview, spaceId: spaceId, environmentId: environmentId }), _jsxs(Box, { paddingX: 2, flexDirection: "column", children: [breakingWithImpact && (_jsxs(Text, { color: "red", bold: true, children: [' ', "\u26A0 Breaking changes will affect downstream entities. Press Enter to acknowledge and apply."] })), _jsxs(Text, { children: [' ', "Press ", _jsx(Text, { bold: true, children: "Enter" }), " to apply, ", _jsx(Text, { bold: true, children: "Esc" }), " to cancel"] })] })] }));
|
|
23
14
|
}
|
|
24
|
-
export function ServerPreviewApp({ preview, spaceId, environmentId
|
|
15
|
+
export function ServerPreviewApp({ preview, spaceId, environmentId }) {
|
|
25
16
|
useInput((input, key) => {
|
|
26
17
|
if (key.escape || input === 'q')
|
|
27
18
|
process.exit(0);
|
|
28
19
|
});
|
|
29
|
-
return
|
|
20
|
+
return _jsx(ServerPreviewView, { preview: preview, spaceId: spaceId, environmentId: environmentId });
|
|
30
21
|
}
|
|
31
22
|
export function ServerApplyProgress({ spaceId, environmentId, status, operationId, error, }) {
|
|
32
23
|
useInput((_input, key) => {
|
|
@@ -4,7 +4,6 @@ interface ServerPreviewViewProps {
|
|
|
4
4
|
preview: ServerPreviewResponse;
|
|
5
5
|
spaceId: string;
|
|
6
6
|
environmentId: string;
|
|
7
|
-
allowDeletions: boolean;
|
|
8
7
|
}
|
|
9
|
-
export declare function ServerPreviewView({ preview, spaceId, environmentId
|
|
8
|
+
export declare function ServerPreviewView({ preview, spaceId, environmentId }: ServerPreviewViewProps): React.ReactElement;
|
|
10
9
|
export {};
|
|
@@ -13,14 +13,11 @@ function DraftWarning({ hasDraft }) {
|
|
|
13
13
|
return null;
|
|
14
14
|
return _jsx(Text, { color: "yellow", children: " \u26A1 has pending draft changes" });
|
|
15
15
|
}
|
|
16
|
-
export function ServerPreviewView({ preview, spaceId, environmentId
|
|
16
|
+
export function ServerPreviewView({ preview, spaceId, environmentId }) {
|
|
17
17
|
const { components, tokens } = preview;
|
|
18
18
|
const totalComponents = components.new.length + components.changed.length + components.unchanged.length + components.removed.length;
|
|
19
19
|
const totalTokens = tokens.new.length + tokens.changed.length + tokens.unchanged.length + tokens.removed.length;
|
|
20
|
-
return (_jsxs(Box, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [_jsxs(Text, { bold: true, children: ["Preview \u2014 ", environmentId, " @ ", spaceId] }), _jsx(Text, { children: " " }), totalComponents > 0 && (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { bold: true, children: [" Component Types (", totalComponents, " total)"] }), _jsxs(Text, { color: "green", children: [" \u2746 ", components.new.length, " to create"] }), _jsxs(Text, { color: "yellow", children: [" ~ ", components.changed.length, " to update"] }), _jsxs(Text, { color:
|
|
20
|
+
return (_jsxs(Box, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [_jsxs(Text, { bold: true, children: ["Preview \u2014 ", environmentId, " @ ", spaceId] }), _jsx(Text, { children: " " }), totalComponents > 0 && (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { bold: true, children: [" Component Types (", totalComponents, " total)"] }), _jsxs(Text, { color: "green", children: [" \u2746 ", components.new.length, " to create"] }), _jsxs(Text, { color: "yellow", children: [" ~ ", components.changed.length, " to update"] }), _jsxs(Text, { color: "red", children: [" \u2717 ", components.removed.length, " to remove"] }), _jsxs(Text, { dimColor: true, children: [" \u00B7 ", components.unchanged.length, " unchanged"] }), components.changed.map((item, i) => (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { flexDirection: "row", children: [_jsxs(Text, { color: "yellow", children: [" ~ ", item.current.name] }), _jsx(DraftWarning, { hasDraft: item.hasPendingDraftChanges })] }), _jsx(BreakingBadge, { item: item })] }, i))), _jsx(Text, { children: " " })] })), totalTokens > 0 && (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { bold: true, children: [" Design Tokens (", totalTokens, " total)"] }), _jsxs(Text, { color: "green", children: [" \u2746 ", tokens.new.length, " to create"] }), _jsxs(Text, { color: "yellow", children: [" ~ ", tokens.changed.length, " to update"] }), _jsxs(Text, { color: "red", children: [" \u2717 ", tokens.removed.length, " to remove"] }), _jsxs(Text, { dimColor: true, children: [" \u00B7 ", tokens.unchanged.length, " unchanged"] }), tokens.changed
|
|
21
21
|
.filter((t) => t.hasPendingDraftChanges)
|
|
22
|
-
.map((item, i) => (_jsxs(Box, { flexDirection: "row", children: [_jsxs(Text, { color: "yellow", children: [" ~ ", item.current.name] }), _jsx(DraftWarning, { hasDraft: true })] }, i))), _jsx(Text, { children: " " })] })),
|
|
23
|
-
(preview.suppressedDeletions?.components ?? 0) + (preview.suppressedDeletions?.tokens ?? 0) > 0 && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: "yellow", children: [' ', "\u2298 ", (preview.suppressedDeletions?.components ?? 0) + (preview.suppressedDeletions?.tokens ?? 0), ' ', (preview.suppressedDeletions?.components ?? 0) + (preview.suppressedDeletions?.tokens ?? 0) === 1
|
|
24
|
-
? 'entity'
|
|
25
|
-
: 'entities', ' ', "skipped (rerun with --allow-deletions to remove them)"] }) })), _jsx(Text, { dimColor: true, children: " Press Q to exit." })] }));
|
|
22
|
+
.map((item, i) => (_jsxs(Box, { flexDirection: "row", children: [_jsxs(Text, { color: "yellow", children: [" ~ ", item.current.name] }), _jsx(DraftWarning, { hasDraft: true })] }, i))), _jsx(Text, { children: " " })] })), _jsx(Text, { dimColor: true, children: " Press Q to exit." })] }));
|
|
26
23
|
}
|
|
@@ -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 {
|
|
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;
|
|
@@ -418,8 +418,6 @@ export async function runPipeline(opts, progressWriter, cliPathOverride) {
|
|
|
418
418
|
pushArgs.push('--host', opts.host);
|
|
419
419
|
if (opts.verbose)
|
|
420
420
|
pushArgs.push('--verbose');
|
|
421
|
-
if (opts.allowDeletions)
|
|
422
|
-
pushArgs.push('--allow-deletions');
|
|
423
421
|
pushArgs.push('--yes');
|
|
424
422
|
const pushStepId = createStep(db, sessionId, 'apply push', {
|
|
425
423
|
components: componentsPath,
|
|
@@ -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,
|
|
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,
|
|
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();
|
|
@@ -826,7 +826,7 @@ export function WizardApp({ initialSpaceId = '', initialEnvironmentId = 'master'
|
|
|
826
826
|
tokens = await readTokensFromPath('tokens', tokensPath);
|
|
827
827
|
}
|
|
828
828
|
let manifest = buildManifest(components, tokens, { deleteAllComponents: allowEmptyDeleteAllRef.current });
|
|
829
|
-
let preview = await client.previewImport(manifest
|
|
829
|
+
let preview = await client.previewImport(manifest);
|
|
830
830
|
if (extractSessionId) {
|
|
831
831
|
let needsRepreview = false;
|
|
832
832
|
const db = openPipelineDb();
|
|
@@ -848,7 +848,7 @@ export function WizardApp({ initialSpaceId = '', initialEnvironmentId = 'master'
|
|
|
848
848
|
if (needsRepreview) {
|
|
849
849
|
components = loadCDFComponents(db, extractSessionId);
|
|
850
850
|
manifest = buildManifest(components, tokens, { deleteAllComponents: allowEmptyDeleteAllRef.current });
|
|
851
|
-
preview = await client.previewImport(manifest
|
|
851
|
+
preview = await client.previewImport(manifest);
|
|
852
852
|
}
|
|
853
853
|
}
|
|
854
854
|
finally {
|
|
@@ -942,7 +942,7 @@ export function WizardApp({ initialSpaceId = '', initialEnvironmentId = 'master'
|
|
|
942
942
|
});
|
|
943
943
|
}
|
|
944
944
|
};
|
|
945
|
-
const runPush = async (manifest, spaceId, environmentId, cmaToken, host, acknowledgeBreakingChanges,
|
|
945
|
+
const runPush = async (manifest, spaceId, environmentId, cmaToken, host, acknowledgeBreakingChanges, preview) => {
|
|
946
946
|
if (shouldRefusePush(state)) {
|
|
947
947
|
update(buildSkippedPushTransition());
|
|
948
948
|
return;
|
|
@@ -982,7 +982,7 @@ export function WizardApp({ initialSpaceId = '', initialEnvironmentId = 'master'
|
|
|
982
982
|
environmentId,
|
|
983
983
|
host: resolvedHost,
|
|
984
984
|
});
|
|
985
|
-
let operation = await client.applyImport(manifest,
|
|
985
|
+
let operation = await client.applyImport(manifest, acknowledgeBreakingChanges);
|
|
986
986
|
try {
|
|
987
987
|
logStep({
|
|
988
988
|
applyResponse: {
|
|
@@ -1433,7 +1433,7 @@ export function WizardApp({ initialSpaceId = '', initialEnvironmentId = 'master'
|
|
|
1433
1433
|
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 }));
|
|
1434
1434
|
}
|
|
1435
1435
|
case 'final-review': {
|
|
1436
|
-
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,
|
|
1436
|
+
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) => {
|
|
1437
1437
|
process.stderr.write(`Accepted: ${accepted} Rejected: ${rejected} Unresolved: ${unresolved}\n`);
|
|
1438
1438
|
let acceptedCount = accepted;
|
|
1439
1439
|
const detectAcceptedCycles = () => {
|
|
@@ -1601,8 +1601,8 @@ export function WizardApp({ initialSpaceId = '', initialEnvironmentId = 'master'
|
|
|
1601
1601
|
// present-but-empty (only $schema), so editing would dead-end on the
|
|
1602
1602
|
// "No generated definitions found" screen.
|
|
1603
1603
|
const editableComponentCount = Object.keys(state.manifest?.componentsManifest ?? {}).filter((k) => k !== '$schema').length;
|
|
1604
|
-
return (_jsx(WizardPreviewStep, { preview: state.serverPreview, spaceId: state.spaceId, environmentId: state.environmentId, stepNumber: totalSteps, totalSteps: totalSteps,
|
|
1605
|
-
void runPush(state.manifest, state.spaceId, state.environmentId, state.cmaToken, state.host, acknowledge,
|
|
1604
|
+
return (_jsx(WizardPreviewStep, { preview: state.serverPreview, spaceId: state.spaceId, environmentId: state.environmentId, stepNumber: totalSteps, totalSteps: totalSteps, onConfirm: (acknowledge) => {
|
|
1605
|
+
void runPush(state.manifest, state.spaceId, state.environmentId, state.cmaToken, state.host, acknowledge, state.serverPreview);
|
|
1606
1606
|
}, ...(editableComponentCount > 0 ? { onEdit: () => void runEditFromPreview() } : {}), onSaveFiles: () => {
|
|
1607
1607
|
void startSaveFlow();
|
|
1608
1608
|
}, 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,
|
|
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,
|
|
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
|
|
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,
|
|
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,
|
|
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
|
-
|
|
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,
|
|
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,
|
|
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,15 +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
|
-
const suppressedCount = (preview.suppressedDeletions?.components ?? 0) + (preview.suppressedDeletions?.tokens ?? 0);
|
|
114
108
|
useImmediateInput((input, key) => {
|
|
115
109
|
if (key.return) {
|
|
116
|
-
onConfirm(breakingWithImpact
|
|
117
|
-
return;
|
|
118
|
-
}
|
|
119
|
-
if ((input === 'x' || input === 'X') && fetchedAllowDeletions && removedCount > 0) {
|
|
120
|
-
setAllowDeletions((prev) => !prev);
|
|
110
|
+
onConfirm(breakingWithImpact);
|
|
121
111
|
return;
|
|
122
112
|
}
|
|
123
113
|
if (input === 'd' || input === 'D') {
|
|
@@ -159,12 +149,12 @@ export function WizardPreviewStep({ preview, spaceId, environmentId, stepNumber,
|
|
|
159
149
|
const { components, tokens } = preview;
|
|
160
150
|
const hasComponents = components.new.length + components.changed.length + components.removed.length > 0;
|
|
161
151
|
const hasTokens = tokens.new.length + tokens.changed.length + tokens.removed.length > 0;
|
|
162
|
-
const hasAnything = hasComponents || hasTokens
|
|
152
|
+
const hasAnything = hasComponents || hasTokens;
|
|
163
153
|
return (_jsxs(Box, { flexDirection: "column", gap: 1, paddingX: 2, paddingY: 1, children: [_jsxs(Box, { flexDirection: "column", gap: 0, children: [_jsx(Text, { dimColor: true, children: '─'.repeat(40) }), _jsxs(Box, { gap: 1, children: [_jsxs(Text, { bold: true, children: ["Step ", stepNumber, " of ", totalSteps] }), _jsx(Text, { bold: true, children: "\u2014" }), _jsx(Text, { bold: true, children: "Push to Contentful" })] }), _jsx(Text, { dimColor: true, children: '─'.repeat(40) })] }), hasAnything ? (_jsxs(_Fragment, { children: [_jsx(Text, { children: "Here's what will happen in your space:" }), hasComponents && (_jsxs(Box, { flexDirection: "column", gap: 0, children: [_jsx(Box, { gap: 1, marginTop: 1, children: _jsx(Text, { bold: true, dimColor: true, children: "ComponentTypes" }) }), components.new.length > 0 && (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { gap: 1, children: [_jsx(Text, { color: PALETTE.success, children: " \uFF0B" }), _jsxs(Text, { children: [components.new.length, " will be created"] })] }), components.new.map((item, i) => {
|
|
164
154
|
const name = item.key ?? item.$name ?? 'unknown';
|
|
165
155
|
return (_jsxs(Text, { color: PALETTE.success, children: [' ', "+ ", name] }, `new-${i}`));
|
|
166
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) => {
|
|
167
157
|
const isBreaking = item.changeClassification?.classification === 'breaking';
|
|
168
158
|
return (_jsxs(Text, { color: isBreaking ? PALETTE.error : PALETTE.warning, children: [' ', isBreaking ? '⚠' : '~', " ", item.current.name] }, `chg-${i}`));
|
|
169
|
-
})] })), components.removed.length > 0 && (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { gap: 1, children: [_jsx(Text, { color:
|
|
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" })] })] }));
|
|
170
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;
|
|
Binary file
|
|
@@ -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)
|
|
@@ -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
|
-
}
|
|
@@ -26,7 +26,5 @@ export type ModifyLauncherInput = {
|
|
|
26
26
|
initialHost?: string;
|
|
27
27
|
/** Pre-fill CMA token (from credentials.json / env). */
|
|
28
28
|
initialCmaToken?: string;
|
|
29
|
-
/** From `--allow-deletions` flag. Forwarded to wizard's push step. */
|
|
30
|
-
allowDeletions?: boolean;
|
|
31
29
|
};
|
|
32
30
|
export declare function launchModifyWizard(input: ModifyLauncherInput): Promise<void>;
|
|
@@ -35,8 +35,6 @@ export async function launchModifyWizard(input) {
|
|
|
35
35
|
props.initialHost = input.initialHost;
|
|
36
36
|
if (input.initialCmaToken)
|
|
37
37
|
props.initialCmaToken = input.initialCmaToken;
|
|
38
|
-
if (input.allowDeletions !== undefined)
|
|
39
|
-
props.allowDeletions = input.allowDeletions;
|
|
40
38
|
const { waitUntilExit } = render(createElement(WizardApp, props));
|
|
41
39
|
await waitUntilExit();
|
|
42
40
|
}
|
|
@@ -16,8 +16,6 @@ export type ReplayRunOptions = {
|
|
|
16
16
|
interactive?: boolean;
|
|
17
17
|
/** When true, bypass the source/saved-file staleness check. */
|
|
18
18
|
force?: boolean;
|
|
19
|
-
/** From `--allow-deletions` flag. Forwarded verbatim to the pushed session's apply request. */
|
|
20
|
-
allowDeletions?: boolean;
|
|
21
19
|
/**
|
|
22
20
|
* Test seam: replace the interactive prompt with a deterministic resolver.
|
|
23
21
|
* The CLI surface never sets this; only used by tests.
|
|
@@ -59,8 +57,6 @@ export type ModifyRunOptions = {
|
|
|
59
57
|
outDir?: string;
|
|
60
58
|
/** When true, bypass the source/saved-file staleness check. */
|
|
61
59
|
force?: boolean;
|
|
62
|
-
/** From `--allow-deletions` flag. Forwarded through the modify wizard's push step. */
|
|
63
|
-
allowDeletions?: boolean;
|
|
64
60
|
};
|
|
65
61
|
/**
|
|
66
62
|
* Re-open the wizard with a prior run's extract/generate session pre-populated
|
|
@@ -83,7 +83,6 @@ export async function replayRun(opts) {
|
|
|
83
83
|
environmentId,
|
|
84
84
|
cmaToken,
|
|
85
85
|
...(host ? { host } : {}),
|
|
86
|
-
...(opts.allowDeletions ? { allowDeletions: true } : {}),
|
|
87
86
|
});
|
|
88
87
|
if (!result.ok) {
|
|
89
88
|
throw new Error(result.error);
|
|
@@ -99,7 +98,6 @@ export async function replayRun(opts) {
|
|
|
99
98
|
environmentId,
|
|
100
99
|
cmaToken,
|
|
101
100
|
...(host ? { host } : {}),
|
|
102
|
-
...(opts.allowDeletions ? { allowDeletions: true } : {}),
|
|
103
101
|
});
|
|
104
102
|
if (!tokenResult.ok) {
|
|
105
103
|
throw new Error(tokenResult.error);
|
|
@@ -159,6 +157,5 @@ export async function modifyRun(opts) {
|
|
|
159
157
|
...(mergedEnvironmentId ? { initialEnvironmentId: mergedEnvironmentId } : {}),
|
|
160
158
|
...(mergedHost ? { initialHost: mergedHost } : {}),
|
|
161
159
|
...(mergedCmaToken ? { initialCmaToken: mergedCmaToken } : {}),
|
|
162
|
-
...(opts.allowDeletions !== undefined ? { allowDeletions: opts.allowDeletions } : {}),
|
|
163
160
|
});
|
|
164
161
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contentful/experience-design-system-cli",
|
|
3
|
-
"version": "2.18.1-dev-build-
|
|
3
|
+
"version": "2.18.1-dev-build-b4ecc99.0",
|
|
4
4
|
"description": "Contentful Experiences design system import CLI",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -34,19 +34,19 @@
|
|
|
34
34
|
"react": "^18.3.1",
|
|
35
35
|
"react-devtools-core": "^4.19.1",
|
|
36
36
|
"react-dom": "^18.3.1",
|
|
37
|
-
"@contentful/experience-design-system-
|
|
38
|
-
"@contentful/experience-design-system-extraction": "2.18.1-dev-build-
|
|
39
|
-
"@contentful/experience-design-system-
|
|
37
|
+
"@contentful/experience-design-system-client": "2.18.1-dev-build-b4ecc99.0",
|
|
38
|
+
"@contentful/experience-design-system-extraction": "2.18.1-dev-build-b4ecc99.0",
|
|
39
|
+
"@contentful/experience-design-system-types": "2.18.1-dev-build-b4ecc99.0"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@tsconfig/node24": "^24.0.3",
|
|
43
43
|
"@types/node": "^24.0.3",
|
|
44
44
|
"@types/react": "^18.3.24",
|
|
45
|
-
"eslint": "^9.39.
|
|
45
|
+
"eslint": "^9.39.5",
|
|
46
46
|
"eslint-config-prettier": "^10.1.8",
|
|
47
|
-
"eslint-plugin-prettier": "^5.5.
|
|
47
|
+
"eslint-plugin-prettier": "^5.5.6",
|
|
48
48
|
"ink-testing-library": "^4.0.0",
|
|
49
|
-
"typescript-eslint": "^8.
|
|
49
|
+
"typescript-eslint": "^8.66.0",
|
|
50
50
|
"vitest": "^4.0.16"
|
|
51
51
|
},
|
|
52
52
|
"repository": {
|