@contentful/experience-design-system-cli 2.18.1-dev-build-0f85b83.0 → 2.18.1-dev-build-83cbc0a.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 +3 -3
- package/dist/src/analyze/command.js +3 -3
- package/dist/src/analyze/composition/parse-map-edges.d.ts +1 -1
- package/dist/src/analyze/select/tui/App.js +1 -4
- package/dist/src/analyze/select-agent/command.js +6 -5
- package/dist/src/apply/api-client.d.ts +2 -5
- package/dist/src/apply/api-client.js +4 -7
- package/dist/src/apply/command.js +10 -27
- package/dist/src/apply/preview-utils.d.ts +1 -5
- package/dist/src/apply/preview-utils.js +1 -5
- 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 -3
- package/dist/src/generate/command.d.ts +0 -6
- package/dist/src/generate/command.js +7 -17
- 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 +9 -9
- 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 +3 -12
- 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/agent-model-options.js +1 -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/dist/src/session/cache-keys.d.ts +1 -1
- package/dist/src/session/cache-keys.js +1 -1
- package/dist/src/session/db.d.ts +1 -1
- package/dist/src/session/db.js +1 -1
- package/package.json +6 -6
- package/dist/src/generate/agent-runner.d.ts +0 -125
- package/dist/src/generate/agent-runner.js +0 -427
- package/dist/src/generate/progress.d.ts +0 -9
- package/dist/src/generate/progress.js +0 -11
- package/dist/src/generate/prompt-builder.d.ts +0 -26
- package/dist/src/generate/prompt-builder.js +0 -213
- package/dist/src/lib/agent-names.d.ts +0 -4
- package/dist/src/lib/agent-names.js +0 -5
- package/skills/generate-components.md +0 -427
- package/skills/generate-tokens.md +0 -194
- package/skills/select-components.md +0 -224
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-83cbc0a.0",
|
|
4
4
|
"description": "Contentful Experiences design system import CLI",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -25,7 +25,6 @@
|
|
|
25
25
|
"files": [
|
|
26
26
|
"bin/",
|
|
27
27
|
"dist/",
|
|
28
|
-
"skills/",
|
|
29
28
|
"prompts/"
|
|
30
29
|
],
|
|
31
30
|
"scripts": {
|
|
@@ -40,6 +39,7 @@
|
|
|
40
39
|
"dependencies": {
|
|
41
40
|
"@contentful/experience-design-system-client": "workspace:*",
|
|
42
41
|
"@contentful/experience-design-system-extraction": "workspace:*",
|
|
42
|
+
"@contentful/experience-design-system-generation": "workspace:*",
|
|
43
43
|
"@contentful/experience-design-system-types": "workspace:*",
|
|
44
44
|
"commander": "^13.1.0",
|
|
45
45
|
"ink": "^4.4.1",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"react-dom": "^18.3.1"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
|
-
"@tsconfig/node24": "^24.0.
|
|
51
|
+
"@tsconfig/node24": "^24.0.4",
|
|
52
52
|
"@types/node": "^24.0.3",
|
|
53
53
|
"@types/react": "^18.3.24",
|
|
54
54
|
"eslint": "^9.39.2",
|
|
@@ -19,11 +19,11 @@ import { buildCompositionInputHash } from './composition/composition-cache-key.j
|
|
|
19
19
|
import { runParserInSandbox } from './composition/agent-parser/sandbox.js';
|
|
20
20
|
import { resolveViaAgentParser } from './composition/agent-parser/resolve-via-parser.js';
|
|
21
21
|
import { parsePromptOverrides, resolvePromptOverride } from '../lib/prompt-overrides.js';
|
|
22
|
-
import { DEFAULT_AGENT_NAME, isAgentName } from '
|
|
23
|
-
import { runAgent } from '../generate/agent-runner.js';
|
|
22
|
+
import { DEFAULT_AGENT_NAME, isAgentName, runAgent, } from '@contentful/experience-design-system-generation';
|
|
24
23
|
import { readExperiencesCredentials } from '../credentials-store.js';
|
|
25
24
|
import { buildAnalyzeViewRows, partitionGlobalWarnings } from './build-analyze-view-rows.js';
|
|
26
25
|
import { getInteractiveTerminalSupport } from '../lib/terminal-capabilities.js';
|
|
26
|
+
import { getDebugLogger } from '../lib/debug-logger.js';
|
|
27
27
|
const SCANNED_FILE_EXTENSIONS = new Set(['.astro', '.js', '.jsx', '.svelte', '.ts', '.tsx', '.vue']);
|
|
28
28
|
const IGNORED_DIRECTORY_NAMES = new Set([
|
|
29
29
|
'.git',
|
|
@@ -351,9 +351,9 @@ export function registerAnalyzeCommand(program) {
|
|
|
351
351
|
const res = await runAgent({
|
|
352
352
|
agent: resolverAgent,
|
|
353
353
|
prompt,
|
|
354
|
-
interactive: false,
|
|
355
354
|
timeoutMs: 120_000,
|
|
356
355
|
promptViaStdin: true,
|
|
356
|
+
onDebugEvent: (name, payload) => getDebugLogger().event('agent', name, payload),
|
|
357
357
|
});
|
|
358
358
|
lastAgentExitCode = res.exitCode;
|
|
359
359
|
if (res.exitCode !== 0 && res.stderr.trim()) {
|
|
@@ -2,7 +2,7 @@ import type { CompositionEdge } from './interchange-schema.js';
|
|
|
2
2
|
/**
|
|
3
3
|
* Lenient JSONL parser for the composition-mapping agent's tool-call output
|
|
4
4
|
* (spec T4). Mirrors `parseSelectToolCallLines` / `parseToolCallLines` in
|
|
5
|
-
* `
|
|
5
|
+
* `@contentful/experience-design-system-generation`'s `agent-runner.ts`: one JSON object per line, each with a `tool`
|
|
6
6
|
* field from a fixed allowlist. A line that fails JSON.parse or validation is
|
|
7
7
|
* DROPPED into `warnings[]` (with a reason) and parsing CONTINUES — no retry,
|
|
8
8
|
* no throw. Non-`{` prose and blank lines are skipped silently.
|
|
@@ -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 ?? '';
|
|
@@ -3,19 +3,21 @@ import { openPipelineDb, loadRawComponents, loadScannedFiles, createStep, update
|
|
|
3
3
|
import { hashPromptForSkill } from '../../session/cache-keys.js';
|
|
4
4
|
import { appendReviewEvent, getRefineArtifactsRoot, ensureRefineSession, getRefineSessionPaths, saveReviewState, } from '../select/persistence.js';
|
|
5
5
|
import { loadReviewInput } from '../select/parser.js';
|
|
6
|
-
import { buildPrompt } from '
|
|
7
|
-
import { formatCustomPromptBanner } from '../../generate/command.js';
|
|
8
|
-
import { AGENT_NAMES, isAgentName, parseSelectToolCallLines, runAgent } from '../../generate/agent-runner.js';
|
|
6
|
+
import { AGENT_NAMES, buildPrompt, createLocalCliAgentInvoker, formatCustomPromptBanner, isAgentName, parseSelectToolCallLines, } from '@contentful/experience-design-system-generation';
|
|
9
7
|
import { access } from 'node:fs/promises';
|
|
10
8
|
import { readExperiencesCredentials } from '../../credentials-store.js';
|
|
11
9
|
import { OutputFormatter, c } from '../../output/format.js';
|
|
12
10
|
import { buildRepoContextIndex, buildSelectionContext } from './context-builder.js';
|
|
13
11
|
import { runShowRationale } from './show-rationale.js';
|
|
14
12
|
import { isAbsolute, resolve } from 'node:path';
|
|
13
|
+
import { getDebugLogger } from '../../lib/debug-logger.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;
|
|
18
17
|
export const DEFAULT_BATCH_SIZE = 5;
|
|
18
|
+
const invoker = createLocalCliAgentInvoker({
|
|
19
|
+
onDebugEvent: (name, payload) => getDebugLogger().event('agent', name, payload),
|
|
20
|
+
});
|
|
19
21
|
function resolveBatchSize() {
|
|
20
22
|
const raw = process.env.EDS_SELECT_BATCH_SIZE;
|
|
21
23
|
if (!raw)
|
|
@@ -109,11 +111,10 @@ async function selectBatch(agent, model, batch, total, verbose, skillPathOverrid
|
|
|
109
111
|
const formatter = new OutputFormatter(verbose, (s) => {
|
|
110
112
|
outputBuf += s;
|
|
111
113
|
});
|
|
112
|
-
const result = await
|
|
114
|
+
const result = await invoker.invoke({
|
|
113
115
|
agent,
|
|
114
116
|
model,
|
|
115
117
|
prompt,
|
|
116
|
-
interactive: false,
|
|
117
118
|
timeoutMs: DEFAULT_TIMEOUT_MS,
|
|
118
119
|
onOutput: (chunk) => formatter.push(chunk),
|
|
119
120
|
});
|
|
@@ -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,20 +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
|
-
body:
|
|
283
|
+
body: manifest,
|
|
285
284
|
parseAs: 'json',
|
|
286
285
|
}));
|
|
287
286
|
if (!result.response.ok) {
|
|
@@ -297,14 +296,12 @@ export class ImportApiClient {
|
|
|
297
296
|
debug.event('apply', 'preview.ok', { status: result.response.status, durationMs: Date.now() - startedAt });
|
|
298
297
|
return sanitizePreviewResponse(parsed);
|
|
299
298
|
}
|
|
300
|
-
async applyImport(manifest,
|
|
301
|
-
const { acknowledgeBreakingChanges, allowDeletions = false } = options;
|
|
299
|
+
async applyImport(manifest, acknowledgeBreakingChanges) {
|
|
302
300
|
const debug = getDebugLogger();
|
|
303
301
|
const startedAt = Date.now();
|
|
304
302
|
debug.event('apply', 'apply.request', {
|
|
305
303
|
url: `${this.base()}/design_systems/imports/apply`,
|
|
306
304
|
acknowledgeBreakingChanges,
|
|
307
|
-
allowDeletions,
|
|
308
305
|
});
|
|
309
306
|
let result;
|
|
310
307
|
try {
|
|
@@ -312,7 +309,7 @@ export class ImportApiClient {
|
|
|
312
309
|
baseUrl: this.host,
|
|
313
310
|
headers: this.headers(),
|
|
314
311
|
path: { spaceId: this.spaceId, environmentId: this.environmentId },
|
|
315
|
-
body: { ...manifest, acknowledgeBreakingChanges
|
|
312
|
+
body: { ...manifest, acknowledgeBreakingChanges },
|
|
316
313
|
parseAs: 'json',
|
|
317
314
|
});
|
|
318
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) {
|
|
@@ -7,10 +7,6 @@ import type { ServerPreviewResponse } from '@contentful/experience-design-system
|
|
|
7
7
|
* would be a pure no-op (INTEG-4411 refined guard).
|
|
8
8
|
*
|
|
9
9
|
* A push that produces ANY entry in ANY bucket — including a rejection that
|
|
10
|
-
* removes a server-side component — is NOT empty.
|
|
11
|
-
* removals entirely (empty removed[]) unless the preview was fetched with
|
|
12
|
-
* allowDeletions: true, so "empty" here also correctly describes a preview
|
|
13
|
-
* with pending-but-hidden deletions: pushing without --allow-deletions is a
|
|
14
|
-
* genuine no-op in that case too, since the apply gate hides them the same way.
|
|
10
|
+
* removes a server-side component — is NOT empty.
|
|
15
11
|
*/
|
|
16
12
|
export declare function isEmptyPreview(preview: ServerPreviewResponse): boolean;
|
|
@@ -6,11 +6,7 @@
|
|
|
6
6
|
* would be a pure no-op (INTEG-4411 refined guard).
|
|
7
7
|
*
|
|
8
8
|
* A push that produces ANY entry in ANY bucket — including a rejection that
|
|
9
|
-
* removes a server-side component — is NOT empty.
|
|
10
|
-
* removals entirely (empty removed[]) unless the preview was fetched with
|
|
11
|
-
* allowDeletions: true, so "empty" here also correctly describes a preview
|
|
12
|
-
* with pending-but-hidden deletions: pushing without --allow-deletions is a
|
|
13
|
-
* genuine no-op in that case too, since the apply gate hides them the same way.
|
|
9
|
+
* removes a server-side component — is NOT empty.
|
|
14
10
|
*/
|
|
15
11
|
export function isEmptyPreview(preview) {
|
|
16
12
|
const { components, tokens, taxonomies } = preview;
|
|
@@ -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,11 +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: " " })] })),
|
|
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." })] }));
|
|
23
23
|
}
|
|
@@ -1,8 +1,2 @@
|
|
|
1
1
|
import type { Command } from 'commander';
|
|
2
|
-
/**
|
|
3
|
-
* Feature 8: render the warning banner shown when a custom skill prompt is
|
|
4
|
-
* active. Always cites the bundled invariants that the override bypasses so
|
|
5
|
-
* the operator cannot miss it.
|
|
6
|
-
*/
|
|
7
|
-
export declare function formatCustomPromptBanner(skill: 'components' | 'select', path: string): string;
|
|
8
2
|
export declare function registerGenerateCommand(program: Command): void;
|
|
@@ -4,10 +4,9 @@ import { access, readFile, readdir, stat } from 'node:fs/promises';
|
|
|
4
4
|
import { join, resolve } from 'node:path';
|
|
5
5
|
import { execFile } from 'node:child_process';
|
|
6
6
|
import { promisify } from 'node:util';
|
|
7
|
-
import { AGENT_NAMES, describeAgentFailure, isAgentName, parseToolCallLines, parseTokenToolCallLines, resolveBinary,
|
|
7
|
+
import { AGENT_NAMES, createLocalCliAgentInvoker, describeAgentFailure, formatCustomPromptBanner, formatGenerateProgressLine, isAgentName, parseToolCallLines, parseTokenToolCallLines, resolveBinary, resolveSkillPath, buildPrompt, } from '@contentful/experience-design-system-generation';
|
|
8
8
|
import { OutputFormatter, c } from '../output/format.js';
|
|
9
|
-
import {
|
|
10
|
-
import { buildPrompt, resolveSkillPath } from './prompt-builder.js';
|
|
9
|
+
import { getDebugLogger } from '../lib/debug-logger.js';
|
|
11
10
|
import { GenerateView } from './tui/GenerateView.js';
|
|
12
11
|
import { registerGenerateEditCommand } from './edit/command.js';
|
|
13
12
|
import { openPipelineDb, loadRawComponents, applyToolCalls, applyTokenToolCalls, computeComponentInputHash, computeTokenInputHash, lookupCache, lookupCacheByEntity, storeCache, copyComponentFromCache, copyTokensFromCache, renameEmptySlots, } from '../session/db.js';
|
|
@@ -19,16 +18,9 @@ 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;
|
|
21
20
|
const RETRY_BACKOFF_MS = Number(process.env.EDS_RETRY_BACKOFF_MS ?? 5_000);
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
* the operator cannot miss it.
|
|
26
|
-
*/
|
|
27
|
-
export function formatCustomPromptBanner(skill, path) {
|
|
28
|
-
return (`WARNING: Custom prompt active for ${skill}: ${path}\n` +
|
|
29
|
-
` Bundled invariants (utility-wrapper rejection, description content rules) do NOT apply.\n` +
|
|
30
|
-
` You are responsible for the prompt's correctness.\n`);
|
|
31
|
-
}
|
|
21
|
+
const invoker = createLocalCliAgentInvoker({
|
|
22
|
+
onDebugEvent: (name, payload) => getDebugLogger().event('agent', name, payload),
|
|
23
|
+
});
|
|
32
24
|
function die(message) {
|
|
33
25
|
process.stderr.write(`${message}\n`);
|
|
34
26
|
process.exit(1);
|
|
@@ -191,11 +183,10 @@ async function runOneComponent(agent, model, db, sessionId, component, tokensInl
|
|
|
191
183
|
const formatter = new OutputFormatter(verbose, (s) => {
|
|
192
184
|
outputBuf += s;
|
|
193
185
|
});
|
|
194
|
-
const result = await
|
|
186
|
+
const result = await invoker.invoke({
|
|
195
187
|
agent,
|
|
196
188
|
model,
|
|
197
189
|
prompt,
|
|
198
|
-
interactive: false,
|
|
199
190
|
timeoutMs: DEFAULT_TIMEOUT_MS,
|
|
200
191
|
onOutput: (chunk) => formatter.push(chunk),
|
|
201
192
|
});
|
|
@@ -512,11 +503,10 @@ async function runGenerateSkill(skill, opts, verbose = false) {
|
|
|
512
503
|
tokenMapInline,
|
|
513
504
|
outDir: process.cwd(),
|
|
514
505
|
});
|
|
515
|
-
const result = await
|
|
506
|
+
const result = await invoker.invoke({
|
|
516
507
|
agent,
|
|
517
508
|
model,
|
|
518
509
|
prompt,
|
|
519
|
-
interactive: false,
|
|
520
510
|
timeoutMs: DEFAULT_TIMEOUT_MS * 5,
|
|
521
511
|
});
|
|
522
512
|
if (result.timedOut) {
|
|
@@ -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;
|