@contentful/experience-design-system-cli 2.24.1-dev-build-58e271c.0 → 2.24.1-dev-build-abcd76f.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 +0 -23
- package/dist/package.json +3 -4
- package/dist/src/analyze/command.js +2 -8
- package/dist/src/analyze/select/command.js +9 -13
- package/dist/src/analyze/select-agent/command.js +11 -14
- package/dist/src/apply/api-client.d.ts +0 -3
- package/dist/src/apply/api-client.js +1 -14
- package/dist/src/apply/command.d.ts +1 -1
- package/dist/src/apply/command.js +50 -71
- package/dist/src/generate/command.js +9 -15
- package/dist/src/generate/edit/command.js +0 -1
- package/dist/src/import/orchestrator.js +12 -18
- package/dist/src/index.js +1 -6
- package/dist/src/print/command.js +13 -16
- package/dist/src/program.js +1 -8
- package/package.json +7 -8
- 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
|
@@ -16,10 +16,9 @@ import { addAllowDeletionsOption, addArtifactInputOptions, addCompositionOptions
|
|
|
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';
|
|
19
|
-
|
|
20
|
-
async function die(message, fields = {}) {
|
|
19
|
+
function die(message) {
|
|
21
20
|
process.stderr.write(`${message}\n`);
|
|
22
|
-
|
|
21
|
+
process.exit(1);
|
|
23
22
|
}
|
|
24
23
|
async function pathExists(p) {
|
|
25
24
|
return access(p)
|
|
@@ -28,7 +27,7 @@ async function pathExists(p) {
|
|
|
28
27
|
}
|
|
29
28
|
async function assertFileExists(flag, p) {
|
|
30
29
|
if (!(await pathExists(p)))
|
|
31
|
-
|
|
30
|
+
die(`Error: file not found: ${p} (from ${flag})`);
|
|
32
31
|
}
|
|
33
32
|
async function readJsonFile(flag, p) {
|
|
34
33
|
let text;
|
|
@@ -36,13 +35,13 @@ async function readJsonFile(flag, p) {
|
|
|
36
35
|
text = await readFile(p, 'utf8');
|
|
37
36
|
}
|
|
38
37
|
catch {
|
|
39
|
-
|
|
38
|
+
die(`Error: file not found: ${p} (from ${flag})`);
|
|
40
39
|
}
|
|
41
40
|
try {
|
|
42
41
|
return JSON.parse(text);
|
|
43
42
|
}
|
|
44
43
|
catch {
|
|
45
|
-
|
|
44
|
+
die(`Error: ${flag} is not valid JSON: ${p}`);
|
|
46
45
|
}
|
|
47
46
|
}
|
|
48
47
|
const IGNORE_TOKEN_DIRS = new Set(['node_modules', 'dist', 'build', '.next', '.nuxt', '.git']);
|
|
@@ -84,12 +83,12 @@ export async function readTokensFromPath(flag, p) {
|
|
|
84
83
|
s = await stat(p);
|
|
85
84
|
}
|
|
86
85
|
catch {
|
|
87
|
-
|
|
86
|
+
die(`Error: file not found: ${p} (from ${flag})`);
|
|
88
87
|
}
|
|
89
88
|
if (s.isDirectory()) {
|
|
90
89
|
const files = await collectJsonFiles(p);
|
|
91
90
|
if (files.length === 0)
|
|
92
|
-
|
|
91
|
+
die(`Error: no .json files found in directory: ${p} (from ${flag})`);
|
|
93
92
|
const merged = {};
|
|
94
93
|
for (const file of files.sort()) {
|
|
95
94
|
let text;
|
|
@@ -112,36 +111,36 @@ export async function readTokensFromPath(flag, p) {
|
|
|
112
111
|
}
|
|
113
112
|
const { valid, errors } = validateDTCG(merged);
|
|
114
113
|
if (!valid)
|
|
115
|
-
|
|
114
|
+
die(`Error: ${flag} contains invalid token types:\n${errors.map((e) => ` ${e.path}: ${e.message}`).join('\n')}`);
|
|
116
115
|
return flattenDTCG(merged, '');
|
|
117
116
|
}
|
|
118
117
|
const raw = await readJsonFile(flag, p);
|
|
119
118
|
if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) {
|
|
120
|
-
|
|
119
|
+
die(`Error: ${flag} is not valid JSON: expected an object`);
|
|
121
120
|
}
|
|
122
121
|
const { valid, errors } = validateDTCG(raw);
|
|
123
122
|
if (!valid)
|
|
124
|
-
|
|
123
|
+
die(`Error: ${flag} contains invalid token types:\n${errors.map((e) => ` ${e.path}: ${e.message}`).join('\n')}`);
|
|
125
124
|
return flattenDTCG(raw, '');
|
|
126
125
|
}
|
|
127
126
|
async function resolveSharedInputs(opts) {
|
|
128
127
|
if (!opts.components && !opts.tokens && !opts.session) {
|
|
129
|
-
|
|
128
|
+
die('Error: at least one of --components, --tokens, or --session is required');
|
|
130
129
|
}
|
|
131
130
|
if (opts.session && opts.components) {
|
|
132
|
-
|
|
131
|
+
die('Error: --session and --components are mutually exclusive');
|
|
133
132
|
}
|
|
134
133
|
const spaceId = opts.spaceId ?? process.env.CONTENTFUL_SPACE_ID;
|
|
135
134
|
const environmentId = opts.environmentId ?? process.env.CONTENTFUL_ENVIRONMENT_ID;
|
|
136
135
|
if (!spaceId)
|
|
137
|
-
|
|
136
|
+
die('Error: --space-id is required (or set CONTENTFUL_SPACE_ID)');
|
|
138
137
|
if (!environmentId)
|
|
139
|
-
|
|
138
|
+
die('Error: --environment-id is required (or set CONTENTFUL_ENVIRONMENT_ID)');
|
|
140
139
|
opts.spaceId = spaceId;
|
|
141
140
|
opts.environmentId = environmentId;
|
|
142
141
|
const cmaToken = opts.cmaToken ?? process.env.CONTENTFUL_MANAGEMENT_TOKEN;
|
|
143
142
|
if (!cmaToken) {
|
|
144
|
-
|
|
143
|
+
die('Error: CMA token is required. Pass --cma-token or set CONTENTFUL_MANAGEMENT_TOKEN');
|
|
145
144
|
}
|
|
146
145
|
if (opts.components)
|
|
147
146
|
await assertFileExists('--components', opts.components);
|
|
@@ -155,14 +154,14 @@ async function resolveSharedInputs(opts) {
|
|
|
155
154
|
db.close();
|
|
156
155
|
}
|
|
157
156
|
if (components.length === 0) {
|
|
158
|
-
|
|
157
|
+
die(`Error: session '${opts.session}' has no generated components. Run generate components first.`);
|
|
159
158
|
}
|
|
160
159
|
}
|
|
161
160
|
else if (opts.components) {
|
|
162
161
|
const raw = await readJsonFile('--components', opts.components);
|
|
163
162
|
const result = validateCDF(raw);
|
|
164
163
|
if (!result.valid) {
|
|
165
|
-
|
|
164
|
+
die(`Error: --components failed schema validation: ${result.errors.map((e) => e.message).join(', ')}`);
|
|
166
165
|
}
|
|
167
166
|
components = result.components;
|
|
168
167
|
}
|
|
@@ -214,12 +213,12 @@ export function formatSlotCycleReport(cycles) {
|
|
|
214
213
|
}
|
|
215
214
|
return lines;
|
|
216
215
|
}
|
|
217
|
-
export
|
|
216
|
+
export function assertNoSlotCycles(components) {
|
|
218
217
|
const cycles = detectSlotCycles(components);
|
|
219
218
|
if (cycles.length === 0)
|
|
220
219
|
return;
|
|
221
220
|
process.stderr.write(formatSlotCycleReport(cycles).join('\n') + '\n');
|
|
222
|
-
|
|
221
|
+
process.exit(1);
|
|
223
222
|
}
|
|
224
223
|
export function extractComponentsFromManifest(manifest) {
|
|
225
224
|
const componentsManifest = manifest?.componentsManifest;
|
|
@@ -428,24 +427,18 @@ export function registerApplyCommand(program) {
|
|
|
428
427
|
}
|
|
429
428
|
catch (e) {
|
|
430
429
|
if (e instanceof ApiError)
|
|
431
|
-
|
|
430
|
+
die(`Error: ${formatApiError(e)}`);
|
|
432
431
|
throw e;
|
|
433
432
|
}
|
|
434
433
|
const { components, tokens, client } = inputs;
|
|
435
|
-
const spaceId = opts.spaceId;
|
|
436
|
-
const environmentId = opts.environmentId;
|
|
437
|
-
await bindAnalyticsSessionId(opts.session, {
|
|
438
|
-
space_key: spaceId,
|
|
439
|
-
environment_key: environmentId,
|
|
440
|
-
});
|
|
441
434
|
try {
|
|
442
435
|
await client.validateToken();
|
|
443
436
|
}
|
|
444
437
|
catch (e) {
|
|
445
438
|
if (e instanceof ApiError)
|
|
446
|
-
|
|
439
|
+
die(`Error: ${formatApiError(e)}`);
|
|
447
440
|
const cause = e instanceof Error && e.cause instanceof Error ? e.cause.message : '';
|
|
448
|
-
|
|
441
|
+
die(`Error: unable to connect to API host${cause ? `: ${cause}` : ''}`);
|
|
449
442
|
}
|
|
450
443
|
const manifest = buildManifest(components, tokens);
|
|
451
444
|
let preview;
|
|
@@ -454,10 +447,11 @@ export function registerApplyCommand(program) {
|
|
|
454
447
|
}
|
|
455
448
|
catch (e) {
|
|
456
449
|
if (e instanceof ApiError)
|
|
457
|
-
|
|
450
|
+
die(`Error: ${formatApiError(e)}`);
|
|
458
451
|
throw e;
|
|
459
452
|
}
|
|
460
|
-
|
|
453
|
+
const spaceId = opts.spaceId;
|
|
454
|
+
const environmentId = opts.environmentId;
|
|
461
455
|
if (getInteractiveTerminalSupport().supported) {
|
|
462
456
|
const { waitUntilExit } = render(createElement(ServerPreviewApp, {
|
|
463
457
|
preview,
|
|
@@ -469,7 +463,7 @@ export function registerApplyCommand(program) {
|
|
|
469
463
|
}
|
|
470
464
|
else {
|
|
471
465
|
process.stdout.write(JSON.stringify(buildPreviewOutput(preview, spaceId, environmentId), null, 2) + '\n');
|
|
472
|
-
|
|
466
|
+
process.exit(0);
|
|
473
467
|
}
|
|
474
468
|
});
|
|
475
469
|
const pushCmd = applyCmd.command('push').description('Write component types and design tokens to Contentful ExO');
|
|
@@ -486,7 +480,7 @@ export function registerApplyCommand(program) {
|
|
|
486
480
|
const isTTY = getInteractiveTerminalSupport().supported;
|
|
487
481
|
if (!isTTY && !opts.yes) {
|
|
488
482
|
process.stderr.write('Error: apply push requires --yes in non-interactive mode\n');
|
|
489
|
-
|
|
483
|
+
process.exit(1);
|
|
490
484
|
}
|
|
491
485
|
let inputs;
|
|
492
486
|
try {
|
|
@@ -494,23 +488,17 @@ export function registerApplyCommand(program) {
|
|
|
494
488
|
}
|
|
495
489
|
catch (e) {
|
|
496
490
|
if (e instanceof ApiError)
|
|
497
|
-
|
|
491
|
+
die(`Error: ${formatApiError(e, opts.verbose)}`);
|
|
498
492
|
throw e;
|
|
499
493
|
}
|
|
500
494
|
const { components, tokens, client } = inputs;
|
|
501
|
-
|
|
502
|
-
const environmentId = opts.environmentId;
|
|
503
|
-
await bindAnalyticsSessionId(opts.session, {
|
|
504
|
-
space_key: spaceId,
|
|
505
|
-
environment_key: environmentId,
|
|
506
|
-
});
|
|
507
|
-
await assertNoSlotCycles(components);
|
|
495
|
+
assertNoSlotCycles(components);
|
|
508
496
|
try {
|
|
509
497
|
await client.validateToken();
|
|
510
498
|
}
|
|
511
499
|
catch (e) {
|
|
512
500
|
if (e instanceof ApiError)
|
|
513
|
-
|
|
501
|
+
die(`Error: ${formatApiError(e, opts.verbose)}`);
|
|
514
502
|
throw e;
|
|
515
503
|
}
|
|
516
504
|
const manifest = buildManifest(components, tokens);
|
|
@@ -520,10 +508,11 @@ export function registerApplyCommand(program) {
|
|
|
520
508
|
}
|
|
521
509
|
catch (e) {
|
|
522
510
|
if (e instanceof ApiError)
|
|
523
|
-
|
|
511
|
+
die(`Error: ${formatApiError(e, opts.verbose)}`);
|
|
524
512
|
throw e;
|
|
525
513
|
}
|
|
526
|
-
|
|
514
|
+
const spaceId = opts.spaceId;
|
|
515
|
+
const environmentId = opts.environmentId;
|
|
527
516
|
if (opts.dryRun) {
|
|
528
517
|
if (isTTY) {
|
|
529
518
|
const { waitUntilExit } = render(createElement(ServerPreviewApp, {
|
|
@@ -537,7 +526,7 @@ export function registerApplyCommand(program) {
|
|
|
537
526
|
else {
|
|
538
527
|
process.stdout.write(JSON.stringify(buildPreviewOutput(preview, spaceId, environmentId), null, 2) + '\n');
|
|
539
528
|
}
|
|
540
|
-
|
|
529
|
+
process.exit(0);
|
|
541
530
|
}
|
|
542
531
|
if (isEmptyPreview(preview)) {
|
|
543
532
|
if (isTTY && !opts.yes) {
|
|
@@ -546,14 +535,14 @@ export function registerApplyCommand(program) {
|
|
|
546
535
|
else {
|
|
547
536
|
process.stdout.write(JSON.stringify(buildPreviewOutput(preview, spaceId, environmentId), null, 2) + '\n');
|
|
548
537
|
}
|
|
549
|
-
|
|
538
|
+
process.exit(0);
|
|
550
539
|
}
|
|
551
540
|
const breakingWithImpact = hasBreakingChangesWithImpact(preview);
|
|
552
541
|
if (!isTTY || opts.yes) {
|
|
553
542
|
if (breakingWithImpact && !opts.force) {
|
|
554
543
|
process.stderr.write('Error: breaking changes with downstream impact detected. Use --force to acknowledge.\n');
|
|
555
544
|
process.stdout.write(JSON.stringify(buildPreviewOutput(preview, spaceId, environmentId), null, 2) + '\n');
|
|
556
|
-
|
|
545
|
+
process.exit(1);
|
|
557
546
|
}
|
|
558
547
|
const verbose = opts.verbose ?? false;
|
|
559
548
|
if (verbose) {
|
|
@@ -568,7 +557,7 @@ export function registerApplyCommand(program) {
|
|
|
568
557
|
}
|
|
569
558
|
catch (e) {
|
|
570
559
|
if (e instanceof ApiError)
|
|
571
|
-
|
|
560
|
+
die(`Error: ${formatApiError(e, opts.verbose)}`);
|
|
572
561
|
throw e;
|
|
573
562
|
}
|
|
574
563
|
process.stderr.write(`Apply operation started: ${operation.sys.id}\n`);
|
|
@@ -577,14 +566,12 @@ export function registerApplyCommand(program) {
|
|
|
577
566
|
}
|
|
578
567
|
catch (e) {
|
|
579
568
|
if (e instanceof ApiError)
|
|
580
|
-
|
|
569
|
+
die(`Error: ${formatApiError(e, opts.verbose)}`);
|
|
581
570
|
throw e;
|
|
582
571
|
}
|
|
583
572
|
const summary = buildApplyOutput(operation, spaceId, environmentId, opts.host);
|
|
584
|
-
recordApplyOutcome(client, spaceId, environmentId, operation);
|
|
585
573
|
process.stdout.write(JSON.stringify(summary, null, 2) + '\n');
|
|
586
|
-
|
|
587
|
-
await exitWithAnalytics(exitCode);
|
|
574
|
+
process.exit(operation.sys.status === 'succeeded' ? 0 : 1);
|
|
588
575
|
return;
|
|
589
576
|
}
|
|
590
577
|
await new Promise((resolvePromise) => {
|
|
@@ -634,7 +621,6 @@ export function registerApplyCommand(program) {
|
|
|
634
621
|
}
|
|
635
622
|
throw e;
|
|
636
623
|
}
|
|
637
|
-
recordApplyOutcome(client, spaceId, environmentId, operation);
|
|
638
624
|
instance.rerender(createElement(ServerApplyDone, {
|
|
639
625
|
operation,
|
|
640
626
|
spaceId,
|
|
@@ -653,7 +639,7 @@ export function registerApplyCommand(program) {
|
|
|
653
639
|
void runApply(acknowledge, applyDeletions);
|
|
654
640
|
},
|
|
655
641
|
onCancel: () => {
|
|
656
|
-
|
|
642
|
+
process.exit(0);
|
|
657
643
|
},
|
|
658
644
|
}));
|
|
659
645
|
void instance.waitUntilExit().then(() => resolvePromise());
|
|
@@ -678,17 +664,17 @@ export function registerApplyCommand(program) {
|
|
|
678
664
|
}
|
|
679
665
|
catch (e) {
|
|
680
666
|
if (e instanceof ApiError)
|
|
681
|
-
|
|
667
|
+
die(`Error: ${formatApiError(e)}`);
|
|
682
668
|
throw e;
|
|
683
669
|
}
|
|
684
670
|
const { components, tokens, client } = inputs;
|
|
685
|
-
|
|
671
|
+
assertNoSlotCycles(components);
|
|
686
672
|
try {
|
|
687
673
|
await client.validateToken();
|
|
688
674
|
}
|
|
689
675
|
catch (e) {
|
|
690
676
|
if (e instanceof ApiError)
|
|
691
|
-
|
|
677
|
+
die(`Error: ${formatApiError(e)}`);
|
|
692
678
|
throw e;
|
|
693
679
|
}
|
|
694
680
|
const fullManifest = buildManifest(components, tokens);
|
|
@@ -698,26 +684,21 @@ export function registerApplyCommand(program) {
|
|
|
698
684
|
}
|
|
699
685
|
catch (e) {
|
|
700
686
|
if (e instanceof ApiError)
|
|
701
|
-
|
|
687
|
+
die(`Error: ${formatApiError(e)}`);
|
|
702
688
|
throw e;
|
|
703
689
|
}
|
|
704
690
|
const spaceId = opts.spaceId;
|
|
705
691
|
const environmentId = opts.environmentId;
|
|
706
|
-
await bindAnalyticsSessionId(opts.session, {
|
|
707
|
-
space_key: spaceId,
|
|
708
|
-
environment_key: environmentId,
|
|
709
|
-
});
|
|
710
|
-
recordContentfulContext(client, spaceId, environmentId);
|
|
711
692
|
const entities = getSelectableEntities(preview);
|
|
712
693
|
if (entities.length === 0) {
|
|
713
694
|
process.stderr.write('Nothing to change — design system is up to date.\n');
|
|
714
|
-
|
|
695
|
+
process.exit(0);
|
|
715
696
|
}
|
|
716
697
|
if (nonInteractive) {
|
|
717
698
|
const selectedKeys = resolveNonInteractiveSelection(entities, opts);
|
|
718
699
|
if (selectedKeys.size === 0) {
|
|
719
700
|
process.stderr.write('No entities matched selection criteria.\n');
|
|
720
|
-
|
|
701
|
+
process.exit(0);
|
|
721
702
|
}
|
|
722
703
|
const selectedComponentKeys = new Set();
|
|
723
704
|
const selectedTokenPaths = new Set();
|
|
@@ -733,7 +714,7 @@ export function registerApplyCommand(program) {
|
|
|
733
714
|
const hasBreaking = entities.some((e) => e.isBreaking && selectedKeys.has(makeSelectKey(e.kind, e.id)));
|
|
734
715
|
if (hasBreaking && !opts.force) {
|
|
735
716
|
process.stderr.write('Error: selection includes breaking changes. Use --force to acknowledge.\n');
|
|
736
|
-
|
|
717
|
+
process.exit(1);
|
|
737
718
|
}
|
|
738
719
|
let operation;
|
|
739
720
|
try {
|
|
@@ -744,7 +725,7 @@ export function registerApplyCommand(program) {
|
|
|
744
725
|
}
|
|
745
726
|
catch (e) {
|
|
746
727
|
if (e instanceof ApiError)
|
|
747
|
-
|
|
728
|
+
die(`Error: ${formatApiError(e)}`);
|
|
748
729
|
throw e;
|
|
749
730
|
}
|
|
750
731
|
process.stderr.write(`Apply operation started: ${operation.sys.id}\n`);
|
|
@@ -753,13 +734,12 @@ export function registerApplyCommand(program) {
|
|
|
753
734
|
}
|
|
754
735
|
catch (e) {
|
|
755
736
|
if (e instanceof ApiError)
|
|
756
|
-
|
|
737
|
+
die(`Error: ${formatApiError(e)}`);
|
|
757
738
|
throw e;
|
|
758
739
|
}
|
|
759
740
|
const summary = buildApplyOutput(operation, spaceId, environmentId, opts.host);
|
|
760
|
-
recordApplyOutcome(client, spaceId, environmentId, operation);
|
|
761
741
|
process.stdout.write(JSON.stringify(summary, null, 2) + '\n');
|
|
762
|
-
|
|
742
|
+
process.exit(operation.sys.status === 'succeeded' ? 0 : 1);
|
|
763
743
|
return;
|
|
764
744
|
}
|
|
765
745
|
await new Promise((resolvePromise) => {
|
|
@@ -821,7 +801,6 @@ export function registerApplyCommand(program) {
|
|
|
821
801
|
}
|
|
822
802
|
throw e;
|
|
823
803
|
}
|
|
824
|
-
recordApplyOutcome(client, spaceId, environmentId, operation);
|
|
825
804
|
instance.rerender(createElement(ServerApplyDone, {
|
|
826
805
|
operation,
|
|
827
806
|
spaceId,
|
|
@@ -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`)
|
|
@@ -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)
|
|
@@ -431,7 +425,7 @@ export async function runPipeline(opts, progressWriter, cliPathOverride) {
|
|
|
431
425
|
components: componentsPath,
|
|
432
426
|
});
|
|
433
427
|
const t0 = Date.now();
|
|
434
|
-
let r = await runStep(pushArgs, cliPath,
|
|
428
|
+
let r = await runStep(pushArgs, cliPath, { FORCE_COLOR: '1' }, true);
|
|
435
429
|
const excludedByRetry = [];
|
|
436
430
|
let validationRetryCount = 0;
|
|
437
431
|
while (validationRetryCount < MAX_VALIDATION_RETRIES && isPreviewValidationError(r) && extractSessionId) {
|
|
@@ -448,10 +442,10 @@ export async function runPipeline(opts, progressWriter, cliPathOverride) {
|
|
|
448
442
|
'--exclude-components',
|
|
449
443
|
offenders.join(','),
|
|
450
444
|
];
|
|
451
|
-
const rejectResult = await runStep(rejectArgs, cliPath
|
|
445
|
+
const rejectResult = await runStep(rejectArgs, cliPath);
|
|
452
446
|
if (rejectResult.exitCode !== 0)
|
|
453
447
|
break;
|
|
454
|
-
r = await runStep(pushArgs, cliPath,
|
|
448
|
+
r = await runStep(pushArgs, cliPath, { FORCE_COLOR: '1' }, true);
|
|
455
449
|
validationRetryCount++;
|
|
456
450
|
}
|
|
457
451
|
const durationMs = Date.now() - t0;
|
|
@@ -486,10 +480,10 @@ export async function runPipeline(opts, progressWriter, cliPathOverride) {
|
|
|
486
480
|
'--exclude-components',
|
|
487
481
|
cycleNames.join(','),
|
|
488
482
|
];
|
|
489
|
-
const rejectResult = await runStep(rejectArgs, cliPath
|
|
483
|
+
const rejectResult = await runStep(rejectArgs, cliPath);
|
|
490
484
|
if (rejectResult.exitCode === 0) {
|
|
491
485
|
const retryT0 = Date.now();
|
|
492
|
-
const retryR = await runStep(pushArgs, cliPath,
|
|
486
|
+
const retryR = await runStep(pushArgs, cliPath, { FORCE_COLOR: '1' }, true);
|
|
493
487
|
const retryDurationMs = Date.now() - t0 + (Date.now() - retryT0);
|
|
494
488
|
if (isSlotCycleError(retryR)) {
|
|
495
489
|
const retryReport = extractCycleReport(retryR.stderr);
|
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
|
});
|