@contentful/experience-design-system-cli 2.7.5-dev-build-752dc9c.0 → 2.10.1-dev-build-90df010.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/dist/package.json +1 -1
- package/dist/src/analyze/build-analyze-view-rows.d.ts +23 -0
- package/dist/src/analyze/build-analyze-view-rows.js +39 -0
- package/dist/src/analyze/command.js +13 -10
- package/dist/src/analyze/extract/validate.d.ts +13 -1
- package/dist/src/analyze/extract/validate.js +32 -5
- package/dist/src/analyze/select/command.d.ts +37 -0
- package/dist/src/analyze/select/command.js +200 -9
- package/dist/src/analyze/select/tui/App.js +1 -9
- package/dist/src/analyze/select/tui/components/Sidebar.d.ts +1 -1
- package/dist/src/analyze/select/tui/components/Sidebar.js +26 -3
- package/dist/src/analyze/select-agent/command.js +22 -10
- package/dist/src/analyze/tui/AnalyzeView.d.ts +8 -0
- package/dist/src/analyze/tui/AnalyzeView.js +5 -2
- package/dist/src/apply/api-client.d.ts +20 -0
- package/dist/src/apply/api-client.js +71 -5
- package/dist/src/generate/command.js +21 -2
- package/dist/src/import/orchestrator.d.ts +21 -0
- package/dist/src/import/orchestrator.js +95 -14
- package/dist/src/import/tui/WizardApp.d.ts +13 -0
- package/dist/src/import/tui/WizardApp.js +224 -52
- package/dist/src/import/tui/steps/GateStep.d.ts +2 -1
- package/dist/src/import/tui/steps/GateStep.js +4 -2
- package/dist/src/import/tui/steps/PreviewValidationErrorStep.d.ts +11 -0
- package/dist/src/import/tui/steps/PreviewValidationErrorStep.js +14 -0
- package/dist/src/import/tui/wizard-422-helpers.d.ts +48 -0
- package/dist/src/import/tui/wizard-422-helpers.js +60 -0
- package/dist/src/program.d.ts +17 -0
- package/dist/src/program.js +27 -4
- package/dist/src/session/db.d.ts +13 -0
- package/dist/src/session/db.js +50 -0
- package/dist/src/types.d.ts +1 -1
- package/package.json +2 -2
- package/skills/generate-components.md +2 -0
package/dist/src/program.d.ts
CHANGED
|
@@ -1,2 +1,19 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
|
+
type SpawnedChild = {
|
|
3
|
+
on(event: 'error', listener: (err: unknown) => void): unknown;
|
|
4
|
+
on(event: 'exit', listener: (code: number | null) => void): unknown;
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* Run the spawn lifecycle for the build command. Extracted so the
|
|
8
|
+
* error-surfacing path is testable: previously `child.on('error', ...)`
|
|
9
|
+
* silently returned exit code 1 with no context, leaving the user
|
|
10
|
+
* staring at a generic non-zero exit when `pnpm` wasn't on PATH.
|
|
11
|
+
*/
|
|
12
|
+
export declare function runBuild(opts: {
|
|
13
|
+
spawnFn: () => SpawnedChild;
|
|
14
|
+
stderrWrite: (chunk: string) => void;
|
|
15
|
+
}): Promise<{
|
|
16
|
+
exitCode: number;
|
|
17
|
+
}>;
|
|
2
18
|
export declare function createProgram(): Command;
|
|
19
|
+
export {};
|
package/dist/src/program.js
CHANGED
|
@@ -12,6 +12,30 @@ import { registerImportCommand } from './import/command.js';
|
|
|
12
12
|
import { registerSetupCommand } from './setup/command.js';
|
|
13
13
|
const require = createRequire(import.meta.url);
|
|
14
14
|
const pkg = require('../package.json');
|
|
15
|
+
/**
|
|
16
|
+
* Run the spawn lifecycle for the build command. Extracted so the
|
|
17
|
+
* error-surfacing path is testable: previously `child.on('error', ...)`
|
|
18
|
+
* silently returned exit code 1 with no context, leaving the user
|
|
19
|
+
* staring at a generic non-zero exit when `pnpm` wasn't on PATH.
|
|
20
|
+
*/
|
|
21
|
+
export async function runBuild(opts) {
|
|
22
|
+
return new Promise((resolvePromise) => {
|
|
23
|
+
const child = opts.spawnFn();
|
|
24
|
+
let settled = false;
|
|
25
|
+
const settle = (exitCode) => {
|
|
26
|
+
if (settled)
|
|
27
|
+
return;
|
|
28
|
+
settled = true;
|
|
29
|
+
resolvePromise({ exitCode });
|
|
30
|
+
};
|
|
31
|
+
child.on('error', (err) => {
|
|
32
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
33
|
+
opts.stderrWrite(`Error: failed to spawn build subprocess: ${message}\n`);
|
|
34
|
+
settle(1);
|
|
35
|
+
});
|
|
36
|
+
child.on('exit', (code) => settle(code ?? 1));
|
|
37
|
+
});
|
|
38
|
+
}
|
|
15
39
|
function registerBuildCommand(program) {
|
|
16
40
|
program
|
|
17
41
|
.command('build')
|
|
@@ -19,10 +43,9 @@ function registerBuildCommand(program) {
|
|
|
19
43
|
.action(async () => {
|
|
20
44
|
const pkgRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..', '..');
|
|
21
45
|
process.stderr.write('⚙ Building from source...\n');
|
|
22
|
-
const exitCode = await
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
child.on('exit', (code) => resolvePromise(code ?? 1));
|
|
46
|
+
const { exitCode } = await runBuild({
|
|
47
|
+
spawnFn: () => spawn('pnpm', ['build'], { cwd: pkgRoot, stdio: 'inherit' }),
|
|
48
|
+
stderrWrite: (s) => process.stderr.write(s),
|
|
26
49
|
});
|
|
27
50
|
process.exit(exitCode);
|
|
28
51
|
});
|
package/dist/src/session/db.d.ts
CHANGED
|
@@ -53,6 +53,19 @@ export type RawComponentWithId = RawComponentDefinition & {
|
|
|
53
53
|
component_id: string;
|
|
54
54
|
};
|
|
55
55
|
export declare function loadRawComponents(db: DatabaseSync, sessionId: string, allowedNames?: Set<string>): RawComponentWithId[];
|
|
56
|
+
/**
|
|
57
|
+
* Rename empty-named slots in the DB to heuristic names before generation.
|
|
58
|
+
* The LLM classify_slot tool call is matched back to the DB row by name, so a
|
|
59
|
+
* row with name="" can never be updated by the LLM — renaming it here makes it
|
|
60
|
+
* classifiable. Returns one warning string per renamed slot.
|
|
61
|
+
*/
|
|
62
|
+
export declare function renameEmptySlots(db: DatabaseSync, sessionId: string, componentId: string, componentName: string, slotCount: number): {
|
|
63
|
+
renames: Array<{
|
|
64
|
+
oldName: string;
|
|
65
|
+
newName: string;
|
|
66
|
+
}>;
|
|
67
|
+
warnings: string[];
|
|
68
|
+
};
|
|
56
69
|
export declare function storeCDFComponents(db: DatabaseSync, sessionId: string, components: Array<{
|
|
57
70
|
key: string;
|
|
58
71
|
entry: CDFComponentEntry;
|
package/dist/src/session/db.js
CHANGED
|
@@ -563,6 +563,45 @@ export function loadRawComponents(db, sessionId, allowedNames) {
|
|
|
563
563
|
}),
|
|
564
564
|
}));
|
|
565
565
|
}
|
|
566
|
+
/**
|
|
567
|
+
* Rename empty-named slots in the DB to heuristic names before generation.
|
|
568
|
+
* The LLM classify_slot tool call is matched back to the DB row by name, so a
|
|
569
|
+
* row with name="" can never be updated by the LLM — renaming it here makes it
|
|
570
|
+
* classifiable. Returns one warning string per renamed slot.
|
|
571
|
+
*/
|
|
572
|
+
export function renameEmptySlots(db, sessionId, componentId, componentName, slotCount) {
|
|
573
|
+
const emptySlots = db
|
|
574
|
+
.prepare(`SELECT name, position FROM raw_slots
|
|
575
|
+
WHERE session_id = ? AND component_id = ? AND trim(name) = ''
|
|
576
|
+
ORDER BY position`)
|
|
577
|
+
.all(sessionId, componentId);
|
|
578
|
+
if (emptySlots.length === 0)
|
|
579
|
+
return { renames: [], warnings: [] };
|
|
580
|
+
const renames = [];
|
|
581
|
+
const warnings = [];
|
|
582
|
+
const rename = db.prepare(`UPDATE raw_slots SET name = ? WHERE session_id = ? AND component_id = ? AND name = ? AND position = ?`);
|
|
583
|
+
// Multi-statement write — wrap in a transaction so a SIGINT or driver error
|
|
584
|
+
// mid-loop leaves raw_slots either fully renamed or fully untouched, never
|
|
585
|
+
// half-renamed (which would corrupt the prompt-vs-DB invariant the LLM
|
|
586
|
+
// relies on for classify_slot). Matches the existing BEGIN/COMMIT pattern
|
|
587
|
+
// throughout this file (see storeRawComponents, createStep, etc.).
|
|
588
|
+
db.exec('BEGIN');
|
|
589
|
+
try {
|
|
590
|
+
for (const slot of emptySlots) {
|
|
591
|
+
// Single unnamed slot → "children". Multiple → positional names.
|
|
592
|
+
const newName = slotCount === 1 ? 'children' : `slot_${slot.position}`;
|
|
593
|
+
rename.run(newName, sessionId, componentId, slot.name, slot.position);
|
|
594
|
+
renames.push({ oldName: slot.name, newName });
|
|
595
|
+
warnings.push(`${componentName}: slot at position ${slot.position} had empty name — renamed to "${newName}" for classification`);
|
|
596
|
+
}
|
|
597
|
+
db.exec('COMMIT');
|
|
598
|
+
}
|
|
599
|
+
catch (e) {
|
|
600
|
+
db.exec('ROLLBACK');
|
|
601
|
+
throw e;
|
|
602
|
+
}
|
|
603
|
+
return { renames, warnings };
|
|
604
|
+
}
|
|
566
605
|
function groupBy(items, key) {
|
|
567
606
|
const map = new Map();
|
|
568
607
|
for (const item of items) {
|
|
@@ -676,6 +715,12 @@ export function loadCDFComponents(db, sessionId) {
|
|
|
676
715
|
return null;
|
|
677
716
|
const $properties = {};
|
|
678
717
|
for (const p of compProps) {
|
|
718
|
+
// Hallucination insurance: drop any prop whose name didn't survive trim.
|
|
719
|
+
// The pre-generate rename guard catches empty-named slots, but if the LLM
|
|
720
|
+
// hallucinated a classify_prop with an empty name into the DB, surface
|
|
721
|
+
// nothing to the manifest builder rather than emitting "$properties: { '': ... }".
|
|
722
|
+
if (!p.name.trim())
|
|
723
|
+
continue;
|
|
679
724
|
const av = allowedValuesByProp.get(`${component_id}::${p.name}`);
|
|
680
725
|
const propDef = {
|
|
681
726
|
$type: p.cdf_type,
|
|
@@ -702,6 +747,11 @@ export function loadCDFComponents(db, sessionId) {
|
|
|
702
747
|
const compSlots = slotsByComponent.get(component_id) ?? [];
|
|
703
748
|
const $slots = {};
|
|
704
749
|
for (const s of compSlots) {
|
|
750
|
+
// Hallucination insurance: same as $properties — drop empty-named slots
|
|
751
|
+
// before they reach buildManifest, which faithfully passes empty keys
|
|
752
|
+
// through and triggers a 422 from the preview API.
|
|
753
|
+
if (!s.name.trim())
|
|
754
|
+
continue;
|
|
705
755
|
const ac = allowedComponentsBySlot.get(`${component_id}::${s.name}`);
|
|
706
756
|
const slotDef = {};
|
|
707
757
|
if (s.description !== null)
|
package/dist/src/types.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { DesignTokenType } from '@contentful/experience-design-system-types';
|
|
2
|
-
export type ExtractionValidationIssueCode = 'EMPTY_COMPONENT_NAME' | 'EMPTY_PROP_NAME' | 'EMPTY_SLOT_NAME' | 'PROP_SLOT_NAME_COLLISION' | 'DUPLICATE_COMPONENT_NAME' | 'EMPTY_COMPONENT';
|
|
2
|
+
export type ExtractionValidationIssueCode = 'EMPTY_COMPONENT_NAME' | 'EMPTY_PROP_NAME' | 'EMPTY_SLOT_NAME' | 'PROP_SLOT_NAME_COLLISION' | 'DUPLICATE_COMPONENT_NAME' | 'EMPTY_COMPONENT' | 'SERVER_VALIDATION_FAILED';
|
|
3
3
|
export type ExtractionValidationIssue = {
|
|
4
4
|
severity: 'error' | 'warning';
|
|
5
5
|
code: ExtractionValidationIssueCode;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contentful/experience-design-system-cli",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.10.1-dev-build-90df010.0",
|
|
4
4
|
"description": "Contentful Experiences design system import CLI",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"react-dom": "^18.3.1",
|
|
37
37
|
"ts-morph": "^27.0.2",
|
|
38
38
|
"typescript": "^5.9.3",
|
|
39
|
-
"@contentful/experience-design-system-types": "2.
|
|
39
|
+
"@contentful/experience-design-system-types": "2.10.1-dev-build-90df010.0"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@tsconfig/node24": "^24.0.3",
|
|
@@ -251,6 +251,8 @@ For each `RawSlotDefinition`:
|
|
|
251
251
|
- `false` if clearly optional (icon slot, footer slot with a default, decorative slot)
|
|
252
252
|
- Default to `true` when the source gives no signal
|
|
253
253
|
|
|
254
|
+
**Pre-named slots:** If the input contains a slot whose `name` was already inferred by the pipeline (e.g. `"children"`, `"slot_0"`), treat it as you would any named slot — classify it normally. The pipeline renames empty-named slots to heuristic names before passing them to you; your job is to confirm or enrich the classification (set `required`, `description`, `allowed_components`), not to rename again.
|
|
255
|
+
|
|
254
256
|
---
|
|
255
257
|
|
|
256
258
|
## Examples
|