@contentful/experience-design-system-cli 2.26.7-dev-build-6f3b072.0 → 2.26.7-dev-build-f5a509c.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contentful/experience-design-system-cli",
3
- "version": "2.26.7-dev-build-6f3b072.0",
3
+ "version": "2.26.7-dev-build-f5a509c.0",
4
4
  "description": "Contentful Experiences design system import CLI",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -37,6 +37,8 @@ type FieldEditorProps = {
37
37
  kind: 'prop' | 'slot';
38
38
  name: string;
39
39
  };
40
+ /** Hide non-importable property categories from the form without removing them from its saved state. */
41
+ showHiddenProps?: boolean;
40
42
  };
41
43
  export declare function simulateGraphWithCandidate(projectSlotGraph: ComponentSlotInfo[], selfName: string, currentSlots: {
42
44
  name: string;
@@ -55,5 +57,5 @@ export declare function computeAllowedComponentReplacementCandidates(projectSlot
55
57
  name: string;
56
58
  allowedComponents: string[];
57
59
  }[], targetSlotName: string, replaceIndex: number): string[];
58
- export declare function FieldEditor({ value, width, height, active, onChange, onSave, onDiscard, onExit, metadata, onTogglePropRationale, propRationaleKey, onToggleComponentRationale, componentRationaleKey, onToggleSourceExternal, onTextEntryActiveChange, projectSlotGraph, currentComponentName, onDirtyChange, discardTrigger, initialFocusTarget, }: FieldEditorProps): React.ReactElement;
60
+ export declare function FieldEditor({ value, width, height, active, onChange, onSave, onDiscard, onExit, metadata, onTogglePropRationale, propRationaleKey, onToggleComponentRationale, componentRationaleKey, onToggleSourceExternal, onTextEntryActiveChange, projectSlotGraph, currentComponentName, onDirtyChange, discardTrigger, initialFocusTarget, showHiddenProps, }: FieldEditorProps): React.ReactElement;
59
61
  export {};
@@ -0,0 +1,13 @@
1
+ import type { CDFComponentEntry } from '@contentful/experience-design-system-types';
2
+ type ReviewJsonComponent = {
3
+ key: string;
4
+ entry: CDFComponentEntry;
5
+ };
6
+ /**
7
+ * Builds the exact JSON string rendered by the read-only review panel.
8
+ *
9
+ * The FieldEditor intentionally continues to use the unfiltered component
10
+ * definition so toggling the panel never changes what an operator can save.
11
+ */
12
+ export declare function getReviewJsonPanelValue(selected: ReviewJsonComponent | null, showHiddenProps: boolean): string;
13
+ export {};
package/dist/src/index.js CHANGED
@@ -23,87 +23,23 @@ var init_agent_names = __esm({
23
23
 
24
24
  // packages/experience-design-system-generation/dist/src/agent-runner.js
25
25
  import { spawn } from "node:child_process";
26
- function scanJsonObjects(line) {
27
- const objects = [];
28
- let i = 0;
29
- while (i < line.length) {
30
- while (i < line.length && /\s/.test(line[i]))
31
- i++;
32
- if (i >= line.length)
33
- break;
34
- if (line[i] !== "{")
35
- return { objects, trailing: line.slice(i), malformed: objects.length === 0 };
36
- let depth = 0;
37
- let inString = false;
38
- let escaped = false;
39
- let end = -1;
40
- for (let j = i; j < line.length; j++) {
41
- const ch = line[j];
42
- if (escaped) {
43
- escaped = false;
44
- continue;
45
- }
46
- if (ch === "\\") {
47
- if (inString)
48
- escaped = true;
49
- continue;
50
- }
51
- if (ch === '"') {
52
- inString = !inString;
53
- continue;
54
- }
55
- if (inString)
56
- continue;
57
- if (ch === "{")
58
- depth++;
59
- else if (ch === "}") {
60
- depth--;
61
- if (depth === 0) {
62
- end = j;
63
- break;
64
- }
65
- }
66
- }
67
- if (end === -1)
68
- return { objects, trailing: "", malformed: true };
69
- let parsed;
70
- try {
71
- parsed = JSON.parse(line.slice(i, end + 1));
72
- } catch {
73
- return { objects, trailing: "", malformed: true };
74
- }
75
- if (typeof parsed === "object" && parsed !== null)
76
- objects.push(parsed);
77
- i = end + 1;
78
- }
79
- return { objects, trailing: "", malformed: false };
80
- }
81
- function readToolCallObjects(stdout) {
82
- const objects = [];
26
+ function parseSelectToolCallLines(stdout) {
27
+ const calls = [];
83
28
  const warnings = [];
84
29
  for (const raw of stdout.split("\n")) {
85
30
  const line = raw.trim();
86
31
  if (!line.startsWith("{"))
87
32
  continue;
88
- const { objects: found, trailing, malformed } = scanJsonObjects(line);
89
- if (malformed) {
33
+ let obj;
34
+ try {
35
+ obj = JSON.parse(line);
36
+ } catch {
90
37
  warnings.push(`unparseable line: ${line.slice(0, 120)}`);
91
38
  continue;
92
39
  }
93
- if (trailing.trim()) {
94
- warnings.push(`ignored trailing content after JSON: ${trailing.trim().slice(0, 120)}`);
95
- }
96
- for (const obj of found) {
97
- if ("tool" in obj)
98
- objects.push(obj);
99
- }
100
- }
101
- return { objects, warnings };
102
- }
103
- function parseSelectToolCallLines(stdout) {
104
- const calls = [];
105
- const { objects, warnings } = readToolCallObjects(stdout);
106
- for (const rec of objects) {
40
+ if (typeof obj !== "object" || obj === null || !("tool" in obj))
41
+ continue;
42
+ const rec = obj;
107
43
  if (!VALID_SELECT_TOOL_NAMES.has(rec.tool))
108
44
  continue;
109
45
  if (typeof rec.name !== "string" || !rec.name) {
@@ -129,8 +65,21 @@ function parseSelectToolCallLines(stdout) {
129
65
  }
130
66
  function parseToolCallLines(stdout) {
131
67
  const calls = [];
132
- const { objects, warnings } = readToolCallObjects(stdout);
133
- for (const rec of objects) {
68
+ const warnings = [];
69
+ for (const raw of stdout.split("\n")) {
70
+ const line = raw.trim();
71
+ if (!line.startsWith("{"))
72
+ continue;
73
+ let obj;
74
+ try {
75
+ obj = JSON.parse(line);
76
+ } catch {
77
+ warnings.push(`unparseable line: ${line.slice(0, 120)}`);
78
+ continue;
79
+ }
80
+ if (typeof obj !== "object" || obj === null || !("tool" in obj))
81
+ continue;
82
+ const rec = obj;
134
83
  if (!VALID_TOOL_NAMES.has(rec.tool)) {
135
84
  warnings.push(`unknown tool: ${String(rec.tool)}`);
136
85
  continue;
@@ -218,8 +167,21 @@ function parseToolCallLines(stdout) {
218
167
  }
219
168
  function parseTokenToolCallLines(stdout) {
220
169
  const calls = [];
221
- const { objects, warnings } = readToolCallObjects(stdout);
222
- for (const rec of objects) {
170
+ const warnings = [];
171
+ for (const raw of stdout.split("\n")) {
172
+ const line = raw.trim();
173
+ if (!line.startsWith("{"))
174
+ continue;
175
+ let obj;
176
+ try {
177
+ obj = JSON.parse(line);
178
+ } catch {
179
+ warnings.push(`unparseable line: ${line.slice(0, 120)}`);
180
+ continue;
181
+ }
182
+ if (typeof obj !== "object" || obj === null || !("tool" in obj))
183
+ continue;
184
+ const rec = obj;
223
185
  if (!VALID_TOKEN_TOOL_NAMES.has(rec.tool))
224
186
  continue;
225
187
  if (rec.tool === "set_token") {
@@ -8592,6 +8554,66 @@ function applyDbMigrations(db) {
8592
8554
  if (!rawPropColNames.has("source_end_line")) {
8593
8555
  db.exec("ALTER TABLE raw_props ADD COLUMN source_end_line INTEGER");
8594
8556
  }
8557
+ const rawPropsDdl = db.prepare(`SELECT sql FROM sqlite_master WHERE type = 'table' AND name = 'raw_props'`).get();
8558
+ if (rawPropsDdl && !rawPropsDdl.sql.includes(`'unattached'`)) {
8559
+ db.exec("PRAGMA foreign_keys = OFF");
8560
+ try {
8561
+ db.exec("BEGIN");
8562
+ try {
8563
+ db.exec(`
8564
+ CREATE TABLE raw_props__new (
8565
+ session_id TEXT NOT NULL,
8566
+ component_id TEXT NOT NULL,
8567
+ name TEXT NOT NULL,
8568
+ type TEXT NOT NULL,
8569
+ required INTEGER NOT NULL CHECK (required IN (0, 1)),
8570
+ category TEXT CHECK (category IN ('content', 'design', 'state')),
8571
+ default_value TEXT,
8572
+ description TEXT,
8573
+ token_reference TEXT,
8574
+ position INTEGER NOT NULL,
8575
+ cdf_type TEXT,
8576
+ cdf_category TEXT CHECK (cdf_category IN ('content', 'design', 'state', 'unattached')),
8577
+ cdf_token_kind TEXT,
8578
+ rationale TEXT,
8579
+ source_start_line INTEGER,
8580
+ source_end_line INTEGER,
8581
+ PRIMARY KEY (session_id, component_id, name),
8582
+ FOREIGN KEY (session_id, component_id) REFERENCES raw_components(session_id, component_id) ON DELETE CASCADE
8583
+ );
8584
+
8585
+ INSERT INTO raw_props__new
8586
+ (session_id, component_id, name, type, required, category, default_value,
8587
+ description, token_reference, position, cdf_type, cdf_category, cdf_token_kind,
8588
+ rationale, source_start_line, source_end_line)
8589
+ SELECT
8590
+ session_id, component_id, name, type, required, category, default_value,
8591
+ description, token_reference, position, cdf_type, cdf_category, cdf_token_kind,
8592
+ rationale, source_start_line, source_end_line
8593
+ FROM raw_props;
8594
+
8595
+ DROP TABLE raw_props;
8596
+ ALTER TABLE raw_props__new RENAME TO raw_props;
8597
+ CREATE INDEX IF NOT EXISTS idx_raw_props_session ON raw_props(session_id, component_id);
8598
+
8599
+ -- Rows written by a pre-migration exclude_prop still say cdf_type = 'excluded'
8600
+ -- with cdf_category = NULL. Backfill them into the new unattached shape so an
8601
+ -- in-flight local session doesn't end up with an unprintable half-migrated row.
8602
+ UPDATE raw_props
8603
+ SET cdf_category = 'unattached',
8604
+ cdf_type = CASE WHEN type = 'boolean' THEN 'boolean' ELSE 'string' END,
8605
+ required = 0
8606
+ WHERE cdf_type = 'excluded';
8607
+ `);
8608
+ db.exec("COMMIT");
8609
+ } catch (e) {
8610
+ db.exec("ROLLBACK");
8611
+ throw e;
8612
+ }
8613
+ } finally {
8614
+ db.exec("PRAGMA foreign_keys = ON");
8615
+ }
8616
+ }
8595
8617
  if (!rawCompColNames.has("reject_reason")) {
8596
8618
  db.exec("ALTER TABLE raw_components ADD COLUMN reject_reason TEXT");
8597
8619
  }
@@ -8777,7 +8799,12 @@ function applyToolCalls(db, sessionId2, componentId, componentName, calls, incom
8777
8799
  WHERE session_id = ? AND component_id = ? AND name = ?`
8778
8800
  );
8779
8801
  const clearProp = db.prepare(
8780
- `UPDATE raw_props SET cdf_type = 'excluded', cdf_category = NULL, cdf_token_kind = NULL, rationale = ?
8802
+ `UPDATE raw_props
8803
+ SET cdf_type = CASE WHEN type = 'boolean' THEN 'boolean' ELSE 'string' END,
8804
+ cdf_category = 'unattached',
8805
+ cdf_token_kind = NULL,
8806
+ required = 0,
8807
+ rationale = ?
8781
8808
  WHERE session_id = ? AND component_id = ? AND name = ?`
8782
8809
  );
8783
8810
  const deleteAllowedValues = db.prepare(
@@ -9376,7 +9403,7 @@ function loadCDFComponents(db, sessionId2) {
9376
9403
  `SELECT component_id, name, required, default_value, description,
9377
9404
  cdf_type, cdf_category, cdf_token_kind, position
9378
9405
  FROM raw_props
9379
- WHERE session_id = ? AND cdf_type IS NOT NULL AND cdf_type != 'excluded'
9406
+ WHERE session_id = ? AND cdf_type IS NOT NULL
9380
9407
  ORDER BY component_id, position`
9381
9408
  ).all(sessionId2);
9382
9409
  const allowedValues = db.prepare(
@@ -21346,6 +21373,27 @@ var init_merge_ai_decisions = __esm({
21346
21373
  }
21347
21374
  });
21348
21375
 
21376
+ // packages/experience-design-system-cli/src/import/tui/steps/review-json-panel.ts
21377
+ function getReviewJsonPanelValue(selected, showHiddenProps) {
21378
+ if (!selected) return "";
21379
+ const entry = showHiddenProps ? selected.entry : {
21380
+ ...selected.entry,
21381
+ $properties: Object.fromEntries(
21382
+ Object.entries(selected.entry.$properties ?? {}).filter(
21383
+ ([, definition]) => !HIDDEN_PROP_CATEGORIES.has(definition.$category)
21384
+ )
21385
+ )
21386
+ };
21387
+ return JSON.stringify({ [selected.key]: entry }, null, 2);
21388
+ }
21389
+ var HIDDEN_PROP_CATEGORIES;
21390
+ var init_review_json_panel = __esm({
21391
+ "packages/experience-design-system-cli/src/import/tui/steps/review-json-panel.ts"() {
21392
+ "use strict";
21393
+ HIDDEN_PROP_CATEGORIES = /* @__PURE__ */ new Set(["state", "unattached"]);
21394
+ }
21395
+ });
21396
+
21349
21397
  // packages/experience-design-system-cli/src/analyze/cycle-view.ts
21350
21398
  function computeCycleView(components) {
21351
21399
  const filtered = components.filter((c2) => c2.status !== "rejected");
@@ -21952,7 +22000,8 @@ function FieldEditor({
21952
22000
  currentComponentName,
21953
22001
  onDirtyChange,
21954
22002
  discardTrigger,
21955
- initialFocusTarget
22003
+ initialFocusTarget,
22004
+ showHiddenProps = true
21956
22005
  }) {
21957
22006
  const { state: initialState, error: parseError } = parseToState(value);
21958
22007
  const [editorState, setEditorState] = useState23(initialState);
@@ -22033,12 +22082,34 @@ function FieldEditor({
22033
22082
  const [showHelp, setShowHelp] = useState23(false);
22034
22083
  const props = editorState.props;
22035
22084
  const slots = editorState.slots;
22085
+ const visiblePropIndexes = React23.useMemo(
22086
+ () => props.flatMap(
22087
+ (prop, index) => showHiddenProps || prop.category !== "state" && prop.category !== "unattached" ? [index] : []
22088
+ ),
22089
+ [props, showHiddenProps]
22090
+ );
22091
+ const visiblePropPosition = visiblePropIndexes.indexOf(propIdx);
22036
22092
  const textEntryActive = focusLevel === "field" && activeField === "description" || focusLevel === "field" && activeField === "default" && (editorState.props[propIdx]?.type === "string" || editorState.props[propIdx]?.type === "token") || editingValue != null;
22037
22093
  React23.useEffect(() => {
22038
22094
  onTextEntryActiveChange?.(textEntryActive);
22039
22095
  }, [textEntryActive, onTextEntryActiveChange]);
22040
22096
  const currentProp = props[propIdx] ?? null;
22041
22097
  const currentSlot = slots[slotIdx] ?? null;
22098
+ React23.useEffect(() => {
22099
+ if (showHiddenProps || inSlots || inComponentDesc || visiblePropPosition >= 0) return;
22100
+ if (visiblePropIndexes.length > 0) {
22101
+ setPropIdx(visiblePropIndexes[0]);
22102
+ return;
22103
+ }
22104
+ if (slots.length > 0) {
22105
+ setInSlots(true);
22106
+ setSlotIdx(0);
22107
+ setFocusLevel("slot");
22108
+ return;
22109
+ }
22110
+ setInComponentDesc(true);
22111
+ setFocusLevel("componentDescription");
22112
+ }, [inComponentDesc, inSlots, showHiddenProps, slots.length, visiblePropIndexes, visiblePropPosition]);
22042
22113
  const commit = (next) => {
22043
22114
  setEditorState(next);
22044
22115
  onChange(serializeState(next, value));
@@ -22240,8 +22311,8 @@ function FieldEditor({
22240
22311
  }
22241
22312
  if (focusLevel === "prop") {
22242
22313
  if (key.upArrow || input === "k") {
22243
- if (propIdx > 0) {
22244
- setPropIdx(propIdx - 1);
22314
+ if (visiblePropPosition > 0) {
22315
+ setPropIdx(visiblePropIndexes[visiblePropPosition - 1]);
22245
22316
  } else {
22246
22317
  setFocusLevel("componentDescription");
22247
22318
  setInSlots(false);
@@ -22250,8 +22321,8 @@ function FieldEditor({
22250
22321
  return;
22251
22322
  }
22252
22323
  if (key.downArrow || input === "j") {
22253
- if (propIdx < props.length - 1) {
22254
- setPropIdx(propIdx + 1);
22324
+ if (visiblePropPosition >= 0 && visiblePropPosition < visiblePropIndexes.length - 1) {
22325
+ setPropIdx(visiblePropIndexes[visiblePropPosition + 1]);
22255
22326
  } else if (slots.length > 0) {
22256
22327
  setInSlots(true);
22257
22328
  setSlotIdx(0);
@@ -22272,9 +22343,9 @@ function FieldEditor({
22272
22343
  return;
22273
22344
  }
22274
22345
  if (key.downArrow || input === "j") {
22275
- if (props.length > 0) {
22346
+ if (visiblePropIndexes.length > 0) {
22276
22347
  setFocusLevel("prop");
22277
- setPropIdx(0);
22348
+ setPropIdx(visiblePropIndexes[0]);
22278
22349
  setInSlots(false);
22279
22350
  setInComponentDesc(false);
22280
22351
  } else if (slots.length > 0) {
@@ -22297,9 +22368,9 @@ function FieldEditor({
22297
22368
  if (key.upArrow || input === "k") {
22298
22369
  if (slotIdx > 0) {
22299
22370
  setSlotIdx(slotIdx - 1);
22300
- } else if (props.length > 0) {
22371
+ } else if (visiblePropIndexes.length > 0) {
22301
22372
  setInSlots(false);
22302
- setPropIdx(props.length - 1);
22373
+ setPropIdx(visiblePropIndexes[visiblePropIndexes.length - 1]);
22303
22374
  setFocusLevel("prop");
22304
22375
  }
22305
22376
  return;
@@ -22644,9 +22715,9 @@ function FieldEditor({
22644
22715
  })();
22645
22716
  const rows = [];
22646
22717
  rows.push({ kind: "component-description" });
22647
- if (props.length > 0) {
22648
- rows.push({ kind: "header", label: `\u2500\u2500 PROPERTIES (${props.length}) `, section: "properties" });
22649
- props.forEach((_, i) => rows.push({ kind: "prop", idx: i }));
22718
+ if (visiblePropIndexes.length > 0) {
22719
+ rows.push({ kind: "header", label: `\u2500\u2500 PROPERTIES (${visiblePropIndexes.length}) `, section: "properties" });
22720
+ visiblePropIndexes.forEach((idx) => rows.push({ kind: "prop", idx }));
22650
22721
  }
22651
22722
  if (slots.length > 0) {
22652
22723
  rows.push({ kind: "header", label: `\u2500\u2500 SLOTS (${slots.length}) `, section: "slots" });
@@ -23638,6 +23709,7 @@ function GenerateReviewStep({
23638
23709
  const [showFinalize, setShowFinalize] = useState26(false);
23639
23710
  const [showQuit, setShowQuit] = useState26(false);
23640
23711
  const [showJson, setShowJson] = useState26(false);
23712
+ const [showHiddenProps, setShowHiddenProps] = useState26(false);
23641
23713
  const [draftValue, setDraftValue] = useState26("");
23642
23714
  const [saveError, setSaveError] = useState26(null);
23643
23715
  const [finalizeError, setFinalizeError] = useState26(initialFinalizeError);
@@ -24587,7 +24659,7 @@ function GenerateReviewStep({
24587
24659
  }
24588
24660
  if (!sidebarFocused && showJson) {
24589
24661
  const current = components[selectedIdx];
24590
- const currentJson = current ? JSON.stringify({ [current.key]: current.entry }, null, 2) : "";
24662
+ const currentJson = getReviewJsonPanelValue(current ?? null, showHiddenProps);
24591
24663
  const totalLines = currentJson.split("\n").length;
24592
24664
  const maxOffset = Math.max(0, totalLines - PANEL_HEIGHT);
24593
24665
  if (input === "g" && !key.ctrl) {
@@ -24724,6 +24796,12 @@ function GenerateReviewStep({
24724
24796
  pendingGRef.current = false;
24725
24797
  return;
24726
24798
  }
24799
+ if (input === "H") {
24800
+ setShowHiddenProps((prev) => !prev);
24801
+ setJsonScrollOffset(0);
24802
+ pendingGRef.current = false;
24803
+ return;
24804
+ }
24727
24805
  if (key.return) {
24728
24806
  const current = components[selectedIdx];
24729
24807
  if (!current) return;
@@ -24824,6 +24902,7 @@ function GenerateReviewStep({
24824
24902
  }
24825
24903
  const selected = components[selectedIdx] ?? null;
24826
24904
  const selectedJson = selected ? JSON.stringify({ [selected.key]: selected.entry }, null, 2) : "";
24905
+ const visibleJsonPanelValue = getReviewJsonPanelValue(selected, showHiddenProps);
24827
24906
  const isEmpty2 = (c2) => Object.keys(c2.entry.$properties).length === 0 && Object.keys(c2.entry.$slots ?? {}).length === 0;
24828
24907
  const emptyCount = components.filter(isEmpty2).length;
24829
24908
  const cycleParticipantSet = cycleView.structural;
@@ -25145,7 +25224,7 @@ function GenerateReviewStep({
25145
25224
  JsonPanel,
25146
25225
  {
25147
25226
  label: "GENERATED DEFINITION (read-only)",
25148
- value: selectedJson,
25227
+ value: visibleJsonPanelValue,
25149
25228
  scrollOffset: jsonScrollOffset,
25150
25229
  width: panelWidth,
25151
25230
  height: PANEL_HEIGHT,
@@ -25155,6 +25234,7 @@ function GenerateReviewStep({
25155
25234
  FieldEditor,
25156
25235
  {
25157
25236
  value: draftValue || selectedJson,
25237
+ showHiddenProps,
25158
25238
  width: panelWidth,
25159
25239
  height: PANEL_HEIGHT,
25160
25240
  active: !sidebarFocused,
@@ -25238,6 +25318,7 @@ function GenerateReviewStep({
25238
25318
  legendEntry("[P]", "component rationale", panelOpen === "component-rationale"),
25239
25319
  legendEntry("[s]", "source", panelOpen === "source"),
25240
25320
  legendEntry("[J]", showJson ? "hide JSON" : "show JSON", showJson),
25321
+ legendEntry("[H]", showHiddenProps ? "hide state/unattached" : "show state/unattached", showHiddenProps),
25241
25322
  breakingChanges.length > 0 && legendEntry("[b]", "see breaking changes", breakingPanel.isOpen),
25242
25323
  removedComponents.length > 0 && legendEntry("[d]", removedBannerCollapsed ? "show removed" : "hide removed", !removedBannerCollapsed),
25243
25324
  legendEntry("[/]", "search", searchOpen || searchQuery.length > 0),
@@ -25268,6 +25349,7 @@ var init_GenerateReviewStep = __esm({
25268
25349
  "packages/experience-design-system-cli/src/import/tui/steps/GenerateReviewStep.tsx"() {
25269
25350
  "use strict";
25270
25351
  init_theme();
25352
+ init_review_json_panel();
25271
25353
  init_GroupedSidebar();
25272
25354
  init_composite_closure();
25273
25355
  init_slot_graph();
@@ -25418,6 +25500,7 @@ function AtomicGenerateReviewStep({
25418
25500
  const [showFinalize, setShowFinalize] = useState27(false);
25419
25501
  const [showQuit, setShowQuit] = useState27(false);
25420
25502
  const [showJson, setShowJson] = useState27(false);
25503
+ const [showHiddenProps, setShowHiddenProps] = useState27(false);
25421
25504
  const [draftValue, setDraftValue] = useState27("");
25422
25505
  const [saveError, setSaveError] = useState27(null);
25423
25506
  const [finalizeError, setFinalizeError] = useState27(initialFinalizeError);
@@ -25781,7 +25864,7 @@ function AtomicGenerateReviewStep({
25781
25864
  }
25782
25865
  if (!sidebarFocused && showJson) {
25783
25866
  const current = components[selectedIdx];
25784
- const currentJson = current ? JSON.stringify({ [current.key]: current.entry }, null, 2) : "";
25867
+ const currentJson = getReviewJsonPanelValue(current ?? null, showHiddenProps);
25785
25868
  const totalLines = currentJson.split("\n").length;
25786
25869
  const maxOffset = Math.max(0, totalLines - PANEL_HEIGHT2);
25787
25870
  if (input === "g" && !key.ctrl) {
@@ -25837,6 +25920,12 @@ function AtomicGenerateReviewStep({
25837
25920
  pendingGRef.current = false;
25838
25921
  return;
25839
25922
  }
25923
+ if (input === "H") {
25924
+ setShowHiddenProps((prev) => !prev);
25925
+ setJsonScrollOffset(0);
25926
+ pendingGRef.current = false;
25927
+ return;
25928
+ }
25840
25929
  if (key.upArrow || input === "k") {
25841
25930
  setSelectedIdx((prev) => {
25842
25931
  const newIdx = Math.max(0, prev - 1);
@@ -25869,6 +25958,7 @@ function AtomicGenerateReviewStep({
25869
25958
  }
25870
25959
  const selected = components[selectedIdx] ?? null;
25871
25960
  const selectedJson = selected ? JSON.stringify({ [selected.key]: selected.entry }, null, 2) : "";
25961
+ const visibleJsonPanelValue = getReviewJsonPanelValue(selected, showHiddenProps);
25872
25962
  const isEmpty2 = (c2) => Object.keys(c2.entry.$properties).length === 0;
25873
25963
  const emptyCount = components.filter(isEmpty2).length;
25874
25964
  const sidebarItems = components.map((c2) => ({
@@ -26044,7 +26134,7 @@ function AtomicGenerateReviewStep({
26044
26134
  JsonPanel,
26045
26135
  {
26046
26136
  label: "GENERATED DEFINITION (read-only)",
26047
- value: selectedJson,
26137
+ value: visibleJsonPanelValue,
26048
26138
  scrollOffset: jsonScrollOffset,
26049
26139
  width: panelWidth,
26050
26140
  height: PANEL_HEIGHT2,
@@ -26054,6 +26144,7 @@ function AtomicGenerateReviewStep({
26054
26144
  FieldEditor,
26055
26145
  {
26056
26146
  value: draftValue || selectedJson,
26147
+ showHiddenProps,
26057
26148
  width: panelWidth,
26058
26149
  height: PANEL_HEIGHT2,
26059
26150
  active: !sidebarFocused,
@@ -26084,7 +26175,7 @@ function AtomicGenerateReviewStep({
26084
26175
  ),
26085
26176
  saveError && /* @__PURE__ */ jsx48(Text47, { color: PALETTE.error, children: "\u2717 " + saveError }),
26086
26177
  /* @__PURE__ */ jsxs47(Text47, { dimColor: true, children: [
26087
- sidebarFocused ? " [a] accept [r] reject [A] accept all [i] prop rationale [I] component rationale [s] source [J] " + (showJson ? "hide JSON" : "show JSON") + " [^z] undo [^y] redo [^r] reload [F] finalize [e/Tab] focus panel" + (livePreview && removedComponents.length > 0 ? " [d] removed list" : "") + " [q] quit" : showJson ? " [j/k] scroll [Ctrl+u/d] half-page [gg/G] top/bottom [Tab] focus list" : " [Tab] focus list (edit fields)",
26178
+ sidebarFocused ? " [a] accept [r] reject [A] accept all [i] prop rationale [I] component rationale [s] source [J] " + (showJson ? "hide JSON" : "show JSON") + " [H] " + (showHiddenProps ? "hide state/unattached" : "show state/unattached") + " [^z] undo [^y] redo [^r] reload [F] finalize [e/Tab] focus panel" + (livePreview && removedComponents.length > 0 ? " [d] removed list" : "") + " [q] quit" : showJson ? " [j/k] scroll [Ctrl+u/d] half-page [gg/G] top/bottom [Tab] focus list" : " [Tab] focus list (edit fields)",
26088
26179
  livePreviewHook.status === "running" && /* @__PURE__ */ jsx48(Text47, { children: ` ${livePreviewSpinner} live preview` }),
26089
26180
  livePreviewHook.disabled && /* @__PURE__ */ jsx48(Text47, { children: " \xB7 live preview disabled" })
26090
26181
  ] })
@@ -26131,6 +26222,7 @@ var init_AtomicGenerateReviewStep = __esm({
26131
26222
  init_useFinalizePreview();
26132
26223
  init_scroll_offset();
26133
26224
  init_theme();
26225
+ init_review_json_panel();
26134
26226
  VISIBLE_COUNT3 = 20;
26135
26227
  PANEL_HEIGHT2 = 22;
26136
26228
  }
@@ -31385,7 +31477,7 @@ async function runGenerateSkill(skill, opts, verbose = false) {
31385
31477
  const allOk = failed.length === 0;
31386
31478
  const cachedNote = cachedResults.length > 0 ? c.dim(` (${cachedResults.length} cached)`) : "";
31387
31479
  process.stderr.write(
31388
- (allOk ? c.green("\u2713") : c.yellow("\u26A0")) + ` ${generated.length + cachedResults.length}/${componentResults.length} components` + cachedNote + c.dim(` ${totalClassified} classified, ${totalExcluded} excluded`) + "\n"
31480
+ (allOk ? c.green("\u2713") : c.yellow("\u26A0")) + ` ${generated.length + cachedResults.length}/${componentResults.length} components` + cachedNote + c.dim(` ${totalClassified} classified, ${totalExcluded} unattached`) + "\n"
31389
31481
  );
31390
31482
  process.stdout.write(`renamed-slots: ${totalRenamedSlots}
31391
31483
  `);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contentful/experience-design-system-cli",
3
- "version": "2.26.7-dev-build-6f3b072.0",
3
+ "version": "2.26.7-dev-build-f5a509c.0",
4
4
  "description": "Contentful Experiences design system import CLI",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -39,7 +39,7 @@
39
39
  "svelte": "^5.56.4",
40
40
  "ts-morph": "^27.0.2",
41
41
  "typescript": "^5.9.3",
42
- "@contentful/experience-design-system-types": "2.26.7-dev-build-6f3b072.0"
42
+ "@contentful/experience-design-system-types": "2.26.7-dev-build-f5a509c.0"
43
43
  },
44
44
  "devDependencies": {
45
45
  "@tsconfig/node24": "^24.0.4",
@@ -51,9 +51,9 @@
51
51
  "ink-testing-library": "^4.0.0",
52
52
  "typescript-eslint": "^8.67.0",
53
53
  "vitest": "^4.0.16",
54
- "@contentful/experience-design-system-client": "2.26.7-dev-build-6f3b072.0",
55
- "@contentful/experience-design-system-extraction": "2.26.7-dev-build-6f3b072.0",
56
- "@contentful/experience-design-system-generation": "2.26.7-dev-build-6f3b072.0"
54
+ "@contentful/experience-design-system-extraction": "2.26.7-dev-build-f5a509c.0",
55
+ "@contentful/experience-design-system-generation": "2.26.7-dev-build-f5a509c.0",
56
+ "@contentful/experience-design-system-client": "2.26.7-dev-build-f5a509c.0"
57
57
  },
58
58
  "repository": {
59
59
  "type": "git",