@contentful/experience-design-system-cli 2.37.1-dev-build-e2dab518.0 → 2.37.1-dev-build-97b615d3.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/app.js CHANGED
@@ -2018,7 +2018,7 @@ var init_cache_keys = __esm({
2018
2018
 
2019
2019
  // packages/experience-design-system-cli/app.tsx
2020
2020
  import { join as join25 } from "node:path";
2021
- import { useEffect as useEffect27, useState as useState33 } from "react";
2021
+ import { useEffect as useEffect26, useState as useState33 } from "react";
2022
2022
 
2023
2023
  // packages/experience-design-system-cli/src/tui/home/home.tsx
2024
2024
  import { useEffect as useEffect2, useState as useState2 } from "react";
@@ -4365,30 +4365,8 @@ function applyScopeDecisions(db, sessionId, decisions) {
4365
4365
  const placeholders = accepted.map(() => "?").join(",");
4366
4366
  db.prepare(`UPDATE raw_components SET status = 'generated' WHERE session_id = ? AND name IN (${placeholders})`).run(sessionId, ...accepted);
4367
4367
  }
4368
- removeSlotAllowedComponents(db, sessionId, decisions.excludedSlotEdges ?? [], rejected);
4369
4368
  db.prepare("UPDATE sessions SET updated_at = ? WHERE id = ?").run(now, sessionId);
4370
4369
  }
4371
- function removeSlotAllowedComponents(db, sessionId, edges, rejectedNames) {
4372
- if (edges.length === 0 && rejectedNames.length === 0)
4373
- return;
4374
- const componentId = db.prepare("SELECT component_id FROM raw_components WHERE session_id = ? AND name = ?");
4375
- const removeEdge = db.prepare("DELETE FROM raw_slot_allowed_components WHERE session_id = ? AND component_id = ? AND allowed_component = ?");
4376
- const removeEverywhere = db.prepare("DELETE FROM raw_slot_allowed_components WHERE session_id = ? AND allowed_component = ?");
4377
- db.exec("BEGIN");
4378
- try {
4379
- for (const edge of edges) {
4380
- const row = componentId.get(sessionId, edge.parent);
4381
- if (row)
4382
- removeEdge.run(sessionId, row.component_id, edge.child);
4383
- }
4384
- for (const name of rejectedNames)
4385
- removeEverywhere.run(sessionId, name);
4386
- db.exec("COMMIT");
4387
- } catch (e) {
4388
- db.exec("ROLLBACK");
4389
- throw e;
4390
- }
4391
- }
4392
4370
  function findLatestSessionForCommand(db, command) {
4393
4371
  return getLatestCompletedSessionForCommand(db, command);
4394
4372
  }
@@ -18392,7 +18370,7 @@ function buildVisibleRows(props) {
18392
18370
  if (visited.has(target)) continue;
18393
18371
  visited.add(target);
18394
18372
  const isCycleMember = cycleParticipants.has(target);
18395
- out.push({ name: target, depth: cur.depth + 1, isCycleMember, parent: cur.name });
18373
+ out.push({ name: target, depth: cur.depth + 1, isCycleMember });
18396
18374
  queue.push({ name: target, depth: cur.depth + 1 });
18397
18375
  }
18398
18376
  }
@@ -18439,8 +18417,7 @@ function buildVisibleRows(props) {
18439
18417
  sharedSuffix,
18440
18418
  cycleChild: child.isCycleMember || void 0,
18441
18419
  itemIdx: childRec?.idx ?? -1,
18442
- rootName: key,
18443
- parentName: child.parent
18420
+ rootName: key
18444
18421
  });
18445
18422
  });
18446
18423
  }
@@ -18523,19 +18500,13 @@ function buildVisibleRows(props) {
18523
18500
  injectedChildren.push({
18524
18501
  name: target,
18525
18502
  depth: parentDepth + 1,
18526
- isCycleChild: true,
18527
- parent: parentName
18503
+ isCycleChild: true
18528
18504
  });
18529
18505
  }
18530
18506
  };
18531
18507
  emitCycleChildrenOf(root, 0);
18532
18508
  for (const c2 of closureChildren) {
18533
- injectedChildren.push({
18534
- name: c2.name,
18535
- depth: c2.depth,
18536
- isCycleChild: false,
18537
- parent: c2.path[c2.path.length - 2] ?? root
18538
- });
18509
+ injectedChildren.push({ name: c2.name, depth: c2.depth, isCycleChild: false });
18539
18510
  emitCycleChildrenOf(c2.name, c2.depth);
18540
18511
  }
18541
18512
  const isLastAtDepth = (idx) => {
@@ -18569,8 +18540,7 @@ function buildVisibleRows(props) {
18569
18540
  sharedSuffix,
18570
18541
  cycleChild: child.isCycleChild || void 0,
18571
18542
  itemIdx: childRec?.idx ?? -1,
18572
- rootName: root,
18573
- parentName: child.parent
18543
+ rootName: root
18574
18544
  });
18575
18545
  });
18576
18546
  }
@@ -18723,7 +18693,7 @@ function GroupedSidebar(props) {
18723
18693
  const rs = itemName ? renderStatusByKey?.get(itemName) : void 0;
18724
18694
  const badge = itemName ? previewBadge(previewAnnotationByKey?.get(itemName)) : null;
18725
18695
  const showInheritance = rs !== void 0 && row.kind !== "cycle" && row.kind !== "empty" && row.kind !== "group-root";
18726
- const supportsSelectionGlyph = selectionStateByKey !== void 0 && itemName !== void 0 && (row.kind === "standalone" || row.kind === "group-root" || row.kind === "group-child" || row.kind === "flat" || row.kind === "empty" || row.kind === "cycle");
18696
+ const supportsSelectionGlyph = selectionStateByKey !== void 0 && itemName !== void 0 && (row.kind === "standalone" || row.kind === "group-root" || row.kind === "group-child" || row.kind === "flat" || row.kind === "cycle");
18727
18697
  const selState = supportsSelectionGlyph ? selectionStateByKey.get(itemName) ?? "undecided" : void 0;
18728
18698
  const isCycleRow = row.kind === "cycle";
18729
18699
  const selStyle = selectionGlyphStyleFor(selState, isCycleRow);
@@ -18753,7 +18723,7 @@ function GroupedSidebar(props) {
18753
18723
  color: isSelected ? PALETTE2.info : labelStyle.dim ? PALETTE2.muted : labelStyle.color,
18754
18724
  bold: isSelected || labelStyle.bold,
18755
18725
  inverse: false,
18756
- underline: isSelected && focused,
18726
+ underline: isSelected && !focused,
18757
18727
  wrap: wrapLabels ? "wrap" : "truncate",
18758
18728
  children: [
18759
18729
  " ",
@@ -19412,7 +19382,6 @@ function resolveKey(mode, key, ctx) {
19412
19382
  function resolveMain(key, ctx) {
19413
19383
  const { input } = key;
19414
19384
  const inMain = ctx.focusedColumn === "main";
19415
- if (key.ctrl && input === "z") return { type: "undo" };
19416
19385
  if (input === "q" || key.escape) {
19417
19386
  if (key.escape && ctx.jumpFilterActive) return { type: "clear-jump-filter" };
19418
19387
  if (key.escape && ctx.searchActive) return { type: "clear-search" };
@@ -19671,42 +19640,21 @@ function rejectNeedsConfirmation(graph, name, state) {
19671
19640
  const ancestors = toReject.filter((n) => n !== name);
19672
19641
  return ancestors.length + toDeselect.length >= 2;
19673
19642
  }
19674
- function removeSlotChild(components, edge) {
19675
- return components.map(
19676
- (component) => component.name === edge.parent ? {
19677
- ...component,
19678
- slots: component.slots?.map((slot) => ({
19679
- ...slot,
19680
- allowedComponents: slot.allowedComponents.filter((name) => name !== edge.child)
19681
- }))
19682
- } : component
19683
- );
19684
- }
19685
- function withoutSlotChildren(components, removedEdges) {
19686
- return removedEdges.reduce(removeSlotChild, components);
19687
- }
19688
- function partitionDecisions(components, state, removedEdges) {
19643
+ function partitionDecisions(components, state) {
19689
19644
  const accepted = [];
19690
19645
  const rejected = [];
19691
19646
  for (const c2 of components) {
19692
19647
  if (state.get(c2.name) === "accepted") accepted.push(c2.name);
19693
19648
  else rejected.push(c2.name);
19694
19649
  }
19695
- const rejectedNames = new Set(rejected);
19696
- const excludedSlotEdges = removedEdges.filter((e) => !rejectedNames.has(e.parent) && !rejectedNames.has(e.child));
19697
- return { accepted, rejected, excludedSlotEdges };
19650
+ return { accepted, rejected };
19698
19651
  }
19699
19652
 
19700
19653
  // packages/experience-design-system-cli/src/tui/import/steps/07-scope-gate/use-scope-gate.ts
19701
- function useScopeGate({ components: loadedComponents, onConfirm, onQuit }) {
19654
+ function useScopeGate({ components, onConfirm, onQuit }) {
19702
19655
  const { columns: totalWidth, rows: terminalRows } = useTerminalSize();
19703
19656
  const columnPlan = useMemo2(() => computeColumnWidths(totalWidth), [totalWidth]);
19704
19657
  const [decisions, setDecisions] = useState12(/* @__PURE__ */ new Map());
19705
- const [removedEdges, setRemovedEdges] = useState12([]);
19706
- const components = useMemo2(
19707
- () => withoutSlotChildren(loadedComponents, removedEdges),
19708
- [loadedComponents, removedEdges]
19709
- );
19710
19658
  const [nav, setNav] = useState12({ cursor: 0, scrollOffset: 0 });
19711
19659
  const [focusedColumn, setFocusedColumn] = useState12("main");
19712
19660
  const [addedComponentsCursor, setAddedComponentsCursor] = useState12(0);
@@ -19878,14 +19826,6 @@ function useScopeGate({ components: loadedComponents, onConfirm, onQuit }) {
19878
19826
  return void 0;
19879
19827
  }
19880
19828
  };
19881
- const focusedNestedEdge = () => {
19882
- const row = visibleRows[safeCursor];
19883
- if (row?.kind !== "group-child" || !row.parentName || row.itemIdx < 0) return void 0;
19884
- const child = groupedItems[row.itemIdx]?.key;
19885
- return child ? { parent: row.parentName, child } : void 0;
19886
- };
19887
- const removeFromParentSlot = (edge) => setRemovedEdges((edges) => [...edges, edge]);
19888
- const undoSlotRemoval = () => setRemovedEdges((edges) => edges.slice(0, -1));
19889
19829
  const jumpCursorTo = (name) => {
19890
19830
  let idx = -1;
19891
19831
  for (let i = 0; i < visibleRows.length; i++) {
@@ -19985,7 +19925,7 @@ function useScopeGate({ components: loadedComponents, onConfirm, onQuit }) {
19985
19925
  onQuit();
19986
19926
  return;
19987
19927
  case "confirm":
19988
- onConfirm(partitionDecisions(components, decisions, removedEdges));
19928
+ onConfirm(partitionDecisions(components, decisions));
19989
19929
  return;
19990
19930
  case "close-help":
19991
19931
  setShowHelp(false);
@@ -20038,11 +19978,6 @@ function useScopeGate({ components: loadedComponents, onConfirm, onQuit }) {
20038
19978
  return;
20039
19979
  }
20040
19980
  case "reject": {
20041
- const edge = focusedColumn === "main" ? focusedNestedEdge() : void 0;
20042
- if (edge) {
20043
- removeFromParentSlot(edge);
20044
- return;
20045
- }
20046
19981
  const key = focusedColumn === "added-components" ? addedComponents[safeAddedComponentsCursor]?.name : focusedRowKey();
20047
19982
  if (key) requestReject(key);
20048
19983
  return;
@@ -20050,9 +19985,6 @@ function useScopeGate({ components: loadedComponents, onConfirm, onQuit }) {
20050
19985
  case "toggle-all":
20051
19986
  decide({ type: "toggle-all" });
20052
19987
  return;
20053
- case "undo":
20054
- undoSlotRemoval();
20055
- return;
20056
19988
  case "accept-unflagged":
20057
19989
  decide({ type: "accept-unflagged" });
20058
19990
  return;
@@ -20652,7 +20584,6 @@ function buildFlowStart(input) {
20652
20584
  }
20653
20585
 
20654
20586
  // packages/experience-design-system-cli/src/tui/import/steps/10-flow/flow/screen.tsx
20655
- import { useEffect as useEffect20, useRef as useRef12 } from "react";
20656
20587
  import { Box as Box41 } from "ink";
20657
20588
 
20658
20589
  // packages/experience-design-system-types/dist/src/cdf/validate.js
@@ -22695,8 +22626,8 @@ function FieldEditor({
22695
22626
  return /* @__PURE__ */ jsxs22(Box21, { flexDirection: "column", width, borderStyle: "single", borderColor: PALETTE3.warning, children: [
22696
22627
  /* @__PURE__ */ jsx27(Text23, { bold: true, color: PALETTE3.warning, children: "FIELD EDITOR \u2014 no fields" }),
22697
22628
  /* @__PURE__ */ jsx27(Text23, { color: PALETTE3.warning, children: "\u26A0 No properties classified for this component. The LLM didn't find anything to classify." }),
22698
- /* @__PURE__ */ jsx27(Text23, { color: PALETTE3.muted, children: "There is nothing to edit here." }),
22699
- /* @__PURE__ */ jsx27(Text23, { color: PALETTE3.muted, children: active ? "[Esc] go back to the list" : "In the list: [r] reject this component \xB7 [a] accept it" })
22629
+ /* @__PURE__ */ jsx27(Text23, { color: PALETTE3.muted, children: "You can add fields manually below or reject this component." }),
22630
+ /* @__PURE__ */ jsx27(Text23, { color: PALETTE3.muted, children: "Enter to save \xB7 Esc to discard" })
22700
22631
  ] });
22701
22632
  }
22702
22633
  const hasEmptyProperties = props.length === 0 && slots.length === 0;
@@ -22911,7 +22842,7 @@ function FieldEditor({
22911
22842
  children: [
22912
22843
  hasEmptyProperties && /* @__PURE__ */ jsx27(Text23, { color: PALETTE3.warning, children: "\u26A0 No properties classified for this component. The LLM didn't find anything to classify. Reject this component or add fields manually." }),
22913
22844
  header,
22914
- /* @__PURE__ */ jsx27(Box21, { flexDirection: "column", width: innerWidth, flexShrink: 0, children: focusLevel === "field" && !inComponentDesc && !inSlots && currentProp ? /* @__PURE__ */ jsx27(
22845
+ /* @__PURE__ */ jsx27(Box21, { flexDirection: "column", width: innerWidth, flexShrink: 0, children: focusLevel === "field" && !inComponentDesc && currentProp ? /* @__PURE__ */ jsx27(
22915
22846
  PropRow,
22916
22847
  {
22917
22848
  prop: currentProp,
@@ -23820,7 +23751,6 @@ function finalizeReviewSession(extractSessionId, components) {
23820
23751
  db.exec("ROLLBACK");
23821
23752
  throw error;
23822
23753
  }
23823
- removeSlotAllowedComponents(db, extractSessionId, [], toReject);
23824
23754
  } finally {
23825
23755
  db.close();
23826
23756
  }
@@ -25552,50 +25482,33 @@ function GenerateReviewStepView({
25552
25482
  const cycle = cycleRows[cyclesCursor];
25553
25483
  return cycle ? enumerateCycleBreaks(cycle, components) : [];
25554
25484
  }, [cycleRows, cyclesCursor, components]);
25555
- const saveSlotChange = (parentKey, nextEntry, historyLabel) => {
25485
+ const handleBreakEdge = (edge) => {
25486
+ const target = components.find((component) => component.key === edge.fromComponent);
25487
+ const slot = target?.entry.$slots?.[edge.slotName];
25488
+ if (!target || !slot || !Array.isArray(slot.$allowedComponents)) return;
25489
+ const nextEntry = {
25490
+ ...target.entry,
25491
+ $slots: {
25492
+ ...target.entry.$slots,
25493
+ [edge.slotName]: {
25494
+ ...slot,
25495
+ $allowedComponents: slot.$allowedComponents.filter((value) => value !== edge.toComponent)
25496
+ }
25497
+ }
25498
+ };
25556
25499
  const next = components.map(
25557
- (component) => component.key === parentKey ? { ...component, entry: nextEntry } : component
25500
+ (component) => component.key === target.key ? { ...component, entry: nextEntry } : component
25558
25501
  );
25559
25502
  setComponents(next);
25560
25503
  const db = openPipelineDb();
25561
25504
  try {
25562
- storeCDFComponents(db, extractSessionId, [{ key: parentKey, entry: nextEntry }]);
25505
+ storeCDFComponents(db, extractSessionId, [{ key: target.key, entry: nextEntry }]);
25563
25506
  } finally {
25564
25507
  db.close();
25565
25508
  }
25566
25509
  recomputeCycles(next);
25567
25510
  livePreviewHook.trigger();
25568
- pushHistorySnapshot(next, historyLabel);
25569
- };
25570
- const handleBreakEdge = (edge) => {
25571
- const target = components.find((component) => component.key === edge.fromComponent);
25572
- const slot = target?.entry.$slots?.[edge.slotName];
25573
- if (!target || !slot || !Array.isArray(slot.$allowedComponents)) return;
25574
- saveSlotChange(
25575
- target.key,
25576
- {
25577
- ...target.entry,
25578
- $slots: {
25579
- ...target.entry.$slots,
25580
- [edge.slotName]: {
25581
- ...slot,
25582
- $allowedComponents: slot.$allowedComponents.filter((value) => value !== edge.toComponent)
25583
- }
25584
- }
25585
- },
25586
- "break-cycle-edge"
25587
- );
25588
- };
25589
- const handleRemoveSlotChild = (parentKey, childKey) => {
25590
- const parent = components.find((component) => component.key === parentKey);
25591
- if (!parent?.entry.$slots) return;
25592
- const slots = Object.fromEntries(
25593
- Object.entries(parent.entry.$slots).map(([slotName, slot]) => [
25594
- slotName,
25595
- Array.isArray(slot.$allowedComponents) ? { ...slot, $allowedComponents: slot.$allowedComponents.filter((value) => value !== childKey) } : slot
25596
- ])
25597
- );
25598
- saveSlotChange(parentKey, { ...parent.entry, $slots: slots }, "remove-slot-child");
25511
+ pushHistorySnapshot(next, "break-cycle-edge");
25599
25512
  };
25600
25513
  const handleRejectComponent = (key) => {
25601
25514
  const rejectCascade2 = computeRejectCascade(key, componentGraph);
@@ -25925,11 +25838,6 @@ function GenerateReviewStepView({
25925
25838
  if (input === "r") {
25926
25839
  const current = components[selectedIdx];
25927
25840
  if (!current) return;
25928
- const row = visibleRowsMemo[cursorRowIdx];
25929
- if (row?.kind === "group-child" && row.parentName) {
25930
- handleRemoveSlotChild(row.parentName, current.key);
25931
- return;
25932
- }
25933
25841
  handleRejectComponent(current.key);
25934
25842
  return;
25935
25843
  }
@@ -27076,18 +26984,10 @@ function FlowScreen({
27076
26984
  controller,
27077
26985
  livePreview = true,
27078
26986
  generatePromptPath,
27079
- onExit,
27080
- onStepChange
26987
+ onExit
27081
26988
  }) {
27082
26989
  const totalSteps = totalStepsFor(state);
27083
26990
  const quit = () => onExit(0);
27084
- const previousStep = useRef12(state.step);
27085
- useEffect20(() => {
27086
- if (previousStep.current !== state.step) {
27087
- onStepChange?.();
27088
- previousStep.current = state.step;
27089
- }
27090
- }, [state.step, onStepChange]);
27091
26991
  const content = (() => {
27092
26992
  switch (state.step) {
27093
26993
  case "final-review":
@@ -27213,7 +27113,7 @@ function FlowScreen({
27213
27113
  }
27214
27114
 
27215
27115
  // packages/experience-design-system-cli/src/tui/import/steps/10-flow/flow/use-flow.ts
27216
- import { useEffect as useEffect21, useRef as useRef13, useSyncExternalStore } from "react";
27116
+ import { useEffect as useEffect20, useRef as useRef12, useSyncExternalStore } from "react";
27217
27117
 
27218
27118
  // packages/experience-design-system-cli/src/tui/import/steps/10-flow/flow/controller.ts
27219
27119
  import { appendFileSync, writeFileSync } from "node:fs";
@@ -27803,6 +27703,12 @@ function createFlowController(start, deps) {
27803
27703
  deps.log({ update: sanitizeForLog(patch) });
27804
27704
  } catch {
27805
27705
  }
27706
+ if (patch.step !== void 0 && patch.step !== state.step) {
27707
+ try {
27708
+ deps.beforeStepChange?.();
27709
+ } catch {
27710
+ }
27711
+ }
27806
27712
  state = { ...state, ...patch };
27807
27713
  for (const listener of listeners) listener();
27808
27714
  };
@@ -27940,28 +27846,32 @@ function createFlowController(start, deps) {
27940
27846
  }
27941
27847
 
27942
27848
  // packages/experience-design-system-cli/src/tui/import/steps/10-flow/flow/use-flow.ts
27943
- function useFlow(start, deps = realFlowDeps) {
27944
- const controller = useRef13();
27849
+ function useFlow(start, options = {}) {
27850
+ const controller = useRef12();
27945
27851
  if (start && !controller.current) {
27946
27852
  try {
27947
27853
  startWizardLog();
27948
27854
  } catch {
27949
27855
  }
27950
- controller.current = createFlowController(start, deps());
27856
+ const flowDeps = (options.deps ?? realFlowDeps)();
27857
+ controller.current = createFlowController(start, {
27858
+ ...flowDeps,
27859
+ ...options.beforeStepChange ? { beforeStepChange: options.beforeStepChange } : {}
27860
+ });
27951
27861
  }
27952
27862
  const current = controller.current;
27953
27863
  const state = useSyncExternalStore(
27954
27864
  (listener) => current?.subscribe(listener) ?? (() => void 0),
27955
27865
  () => current?.getState()
27956
27866
  );
27957
- useEffect21(() => {
27867
+ useEffect20(() => {
27958
27868
  if (!start) controller.current = void 0;
27959
27869
  }, [start]);
27960
27870
  return current && state ? { controller: current, state } : void 0;
27961
27871
  }
27962
27872
 
27963
27873
  // packages/experience-design-system-cli/src/tui/help/PageContainer.tsx
27964
- import { useEffect as useEffect22, useState as useState27 } from "react";
27874
+ import { useEffect as useEffect21, useState as useState27 } from "react";
27965
27875
  import { Box as Box42, Text as Text44, useInput as useInput9 } from "ink";
27966
27876
 
27967
27877
  // packages/experience-design-system-cli/src/tui/debug-store.ts
@@ -28155,7 +28065,7 @@ function Section({ title, rows }) {
28155
28065
  }
28156
28066
  function HelpScreen({ onDone }) {
28157
28067
  const [info, setInfo] = useState27();
28158
- useEffect22(() => {
28068
+ useEffect21(() => {
28159
28069
  startDebugRun({ flow: "help", step: "01-help", menuOption: "Help", inputs: {} });
28160
28070
  void readHelpInfo().then(setInfo);
28161
28071
  }, []);
@@ -28248,7 +28158,7 @@ function SettingsScreen({
28248
28158
  }
28249
28159
 
28250
28160
  // packages/experience-design-system-cli/src/tui/settings/contentful-configuration/ContentfulConfigScreen.tsx
28251
- import { useEffect as useEffect23, useState as useState29 } from "react";
28161
+ import { useEffect as useEffect22, useState as useState29 } from "react";
28252
28162
  import { Box as Box44, Text as Text46, useInput as useInput11 } from "ink";
28253
28163
  import TextInput4 from "ink-text-input";
28254
28164
 
@@ -28316,7 +28226,7 @@ function ConfigurationScreen({ onDone }) {
28316
28226
  const [lastSaved, setLastSaved] = useState29(null);
28317
28227
  const [editing, setEditing] = useState29(false);
28318
28228
  const [valueBeforeEdit, setValueBeforeEdit] = useState29("");
28319
- useEffect23(() => {
28229
+ useEffect22(() => {
28320
28230
  readCredentials().then((cfg) => {
28321
28231
  setConfig(cfg);
28322
28232
  setStage("form");
@@ -28453,7 +28363,7 @@ function ConfigurationScreen({ onDone }) {
28453
28363
  }
28454
28364
 
28455
28365
  // packages/experience-design-system-cli/src/tui/settings/opt-in-analytics/screen.tsx
28456
- import { useEffect as useEffect24, useState as useState30 } from "react";
28366
+ import { useEffect as useEffect23, useState as useState30 } from "react";
28457
28367
  import { Box as Box45, Text as Text47, useInput as useInput12 } from "ink";
28458
28368
 
28459
28369
  // packages/experience-design-system-cli/src/tui/settings/opt-in-analytics/analytics-store.ts
@@ -28476,7 +28386,7 @@ import { Fragment as Fragment18, jsx as jsx56, jsxs as jsxs46 } from "react/jsx-
28476
28386
  function OptInAnalyticsScreen({ onDone }) {
28477
28387
  const [loading, setLoading] = useState30(true);
28478
28388
  const [enabled, setEnabled] = useState30(true);
28479
- useEffect24(() => {
28389
+ useEffect23(() => {
28480
28390
  readAnalyticsSetting().then((setting) => {
28481
28391
  setEnabled(setting.enabled);
28482
28392
  setLoading(false);
@@ -28530,13 +28440,13 @@ function OptInAnalyticsScreen({ onDone }) {
28530
28440
  }
28531
28441
 
28532
28442
  // packages/experience-design-system-cli/src/tui/upgrade/PageContainer.tsx
28533
- import { useEffect as useEffect25, useState as useState31 } from "react";
28443
+ import { useEffect as useEffect24, useState as useState31 } from "react";
28534
28444
  import { Box as Box46, Text as Text48, useInput as useInput13 } from "ink";
28535
28445
  import { jsx as jsx57, jsxs as jsxs47 } from "react/jsx-runtime";
28536
28446
  var UPGRADE_COMMANDS = ["git pull", "pnpm install", "pnpm build"];
28537
28447
  function UpgradeScreen({ onDone }) {
28538
28448
  const [upgradeCheck, setUpgradeCheck] = useState31();
28539
- useEffect25(() => {
28449
+ useEffect24(() => {
28540
28450
  startDebugRun({
28541
28451
  flow: "upgrade",
28542
28452
  step: "01-upgrade",
@@ -28601,13 +28511,13 @@ function renderBody(upgradeCheck) {
28601
28511
  }
28602
28512
 
28603
28513
  // packages/experience-design-system-cli/src/tui/settings/debug-mode/screen.tsx
28604
- import { useEffect as useEffect26, useState as useState32 } from "react";
28514
+ import { useEffect as useEffect25, useState as useState32 } from "react";
28605
28515
  import { Box as Box47, Text as Text49, useInput as useInput14 } from "ink";
28606
28516
  import { jsx as jsx58, jsxs as jsxs48 } from "react/jsx-runtime";
28607
28517
  function DebugModeScreen({ onDone }) {
28608
28518
  const [loading, setLoading] = useState32(true);
28609
28519
  const [enabled, setEnabled] = useState32(true);
28610
- useEffect26(() => {
28520
+ useEffect25(() => {
28611
28521
  readDebugModeSetting().then((setting) => {
28612
28522
  setEnabled(setting.enabled);
28613
28523
  setLoading(false);
@@ -28685,9 +28595,9 @@ function App({ importOptions, inkClear }) {
28685
28595
  const [generationInput, setGenerationInput] = useState33();
28686
28596
  const generation = useGeneration(generationInput);
28687
28597
  const [flowStart, setFlowStart] = useState33();
28688
- const flow = useFlow(flowStart);
28598
+ const flow = useFlow(flowStart, { beforeStepChange: inkClear });
28689
28599
  const [importDefaults, setImportDefaults] = useState33();
28690
- useEffect27(() => {
28600
+ useEffect26(() => {
28691
28601
  if (screen !== "import") {
28692
28602
  setImportDefaults(void 0);
28693
28603
  return;
@@ -28745,12 +28655,12 @@ function App({ importOptions, inkClear }) {
28745
28655
  }
28746
28656
  });
28747
28657
  };
28748
- useEffect27(() => {
28658
+ useEffect26(() => {
28749
28659
  if (!extractionRun || extraction?.status !== "done" || !extraction.result.ok) return;
28750
28660
  setExtractionRun(void 0);
28751
28661
  setScopeRun({ ...extractionRun, extraction: extraction.result.extraction });
28752
28662
  }, [extraction, extractionRun]);
28753
- useEffect27(() => {
28663
+ useEffect26(() => {
28754
28664
  if (!scopeRun || scopeFlow?.status !== "confirmed" || generationInput) return;
28755
28665
  const { extraction: produced, input, generatePromptPath } = scopeRun;
28756
28666
  setGenerationInput({
@@ -28768,7 +28678,7 @@ function App({ importOptions, inkClear }) {
28768
28678
  ...generatePromptPath ? { generatePromptPath } : {}
28769
28679
  });
28770
28680
  }, [scopeFlow, scopeRun, generationInput]);
28771
- useEffect27(() => {
28681
+ useEffect26(() => {
28772
28682
  if (!scopeRun || generation?.status !== "done" || !generation.result.ok) return;
28773
28683
  const { credentialsSkipped, tokenStrategy, extraction: produced, input, generatePromptPath } = scopeRun;
28774
28684
  inkClear();
@@ -28819,8 +28729,7 @@ function App({ importOptions, inkClear }) {
28819
28729
  state: flow.state,
28820
28730
  controller: flow.controller,
28821
28731
  generatePromptPath: flowStart.generatePromptPath,
28822
- onExit: setImportExitCode,
28823
- onStepChange: inkClear
28732
+ onExit: setImportExitCode
28824
28733
  }
28825
28734
  );
28826
28735
  }
package/dist/index.js CHANGED
@@ -4386,30 +4386,8 @@ function applyScopeDecisions(db, sessionId, decisions) {
4386
4386
  const placeholders = accepted.map(() => "?").join(",");
4387
4387
  db.prepare(`UPDATE raw_components SET status = 'generated' WHERE session_id = ? AND name IN (${placeholders})`).run(sessionId, ...accepted);
4388
4388
  }
4389
- removeSlotAllowedComponents(db, sessionId, decisions.excludedSlotEdges ?? [], rejected);
4390
4389
  db.prepare("UPDATE sessions SET updated_at = ? WHERE id = ?").run(now, sessionId);
4391
4390
  }
4392
- function removeSlotAllowedComponents(db, sessionId, edges, rejectedNames) {
4393
- if (edges.length === 0 && rejectedNames.length === 0)
4394
- return;
4395
- const componentId = db.prepare("SELECT component_id FROM raw_components WHERE session_id = ? AND name = ?");
4396
- const removeEdge = db.prepare("DELETE FROM raw_slot_allowed_components WHERE session_id = ? AND component_id = ? AND allowed_component = ?");
4397
- const removeEverywhere = db.prepare("DELETE FROM raw_slot_allowed_components WHERE session_id = ? AND allowed_component = ?");
4398
- db.exec("BEGIN");
4399
- try {
4400
- for (const edge of edges) {
4401
- const row = componentId.get(sessionId, edge.parent);
4402
- if (row)
4403
- removeEdge.run(sessionId, row.component_id, edge.child);
4404
- }
4405
- for (const name of rejectedNames)
4406
- removeEverywhere.run(sessionId, name);
4407
- db.exec("COMMIT");
4408
- } catch (e) {
4409
- db.exec("ROLLBACK");
4410
- throw e;
4411
- }
4412
- }
4413
4391
  function findLatestSessionForCommand(db, command) {
4414
4392
  return getLatestCompletedSessionForCommand(db, command);
4415
4393
  }
@@ -21799,7 +21777,7 @@ function buildVisibleRows(props) {
21799
21777
  if (visited.has(target)) continue;
21800
21778
  visited.add(target);
21801
21779
  const isCycleMember = cycleParticipants.has(target);
21802
- out.push({ name: target, depth: cur.depth + 1, isCycleMember, parent: cur.name });
21780
+ out.push({ name: target, depth: cur.depth + 1, isCycleMember });
21803
21781
  queue.push({ name: target, depth: cur.depth + 1 });
21804
21782
  }
21805
21783
  }
@@ -21846,8 +21824,7 @@ function buildVisibleRows(props) {
21846
21824
  sharedSuffix,
21847
21825
  cycleChild: child.isCycleMember || void 0,
21848
21826
  itemIdx: childRec?.idx ?? -1,
21849
- rootName: key,
21850
- parentName: child.parent
21827
+ rootName: key
21851
21828
  });
21852
21829
  });
21853
21830
  }
@@ -21930,19 +21907,13 @@ function buildVisibleRows(props) {
21930
21907
  injectedChildren.push({
21931
21908
  name: target,
21932
21909
  depth: parentDepth + 1,
21933
- isCycleChild: true,
21934
- parent: parentName
21910
+ isCycleChild: true
21935
21911
  });
21936
21912
  }
21937
21913
  };
21938
21914
  emitCycleChildrenOf(root, 0);
21939
21915
  for (const c2 of closureChildren) {
21940
- injectedChildren.push({
21941
- name: c2.name,
21942
- depth: c2.depth,
21943
- isCycleChild: false,
21944
- parent: c2.path[c2.path.length - 2] ?? root
21945
- });
21916
+ injectedChildren.push({ name: c2.name, depth: c2.depth, isCycleChild: false });
21946
21917
  emitCycleChildrenOf(c2.name, c2.depth);
21947
21918
  }
21948
21919
  const isLastAtDepth = (idx) => {
@@ -21976,8 +21947,7 @@ function buildVisibleRows(props) {
21976
21947
  sharedSuffix,
21977
21948
  cycleChild: child.isCycleChild || void 0,
21978
21949
  itemIdx: childRec?.idx ?? -1,
21979
- rootName: root,
21980
- parentName: child.parent
21950
+ rootName: root
21981
21951
  });
21982
21952
  });
21983
21953
  }
@@ -22130,7 +22100,7 @@ function GroupedSidebar(props) {
22130
22100
  const rs = itemName ? renderStatusByKey?.get(itemName) : void 0;
22131
22101
  const badge = itemName ? previewBadge(previewAnnotationByKey?.get(itemName)) : null;
22132
22102
  const showInheritance = rs !== void 0 && row.kind !== "cycle" && row.kind !== "empty" && row.kind !== "group-root";
22133
- const supportsSelectionGlyph = selectionStateByKey !== void 0 && itemName !== void 0 && (row.kind === "standalone" || row.kind === "group-root" || row.kind === "group-child" || row.kind === "flat" || row.kind === "empty" || row.kind === "cycle");
22103
+ const supportsSelectionGlyph = selectionStateByKey !== void 0 && itemName !== void 0 && (row.kind === "standalone" || row.kind === "group-root" || row.kind === "group-child" || row.kind === "flat" || row.kind === "cycle");
22134
22104
  const selState = supportsSelectionGlyph ? selectionStateByKey.get(itemName) ?? "undecided" : void 0;
22135
22105
  const isCycleRow = row.kind === "cycle";
22136
22106
  const selStyle = selectionGlyphStyleFor(selState, isCycleRow);
@@ -22160,7 +22130,7 @@ function GroupedSidebar(props) {
22160
22130
  color: isSelected ? PALETTE2.info : labelStyle.dim ? PALETTE2.muted : labelStyle.color,
22161
22131
  bold: isSelected || labelStyle.bold,
22162
22132
  inverse: false,
22163
- underline: isSelected && focused,
22133
+ underline: isSelected && !focused,
22164
22134
  wrap: wrapLabels ? "wrap" : "truncate",
22165
22135
  children: [
22166
22136
  " ",
@@ -22911,7 +22881,6 @@ function resolveKey(mode, key, ctx) {
22911
22881
  function resolveMain(key, ctx) {
22912
22882
  const { input } = key;
22913
22883
  const inMain = ctx.focusedColumn === "main";
22914
- if (key.ctrl && input === "z") return { type: "undo" };
22915
22884
  if (input === "q" || key.escape) {
22916
22885
  if (key.escape && ctx.jumpFilterActive) return { type: "clear-jump-filter" };
22917
22886
  if (key.escape && ctx.searchActive) return { type: "clear-search" };
@@ -23210,30 +23179,14 @@ function rejectNeedsConfirmation(graph, name, state) {
23210
23179
  const ancestors = toReject.filter((n) => n !== name);
23211
23180
  return ancestors.length + toDeselect.length >= 2;
23212
23181
  }
23213
- function removeSlotChild(components, edge) {
23214
- return components.map(
23215
- (component) => component.name === edge.parent ? {
23216
- ...component,
23217
- slots: component.slots?.map((slot) => ({
23218
- ...slot,
23219
- allowedComponents: slot.allowedComponents.filter((name) => name !== edge.child)
23220
- }))
23221
- } : component
23222
- );
23223
- }
23224
- function withoutSlotChildren(components, removedEdges) {
23225
- return removedEdges.reduce(removeSlotChild, components);
23226
- }
23227
- function partitionDecisions(components, state, removedEdges) {
23182
+ function partitionDecisions(components, state) {
23228
23183
  const accepted = [];
23229
23184
  const rejected = [];
23230
23185
  for (const c2 of components) {
23231
23186
  if (state.get(c2.name) === "accepted") accepted.push(c2.name);
23232
23187
  else rejected.push(c2.name);
23233
23188
  }
23234
- const rejectedNames = new Set(rejected);
23235
- const excludedSlotEdges = removedEdges.filter((e) => !rejectedNames.has(e.parent) && !rejectedNames.has(e.child));
23236
- return { accepted, rejected, excludedSlotEdges };
23189
+ return { accepted, rejected };
23237
23190
  }
23238
23191
  var init_state = __esm({
23239
23192
  "packages/experience-design-system-cli/src/tui/import/steps/07-scope-gate/state.ts"() {
@@ -23245,15 +23198,10 @@ var init_state = __esm({
23245
23198
 
23246
23199
  // packages/experience-design-system-cli/src/tui/import/steps/07-scope-gate/use-scope-gate.ts
23247
23200
  import { useEffect as useEffect7, useMemo as useMemo2, useRef as useRef4, useState as useState12 } from "react";
23248
- function useScopeGate({ components: loadedComponents, onConfirm, onQuit }) {
23201
+ function useScopeGate({ components, onConfirm, onQuit }) {
23249
23202
  const { columns: totalWidth, rows: terminalRows } = useTerminalSize();
23250
23203
  const columnPlan = useMemo2(() => computeColumnWidths(totalWidth), [totalWidth]);
23251
23204
  const [decisions, setDecisions] = useState12(/* @__PURE__ */ new Map());
23252
- const [removedEdges, setRemovedEdges] = useState12([]);
23253
- const components = useMemo2(
23254
- () => withoutSlotChildren(loadedComponents, removedEdges),
23255
- [loadedComponents, removedEdges]
23256
- );
23257
23205
  const [nav, setNav] = useState12({ cursor: 0, scrollOffset: 0 });
23258
23206
  const [focusedColumn, setFocusedColumn] = useState12("main");
23259
23207
  const [addedComponentsCursor, setAddedComponentsCursor] = useState12(0);
@@ -23425,14 +23373,6 @@ function useScopeGate({ components: loadedComponents, onConfirm, onQuit }) {
23425
23373
  return void 0;
23426
23374
  }
23427
23375
  };
23428
- const focusedNestedEdge = () => {
23429
- const row = visibleRows[safeCursor];
23430
- if (row?.kind !== "group-child" || !row.parentName || row.itemIdx < 0) return void 0;
23431
- const child = groupedItems[row.itemIdx]?.key;
23432
- return child ? { parent: row.parentName, child } : void 0;
23433
- };
23434
- const removeFromParentSlot = (edge) => setRemovedEdges((edges) => [...edges, edge]);
23435
- const undoSlotRemoval = () => setRemovedEdges((edges) => edges.slice(0, -1));
23436
23376
  const jumpCursorTo = (name) => {
23437
23377
  let idx = -1;
23438
23378
  for (let i = 0; i < visibleRows.length; i++) {
@@ -23532,7 +23472,7 @@ function useScopeGate({ components: loadedComponents, onConfirm, onQuit }) {
23532
23472
  onQuit();
23533
23473
  return;
23534
23474
  case "confirm":
23535
- onConfirm(partitionDecisions(components, decisions, removedEdges));
23475
+ onConfirm(partitionDecisions(components, decisions));
23536
23476
  return;
23537
23477
  case "close-help":
23538
23478
  setShowHelp(false);
@@ -23585,11 +23525,6 @@ function useScopeGate({ components: loadedComponents, onConfirm, onQuit }) {
23585
23525
  return;
23586
23526
  }
23587
23527
  case "reject": {
23588
- const edge = focusedColumn === "main" ? focusedNestedEdge() : void 0;
23589
- if (edge) {
23590
- removeFromParentSlot(edge);
23591
- return;
23592
- }
23593
23528
  const key = focusedColumn === "added-components" ? addedComponents[safeAddedComponentsCursor]?.name : focusedRowKey();
23594
23529
  if (key) requestReject(key);
23595
23530
  return;
@@ -23597,9 +23532,6 @@ function useScopeGate({ components: loadedComponents, onConfirm, onQuit }) {
23597
23532
  case "toggle-all":
23598
23533
  decide({ type: "toggle-all" });
23599
23534
  return;
23600
- case "undo":
23601
- undoSlotRemoval();
23602
- return;
23603
23535
  case "accept-unflagged":
23604
23536
  decide({ type: "accept-unflagged" });
23605
23537
  return;
@@ -26514,8 +26446,8 @@ function FieldEditor({
26514
26446
  return /* @__PURE__ */ jsxs22(Box21, { flexDirection: "column", width, borderStyle: "single", borderColor: PALETTE3.warning, children: [
26515
26447
  /* @__PURE__ */ jsx27(Text23, { bold: true, color: PALETTE3.warning, children: "FIELD EDITOR \u2014 no fields" }),
26516
26448
  /* @__PURE__ */ jsx27(Text23, { color: PALETTE3.warning, children: "\u26A0 No properties classified for this component. The LLM didn't find anything to classify." }),
26517
- /* @__PURE__ */ jsx27(Text23, { color: PALETTE3.muted, children: "There is nothing to edit here." }),
26518
- /* @__PURE__ */ jsx27(Text23, { color: PALETTE3.muted, children: active ? "[Esc] go back to the list" : "In the list: [r] reject this component \xB7 [a] accept it" })
26449
+ /* @__PURE__ */ jsx27(Text23, { color: PALETTE3.muted, children: "You can add fields manually below or reject this component." }),
26450
+ /* @__PURE__ */ jsx27(Text23, { color: PALETTE3.muted, children: "Enter to save \xB7 Esc to discard" })
26519
26451
  ] });
26520
26452
  }
26521
26453
  const hasEmptyProperties = props.length === 0 && slots.length === 0;
@@ -26730,7 +26662,7 @@ function FieldEditor({
26730
26662
  children: [
26731
26663
  hasEmptyProperties && /* @__PURE__ */ jsx27(Text23, { color: PALETTE3.warning, children: "\u26A0 No properties classified for this component. The LLM didn't find anything to classify. Reject this component or add fields manually." }),
26732
26664
  header,
26733
- /* @__PURE__ */ jsx27(Box21, { flexDirection: "column", width: innerWidth, flexShrink: 0, children: focusLevel === "field" && !inComponentDesc && !inSlots && currentProp ? /* @__PURE__ */ jsx27(
26665
+ /* @__PURE__ */ jsx27(Box21, { flexDirection: "column", width: innerWidth, flexShrink: 0, children: focusLevel === "field" && !inComponentDesc && currentProp ? /* @__PURE__ */ jsx27(
26734
26666
  PropRow,
26735
26667
  {
26736
26668
  prop: currentProp,
@@ -27734,7 +27666,6 @@ function finalizeReviewSession(extractSessionId, components) {
27734
27666
  db.exec("ROLLBACK");
27735
27667
  throw error;
27736
27668
  }
27737
- removeSlotAllowedComponents(db, extractSessionId, [], toReject);
27738
27669
  } finally {
27739
27670
  db.close();
27740
27671
  }
@@ -29513,50 +29444,33 @@ function GenerateReviewStepView({
29513
29444
  const cycle = cycleRows[cyclesCursor];
29514
29445
  return cycle ? enumerateCycleBreaks(cycle, components) : [];
29515
29446
  }, [cycleRows, cyclesCursor, components]);
29516
- const saveSlotChange = (parentKey, nextEntry, historyLabel) => {
29447
+ const handleBreakEdge = (edge) => {
29448
+ const target = components.find((component) => component.key === edge.fromComponent);
29449
+ const slot = target?.entry.$slots?.[edge.slotName];
29450
+ if (!target || !slot || !Array.isArray(slot.$allowedComponents)) return;
29451
+ const nextEntry = {
29452
+ ...target.entry,
29453
+ $slots: {
29454
+ ...target.entry.$slots,
29455
+ [edge.slotName]: {
29456
+ ...slot,
29457
+ $allowedComponents: slot.$allowedComponents.filter((value) => value !== edge.toComponent)
29458
+ }
29459
+ }
29460
+ };
29517
29461
  const next = components.map(
29518
- (component) => component.key === parentKey ? { ...component, entry: nextEntry } : component
29462
+ (component) => component.key === target.key ? { ...component, entry: nextEntry } : component
29519
29463
  );
29520
29464
  setComponents(next);
29521
29465
  const db = openPipelineDb();
29522
29466
  try {
29523
- storeCDFComponents(db, extractSessionId, [{ key: parentKey, entry: nextEntry }]);
29467
+ storeCDFComponents(db, extractSessionId, [{ key: target.key, entry: nextEntry }]);
29524
29468
  } finally {
29525
29469
  db.close();
29526
29470
  }
29527
29471
  recomputeCycles(next);
29528
29472
  livePreviewHook.trigger();
29529
- pushHistorySnapshot(next, historyLabel);
29530
- };
29531
- const handleBreakEdge = (edge) => {
29532
- const target = components.find((component) => component.key === edge.fromComponent);
29533
- const slot = target?.entry.$slots?.[edge.slotName];
29534
- if (!target || !slot || !Array.isArray(slot.$allowedComponents)) return;
29535
- saveSlotChange(
29536
- target.key,
29537
- {
29538
- ...target.entry,
29539
- $slots: {
29540
- ...target.entry.$slots,
29541
- [edge.slotName]: {
29542
- ...slot,
29543
- $allowedComponents: slot.$allowedComponents.filter((value) => value !== edge.toComponent)
29544
- }
29545
- }
29546
- },
29547
- "break-cycle-edge"
29548
- );
29549
- };
29550
- const handleRemoveSlotChild = (parentKey, childKey) => {
29551
- const parent = components.find((component) => component.key === parentKey);
29552
- if (!parent?.entry.$slots) return;
29553
- const slots = Object.fromEntries(
29554
- Object.entries(parent.entry.$slots).map(([slotName, slot]) => [
29555
- slotName,
29556
- Array.isArray(slot.$allowedComponents) ? { ...slot, $allowedComponents: slot.$allowedComponents.filter((value) => value !== childKey) } : slot
29557
- ])
29558
- );
29559
- saveSlotChange(parentKey, { ...parent.entry, $slots: slots }, "remove-slot-child");
29473
+ pushHistorySnapshot(next, "break-cycle-edge");
29560
29474
  };
29561
29475
  const handleRejectComponent = (key) => {
29562
29476
  const rejectCascade2 = computeRejectCascade(key, componentGraph);
@@ -29886,11 +29800,6 @@ function GenerateReviewStepView({
29886
29800
  if (input === "r") {
29887
29801
  const current = components[selectedIdx];
29888
29802
  if (!current) return;
29889
- const row = visibleRowsMemo[cursorRowIdx];
29890
- if (row?.kind === "group-child" && row.parentName) {
29891
- handleRemoveSlotChild(row.parentName, current.key);
29892
- return;
29893
- }
29894
29803
  handleRejectComponent(current.key);
29895
29804
  return;
29896
29805
  }
@@ -31225,7 +31134,6 @@ var init_run_teaser = __esm({
31225
31134
  });
31226
31135
 
31227
31136
  // packages/experience-design-system-cli/src/tui/import/steps/10-flow/flow/screen.tsx
31228
- import { useEffect as useEffect20, useRef as useRef12 } from "react";
31229
31137
  import { Box as Box41 } from "ink";
31230
31138
  import { jsx as jsx52, jsxs as jsxs42 } from "react/jsx-runtime";
31231
31139
  function totalStepsFor(state) {
@@ -31241,18 +31149,10 @@ function FlowScreen({
31241
31149
  controller,
31242
31150
  livePreview = true,
31243
31151
  generatePromptPath,
31244
- onExit,
31245
- onStepChange
31152
+ onExit
31246
31153
  }) {
31247
31154
  const totalSteps = totalStepsFor(state);
31248
31155
  const quit = () => onExit(0);
31249
- const previousStep = useRef12(state.step);
31250
- useEffect20(() => {
31251
- if (previousStep.current !== state.step) {
31252
- onStepChange?.();
31253
- previousStep.current = state.step;
31254
- }
31255
- }, [state.step, onStepChange]);
31256
31156
  const content = (() => {
31257
31157
  switch (state.step) {
31258
31158
  case "final-review":
@@ -32020,6 +31920,12 @@ function createFlowController(start, deps) {
32020
31920
  deps.log({ update: sanitizeForLog(patch) });
32021
31921
  } catch {
32022
31922
  }
31923
+ if (patch.step !== void 0 && patch.step !== state.step) {
31924
+ try {
31925
+ deps.beforeStepChange?.();
31926
+ } catch {
31927
+ }
31928
+ }
32023
31929
  state = { ...state, ...patch };
32024
31930
  for (const listener of listeners) listener();
32025
31931
  };
@@ -32172,22 +32078,26 @@ var init_controller = __esm({
32172
32078
  });
32173
32079
 
32174
32080
  // packages/experience-design-system-cli/src/tui/import/steps/10-flow/flow/use-flow.ts
32175
- import { useEffect as useEffect21, useRef as useRef13, useSyncExternalStore } from "react";
32176
- function useFlow(start, deps = realFlowDeps) {
32177
- const controller = useRef13();
32081
+ import { useEffect as useEffect20, useRef as useRef12, useSyncExternalStore } from "react";
32082
+ function useFlow(start, options = {}) {
32083
+ const controller = useRef12();
32178
32084
  if (start && !controller.current) {
32179
32085
  try {
32180
32086
  startWizardLog();
32181
32087
  } catch {
32182
32088
  }
32183
- controller.current = createFlowController(start, deps());
32089
+ const flowDeps = (options.deps ?? realFlowDeps)();
32090
+ controller.current = createFlowController(start, {
32091
+ ...flowDeps,
32092
+ ...options.beforeStepChange ? { beforeStepChange: options.beforeStepChange } : {}
32093
+ });
32184
32094
  }
32185
32095
  const current = controller.current;
32186
32096
  const state = useSyncExternalStore(
32187
32097
  (listener) => current?.subscribe(listener) ?? (() => void 0),
32188
32098
  () => current?.getState()
32189
32099
  );
32190
- useEffect21(() => {
32100
+ useEffect20(() => {
32191
32101
  if (!start) controller.current = void 0;
32192
32102
  }, [start]);
32193
32103
  return current && state ? { controller: current, state } : void 0;
@@ -32400,7 +32310,7 @@ var init_help_info = __esm({
32400
32310
  });
32401
32311
 
32402
32312
  // packages/experience-design-system-cli/src/tui/help/PageContainer.tsx
32403
- import { useEffect as useEffect22, useState as useState27 } from "react";
32313
+ import { useEffect as useEffect21, useState as useState27 } from "react";
32404
32314
  import { Box as Box42, Text as Text44, useInput as useInput9 } from "ink";
32405
32315
  import { Fragment as Fragment16, jsx as jsx53, jsxs as jsxs43 } from "react/jsx-runtime";
32406
32316
  function Section({ title, rows }) {
@@ -32414,7 +32324,7 @@ function Section({ title, rows }) {
32414
32324
  }
32415
32325
  function HelpScreen({ onDone }) {
32416
32326
  const [info, setInfo] = useState27();
32417
- useEffect22(() => {
32327
+ useEffect21(() => {
32418
32328
  startDebugRun({ flow: "help", step: "01-help", menuOption: "Help", inputs: {} });
32419
32329
  void readHelpInfo().then(setInfo);
32420
32330
  }, []);
@@ -32563,7 +32473,7 @@ var init_config_store = __esm({
32563
32473
  });
32564
32474
 
32565
32475
  // packages/experience-design-system-cli/src/tui/settings/contentful-configuration/ContentfulConfigScreen.tsx
32566
- import { useEffect as useEffect23, useState as useState29 } from "react";
32476
+ import { useEffect as useEffect22, useState as useState29 } from "react";
32567
32477
  import { Box as Box44, Text as Text46, useInput as useInput11 } from "ink";
32568
32478
  import TextInput4 from "ink-text-input";
32569
32479
  import { Fragment as Fragment17, jsx as jsx55, jsxs as jsxs45 } from "react/jsx-runtime";
@@ -32585,7 +32495,7 @@ function ConfigurationScreen({ onDone }) {
32585
32495
  const [lastSaved, setLastSaved] = useState29(null);
32586
32496
  const [editing, setEditing] = useState29(false);
32587
32497
  const [valueBeforeEdit, setValueBeforeEdit] = useState29("");
32588
- useEffect23(() => {
32498
+ useEffect22(() => {
32589
32499
  readCredentials().then((cfg) => {
32590
32500
  setConfig(cfg);
32591
32501
  setStage("form");
@@ -32769,13 +32679,13 @@ var init_analytics_store = __esm({
32769
32679
  });
32770
32680
 
32771
32681
  // packages/experience-design-system-cli/src/tui/settings/opt-in-analytics/screen.tsx
32772
- import { useEffect as useEffect24, useState as useState30 } from "react";
32682
+ import { useEffect as useEffect23, useState as useState30 } from "react";
32773
32683
  import { Box as Box45, Text as Text47, useInput as useInput12 } from "ink";
32774
32684
  import { Fragment as Fragment18, jsx as jsx56, jsxs as jsxs46 } from "react/jsx-runtime";
32775
32685
  function OptInAnalyticsScreen({ onDone }) {
32776
32686
  const [loading, setLoading] = useState30(true);
32777
32687
  const [enabled, setEnabled] = useState30(true);
32778
- useEffect24(() => {
32688
+ useEffect23(() => {
32779
32689
  readAnalyticsSetting().then((setting) => {
32780
32690
  setEnabled(setting.enabled);
32781
32691
  setLoading(false);
@@ -32838,12 +32748,12 @@ var init_screen11 = __esm({
32838
32748
  });
32839
32749
 
32840
32750
  // packages/experience-design-system-cli/src/tui/upgrade/PageContainer.tsx
32841
- import { useEffect as useEffect25, useState as useState31 } from "react";
32751
+ import { useEffect as useEffect24, useState as useState31 } from "react";
32842
32752
  import { Box as Box46, Text as Text48, useInput as useInput13 } from "ink";
32843
32753
  import { jsx as jsx57, jsxs as jsxs47 } from "react/jsx-runtime";
32844
32754
  function UpgradeScreen({ onDone }) {
32845
32755
  const [upgradeCheck, setUpgradeCheck] = useState31();
32846
- useEffect25(() => {
32756
+ useEffect24(() => {
32847
32757
  startDebugRun({
32848
32758
  flow: "upgrade",
32849
32759
  step: "01-upgrade",
@@ -32918,13 +32828,13 @@ var init_PageContainer4 = __esm({
32918
32828
  });
32919
32829
 
32920
32830
  // packages/experience-design-system-cli/src/tui/settings/debug-mode/screen.tsx
32921
- import { useEffect as useEffect26, useState as useState32 } from "react";
32831
+ import { useEffect as useEffect25, useState as useState32 } from "react";
32922
32832
  import { Box as Box47, Text as Text49, useInput as useInput14 } from "ink";
32923
32833
  import { jsx as jsx58, jsxs as jsxs48 } from "react/jsx-runtime";
32924
32834
  function DebugModeScreen({ onDone }) {
32925
32835
  const [loading, setLoading] = useState32(true);
32926
32836
  const [enabled, setEnabled] = useState32(true);
32927
- useEffect26(() => {
32837
+ useEffect25(() => {
32928
32838
  readDebugModeSetting().then((setting) => {
32929
32839
  setEnabled(setting.enabled);
32930
32840
  setLoading(false);
@@ -32987,7 +32897,7 @@ __export(app_exports, {
32987
32897
  runApp: () => runApp
32988
32898
  });
32989
32899
  import { join as join27 } from "node:path";
32990
- import { useEffect as useEffect27, useState as useState33 } from "react";
32900
+ import { useEffect as useEffect26, useState as useState33 } from "react";
32991
32901
  import { Fragment as Fragment19, jsx as jsx59 } from "react/jsx-runtime";
32992
32902
  function App({ importOptions, inkClear }) {
32993
32903
  const [screen, setScreen] = useState33("start");
@@ -33017,9 +32927,9 @@ function App({ importOptions, inkClear }) {
33017
32927
  const [generationInput, setGenerationInput] = useState33();
33018
32928
  const generation = useGeneration(generationInput);
33019
32929
  const [flowStart, setFlowStart] = useState33();
33020
- const flow = useFlow(flowStart);
32930
+ const flow = useFlow(flowStart, { beforeStepChange: inkClear });
33021
32931
  const [importDefaults, setImportDefaults] = useState33();
33022
- useEffect27(() => {
32932
+ useEffect26(() => {
33023
32933
  if (screen !== "import") {
33024
32934
  setImportDefaults(void 0);
33025
32935
  return;
@@ -33077,12 +32987,12 @@ function App({ importOptions, inkClear }) {
33077
32987
  }
33078
32988
  });
33079
32989
  };
33080
- useEffect27(() => {
32990
+ useEffect26(() => {
33081
32991
  if (!extractionRun || extraction?.status !== "done" || !extraction.result.ok) return;
33082
32992
  setExtractionRun(void 0);
33083
32993
  setScopeRun({ ...extractionRun, extraction: extraction.result.extraction });
33084
32994
  }, [extraction, extractionRun]);
33085
- useEffect27(() => {
32995
+ useEffect26(() => {
33086
32996
  if (!scopeRun || scopeFlow?.status !== "confirmed" || generationInput) return;
33087
32997
  const { extraction: produced, input, generatePromptPath } = scopeRun;
33088
32998
  setGenerationInput({
@@ -33100,7 +33010,7 @@ function App({ importOptions, inkClear }) {
33100
33010
  ...generatePromptPath ? { generatePromptPath } : {}
33101
33011
  });
33102
33012
  }, [scopeFlow, scopeRun, generationInput]);
33103
- useEffect27(() => {
33013
+ useEffect26(() => {
33104
33014
  if (!scopeRun || generation?.status !== "done" || !generation.result.ok) return;
33105
33015
  const { credentialsSkipped, tokenStrategy, extraction: produced, input, generatePromptPath } = scopeRun;
33106
33016
  inkClear();
@@ -33151,8 +33061,7 @@ function App({ importOptions, inkClear }) {
33151
33061
  state: flow.state,
33152
33062
  controller: flow.controller,
33153
33063
  generatePromptPath: flowStart.generatePromptPath,
33154
- onExit: setImportExitCode,
33155
- onStepChange: inkClear
33064
+ onExit: setImportExitCode
33156
33065
  }
33157
33066
  );
33158
33067
  }
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contentful/experience-design-system-cli",
3
- "version": "2.37.1-dev-build-e2dab518.0",
3
+ "version": "2.37.1-dev-build-97b615d3.0",
4
4
  "description": "Contentful Experiences design system import CLI",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -80,7 +80,5 @@ export type GateAction = {
80
80
  type: 'toggle-jump-filter';
81
81
  } | {
82
82
  type: 'toggle-view';
83
- } | {
84
- type: 'undo';
85
83
  };
86
84
  export declare function resolveKey(mode: GateMode, key: KeyPress, ctx: GateContext): GateAction;
@@ -1,4 +1,4 @@
1
1
  export declare function CompactControlBar({ hasGroupRoots, searchActive }: {
2
2
  hasGroupRoots: boolean;
3
3
  searchActive: boolean;
4
- }): import("react/jsx-runtime").JSX.Element;
4
+ }): import("react").JSX.Element;
@@ -45,8 +45,6 @@ export interface VisibleRow {
45
45
  cycleChild?: boolean;
46
46
  itemIdx: number;
47
47
  rootName?: string;
48
- /** The parent whose slot the nested row sits in. */
49
- parentName?: string;
50
48
  }
51
49
  export declare function buildVisibleRows(props: {
52
50
  items: GroupedSidebarItem[];
@@ -1,5 +1,5 @@
1
1
  import { type ScopeGraph } from './graph/index.js';
2
- import type { Decision, ParentChildEdge, ScopeComponent, ScopeDecisions } from './types.js';
2
+ import type { Decision, ScopeComponent, ScopeDecisions } from './types.js';
3
3
  export type DecisionState = Map<string, Decision>;
4
4
  export type DecisionAction = {
5
5
  type: 'accept';
@@ -15,6 +15,5 @@ export type DecisionAction = {
15
15
  export declare function reduceDecisions(state: DecisionState, action: DecisionAction, components: ScopeComponent[], graph: ScopeGraph): DecisionState;
16
16
  /** Whether rejecting `name` touches 2 or more other components, so the screen has to ask first. */
17
17
  export declare function rejectNeedsConfirmation(graph: ScopeGraph, name: string, state: DecisionState): boolean;
18
- export declare function withoutSlotChildren(components: ScopeComponent[], removedEdges: ParentChildEdge[]): ScopeComponent[];
19
18
  /** Everything not accepted counts as rejected, as legacy's `partition` did. */
20
- export declare function partitionDecisions(components: ScopeComponent[], state: DecisionState, removedEdges: ParentChildEdge[]): ScopeDecisions;
19
+ export declare function partitionDecisions(components: ScopeComponent[], state: DecisionState): ScopeDecisions;
@@ -10,17 +10,10 @@ export type ScopeComponent = Omit<ScopeComponentRow, 'aiDecision' | 'aiReason' |
10
10
  slots?: ScopeComponentRow['slots'];
11
11
  };
12
12
  export type Decision = 'accepted' | 'rejected' | 'undecided';
13
- /** One slot edge: `parent` allows `child` in a slot. */
14
- export interface ParentChildEdge {
15
- parent: string;
16
- child: string;
17
- }
18
13
  /** What the user confirmed. Becomes `ImportHandoff.scope`; the legacy wizard saves it and starts generation. */
19
14
  export interface ScopeDecisions {
20
15
  accepted: string[];
21
16
  rejected: string[];
22
- /** Slot edges removed at the gate. The child keeps its own decision. Missing means none were removed. */
23
- excludedSlotEdges?: ParentChildEdge[];
24
17
  }
25
18
  export type ScopeGateLoad = {
26
19
  ok: true;
@@ -10,7 +10,7 @@ export interface PendingRejectCascade {
10
10
  ancestors: string[];
11
11
  descendants: string[];
12
12
  }
13
- export declare function useScopeGate({ components: loadedComponents, onConfirm, onQuit }: UseScopeGateOptions): {
13
+ export declare function useScopeGate({ components, onConfirm, onQuit }: UseScopeGateOptions): {
14
14
  totalWidth: number;
15
15
  columnPlan: {
16
16
  layout: "single" | "two-column";
@@ -1,9 +1,11 @@
1
1
  import type { GenerationHandoff } from '@contentful/experience-design-system-types/handoff';
2
- import type { ScopeDecisions } from '../07-scope-gate/types.js';
3
2
  export interface GenerationInput {
4
3
  /** The extraction session the scope was decided on. */
5
4
  sessionId: string;
6
- decisions: ScopeDecisions;
5
+ decisions: {
6
+ accepted: string[];
7
+ rejected: string[];
8
+ };
7
9
  /**
8
10
  * The cache check that ran while the scope gate was open, which restores cached definitions into the pipeline
9
11
  * database. The stage waits for it before saving the decisions, since both write to that database.
@@ -38,6 +38,12 @@ export interface FlowDeps {
38
38
  /** Writes one line of the wizard's step log. */
39
39
  log: (entry: Record<string, unknown>) => void;
40
40
  stderr: (text: string) => void;
41
+ /**
42
+ * Called when the step is about to change, before anything is told about the new one. The host clears the terminal
43
+ * here so the next screen is drawn on a clean one. It has to be before: Ink paints as soon as it is told, and a clear
44
+ * after the paint wipes a static screen like the done step, which nothing draws again.
45
+ */
46
+ beforeStepChange?: () => void;
41
47
  }
42
48
  export declare function startWizardLog(): void;
43
49
  export declare function realFlowDeps(): FlowDeps;
@@ -8,12 +8,10 @@ interface FlowScreenProps {
8
8
  generatePromptPath?: string;
9
9
  /** Leaves the import with the exit code the wizard would have exited with. */
10
10
  onExit: (exitCode: number) => void;
11
- /** Called when the step changes so the host can clear Ink's render buffer without scrollback pollution. */
12
- onStepChange?: () => void;
13
11
  }
14
12
  /** How many steps the import has, as the wizard counted them. */
15
13
  export declare function totalStepsFor(state: Pick<FlowState, 'tokensPath' | 'rawTokensPath' | 'mapTokensEligible'>): number;
16
14
  /** Whether the preview gate offers "[e] Edit definitions": only when the document has components to edit. */
17
15
  export declare function canEditFromPreview(cdf: FlowState['cdf']): boolean;
18
- export declare function FlowScreen({ state, controller, livePreview, generatePromptPath, onExit, onStepChange, }: FlowScreenProps): React.ReactElement;
16
+ export declare function FlowScreen({ state, controller, livePreview, generatePromptPath, onExit, }: FlowScreenProps): React.ReactElement;
19
17
  export {};
@@ -3,7 +3,10 @@ import { type FlowController, type FlowDeps, type FlowStart } from './controller
3
3
  * The flow for a start, once. `start` is undefined until the generation stage has finished, so the hook can be called
4
4
  * unconditionally; the step log is started with the controller, as the wizard started it with its first render.
5
5
  */
6
- export declare function useFlow(start: FlowStart | undefined, deps?: () => FlowDeps): {
6
+ export declare function useFlow(start: FlowStart | undefined, options?: {
7
+ beforeStepChange?: () => void;
8
+ deps?: () => FlowDeps;
9
+ }): {
7
10
  controller: FlowController;
8
11
  state: ReturnType<FlowController['getState']>;
9
12
  } | undefined;
package/legacy/bin/cli.js CHANGED
File without changes
@@ -6,19 +6,19 @@ type PreferenceScreenProps = {
6
6
  export declare const PREFERENCE_OPTIONS: readonly [{
7
7
  readonly key: "customPrompts";
8
8
  readonly label: "Custom prompts";
9
- readonly Screen: ({ onDone }: PreferenceScreenProps) => import("react/jsx-runtime").JSX.Element;
9
+ readonly Screen: ({ onDone }: PreferenceScreenProps) => React.JSX.Element;
10
10
  }, {
11
11
  readonly key: "debug";
12
12
  readonly label: "Debug logging";
13
- readonly Screen: ({ onDone }: PreferenceScreenProps) => import("react/jsx-runtime").JSX.Element;
13
+ readonly Screen: ({ onDone }: PreferenceScreenProps) => React.JSX.Element;
14
14
  }, {
15
15
  readonly key: "analytics";
16
16
  readonly label: "Usage analytics";
17
- readonly Screen: ({ onDone }: PreferenceScreenProps) => import("react/jsx-runtime").JSX.Element;
17
+ readonly Screen: ({ onDone }: PreferenceScreenProps) => React.JSX.Element;
18
18
  }, {
19
19
  readonly key: "noColor";
20
20
  readonly label: "Terminal colors";
21
- readonly Screen: ({ onDone }: PreferenceScreenProps) => import("react/jsx-runtime").JSX.Element;
21
+ readonly Screen: ({ onDone }: PreferenceScreenProps) => React.JSX.Element;
22
22
  }];
23
23
  export declare function PreferencesMenu({ onDone }: {
24
24
  onDone: StepDone;
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contentful/experience-design-system-cli",
3
- "version": "2.37.1-dev-build-e2dab518.0",
3
+ "version": "2.37.1-dev-build-97b615d3.0",
4
4
  "description": "Contentful Experiences design system import CLI",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contentful/experience-design-system-cli",
3
- "version": "2.37.1-dev-build-e2dab518.0",
3
+ "version": "2.37.1-dev-build-97b615d3.0",
4
4
  "description": "Contentful Experiences design system import CLI",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -29,6 +29,8 @@
29
29
  "skills/"
30
30
  ],
31
31
  "dependencies": {
32
+ "@contentful/experience-design-system-backend-pipeline": "2.37.1-dev-build-97b615d3.0",
33
+ "@contentful/experience-design-system-types": "2.37.1-dev-build-97b615d3.0",
32
34
  "@inkjs/ui": "^2.0.0",
33
35
  "@segment/analytics-node": "^3.0.0",
34
36
  "@vue/compiler-sfc": "^3.5.31",
@@ -44,9 +46,7 @@
44
46
  "svelte": "^5.56.4",
45
47
  "ts-morph": "^27.0.2",
46
48
  "typescript": "^5.9.3",
47
- "zod": "^4.6.5",
48
- "@contentful/experience-design-system-types": "2.37.1-dev-build-e2dab518.0",
49
- "@contentful/experience-design-system-backend-pipeline": "2.37.1-dev-build-e2dab518.0"
49
+ "zod": "^4.6.5"
50
50
  },
51
51
  "devDependencies": {
52
52
  "@tsconfig/node24": "^24.0.4",