@contentful/experience-design-system-cli 2.14.2 → 2.15.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.
Files changed (193) hide show
  1. package/README.md +64 -2
  2. package/dist/package.json +3 -2
  3. package/dist/src/analyze/command.d.ts +11 -0
  4. package/dist/src/analyze/command.js +298 -3
  5. package/dist/src/analyze/composite-closure.d.ts +25 -0
  6. package/dist/src/analyze/composite-closure.js +0 -0
  7. package/dist/src/analyze/composition/agent-parser/author-prompt.d.ts +4 -0
  8. package/dist/src/analyze/composition/agent-parser/author-prompt.js +22 -0
  9. package/dist/src/analyze/composition/agent-parser/extract-parser.d.ts +8 -0
  10. package/dist/src/analyze/composition/agent-parser/extract-parser.js +44 -0
  11. package/dist/src/analyze/composition/agent-parser/load-prompt.d.ts +7 -0
  12. package/dist/src/analyze/composition/agent-parser/load-prompt.js +31 -0
  13. package/dist/src/analyze/composition/agent-parser/resolve-via-parser.d.ts +46 -0
  14. package/dist/src/analyze/composition/agent-parser/resolve-via-parser.js +88 -0
  15. package/dist/src/analyze/composition/agent-parser/sandbox.d.ts +45 -0
  16. package/dist/src/analyze/composition/agent-parser/sandbox.js +187 -0
  17. package/dist/src/analyze/composition/apply-mapping.d.ts +22 -0
  18. package/dist/src/analyze/composition/apply-mapping.js +67 -0
  19. package/dist/src/analyze/composition/candidate-critic-agent.d.ts +7 -0
  20. package/dist/src/analyze/composition/candidate-critic-agent.js +39 -0
  21. package/dist/src/analyze/composition/candidate-critic.d.ts +32 -0
  22. package/dist/src/analyze/composition/candidate-critic.js +63 -0
  23. package/dist/src/analyze/composition/candidate-files.d.ts +34 -0
  24. package/dist/src/analyze/composition/candidate-files.js +131 -0
  25. package/dist/src/analyze/composition/composition-cache-key.d.ts +19 -0
  26. package/dist/src/analyze/composition/composition-cache-key.js +19 -0
  27. package/dist/src/analyze/composition/interchange-schema.d.ts +37 -0
  28. package/dist/src/analyze/composition/interchange-schema.js +61 -0
  29. package/dist/src/analyze/composition/merge-edges.d.ts +19 -0
  30. package/dist/src/analyze/composition/merge-edges.js +50 -0
  31. package/dist/src/analyze/composition/parse-map-edges.d.ts +16 -0
  32. package/dist/src/analyze/composition/parse-map-edges.js +55 -0
  33. package/dist/src/analyze/composition/resolve-mapping-cli.d.ts +23 -0
  34. package/dist/src/analyze/composition/resolve-mapping-cli.js +29 -0
  35. package/dist/src/analyze/composition/resolve-mapping.d.ts +59 -0
  36. package/dist/src/analyze/composition/resolve-mapping.js +94 -0
  37. package/dist/src/analyze/cycle-detection.d.ts +27 -0
  38. package/dist/src/analyze/cycle-detection.js +234 -0
  39. package/dist/src/analyze/cycle-view.d.ts +7 -0
  40. package/dist/src/analyze/cycle-view.js +28 -0
  41. package/dist/src/analyze/fuzzy-search.d.ts +3 -0
  42. package/dist/src/analyze/fuzzy-search.js +55 -0
  43. package/dist/src/analyze/issue-inheritance.d.ts +12 -0
  44. package/dist/src/analyze/issue-inheritance.js +108 -0
  45. package/dist/src/analyze/lineage.d.ts +29 -0
  46. package/dist/src/analyze/lineage.js +0 -0
  47. package/dist/src/analyze/scope-gate-cascade.d.ts +11 -0
  48. package/dist/src/analyze/scope-gate-cascade.js +170 -0
  49. package/dist/src/analyze/search-neighborhood.d.ts +3 -0
  50. package/dist/src/analyze/search-neighborhood.js +56 -0
  51. package/dist/src/analyze/select/tui/App.js +5 -16
  52. package/dist/src/analyze/select/tui/components/ComponentRationalePanel.d.ts +0 -4
  53. package/dist/src/analyze/select/tui/components/ComponentRationalePanel.js +3 -15
  54. package/dist/src/analyze/select/tui/components/FieldEditor.d.ts +29 -38
  55. package/dist/src/analyze/select/tui/components/FieldEditor.js +309 -185
  56. package/dist/src/analyze/select/tui/components/FinalizeDialog.d.ts +13 -1
  57. package/dist/src/analyze/select/tui/components/FinalizeDialog.js +23 -2
  58. package/dist/src/analyze/select/tui/components/GotoBanner.d.ts +31 -0
  59. package/dist/src/analyze/select/tui/components/GotoBanner.js +30 -0
  60. package/dist/src/analyze/select/tui/components/GroupedSidebar.d.ts +91 -0
  61. package/dist/src/analyze/select/tui/components/GroupedSidebar.js +497 -0
  62. package/dist/src/analyze/select/tui/components/HelpOverlay.d.ts +13 -1
  63. package/dist/src/analyze/select/tui/components/HelpOverlay.js +9 -3
  64. package/dist/src/analyze/select/tui/components/JsonEditor.js +3 -3
  65. package/dist/src/analyze/select/tui/components/LineagePanel.d.ts +14 -0
  66. package/dist/src/analyze/select/tui/components/LineagePanel.js +22 -0
  67. package/dist/src/analyze/select/tui/components/RationalePanel.d.ts +0 -7
  68. package/dist/src/analyze/select/tui/components/RationalePanel.js +3 -15
  69. package/dist/src/analyze/select/tui/components/Sidebar.d.ts +0 -6
  70. package/dist/src/analyze/select/tui/components/Sidebar.js +11 -27
  71. package/dist/src/analyze/select/tui/components/StatusBar.js +2 -1
  72. package/dist/src/analyze/select/tui/components/removed-components-text.d.ts +7 -0
  73. package/dist/src/analyze/select/tui/components/removed-components-text.js +11 -0
  74. package/dist/src/analyze/select/tui/hooks/useImmediateInput.d.ts +1 -5
  75. package/dist/src/analyze/select/tui/hooks/useImmediateInput.js +8 -10
  76. package/dist/src/analyze/select/tui/theme.d.ts +15 -0
  77. package/dist/src/analyze/select/tui/theme.js +28 -0
  78. package/dist/src/analyze/selection-cascade.d.ts +3 -0
  79. package/dist/src/analyze/selection-cascade.js +19 -0
  80. package/dist/src/analyze/slot-graph.d.ts +11 -0
  81. package/dist/src/analyze/slot-graph.js +17 -0
  82. package/dist/src/apply/api-client.d.ts +2 -1
  83. package/dist/src/apply/api-client.js +40 -6
  84. package/dist/src/apply/command.d.ts +17 -1
  85. package/dist/src/apply/command.js +69 -11
  86. package/dist/src/apply/error-parser.d.ts +16 -0
  87. package/dist/src/apply/error-parser.js +117 -0
  88. package/dist/src/apply/tui/ServerPreviewView.js +3 -1
  89. package/dist/src/credentials-store.d.ts +6 -0
  90. package/dist/src/credentials-store.js +5 -1
  91. package/dist/src/generate/agent-runner.d.ts +6 -0
  92. package/dist/src/generate/agent-runner.js +24 -8
  93. package/dist/src/import/command.js +69 -31
  94. package/dist/src/import/cycle-auto-reject.d.ts +4 -0
  95. package/dist/src/import/cycle-auto-reject.js +14 -0
  96. package/dist/src/import/orchestrator.d.ts +20 -7
  97. package/dist/src/import/orchestrator.js +139 -35
  98. package/dist/src/import/strip-allowed-components.d.ts +18 -0
  99. package/dist/src/import/strip-allowed-components.js +22 -0
  100. package/dist/src/import/tui/CustomPromptBanner.d.ts +0 -5
  101. package/dist/src/import/tui/CustomPromptBanner.js +2 -1
  102. package/dist/src/import/tui/WizardApp.d.ts +10 -74
  103. package/dist/src/import/tui/WizardApp.js +234 -246
  104. package/dist/src/import/tui/ai-flag.d.ts +5 -0
  105. package/dist/src/import/tui/ai-flag.js +6 -0
  106. package/dist/src/import/tui/autocomplete.d.ts +5 -0
  107. package/dist/src/import/tui/autocomplete.js +32 -0
  108. package/dist/src/import/tui/components/AutoFilterBanner.d.ts +10 -0
  109. package/dist/src/import/tui/components/AutoFilterBanner.js +19 -0
  110. package/dist/src/import/tui/components/CounterStrip.d.ts +12 -0
  111. package/dist/src/import/tui/components/CounterStrip.js +12 -0
  112. package/dist/src/import/tui/components/LegendEntry.d.ts +2 -0
  113. package/dist/src/import/tui/components/LegendEntry.js +6 -0
  114. package/dist/src/import/tui/cycle-panel-scroll.d.ts +8 -0
  115. package/dist/src/import/tui/cycle-panel-scroll.js +33 -0
  116. package/dist/src/import/tui/final-review-host.d.ts +3 -7
  117. package/dist/src/import/tui/final-review-host.js +9 -4
  118. package/dist/src/import/tui/group-collapse.d.ts +2 -0
  119. package/dist/src/import/tui/group-collapse.js +11 -0
  120. package/dist/src/import/tui/history.d.ts +22 -0
  121. package/dist/src/import/tui/history.js +53 -0
  122. package/dist/src/import/tui/hooks/useLineage.d.ts +32 -0
  123. package/dist/src/import/tui/hooks/useLineage.js +50 -0
  124. package/dist/src/import/tui/hooks/useOverlayPanel.d.ts +13 -0
  125. package/dist/src/import/tui/hooks/useOverlayPanel.js +27 -0
  126. package/dist/src/import/tui/lineage-layout.d.ts +75 -0
  127. package/dist/src/import/tui/lineage-layout.js +82 -0
  128. package/dist/src/import/tui/runLivePreview.d.ts +11 -0
  129. package/dist/src/import/tui/runLivePreview.js +7 -1
  130. package/dist/src/import/tui/scope-gate-columns.d.ts +31 -0
  131. package/dist/src/import/tui/scope-gate-columns.js +94 -0
  132. package/dist/src/import/tui/scope-gate-host.d.ts +3 -1
  133. package/dist/src/import/tui/scope-gate-host.js +11 -3
  134. package/dist/src/import/tui/sidebar-width.d.ts +1 -0
  135. package/dist/src/import/tui/sidebar-width.js +3 -0
  136. package/dist/src/import/tui/step-filters.d.ts +19 -0
  137. package/dist/src/import/tui/step-filters.js +42 -0
  138. package/dist/src/import/tui/steps/AtomicGenerateReviewStep.d.ts +42 -0
  139. package/dist/src/import/tui/steps/AtomicGenerateReviewStep.js +726 -0
  140. package/dist/src/import/tui/steps/AtomicScopeGateStep.d.ts +3 -0
  141. package/dist/src/import/tui/steps/AtomicScopeGateStep.js +211 -0
  142. package/dist/src/import/tui/steps/CredentialsStep.js +5 -18
  143. package/dist/src/import/tui/steps/DoneStep.d.ts +0 -2
  144. package/dist/src/import/tui/steps/DoneStep.js +3 -2
  145. package/dist/src/import/tui/steps/ErrorStep.js +2 -1
  146. package/dist/src/import/tui/steps/GenerateReviewStep.d.ts +19 -25
  147. package/dist/src/import/tui/steps/GenerateReviewStep.js +1258 -229
  148. package/dist/src/import/tui/steps/PathValidationStep.js +3 -2
  149. package/dist/src/import/tui/steps/PreviewStep.js +2 -1
  150. package/dist/src/import/tui/steps/PushDecisionGateStep.d.ts +0 -7
  151. package/dist/src/import/tui/steps/PushDecisionGateStep.js +3 -6
  152. package/dist/src/import/tui/steps/PushingStep.js +2 -1
  153. package/dist/src/import/tui/steps/RunningStep.d.ts +4 -1
  154. package/dist/src/import/tui/steps/RunningStep.js +3 -2
  155. package/dist/src/import/tui/steps/ScopeGateStep.d.ts +24 -0
  156. package/dist/src/import/tui/steps/ScopeGateStep.js +850 -193
  157. package/dist/src/import/tui/steps/TokenInputStep.js +2 -1
  158. package/dist/src/import/tui/steps/WelcomeStep.js +2 -1
  159. package/dist/src/import/tui/steps/WizardPreviewStep.d.ts +6 -0
  160. package/dist/src/import/tui/steps/WizardPreviewStep.js +95 -56
  161. package/dist/src/import/tui/steps/auto-reject-decision.d.ts +7 -0
  162. package/dist/src/import/tui/steps/auto-reject-decision.js +9 -0
  163. package/dist/src/import/tui/steps/breaking-change-format.d.ts +2 -0
  164. package/dist/src/import/tui/steps/breaking-change-format.js +24 -0
  165. package/dist/src/import/tui/steps/enumerate-cycle-breaks.d.ts +14 -0
  166. package/dist/src/import/tui/steps/enumerate-cycle-breaks.js +0 -0
  167. package/dist/src/import/tui/steps/preview-diff.js +48 -5
  168. package/dist/src/import/tui/useFinalizePreview.d.ts +34 -0
  169. package/dist/src/import/tui/useFinalizePreview.js +0 -0
  170. package/dist/src/import/tui/useLivePreview.d.ts +3 -0
  171. package/dist/src/import/tui/useLivePreview.js +1 -0
  172. package/dist/src/import/tui/wizard-state-transitions.d.ts +5 -59
  173. package/dist/src/import/tui/wizard-state-transitions.js +5 -60
  174. package/dist/src/lib/composition-mode.d.ts +28 -0
  175. package/dist/src/lib/composition-mode.js +37 -0
  176. package/dist/src/lib/prompt-overrides.d.ts +38 -0
  177. package/dist/src/lib/prompt-overrides.js +69 -0
  178. package/dist/src/print/command.js +19 -1
  179. package/dist/src/runs/modify-launcher.d.ts +3 -0
  180. package/dist/src/runs/modify-launcher.js +2 -0
  181. package/dist/src/runs/replay-helpers.js +1 -0
  182. package/dist/src/runs/run-picker.js +2 -18
  183. package/dist/src/runs/store.d.ts +4 -0
  184. package/dist/src/session/db.d.ts +23 -40
  185. package/dist/src/session/db.js +110 -138
  186. package/dist/src/setup/composition-mode-prompt.d.ts +14 -0
  187. package/dist/src/setup/composition-mode-prompt.js +37 -0
  188. package/package.json +5 -4
  189. package/prompts/composition-dir-critic.md +7 -0
  190. package/prompts/composition-edges.md +8 -0
  191. package/prompts/composition-parser-repair-empty.md +1 -0
  192. package/prompts/composition-parser-repair-error.md +2 -0
  193. package/prompts/composition-parser.md +42 -0
@@ -0,0 +1,3 @@
1
+ import React from 'react';
2
+ import type { ScopeGateStepProps } from './ScopeGateStep.js';
3
+ export declare function AtomicScopeGateStep({ components, onConfirm, onQuit, aiFilterStatus, aiFilterProgress, aiFilterError, onCancelAutoFilter, }: ScopeGateStepProps): React.ReactElement;
@@ -0,0 +1,211 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Box, Text, useStdout } from 'ink';
3
+ import React, { useMemo, useState } from 'react';
4
+ import { useImmediateInput } from '../../../analyze/select/tui/hooks/useImmediateInput.js';
5
+ import { PALETTE } from '../../../analyze/select/tui/theme.js';
6
+ import { AutoFilterBanner } from '../components/AutoFilterBanner.js';
7
+ import { CounterStrip } from '../components/CounterStrip.js';
8
+ import { isAiFlagged } from '../ai-flag.js';
9
+ // Atomic-mode scope gate (spec T9). Recovered from the pre-composite `main`
10
+ // implementation: a flat included/excluded list with NO hierarchy affordances
11
+ // (no closures, cycles, cascade, lineage, grouped sidebar, or graph). Styling
12
+ // is ported to PALETTE and the shared AutoFilterBanner/CounterStrip so it reads
13
+ // as the same product as its composite sibling — "fewer panels, identical look."
14
+ const VISIBLE_COUNT = 10;
15
+ const REASON_DISPLAY_MAX = 60;
16
+ const AI_MARKER = '*';
17
+ const REASON_WRAP_INDENT = ' ';
18
+ function truncateReason(reason) {
19
+ if (reason === null || reason === undefined || reason === '')
20
+ return '<no reason given>';
21
+ if (reason.length <= REASON_DISPLAY_MAX)
22
+ return reason;
23
+ return reason.slice(0, REASON_DISPLAY_MAX - 1).trimEnd() + '…';
24
+ }
25
+ export function AtomicScopeGateStep({ components, onConfirm, onQuit, aiFilterStatus = 'idle', aiFilterProgress = null, aiFilterError = null, onCancelAutoFilter, }) {
26
+ const { stdout } = useStdout();
27
+ const totalWidth = stdout?.columns ?? 80;
28
+ // Inverted "included" model, kept from `main` (deliberately NOT the
29
+ // composite step's userDecisions Map — see spec T9 "what to NOT share").
30
+ const [userExcluded, setUserExcluded] = useState(new Set());
31
+ const [userUnExcluded, setUserUnExcluded] = useState(new Set());
32
+ const [cursor, setCursor] = useState(0);
33
+ const [scrollOffset, setScrollOffset] = useState(0);
34
+ const [reasonPanelOpen, setReasonPanelOpen] = useState(false);
35
+ const aiList = components.filter(isAiFlagged);
36
+ const componentsList = components.filter((c) => !isAiFlagged(c));
37
+ const flatList = [...aiList, ...componentsList];
38
+ const isIncluded = (row) => {
39
+ if (userExcluded.has(row.name))
40
+ return false;
41
+ if (userUnExcluded.has(row.name))
42
+ return true;
43
+ // INTEG-4318: exclude on 'rejected' AND 'failed'.
44
+ return row.aiDecision !== 'rejected' && row.aiDecision !== 'failed';
45
+ };
46
+ const partition = () => {
47
+ const accepted = [];
48
+ const rejected = [];
49
+ for (const c of flatList) {
50
+ if (isIncluded(c))
51
+ accepted.push(c.name);
52
+ else
53
+ rejected.push(c.name);
54
+ }
55
+ return { accepted, rejected };
56
+ };
57
+ const toggleFocused = () => {
58
+ const target = flatList[cursor];
59
+ if (!target)
60
+ return;
61
+ const currentlyIn = isIncluded(target);
62
+ if (currentlyIn) {
63
+ setUserExcluded((prev) => {
64
+ if (prev.has(target.name))
65
+ return prev;
66
+ const next = new Set(prev);
67
+ next.add(target.name);
68
+ return next;
69
+ });
70
+ setUserUnExcluded((prev) => {
71
+ if (!prev.has(target.name))
72
+ return prev;
73
+ const next = new Set(prev);
74
+ next.delete(target.name);
75
+ return next;
76
+ });
77
+ }
78
+ else {
79
+ setUserUnExcluded((prev) => {
80
+ if (prev.has(target.name))
81
+ return prev;
82
+ const next = new Set(prev);
83
+ next.add(target.name);
84
+ return next;
85
+ });
86
+ setUserExcluded((prev) => {
87
+ if (!prev.has(target.name))
88
+ return prev;
89
+ const next = new Set(prev);
90
+ next.delete(target.name);
91
+ return next;
92
+ });
93
+ }
94
+ };
95
+ useImmediateInput((input, key) => {
96
+ if (input === 'q' || key.escape) {
97
+ if (aiFilterStatus === 'running' && onCancelAutoFilter) {
98
+ onCancelAutoFilter();
99
+ return;
100
+ }
101
+ if (key.escape && reasonPanelOpen) {
102
+ setReasonPanelOpen(false);
103
+ return;
104
+ }
105
+ onQuit();
106
+ return;
107
+ }
108
+ if (input === 'f' || input === 'F') {
109
+ onConfirm(partition());
110
+ return;
111
+ }
112
+ if (input === 's') {
113
+ setReasonPanelOpen((prev) => !prev);
114
+ return;
115
+ }
116
+ if (input === 'a' || input === ' ' || input === 'r') {
117
+ toggleFocused();
118
+ return;
119
+ }
120
+ if (input === 'A') {
121
+ const compNames = componentsList.map((c) => c.name);
122
+ const anyCompExcluded = componentsList.some((c) => !isIncluded(c));
123
+ if (anyCompExcluded) {
124
+ setUserUnExcluded((prev) => {
125
+ const next = new Set(prev);
126
+ for (const n of compNames)
127
+ next.add(n);
128
+ return next;
129
+ });
130
+ setUserExcluded((prev) => {
131
+ const next = new Set(prev);
132
+ for (const n of compNames)
133
+ next.delete(n);
134
+ return next;
135
+ });
136
+ }
137
+ else {
138
+ setUserExcluded((prev) => {
139
+ const next = new Set(prev);
140
+ for (const n of compNames)
141
+ next.add(n);
142
+ return next;
143
+ });
144
+ setUserUnExcluded((prev) => {
145
+ const next = new Set(prev);
146
+ for (const n of compNames)
147
+ next.delete(n);
148
+ return next;
149
+ });
150
+ }
151
+ return;
152
+ }
153
+ if (key.upArrow || input === 'k') {
154
+ const len = flatList.length;
155
+ if (len === 0)
156
+ return;
157
+ setCursor((c) => {
158
+ const next = c <= 0 ? 0 : c - 1;
159
+ setScrollOffset((prev) => Math.min(prev, next));
160
+ return next;
161
+ });
162
+ return;
163
+ }
164
+ if (key.downArrow || input === 'j') {
165
+ const len = flatList.length;
166
+ if (len === 0)
167
+ return;
168
+ setCursor((c) => {
169
+ const next = c >= len - 1 ? len - 1 : c + 1;
170
+ setScrollOffset((prev) => (next >= prev + VISIBLE_COUNT ? next - VISIBLE_COUNT + 1 : prev));
171
+ return next;
172
+ });
173
+ return;
174
+ }
175
+ });
176
+ const total = flatList.length;
177
+ const includedCount = useMemo(() => flatList.filter((c) => isIncluded(c)).length, [components, userExcluded, userUnExcluded]);
178
+ const hasAnyAi = flatList.some(isAiFlagged);
179
+ const visibleEnd = Math.min(scrollOffset + VISIBLE_COUNT, total);
180
+ const visible = flatList.slice(scrollOffset, visibleEnd);
181
+ const above = scrollOffset;
182
+ const below = Math.max(0, total - visibleEnd);
183
+ const allRejected = aiFilterStatus === 'complete' && total > 0 && flatList.every((c) => !isIncluded(c));
184
+ // Atomic has no groups; the counter strip shows binary included/excluded.
185
+ const counters = {
186
+ accepted: includedCount,
187
+ rejected: total - includedCount,
188
+ undecided: 0,
189
+ groups: 0,
190
+ total,
191
+ };
192
+ return (_jsxs(Box, { flexDirection: "column", gap: 1, paddingX: 2, paddingY: 1, children: [_jsx(Text, { color: PALETTE.success, children: "\u2713 Extraction complete" }), _jsxs(Text, { dimColor: true, children: ["Found ", total, " component", total === 1 ? '' : 's', ". Pick which ones to import. Generation runs only on the included set."] }), _jsx(AutoFilterBanner, { status: aiFilterStatus, progress: aiFilterProgress, error: aiFilterError }), _jsx(CounterStrip, { counters: counters, totalWidth: totalWidth }), reasonPanelOpen && flatList[cursor] !== undefined && isAiFlagged(flatList[cursor]) && (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: PALETTE.border, paddingX: 1, marginTop: 1, children: [_jsx(Text, { dimColor: true, bold: true, children: `AI rejection reason: ${flatList[cursor].name}` }), _jsx(Text, { children: flatList[cursor].aiReason ?? '<no reason given>' }), _jsx(Text, { dimColor: true, children: "[s] close \u00B7 [Esc] close" })] })), allRejected ? (_jsx(Box, { marginTop: 1, children: _jsx(Text, { color: PALETTE.warning, children: "AI excluded all components \u2014 press [a] to override or [q] to quit" }) })) : (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [above > 0 && _jsxs(Text, { dimColor: true, children: ["\u2191 ", above, " above"] }), visible.map((c, vi) => {
193
+ const i = vi + scrollOffset;
194
+ const isCursor = i === cursor;
195
+ const included = isIncluded(c);
196
+ const aiFlagged = isAiFlagged(c);
197
+ const prefix = isCursor ? '›' : ' ';
198
+ const stateGlyph = included ? '[✓]' : '[✗]';
199
+ const stateColor = included ? PALETTE.success : PALETTE.error;
200
+ const aiMarkerNode = aiFlagged ? _jsx(Text, { color: PALETTE.info, children: `${AI_MARKER} ` }) : null;
201
+ const inlineReason = !isCursor && aiFlagged ? ` ${truncateReason(c.aiReason)}` : '';
202
+ const showAiHeader = aiList.length > 0 && i === 0;
203
+ const showComponentsHeader = componentsList.length > 0 && i === aiList.length;
204
+ const header = showAiHeader ? (_jsx(Text, { bold: true, children: `AI recommended exclusions (${aiList.length})` }, `hdr-ai-${i}`)) : showComponentsHeader ? (_jsx(Text, { bold: true, children: `Components (${componentsList.length})` }, `hdr-comp-${i}`)) : null;
205
+ if (isCursor) {
206
+ const wrapReason = aiFlagged && c.aiReason !== null && c.aiReason !== undefined && c.aiReason.length > 0;
207
+ return (_jsxs(React.Fragment, { children: [header, _jsxs(Text, { children: [_jsx(Text, { color: PALETTE.info, children: `${prefix} ` }), aiMarkerNode, _jsx(Text, { color: stateColor, children: stateGlyph }), _jsx(Text, { color: PALETTE.info, children: ` ${c.name}` })] }), wrapReason && _jsx(Text, { dimColor: true, children: `${REASON_WRAP_INDENT}${c.aiReason}` })] }, c.componentId));
208
+ }
209
+ return (_jsxs(React.Fragment, { children: [header, _jsxs(Text, { children: [_jsx(Text, { children: `${prefix} ` }), aiMarkerNode, _jsx(Text, { color: stateColor, children: stateGlyph }), _jsx(Text, { color: stateColor, children: ` ${c.name}` }), inlineReason !== '' && _jsx(Text, { dimColor: true, children: inlineReason })] })] }, c.componentId));
210
+ }), below > 0 && _jsxs(Text, { dimColor: true, children: ["\u2193 ", below, " below"] })] })), _jsxs(Box, { gap: 3, marginTop: 1, children: [includedCount > 0 ? (_jsxs(Text, { children: [_jsx(Text, { color: PALETTE.success, children: includedCount }), _jsxs(Text, { dimColor: true, children: ["/", total, " included"] })] })) : (_jsx(Text, { color: PALETTE.warning, children: "none included" })), _jsxs(Text, { children: [_jsx(Text, { color: PALETTE.info, children: "[j/k]" }), " ", _jsx(Text, { dimColor: true, children: "move" })] }), _jsxs(Text, { children: [_jsx(Text, { color: PALETTE.info, children: "[a/space]" }), " ", _jsx(Text, { dimColor: true, children: "toggle" })] }), _jsxs(Text, { children: [_jsx(Text, { color: PALETTE.info, children: "[A]" }), " ", _jsx(Text, { dimColor: true, children: "toggle all" })] }), _jsxs(Text, { children: [_jsx(Text, { color: PALETTE.info, children: "[f]" }), " ", _jsx(Text, { dimColor: true, children: "continue" })] }), _jsxs(Text, { children: [_jsx(Text, { color: PALETTE.info, children: "[q]" }), " ", _jsx(Text, { dimColor: true, children: "quit" })] }), hasAnyAi && (_jsxs(Text, { children: [_jsx(Text, { color: PALETTE.info, children: "[s]" }), " ", _jsx(Text, { dimColor: true, children: "AI reason" })] })), hasAnyAi && (_jsxs(Text, { children: [_jsx(Text, { color: PALETTE.info, children: "*" }), " ", _jsx(Text, { dimColor: true, children: "originally excluded by AI" })] }))] })] }));
211
+ }
@@ -1,5 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useState, useEffect, useRef } from 'react';
3
+ import { PALETTE } from '../../../analyze/select/tui/theme.js';
3
4
  import { Box, Text } from 'ink';
4
5
  import { useImmediateInput } from '../../../analyze/select/tui/hooks/useImmediateInput.js';
5
6
  import { DEFAULT_CONFIGURED_HOST, toConfiguredHost } from '../../../host-utils.js';
@@ -12,21 +13,12 @@ export function CredentialsStep({ summary, error: externalError, initialSpaceId
12
13
  const [activeField, setActiveField] = useState('spaceId');
13
14
  const [inlineError, setInlineError] = useState(null);
14
15
  const [cursorVisible, setCursorVisible] = useState(true);
15
- // Tracks whether the operator has typed any printable character into a
16
- // form field since mount. While false, the `s` keybind is interpreted as
17
- // the skip-credentials shortcut. Once the operator has begun typing, `s`
18
- // is routed into the active field as input (we don't want to swallow a
19
- // legitimate letter in a space ID / token / host).
20
16
  const hasTypedRef = useRef(false);
21
17
  useEffect(() => {
22
18
  const interval = setInterval(() => setCursorVisible((v) => !v), 500);
23
19
  return () => clearInterval(interval);
24
20
  }, []);
25
21
  useImmediateInput((input, key) => {
26
- // While we are validating credentials, the screen stays mounted but the
27
- // form is locked — any input is dropped. The exception is `R` when a
28
- // prefetch failed and we expose a retry hook (so the operator can recover
29
- // without backing out of the wizard).
30
22
  if (validating) {
31
23
  return;
32
24
  }
@@ -47,7 +39,6 @@ export function CredentialsStep({ summary, error: externalError, initialSpaceId
47
39
  setActiveField('host');
48
40
  return;
49
41
  }
50
- // Submit
51
42
  if (!spaceId.trim() || !environmentId.trim() || !cmaToken.trim()) {
52
43
  setInlineError('All fields are required.');
53
44
  return;
@@ -74,10 +65,6 @@ export function CredentialsStep({ summary, error: externalError, initialSpaceId
74
65
  onQuit();
75
66
  return;
76
67
  }
77
- // Skip-credentials shortcut. Gated against text-entry mode so the letter
78
- // 's' can still be typed into a form field once the operator has begun
79
- // editing. The legend hint is always rendered (see below) so operators
80
- // know the escape hatch exists from the moment the screen mounts.
81
68
  if ((input === 's' || input === 'S') && onSkip && !hasTypedRef.current) {
82
69
  onSkip();
83
70
  return;
@@ -110,12 +97,12 @@ export function CredentialsStep({ summary, error: externalError, initialSpaceId
110
97
  const isActive = activeField === field;
111
98
  const display = masked ? '•'.repeat(value.length) : value;
112
99
  const fallback = field === 'host' ? DEFAULT_CONFIGURED_HOST : _jsx(Text, { dimColor: true, children: "(empty)" });
113
- return (_jsxs(Box, { gap: 1, children: [_jsx(Text, { color: isActive ? 'cyan' : undefined, children: '?' }), _jsxs(Text, { bold: isActive, children: [label, ":"] }), _jsx(Text, { children: isActive ? display + cursor : display || fallback })] }));
100
+ return (_jsxs(Box, { gap: 1, children: [_jsx(Text, { color: isActive ? PALETTE.info : undefined, children: '?' }), _jsxs(Text, { bold: isActive, children: [label, ":"] }), _jsx(Text, { children: isActive ? display + cursor : display || fallback })] }));
114
101
  }
115
102
  const displayError = inlineError ?? externalError ?? null;
116
- return (_jsxs(Box, { flexDirection: "column", gap: 1, paddingX: 2, paddingY: 1, children: [summary && _jsxs(Text, { color: "green", children: ["\u2713 ", summary] }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { children: initialSpaceId && initialCmaToken
103
+ return (_jsxs(Box, { flexDirection: "column", gap: 1, paddingX: 2, paddingY: 1, children: [summary && _jsxs(Text, { color: PALETTE.success, children: ["\u2713 ", summary] }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { children: initialSpaceId && initialCmaToken
117
104
  ? 'Credentials pre-filled from experiences setup. Press Enter to continue or edit any field to update.'
118
- : 'Enter your Contentful credentials to continue.' }) }), !(initialSpaceId && initialCmaToken) && (_jsx(Text, { dimColor: true, children: "Tip: run experiences setup to save these to ~/.config/experiences/credentials.json so they pre-fill here automatically." })), _jsxs(Box, { flexDirection: "column", gap: 0, marginTop: 1, children: [renderField('Space ID', spaceId, 'spaceId'), renderField('Environment', environmentId, 'environmentId'), renderField('CMA Token', cmaToken, 'cmaToken', true), renderField('API Host', host, 'host')] }), activeField === 'host' && _jsx(Text, { dimColor: true, children: "Default: api.contentful.com \u00B7 EU spaces: api.eu.contentful.com" }), displayError && _jsxs(Text, { color: "red", children: ["\u2717 ", displayError] }), validating && (_jsx(Text, { color: "cyan", children: generatePrefetchStatus === 'running'
105
+ : 'Enter your Contentful credentials to continue.' }) }), !(initialSpaceId && initialCmaToken) && (_jsx(Text, { dimColor: true, children: "Tip: run experiences setup to save these to ~/.config/experiences/credentials.json so they pre-fill here automatically." })), _jsxs(Box, { flexDirection: "column", gap: 0, marginTop: 1, children: [renderField('Space ID', spaceId, 'spaceId'), renderField('Environment', environmentId, 'environmentId'), renderField('CMA Token', cmaToken, 'cmaToken', true), renderField('API Host', host, 'host')] }), activeField === 'host' && _jsx(Text, { dimColor: true, children: "Default: api.contentful.com \u00B7 EU spaces: api.eu.contentful.com" }), displayError && _jsxs(Text, { color: PALETTE.error, children: ["\u2717 ", displayError] }), validating && (_jsx(Text, { color: PALETTE.info, children: generatePrefetchStatus === 'running'
119
106
  ? 'Validating credentials & finishing component generation...'
120
- : 'Validating credentials...' })), !validating && generatePrefetchStatus === 'running' && _jsx(Text, { dimColor: true, children: "Component generation in progress..." }), !validating && generatePrefetchStatus === 'complete' && (_jsx(Text, { color: "green", children: "Component generation complete." })), !validating && generatePrefetchStatus === 'failed' && (_jsxs(Text, { color: "yellow", children: ["Component generation failed", generatePrefetchError ? `: ${generatePrefetchError}` : '', ". Will retry after credential validation.", onRetryPrefetch ? ' Press R to retry now.' : ''] })), _jsxs(Box, { gap: 3, marginTop: 1, children: [_jsx(Text, { dimColor: true, children: "[Enter] Next field / Submit" }), _jsx(Text, { dimColor: true, children: "[Tab] Switch field" }), _jsx(Text, { dimColor: true, children: "[q] Quit" })] }), onSkip && (_jsx(Box, { marginTop: 0, children: _jsx(Text, { dimColor: true, children: "[s] Skip \u2014 review locally only (no push, no live preview)" }) }))] }));
107
+ : 'Validating credentials...' })), !validating && generatePrefetchStatus === 'running' && _jsx(Text, { dimColor: true, children: "Component generation in progress..." }), !validating && generatePrefetchStatus === 'complete' && (_jsx(Text, { color: PALETTE.success, children: "Component generation complete." })), !validating && generatePrefetchStatus === 'failed' && (_jsxs(Text, { color: PALETTE.warning, children: ["Component generation failed", generatePrefetchError ? `: ${generatePrefetchError}` : '', ". Will retry after credential validation.", onRetryPrefetch ? ' Press R to retry now.' : ''] })), _jsxs(Box, { gap: 3, marginTop: 1, children: [_jsx(Text, { dimColor: true, children: "[Enter] Next field / Submit" }), _jsx(Text, { dimColor: true, children: "[Tab] Switch field" }), _jsx(Text, { dimColor: true, children: "[q] Quit" })] }), onSkip && (_jsx(Box, { marginTop: 0, children: _jsx(Text, { dimColor: true, children: "[s] Skip \u2014 review locally only (no push, no live preview)" }) }))] }));
121
108
  }
@@ -15,9 +15,7 @@ type DoneStepProps = {
15
15
  };
16
16
  spaceId: string;
17
17
  environmentId: string;
18
- /** Configured API host (e.g. `api.contentful.com`). Used to derive the webapp URL. */
19
18
  host?: string;
20
- /** Task 8 — pre-formatted run teaser; rendered dim below the space link. */
21
19
  runTeaser?: string;
22
20
  onExit: () => void;
23
21
  };
@@ -1,4 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { PALETTE } from '../../../analyze/select/tui/theme.js';
2
3
  import { Box, Text } from 'ink';
3
4
  import { useImmediateInput } from '../../../analyze/select/tui/hooks/useImmediateInput.js';
4
5
  import { buildPostPushUrl } from '../../../lib/contentful-urls.js';
@@ -17,7 +18,7 @@ export function DoneStep({ componentTypes, designTokens, summary, spaceId, envir
17
18
  designTokens.removed;
18
19
  const success = totalFailed === 0;
19
20
  function EntityRows({ entity, label }) {
20
- return (_jsxs(_Fragment, { children: [entity.created > 0 && (_jsxs(Box, { gap: 1, children: [_jsx(Text, { color: "green", children: "\u2713" }), _jsxs(Text, { children: [entity.created, " ", label, entity.created !== 1 ? 's' : '', " created"] })] })), entity.updated > 0 && (_jsxs(Box, { gap: 1, children: [_jsx(Text, { color: "green", children: "\u2713" }), _jsxs(Text, { children: [entity.updated, " ", label, entity.updated !== 1 ? 's' : '', " updated"] })] })), entity.removed > 0 && (_jsxs(Box, { gap: 1, children: [_jsx(Text, { color: "green", children: "\u2713" }), _jsxs(Text, { children: [entity.removed, " ", label, entity.removed !== 1 ? 's' : '', " removed"] })] })), entity.failed > 0 && (_jsxs(Box, { gap: 1, children: [_jsx(Text, { color: "red", children: "\u2717" }), _jsxs(Text, { color: "red", children: [entity.failed, " ", label, entity.failed !== 1 ? 's' : '', " failed \u2014 check logs above"] })] }))] }));
21
+ return (_jsxs(_Fragment, { children: [entity.created > 0 && (_jsxs(Box, { gap: 1, children: [_jsx(Text, { color: PALETTE.success, children: "\u2713" }), _jsxs(Text, { children: [entity.created, " ", label, entity.created !== 1 ? 's' : '', " created"] })] })), entity.updated > 0 && (_jsxs(Box, { gap: 1, children: [_jsx(Text, { color: PALETTE.success, children: "\u2713" }), _jsxs(Text, { children: [entity.updated, " ", label, entity.updated !== 1 ? 's' : '', " updated"] })] })), entity.removed > 0 && (_jsxs(Box, { gap: 1, children: [_jsx(Text, { color: PALETTE.success, children: "\u2713" }), _jsxs(Text, { children: [entity.removed, " ", label, entity.removed !== 1 ? 's' : '', " removed"] })] })), entity.failed > 0 && (_jsxs(Box, { gap: 1, children: [_jsx(Text, { color: PALETTE.error, children: "\u2717" }), _jsxs(Text, { color: PALETTE.error, children: [entity.failed, " ", label, entity.failed !== 1 ? 's' : '', " failed \u2014 check logs above"] })] }))] }));
21
22
  }
22
- return (_jsxs(Box, { flexDirection: "column", gap: 1, paddingX: 2, paddingY: 1, children: [success ? (_jsx(Text, { bold: true, color: "green", children: "Done!" })) : (_jsx(Text, { bold: true, color: "yellow", children: "\u26A0 Finished with errors" })), totalPushed === 0 && totalFailed === 0 && !summary ? (_jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "Nothing was pushed \u2014 everything was already up to date." }) })) : (_jsxs(Box, { flexDirection: "column", gap: 0, marginTop: 1, children: [_jsx(EntityRows, { entity: componentTypes, label: "Component Type" }), _jsx(EntityRows, { entity: designTokens, label: "Design Token" }), summary && (_jsxs(Box, { gap: 1, marginTop: 1, children: [_jsxs(Text, { dimColor: true, children: ["Server: ", summary.succeeded, "/", summary.total, " succeeded"] }), summary.failed > 0 && _jsxs(Text, { color: "red", children: [", ", summary.failed, " failed"] })] }))] })), _jsxs(Box, { gap: 1, marginTop: 1, children: [_jsx(Text, { dimColor: true, children: "Space:" }), _jsx(Text, { children: spaceId }), _jsx(Text, { dimColor: true, children: "/" }), _jsx(Text, { dimColor: true, children: "Environment:" }), _jsx(Text, { children: environmentId })] }), success && totalPushed > 0 && (_jsxs(Box, { flexDirection: "column", gap: 1, marginTop: 1, children: [_jsx(Text, { dimColor: true, children: "Your design system is now in Contentful ExO." }), _jsxs(Box, { flexDirection: "column", gap: 0, children: [_jsx(Text, { dimColor: true, children: "View it here:" }), _jsx(Text, { color: "cyan", children: buildPostPushUrl({ host: host ?? 'api.contentful.com', spaceId, environmentId }) })] })] })), runTeaser && (_jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: runTeaser }) })), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "[Enter / q] Exit" }) })] }));
23
+ return (_jsxs(Box, { flexDirection: "column", gap: 1, paddingX: 2, paddingY: 1, children: [success ? (_jsx(Text, { bold: true, color: PALETTE.success, children: "Done!" })) : (_jsx(Text, { bold: true, color: PALETTE.warning, children: "\u26A0 Finished with errors" })), totalPushed === 0 && totalFailed === 0 && !summary ? (_jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "Nothing was pushed \u2014 everything was already up to date." }) })) : (_jsxs(Box, { flexDirection: "column", gap: 0, marginTop: 1, children: [_jsx(EntityRows, { entity: componentTypes, label: "Component Type" }), _jsx(EntityRows, { entity: designTokens, label: "Design Token" }), summary && (_jsxs(Box, { gap: 1, marginTop: 1, children: [_jsxs(Text, { dimColor: true, children: ["Server: ", summary.succeeded, "/", summary.total, " succeeded"] }), summary.failed > 0 && _jsxs(Text, { color: PALETTE.error, children: [", ", summary.failed, " failed"] })] }))] })), _jsxs(Box, { gap: 1, marginTop: 1, children: [_jsx(Text, { dimColor: true, children: "Space:" }), _jsx(Text, { children: spaceId }), _jsx(Text, { dimColor: true, children: "/" }), _jsx(Text, { dimColor: true, children: "Environment:" }), _jsx(Text, { children: environmentId })] }), success && totalPushed > 0 && (_jsxs(Box, { flexDirection: "column", gap: 1, marginTop: 1, children: [_jsx(Text, { dimColor: true, children: "Your design system is now in Contentful ExO." }), _jsxs(Box, { flexDirection: "column", gap: 0, children: [_jsx(Text, { dimColor: true, children: "View it here:" }), _jsx(Text, { color: PALETTE.info, children: buildPostPushUrl({ host: host ?? 'api.contentful.com', spaceId, environmentId }) })] })] })), runTeaser && (_jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: runTeaser }) })), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "[Enter / q] Exit" }) })] }));
23
24
  }
@@ -1,4 +1,5 @@
1
1
  import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
+ import { PALETTE } from '../../../analyze/select/tui/theme.js';
2
3
  import { Box, Text } from 'ink';
3
4
  import { useImmediateInput } from '../../../analyze/select/tui/hooks/useImmediateInput.js';
4
5
  export function ErrorStep({ stepName, message, onExit, onRetryCredentials }) {
@@ -11,5 +12,5 @@ export function ErrorStep({ stepName, message, onExit, onRetryCredentials }) {
11
12
  onExit();
12
13
  }
13
14
  });
14
- return (_jsxs(Box, { flexDirection: "column", gap: 1, paddingX: 2, paddingY: 1, children: [_jsxs(Text, { bold: true, color: "red", children: ["\u2717 ", stepName, " failed"] }), _jsx(Text, { color: "red", children: message }), _jsxs(Box, { gap: 3, marginTop: 1, children: [_jsx(Text, { dimColor: true, children: "[Enter / q] Exit" }), onRetryCredentials && _jsx(Text, { dimColor: true, children: "[r] Re-enter credentials" })] })] }));
15
+ return (_jsxs(Box, { flexDirection: "column", gap: 1, paddingX: 2, paddingY: 1, children: [_jsxs(Text, { bold: true, color: PALETTE.error, children: ["\u2717 ", stepName, " failed"] }), _jsx(Text, { color: PALETTE.error, children: message }), _jsxs(Box, { gap: 3, marginTop: 1, children: [_jsx(Text, { dimColor: true, children: "[Enter / q] Exit" }), onRetryCredentials && _jsx(Text, { dimColor: true, children: "[r] Re-enter credentials" })] })] }));
15
16
  }
@@ -1,42 +1,36 @@
1
1
  import React from 'react';
2
- import type { CDFComponentEntry } from '@contentful/experience-design-system-types';
2
+ import type { BreakingChange, CDFComponentEntry, ComponentTypeSummary, DownstreamImpact, ServerPreviewResponse } from '@contentful/experience-design-system-types';
3
3
  type GenerateReviewStepProps = {
4
4
  extractSessionId: string;
5
5
  onFinalize: (accepted: number, rejected: number, unresolved: number) => void;
6
6
  onQuit: () => void;
7
- /**
8
- * Feature 2 (live preview after every save). When `true` (default), the
9
- * wizard re-runs `previewImport` after each successful FieldEditor Ctrl+S
10
- * (debounced 500ms) and refreshes the sidebar's previewAnnotation badges.
11
- * Operator opts out via `experiences import --no-live-preview`.
12
- */
13
7
  livePreview?: boolean;
14
8
  spaceId?: string;
15
9
  environmentId?: string;
16
10
  cmaToken?: string;
17
11
  host?: string;
18
12
  tokensPath?: string;
19
- /**
20
- * INTEG-4411 refined: initial value for the inline `finalizeError` banner.
21
- * The wizard sets this when it routes back to `final-review` after the
22
- * preview API returned an empty diff (pure no-op push). Cleared on the
23
- * next `a` / `A` keystroke.
24
- */
25
13
  initialFinalizeError?: string | null;
26
14
  };
27
- /**
28
- * Sort components for the final-review sidebar so the underlying data array
29
- * matches the visual order. Empty components (zero classified $properties)
30
- * surface at the top via the warning-tier path in Sidebar.tsx; we mirror that
31
- * here so `selectedIdx` indexes into the same order the user sees. Without
32
- * this, j/k navigation lands on different rows than the visually-selected
33
- * one (INTEG-4259).
34
- *
35
- * Within each tier (empty / non-empty) we tie-break alphabetically by `key`.
36
- */
37
15
  export declare function sortComponentsForSidebar<T extends {
38
16
  key: string;
39
17
  entry: CDFComponentEntry;
40
- }>(components: T[]): T[];
18
+ }>(components: T[], cycleParticipants?: Set<string>): T[];
19
+ export { computeCycleAutoRejectTargets } from '../../cycle-auto-reject.js';
20
+ export interface BreakingComponent {
21
+ componentName: string;
22
+ changes: BreakingChange[];
23
+ impact?: DownstreamImpact;
24
+ current?: ComponentTypeSummary;
25
+ }
26
+ export interface BreakingRow {
27
+ label: string;
28
+ componentName: string;
29
+ focusTarget?: {
30
+ kind: 'prop' | 'slot';
31
+ name: string;
32
+ };
33
+ }
34
+ export declare function buildBreakingRows(breakingChanges: BreakingComponent[]): BreakingRow[];
35
+ export declare function deriveBreakingChanges(response: ServerPreviewResponse): BreakingComponent[];
41
36
  export declare function GenerateReviewStep({ extractSessionId, onFinalize, onQuit, livePreview, spaceId, environmentId, cmaToken, host, tokensPath, initialFinalizeError, }: GenerateReviewStepProps): React.ReactElement;
42
- export {};