@contentful/experience-design-system-cli 2.26.1-dev-build-a852362.0 → 2.26.1-dev-build-f03f014.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 (204) hide show
  1. package/dist/package.json +14 -10
  2. package/dist/src/index.js +34937 -9
  3. package/dist/src/lib/cli-path.d.ts +4 -0
  4. package/dist/src/runs/export-helpers.d.ts +1 -12
  5. package/dist/src/runs/push-helpers.d.ts +1 -6
  6. package/package.json +12 -7
  7. package/skills/generate-components.md +427 -0
  8. package/skills/generate-tokens.md +194 -0
  9. package/skills/select-components.md +224 -0
  10. package/dist/src/analytics/apply.js +0 -30
  11. package/dist/src/analytics/client.js +0 -81
  12. package/dist/src/analytics/constants.js +0 -4
  13. package/dist/src/analytics/env.js +0 -14
  14. package/dist/src/analytics/exit.js +0 -24
  15. package/dist/src/analytics/index.js +0 -9
  16. package/dist/src/analytics/normalize.js +0 -18
  17. package/dist/src/analytics/os.js +0 -13
  18. package/dist/src/analytics/session.js +0 -15
  19. package/dist/src/analytics/tracker.js +0 -126
  20. package/dist/src/analytics/types.js +0 -1
  21. package/dist/src/analyze/build-analyze-view-rows.js +0 -63
  22. package/dist/src/analyze/command.js +0 -599
  23. package/dist/src/analyze/composite-closure.js +0 -0
  24. package/dist/src/analyze/composition/agent-parser/author-prompt.js +0 -22
  25. package/dist/src/analyze/composition/agent-parser/extract-parser.js +0 -44
  26. package/dist/src/analyze/composition/agent-parser/load-prompt.js +0 -31
  27. package/dist/src/analyze/composition/agent-parser/resolve-via-parser.js +0 -88
  28. package/dist/src/analyze/composition/agent-parser/sandbox.js +0 -187
  29. package/dist/src/analyze/composition/apply-mapping.js +0 -67
  30. package/dist/src/analyze/composition/candidate-critic-agent.js +0 -39
  31. package/dist/src/analyze/composition/candidate-critic.js +0 -63
  32. package/dist/src/analyze/composition/candidate-files.js +0 -131
  33. package/dist/src/analyze/composition/composition-cache-key.js +0 -19
  34. package/dist/src/analyze/composition/interchange-schema.js +0 -61
  35. package/dist/src/analyze/composition/manifest-doc-evidence.js +0 -136
  36. package/dist/src/analyze/composition/merge-edges.js +0 -70
  37. package/dist/src/analyze/composition/parse-map-edges.js +0 -55
  38. package/dist/src/analyze/composition/resolve-mapping-cli.js +0 -29
  39. package/dist/src/analyze/composition/resolve-mapping.js +0 -111
  40. package/dist/src/analyze/cycle-detection.js +0 -234
  41. package/dist/src/analyze/cycle-view.js +0 -28
  42. package/dist/src/analyze/fuzzy-search.js +0 -55
  43. package/dist/src/analyze/issue-inheritance.js +0 -108
  44. package/dist/src/analyze/lineage.js +0 -0
  45. package/dist/src/analyze/scope-gate-cascade.js +0 -170
  46. package/dist/src/analyze/search-neighborhood.js +0 -56
  47. package/dist/src/analyze/select/command.js +0 -484
  48. package/dist/src/analyze/select/index.js +0 -5
  49. package/dist/src/analyze/select/parser.js +0 -53
  50. package/dist/src/analyze/select/persistence.js +0 -80
  51. package/dist/src/analyze/select/preview-annotations.js +0 -62
  52. package/dist/src/analyze/select/stdout.js +0 -3
  53. package/dist/src/analyze/select/tui/App.js +0 -483
  54. package/dist/src/analyze/select/tui/components/ComponentDetail.js +0 -48
  55. package/dist/src/analyze/select/tui/components/ComponentRationalePanel.js +0 -125
  56. package/dist/src/analyze/select/tui/components/FieldEditor.js +0 -1131
  57. package/dist/src/analyze/select/tui/components/FinalizeDialog.js +0 -36
  58. package/dist/src/analyze/select/tui/components/GotoBanner.js +0 -30
  59. package/dist/src/analyze/select/tui/components/GroupedSidebar.js +0 -517
  60. package/dist/src/analyze/select/tui/components/HelpOverlay.js +0 -17
  61. package/dist/src/analyze/select/tui/components/JsonEditor.js +0 -131
  62. package/dist/src/analyze/select/tui/components/JsonPanel.js +0 -66
  63. package/dist/src/analyze/select/tui/components/LineagePanel.js +0 -22
  64. package/dist/src/analyze/select/tui/components/PreviewSummaryBar.js +0 -29
  65. package/dist/src/analyze/select/tui/components/QuitDialog.js +0 -14
  66. package/dist/src/analyze/select/tui/components/RationalePanel.js +0 -80
  67. package/dist/src/analyze/select/tui/components/Sidebar.js +0 -92
  68. package/dist/src/analyze/select/tui/components/SourcePanel.js +0 -52
  69. package/dist/src/analyze/select/tui/components/StatusBar.js +0 -7
  70. package/dist/src/analyze/select/tui/components/TopBar.js +0 -10
  71. package/dist/src/analyze/select/tui/components/removed-components-text.js +0 -11
  72. package/dist/src/analyze/select/tui/hooks/scroll-offset.js +0 -26
  73. package/dist/src/analyze/select/tui/hooks/useImmediateInput.js +0 -66
  74. package/dist/src/analyze/select/tui/hooks/useKeymap.js +0 -67
  75. package/dist/src/analyze/select/tui/hooks/useSession.js +0 -52
  76. package/dist/src/analyze/select/tui/hooks/useUndo.js +0 -26
  77. package/dist/src/analyze/select/tui/theme.js +0 -28
  78. package/dist/src/analyze/select/types.js +0 -39
  79. package/dist/src/analyze/select-agent/command.js +0 -558
  80. package/dist/src/analyze/select-agent/context-builder.js +0 -197
  81. package/dist/src/analyze/select-agent/show-rationale.js +0 -92
  82. package/dist/src/analyze/selection-cascade.js +0 -19
  83. package/dist/src/analyze/slot-graph.js +0 -17
  84. package/dist/src/analyze/tui/AnalyzeView.js +0 -64
  85. package/dist/src/apply/api-client.js +0 -440
  86. package/dist/src/apply/command.js +0 -845
  87. package/dist/src/apply/manifest.js +0 -1
  88. package/dist/src/apply/preview-utils.js +0 -26
  89. package/dist/src/apply/tui/SelectView.js +0 -34
  90. package/dist/src/apply/tui/ServerApplyView.js +0 -49
  91. package/dist/src/apply/tui/ServerPreviewView.js +0 -23
  92. package/dist/src/credentials-store.js +0 -74
  93. package/dist/src/generate/command.js +0 -597
  94. package/dist/src/generate/edit/command.js +0 -127
  95. package/dist/src/generate/tui/GenerateView.js +0 -10
  96. package/dist/src/host-utils.js +0 -26
  97. package/dist/src/import/agent-model-resolve.js +0 -35
  98. package/dist/src/import/auto-filter-resolve.js +0 -16
  99. package/dist/src/import/command.js +0 -380
  100. package/dist/src/import/cycle-auto-reject.js +0 -14
  101. package/dist/src/import/orchestrator.js +0 -603
  102. package/dist/src/import/path-utils.js +0 -30
  103. package/dist/src/import/picker-dispatch.js +0 -44
  104. package/dist/src/import/print-prompt.js +0 -31
  105. package/dist/src/import/strip-allowed-components.js +0 -22
  106. package/dist/src/import/tui/CustomPromptBanner.js +0 -8
  107. package/dist/src/import/tui/WizardApp.js +0 -1670
  108. package/dist/src/import/tui/ai-flag.js +0 -6
  109. package/dist/src/import/tui/auto-filter-error.js +0 -29
  110. package/dist/src/import/tui/autocomplete.js +0 -32
  111. package/dist/src/import/tui/components/AutoFilterBanner.js +0 -19
  112. package/dist/src/import/tui/components/CounterStrip.js +0 -12
  113. package/dist/src/import/tui/components/LegendEntry.js +0 -6
  114. package/dist/src/import/tui/cycle-panel-scroll.js +0 -33
  115. package/dist/src/import/tui/final-review-host.js +0 -25
  116. package/dist/src/import/tui/group-collapse.js +0 -11
  117. package/dist/src/import/tui/history.js +0 -53
  118. package/dist/src/import/tui/hooks/useLineage.js +0 -50
  119. package/dist/src/import/tui/hooks/useOverlayPanel.js +0 -27
  120. package/dist/src/import/tui/lineage-layout.js +0 -82
  121. package/dist/src/import/tui/merge-ai-decisions.js +0 -22
  122. package/dist/src/import/tui/push-decision-gate-helpers.js +0 -8
  123. package/dist/src/import/tui/push-progress.js +0 -1
  124. package/dist/src/import/tui/run-print-files-helpers.js +0 -8
  125. package/dist/src/import/tui/run-teaser.js +0 -9
  126. package/dist/src/import/tui/runLivePreview.js +0 -82
  127. package/dist/src/import/tui/runScopeGate.js +0 -28
  128. package/dist/src/import/tui/scope-gate-columns.js +0 -94
  129. package/dist/src/import/tui/scope-gate-host.js +0 -28
  130. package/dist/src/import/tui/sidebar-width.js +0 -3
  131. package/dist/src/import/tui/spawn-generate.js +0 -53
  132. package/dist/src/import/tui/step-filters.js +0 -42
  133. package/dist/src/import/tui/steps/AtomicGenerateReviewStep.js +0 -726
  134. package/dist/src/import/tui/steps/AtomicScopeGateStep.js +0 -210
  135. package/dist/src/import/tui/steps/CredentialsStep.js +0 -108
  136. package/dist/src/import/tui/steps/DoneStep.js +0 -24
  137. package/dist/src/import/tui/steps/ErrorStep.js +0 -16
  138. package/dist/src/import/tui/steps/GateStep.js +0 -22
  139. package/dist/src/import/tui/steps/GenerateReviewStep.js +0 -1618
  140. package/dist/src/import/tui/steps/PathValidationStep.js +0 -152
  141. package/dist/src/import/tui/steps/PreviewStep.js +0 -37
  142. package/dist/src/import/tui/steps/PreviewValidationErrorStep.js +0 -23
  143. package/dist/src/import/tui/steps/PushDecisionGateStep.js +0 -73
  144. package/dist/src/import/tui/steps/PushingStep.js +0 -24
  145. package/dist/src/import/tui/steps/RunningStep.js +0 -21
  146. package/dist/src/import/tui/steps/ScopeGateStep.js +0 -907
  147. package/dist/src/import/tui/steps/TokenInputStep.js +0 -88
  148. package/dist/src/import/tui/steps/WelcomeStep.js +0 -34
  149. package/dist/src/import/tui/steps/WizardPreviewStep.js +0 -169
  150. package/dist/src/import/tui/steps/auto-reject-decision.js +0 -9
  151. package/dist/src/import/tui/steps/breaking-change-format.js +0 -24
  152. package/dist/src/import/tui/steps/enumerate-cycle-breaks.js +0 -0
  153. package/dist/src/import/tui/steps/preview-diff.js +0 -175
  154. package/dist/src/import/tui/useFinalizePreview.js +0 -0
  155. package/dist/src/import/tui/useLivePreview.js +0 -122
  156. package/dist/src/import/tui/wizard-422-helpers.js +0 -60
  157. package/dist/src/import/tui/wizard-generate-progress.js +0 -25
  158. package/dist/src/import/tui/wizard-save-flow.js +0 -20
  159. package/dist/src/import/tui/wizard-state-transitions.js +0 -32
  160. package/dist/src/lib/agent-model-options.js +0 -15
  161. package/dist/src/lib/command-options.js +0 -30
  162. package/dist/src/lib/composition-mode.js +0 -39
  163. package/dist/src/lib/contentful-urls.js +0 -27
  164. package/dist/src/lib/debug-logger.js +0 -229
  165. package/dist/src/lib/debug-preamble.js +0 -33
  166. package/dist/src/lib/error-parser.js +0 -269
  167. package/dist/src/lib/prompt-overrides.js +0 -69
  168. package/dist/src/lib/terminal-capabilities.js +0 -51
  169. package/dist/src/lib/user-agent.js +0 -29
  170. package/dist/src/output/format.js +0 -110
  171. package/dist/src/print/command.js +0 -221
  172. package/dist/src/print/validate/tui/ValidateView.js +0 -37
  173. package/dist/src/print/validate/validators/cdf-validator.js +0 -104
  174. package/dist/src/print/validate/validators/dtcg-validator.js +0 -110
  175. package/dist/src/print/validate/validators/format-errors.js +0 -18
  176. package/dist/src/program.js +0 -105
  177. package/dist/src/runs/export-helpers.js +0 -59
  178. package/dist/src/runs/fingerprint.js +0 -75
  179. package/dist/src/runs/ls-command.js +0 -137
  180. package/dist/src/runs/modify-launcher.js +0 -42
  181. package/dist/src/runs/path-prompt.js +0 -72
  182. package/dist/src/runs/push-creds-prompt.js +0 -39
  183. package/dist/src/runs/push-helpers.js +0 -72
  184. package/dist/src/runs/push-launcher.js +0 -77
  185. package/dist/src/runs/replay-helpers.js +0 -164
  186. package/dist/src/runs/resolve-run-target.js +0 -45
  187. package/dist/src/runs/run-picker-mount.js +0 -72
  188. package/dist/src/runs/run-picker.js +0 -129
  189. package/dist/src/runs/save-conflict.js +0 -56
  190. package/dist/src/runs/save-path-resolver.js +0 -75
  191. package/dist/src/runs/staleness.js +0 -140
  192. package/dist/src/runs/store.js +0 -136
  193. package/dist/src/session/cache-keys.js +0 -44
  194. package/dist/src/session/command.js +0 -261
  195. package/dist/src/session/db.js +0 -1538
  196. package/dist/src/session/migration.js +0 -117
  197. package/dist/src/session/session-id.js +0 -212
  198. package/dist/src/session/stats.js +0 -89
  199. package/dist/src/setup/analytics-prompt.js +0 -24
  200. package/dist/src/setup/auto-filter-prompt.js +0 -24
  201. package/dist/src/setup/command.js +0 -966
  202. package/dist/src/setup/composition-mode-prompt.js +0 -37
  203. package/dist/src/setup/debug-mode-prompt.js +0 -22
  204. package/dist/src/types.js +0 -1
@@ -1,3 +0,0 @@
1
- export function formatFinalizeContract(input) {
2
- return JSON.stringify({ status: 'finalized', ...input }, null, 2) + '\n';
3
- }
@@ -1,483 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
3
- import { PALETTE } from './theme.js';
4
- import { Box, Text, useStdout } from 'ink';
5
- import { readFile } from 'node:fs/promises';
6
- import { createReviewSessionDetail } from '../types.js';
7
- import { TopBar } from './components/TopBar.js';
8
- import { Sidebar, sortComponentsForSidebar } from './components/Sidebar.js';
9
- import { countValidationIssues } from '../types.js';
10
- import { ComponentDetail } from './components/ComponentDetail.js';
11
- import { StatusBar } from './components/StatusBar.js';
12
- import { HelpOverlay } from './components/HelpOverlay.js';
13
- import { FinalizeDialog } from './components/FinalizeDialog.js';
14
- import { QuitDialog } from './components/QuitDialog.js';
15
- import { PreviewSummaryBar } from './components/PreviewSummaryBar.js';
16
- import { useKeymap } from './hooks/useKeymap.js';
17
- import { useImmediateInput } from './hooks/useImmediateInput.js';
18
- import { useSession } from './hooks/useSession.js';
19
- import { openPipelineDb, storeRawComponents, loadCDFComponents } from '../../../session/db.js';
20
- import { ImportApiClient } from '../../../apply/api-client.js';
21
- import { readTokensFromPath } from '../../../apply/manifest.js';
22
- import { buildManifest } from '@contentful/experience-design-system-types';
23
- export function App({ sessionId, artifactsRoot, reviewRoot }) {
24
- const { stdout } = useStdout();
25
- const terminalWidth = stdout?.columns ?? 80;
26
- const { session: loadedSession, paths, loading, error: sessionError, saveState, appendEvent, } = useSession({
27
- sessionId,
28
- artifactsRoot,
29
- reviewRoot,
30
- });
31
- const [session, setSession] = useState(null);
32
- const [selectedId, setSelectedId] = useState(null);
33
- const [draftsByComponentId, setDraftsByComponentId] = useState({});
34
- const [sidebarFocused, setSidebarFocused] = useState(true);
35
- const [editMode, setEditMode] = useState(false);
36
- const [sourceVisible, setSourceVisible] = useState(false);
37
- const [showHelp, setShowHelp] = useState(false);
38
- const [showFinalizeDialog, setShowFinalizeDialog] = useState(false);
39
- const [showQuitDialog, setShowQuitDialog] = useState(false);
40
- const [isSaving] = useState(false);
41
- const [saveError, setSaveError] = useState(null);
42
- const [finalizedResult, setFinalizedResult] = useState(null);
43
- const [sidebarScrollOffset, setSidebarScrollOffset] = useState(0);
44
- const [jsonScrollOffset, setJsonScrollOffset] = useState(0);
45
- const [previewAnnotations, setPreviewAnnotations] = useState(() => {
46
- const raw = process.env['EDS_PREVIEW_ANNOTATIONS'];
47
- if (!raw)
48
- return {};
49
- try {
50
- return JSON.parse(raw);
51
- }
52
- catch {
53
- return {};
54
- }
55
- });
56
- const [previewLoading, setPreviewLoading] = useState(false);
57
- const [previewError, setPreviewError] = useState(null);
58
- const [previewResponse, setPreviewResponse] = useState(null);
59
- const refreshPreview = useCallback(async () => {
60
- const cmaToken = process.env['EDS_CMA_TOKEN'];
61
- const spaceId = process.env['EDS_SPACE_ID'];
62
- const environmentId = process.env['EDS_ENVIRONMENT_ID'];
63
- const tokensPath = process.env['EDS_TOKENS_PATH'];
64
- if (!cmaToken || !spaceId || !environmentId)
65
- return;
66
- setPreviewLoading(true);
67
- try {
68
- const db = openPipelineDb();
69
- let components = [];
70
- try {
71
- components = loadCDFComponents(db, sessionId);
72
- }
73
- finally {
74
- db.close();
75
- }
76
- let tokens = [];
77
- if (tokensPath)
78
- tokens = await readTokensFromPath('tokens', tokensPath);
79
- const manifest = buildManifest(components, tokens);
80
- if (!manifest.componentsManifest)
81
- manifest.componentsManifest = {};
82
- const client = new ImportApiClient({ cmaToken, spaceId, environmentId });
83
- // This preview is display-only (component-picker annotations); it never
84
- // triggers an apply, so always request the full diff to keep the
85
- // existing "removed" annotation working.
86
- const preview = await client.previewImport(manifest, true);
87
- const annotations = {};
88
- for (const item of preview.components.new) {
89
- const name = item.name ?? '';
90
- if (name)
91
- annotations[name] = 'new';
92
- }
93
- for (const item of preview.components.removed) {
94
- annotations[item.name] = 'removed';
95
- }
96
- for (const item of preview.components.changed) {
97
- if (item.changeClassification?.classification === 'breaking') {
98
- annotations[item.current.name] = 'breaking';
99
- }
100
- else {
101
- annotations[item.current.name] = 'changed';
102
- }
103
- }
104
- setPreviewAnnotations(annotations);
105
- setPreviewResponse(preview);
106
- setPreviewError(null);
107
- }
108
- catch (err) {
109
- const msg = err instanceof Error ? err.message : String(err);
110
- setPreviewError(msg.includes('token') ? 'Preview request failed' : msg);
111
- }
112
- finally {
113
- setPreviewLoading(false);
114
- }
115
- }, [sessionId]);
116
- const syncSessionToDb = useCallback((currentSession) => {
117
- const db = openPipelineDb();
118
- try {
119
- db.prepare(`UPDATE raw_components SET status = 'extracted' WHERE session_id = ?`).run(sessionId);
120
- const acceptedNames = currentSession.components
121
- .filter((c) => c.status === 'accepted' || c.status === 'reviewed')
122
- .map((c) => c.name);
123
- if (acceptedNames.length > 0) {
124
- db.prepare(`UPDATE raw_components SET status = 'generated' WHERE session_id = ? AND name IN (${acceptedNames.map(() => '?').join(',')})`).run(sessionId, ...acceptedNames);
125
- }
126
- }
127
- finally {
128
- db.close();
129
- }
130
- }, [sessionId]);
131
- const previewDebounceRef = useRef(null);
132
- const debouncedRefreshPreview = useCallback((currentSession) => {
133
- if (previewDebounceRef.current)
134
- clearTimeout(previewDebounceRef.current);
135
- previewDebounceRef.current = setTimeout(() => {
136
- syncSessionToDb(currentSession);
137
- void refreshPreview();
138
- }, 500);
139
- }, [syncSessionToDb, refreshPreview]);
140
- useEffect(() => {
141
- return () => {
142
- if (previewDebounceRef.current)
143
- clearTimeout(previewDebounceRef.current);
144
- };
145
- }, []);
146
- useEffect(() => {
147
- if (loadedSession && !session) {
148
- setSession(loadedSession);
149
- setSelectedId(loadedSession.components[0]?.id ?? null);
150
- }
151
- }, [loadedSession]);
152
- useEffect(() => {
153
- if (session && !previewResponse) {
154
- const raw = process.env['EDS_PREVIEW_COUNTS'];
155
- if (raw) {
156
- try {
157
- const counts = JSON.parse(raw);
158
- setPreviewResponse({
159
- components: {
160
- new: Array(counts.compNew).fill({}),
161
- changed: Array(counts.compChanged).fill({}),
162
- removed: Array(counts.compRemoved).fill({}),
163
- unchanged: Array(counts.compUnchanged).fill({}),
164
- },
165
- tokens: {
166
- new: Array(counts.tokNew).fill({}),
167
- changed: Array(counts.tokChanged).fill({}),
168
- removed: Array(counts.tokRemoved).fill({}),
169
- unchanged: Array(counts.tokUnchanged).fill({}),
170
- },
171
- });
172
- }
173
- catch (err) {
174
- process.stderr.write(`[eds] failed to parse EDS_PREVIEW_COUNTS: ${err instanceof Error ? err.message : String(err)}\n`);
175
- }
176
- }
177
- }
178
- }, [session]);
179
- useEffect(() => {
180
- if (!session || !selectedId)
181
- return;
182
- const selectedComponent = session.components.find((c) => c.id === selectedId);
183
- if (!selectedComponent || selectedComponent.sourceCode !== null)
184
- return;
185
- readFile(selectedComponent.resolvedSourcePath, 'utf8')
186
- .then((code) => {
187
- setSession((prev) => {
188
- if (!prev)
189
- return prev;
190
- return {
191
- ...prev,
192
- components: prev.components.map((c) => (c.id === selectedComponent.id ? { ...c, sourceCode: code } : c)),
193
- };
194
- });
195
- })
196
- .catch(() => {
197
- // Leave as null; SourcePanel shows [No source available]
198
- });
199
- }, [selectedId]);
200
- useEffect(() => {
201
- const handler = () => {
202
- if (Object.keys(draftsByComponentId).length > 0) {
203
- setShowQuitDialog(true);
204
- }
205
- else {
206
- process.exit(1);
207
- }
208
- };
209
- process.on('SIGINT', handler);
210
- return () => {
211
- process.off('SIGINT', handler);
212
- };
213
- }, [draftsByComponentId]);
214
- const updateStatus = async (componentId, newStatus) => {
215
- if (!session || !paths)
216
- return;
217
- const updatedSession = {
218
- ...session,
219
- components: session.components.map((c) => (c.id === componentId ? { ...c, status: newStatus } : c)),
220
- };
221
- setSession(updatedSession);
222
- await saveState(updatedSession);
223
- const component = session.components.find((c) => c.id === componentId);
224
- await appendEvent({
225
- type: 'status_changed',
226
- payload: { componentId, from: component?.status, to: newStatus },
227
- });
228
- debouncedRefreshPreview(updatedSession);
229
- };
230
- const dialogOpen = showHelp || showFinalizeDialog || showQuitDialog;
231
- useKeymap({
232
- sidebarFocused,
233
- editMode,
234
- dialogOpen,
235
- disabled: isSaving,
236
- }, {
237
- onSidebarUp: () => {
238
- if (!session)
239
- return;
240
- const idx = session.components.findIndex((c) => c.id === selectedId);
241
- if (idx > 0) {
242
- setSelectedId(session.components[idx - 1].id);
243
- setJsonScrollOffset(0);
244
- setSidebarScrollOffset((prev) => Math.min(prev, idx - 1));
245
- }
246
- },
247
- onSidebarDown: () => {
248
- if (!session)
249
- return;
250
- const idx = session.components.findIndex((c) => c.id === selectedId);
251
- if (idx < session.components.length - 1) {
252
- setSelectedId(session.components[idx + 1].id);
253
- setJsonScrollOffset(0);
254
- setSidebarScrollOffset((prev) => {
255
- const newIdx = idx + 1;
256
- return newIdx >= prev + visibleCount ? newIdx - visibleCount + 1 : prev;
257
- });
258
- }
259
- },
260
- onSidebarSelect: () => { },
261
- onAccept: () => {
262
- if (selectedId)
263
- void updateStatus(selectedId, 'accepted');
264
- },
265
- onReject: () => {
266
- if (selectedId)
267
- void updateStatus(selectedId, 'rejected');
268
- },
269
- onEnterEditMode: () => {
270
- if (!session || !selectedId)
271
- return;
272
- const component = session.components.find((c) => c.id === selectedId);
273
- if (!component)
274
- return;
275
- setEditMode(true);
276
- setDraftsByComponentId((prev) => ({
277
- ...prev,
278
- [selectedId]: prev[selectedId] ?? JSON.stringify(component.editedProposal, null, 2),
279
- }));
280
- },
281
- onToggleSource: () => {
282
- if (terminalWidth < 120) {
283
- setSaveError('Terminal too narrow for source panel (need 120+ cols)');
284
- setTimeout(() => setSaveError(null), 3000);
285
- return;
286
- }
287
- setSourceVisible((prev) => !prev);
288
- },
289
- onScrollUp: () => {
290
- setJsonScrollOffset((prev) => Math.max(0, prev - 1));
291
- },
292
- onScrollDown: () => {
293
- setJsonScrollOffset((prev) => prev + 1);
294
- },
295
- onToggleFocus: () => setSidebarFocused((prev) => !prev),
296
- onApproveAll: async () => {
297
- if (!session || !paths)
298
- return;
299
- const updatedComponents = session.components.map((c) => c.status === 'needs-review' ? { ...c, status: 'accepted' } : c);
300
- const affected = updatedComponents.filter((c) => c.status === 'accepted').length -
301
- session.components.filter((c) => c.status === 'accepted').length;
302
- const updatedSession = { ...session, components: updatedComponents };
303
- setSession(updatedSession);
304
- await saveState(updatedSession);
305
- await appendEvent({ type: 'approve_all', payload: { affected } });
306
- syncSessionToDb(updatedSession);
307
- void refreshPreview();
308
- },
309
- onFinalize: () => setShowFinalizeDialog(true),
310
- onQuit: () => {
311
- if (Object.keys(draftsByComponentId).length > 0) {
312
- setShowQuitDialog(true);
313
- }
314
- else {
315
- process.exit(1);
316
- }
317
- },
318
- onToggleHelp: () => setShowHelp((prev) => !prev),
319
- });
320
- const sessionSummary = useMemo(() => sortComponentsForSidebar((session?.components ?? []).map((c) => {
321
- const counts = countValidationIssues(c.originalProposal);
322
- return {
323
- id: c.id,
324
- name: c.name,
325
- status: c.status,
326
- previewAnnotation: previewAnnotations[c.name],
327
- extractionConfidence: c.originalProposal.extractionConfidence ?? null,
328
- needsReview: c.originalProposal.needsReview ?? false,
329
- validationErrorCount: counts.errors,
330
- validationWarningCount: counts.warnings,
331
- };
332
- })), [session?.components, previewAnnotations]);
333
- if (loading) {
334
- return _jsx(Text, { children: "Loading session..." });
335
- }
336
- if (sessionError) {
337
- return (_jsxs(Text, { color: PALETTE.error, children: [sessionError, '\nPress q to exit.'] }));
338
- }
339
- if (!session || !paths) {
340
- return _jsx(Text, { color: PALETTE.error, children: "Session unavailable." });
341
- }
342
- if (finalizedResult) {
343
- return _jsx(FinalizedScreen, { result: finalizedResult });
344
- }
345
- const selectedRecord = session.components.find((c) => c.id === selectedId) ?? null;
346
- const sessionDetail = selectedRecord ? createReviewSessionDetail({ ...session, components: [selectedRecord] }) : null;
347
- const selectedDetail = sessionDetail?.components[0] ?? null;
348
- const acceptedCount = session.components.filter((c) => c.status === 'accepted').length;
349
- const rejectedCount = session.components.filter((c) => c.status === 'rejected').length;
350
- const reviewedCount = session.components.filter((c) => c.status === 'reviewed').length;
351
- const needsReviewCount = session.components.filter((c) => c.status === 'needs-review').length;
352
- const hints = editMode
353
- ? [
354
- { key: 'Ctrl+S', label: 'save' },
355
- { key: 'Esc', label: 'discard' },
356
- ]
357
- : dialogOpen
358
- ? []
359
- : [
360
- { key: '?', label: 'help' },
361
- { key: 'q', label: 'quit' },
362
- ];
363
- const collapsed = terminalWidth < 80;
364
- const visibleCount = 20;
365
- const longestName = session.components.reduce((max, c) => Math.max(max, c.name.length), 0);
366
- const sidebarWidth = collapsed ? 3 : Math.min(Math.max(longestName + 5, 14), 22);
367
- const handleDraftSave = async (draft) => {
368
- if (!selectedId || !session || !paths)
369
- return;
370
- if (!draft)
371
- return;
372
- try {
373
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
374
- const parsed = JSON.parse(draft);
375
- const currentStatus = session.components.find((c) => c.id === selectedId)?.status;
376
- const newStatus = currentStatus === 'needs-review' ? 'reviewed' : currentStatus;
377
- const updatedSession = {
378
- ...session,
379
- components: session.components.map((c) => c.id === selectedId
380
- ? {
381
- ...c,
382
- editedProposal: parsed,
383
- status: newStatus,
384
- }
385
- : c),
386
- };
387
- const { [selectedId]: _removed, ...remainingDrafts } = draftsByComponentId;
388
- setSession(updatedSession);
389
- setDraftsByComponentId(remainingDrafts);
390
- setEditMode(false);
391
- await saveState(updatedSession);
392
- await appendEvent({
393
- type: 'draft_saved',
394
- payload: { componentId: selectedId },
395
- });
396
- const allEdited = updatedSession.components.map((c) => c.editedProposal);
397
- const syncDb = openPipelineDb();
398
- try {
399
- storeRawComponents(syncDb, sessionId, allEdited, {
400
- status: 'generated',
401
- preserveCDF: true,
402
- });
403
- }
404
- finally {
405
- syncDb.close();
406
- }
407
- void refreshPreview();
408
- }
409
- catch {
410
- // JSON parse error — JsonEditor already shows the error inline
411
- }
412
- };
413
- const handleDraftDiscard = () => {
414
- if (!selectedId)
415
- return;
416
- const { [selectedId]: _removed, ...remainingDrafts } = draftsByComponentId;
417
- setDraftsByComponentId(remainingDrafts);
418
- setEditMode(false);
419
- };
420
- const handleFinalize = async () => {
421
- if (!session || !paths)
422
- return;
423
- try {
424
- await appendEvent({
425
- type: 'finalized',
426
- payload: {
427
- accepted: acceptedCount,
428
- rejected: rejectedCount,
429
- excluded: needsReviewCount,
430
- },
431
- });
432
- const acceptedNames = new Set(session.components.filter((c) => c.status === 'accepted').map((c) => c.name));
433
- const db = openPipelineDb();
434
- try {
435
- storeRawComponents(db, sessionId, session.components.map((c) => c.editedProposal), { status: 'extracted', preserveCDF: true });
436
- if (acceptedNames.size > 0) {
437
- db.prepare(`UPDATE raw_components SET status = 'generated' WHERE session_id = ? AND name IN (${[...acceptedNames].map(() => '?').join(',')})`).run(sessionId, ...acceptedNames);
438
- }
439
- }
440
- finally {
441
- db.close();
442
- }
443
- const output = JSON.stringify({
444
- status: 'finalized',
445
- sessionDir: paths.sessionDir,
446
- accepted: acceptedCount,
447
- rejected: rejectedCount,
448
- excluded: needsReviewCount,
449
- }, null, 2) + '\n';
450
- process.stdout.write(output);
451
- setFinalizedResult({
452
- accepted: acceptedCount,
453
- rejected: rejectedCount,
454
- excluded: needsReviewCount,
455
- });
456
- }
457
- catch (err) {
458
- setSaveError(String(err));
459
- }
460
- };
461
- return (_jsxs(Box, { flexDirection: "column", children: [_jsx(TopBar, { subcommand: "analyze select", hints: hints }), showHelp && _jsx(HelpOverlay, { mode: "review", onClose: () => setShowHelp(false) }), showFinalizeDialog && (_jsx(FinalizeDialog, { accepted: acceptedCount, rejected: rejectedCount, needsReview: needsReviewCount, onConfirm: () => {
462
- void handleFinalize();
463
- }, onCancel: () => setShowFinalizeDialog(false) })), showQuitDialog && (_jsx(QuitDialog, { hasUnsavedDrafts: Object.keys(draftsByComponentId).length > 0, onConfirm: async () => {
464
- if (paths) {
465
- await appendEvent({
466
- type: 'session_quit',
467
- payload: { reason: 'user_quit' },
468
- });
469
- }
470
- process.exit(1);
471
- }, onCancel: () => setShowQuitDialog(false) })), !showHelp && !showFinalizeDialog && !showQuitDialog && (_jsxs(Box, { flexGrow: 1, children: [_jsx(Sidebar, { components: sessionSummary, selectedId: selectedId, focused: sidebarFocused, scrollOffset: sidebarScrollOffset, visibleCount: visibleCount, onSelect: (id) => {
472
- setSelectedId(id);
473
- setJsonScrollOffset(0);
474
- }, onScrollChange: setSidebarScrollOffset, collapsed: collapsed, width: sidebarWidth }), _jsx(Box, { flexGrow: 1, paddingLeft: 1, children: selectedDetail ? (_jsx(ComponentDetail, { component: selectedDetail, sourceCode: selectedRecord?.sourceCode ?? null, draftValue: selectedId ? (draftsByComponentId[selectedId] ?? '') : '', editMode: editMode, sourceVisible: sourceVisible, jsonScrollOffset: jsonScrollOffset, sourceScrollX: 0, sourceScrollY: 0, terminalWidth: terminalWidth, previewAnnotation: selectedRecord ? previewAnnotations[selectedRecord.name] : undefined, onSaveDraft: (value) => void handleDraftSave(value), onDiscardDraft: handleDraftDiscard, onScrollChange: setJsonScrollOffset })) : (_jsx(Text, { dimColor: true, children: "No component selected" })) })] })), _jsx(PreviewSummaryBar, { preview: previewResponse, loading: previewLoading }), previewError && _jsx(Text, { color: PALETTE.warning, children: '⚠ Preview: ' + previewError }), saveError && _jsx(Text, { color: PALETTE.error, children: '⚠ ' + saveError }), !dialogOpen && (_jsx(StatusBar, { accepted: acceptedCount, rejected: rejectedCount, reviewed: reviewedCount, needsReview: needsReviewCount, onApproveAll: () => { }, onFinalize: () => setShowFinalizeDialog(true) }))] }));
475
- }
476
- function FinalizedScreen({ result, }) {
477
- useImmediateInput((_input, key) => {
478
- if (key.return || _input === 'q' || key.escape) {
479
- process.exit(0);
480
- }
481
- });
482
- return (_jsxs(Box, { flexDirection: "column", paddingX: 2, paddingY: 1, gap: 1, children: [_jsx(Text, { bold: true, color: PALETTE.success, children: "\u2713 Finalized" }), _jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { gap: 1, children: [_jsx(Text, { color: PALETTE.success, children: "\u2713" }), _jsxs(Text, { children: [result.accepted, " accepted"] })] }), result.rejected > 0 && (_jsxs(Box, { gap: 1, children: [_jsx(Text, { color: PALETTE.error, children: "\u2717" }), _jsxs(Text, { children: [result.rejected, " rejected"] })] })), result.excluded > 0 && (_jsxs(Box, { gap: 1, children: [_jsx(Text, { dimColor: true, children: "\u00B7" }), _jsxs(Text, { dimColor: true, children: [result.excluded, " excluded (unresolved)"] })] }))] }), _jsx(Text, { dimColor: true, children: "Decisions saved. Ready for the next step." }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "[Enter / q] Exit" }) })] }));
483
- }
@@ -1,48 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { Box, Text } from 'ink';
3
- import { stripScoringFields } from '../../../../types.js';
4
- import { JsonPanel } from './JsonPanel.js';
5
- import { JsonEditor } from './JsonEditor.js';
6
- import { SourcePanel } from './SourcePanel.js';
7
- function annotationLabel(annotation) {
8
- switch (annotation) {
9
- case 'breaking':
10
- return { text: ' ⚠ breaking', color: 'red' };
11
- case 'changed':
12
- return { text: ' ~ changed', color: 'yellow' };
13
- case 'new':
14
- return { text: ' + new', color: 'green' };
15
- case 'removed':
16
- return { text: ' ✗ removed', color: 'red' };
17
- default:
18
- return null;
19
- }
20
- }
21
- export function ComponentDetail({ component, sourceCode, draftValue, editMode, sourceVisible, jsonScrollOffset, sourceScrollX, sourceScrollY, terminalWidth, previewAnnotation, onSaveDraft, onDiscardDraft, }) {
22
- const sidebarWidth = terminalWidth < 80 ? 5 : 20;
23
- const availableWidth = terminalWidth - sidebarWidth - 2;
24
- const panelHeight = 20;
25
- let originalWidth;
26
- let editWidth;
27
- let sourceWidth;
28
- if (sourceVisible && terminalWidth >= 120) {
29
- originalWidth = Math.floor((availableWidth - 4) / 3);
30
- editWidth = originalWidth;
31
- sourceWidth = availableWidth - originalWidth * 2 - 4;
32
- }
33
- else {
34
- originalWidth = Math.floor((availableWidth - 3) / 2);
35
- editWidth = availableWidth - originalWidth - 3;
36
- sourceWidth = 0;
37
- }
38
- const originalJson = JSON.stringify(stripScoringFields(component.originalProposal), null, 2);
39
- const editedJson = JSON.stringify(stripScoringFields(component.editedProposal), null, 2);
40
- const conf = component.originalProposal.extractionConfidence ?? null;
41
- const nr = component.originalProposal.needsReview ?? false;
42
- const confColor = conf === null ? 'gray' : nr ? 'red' : conf >= 4 ? 'white' : conf >= 3 ? 'yellow' : 'red';
43
- const confLabel = conf === null ? 'confidence: —' : (nr ? '⚑ ' : '') + 'confidence: ' + String(conf) + '/5';
44
- return (_jsxs(Box, { flexDirection: "column", flexGrow: 1, children: [_jsxs(Box, { children: [_jsx(Text, { bold: true, children: component.name }), (() => {
45
- const ann = annotationLabel(previewAnnotation);
46
- return ann ? _jsx(Text, { color: ann.color, children: ann.text }) : null;
47
- })(), _jsx(Text, { color: confColor, children: ' — ' + confLabel }), _jsx(Box, { flexGrow: 1 }), _jsxs(Text, { dimColor: true, children: [sourceVisible ? '[s] hide src' : '[s] src', editMode ? '' : ' [e] edit'] })] }), _jsxs(Box, { children: [_jsx(JsonPanel, { label: "ORIGINAL (read-only)", value: originalJson, scrollOffset: jsonScrollOffset, width: originalWidth, height: panelHeight, active: false }), _jsx(Text, { children: " " }), editMode ? (_jsx(JsonEditor, { value: draftValue || editedJson, width: editWidth, height: panelHeight, onSave: onSaveDraft, onDiscard: onDiscardDraft })) : (_jsx(JsonPanel, { label: "EDIT (draft)", value: draftValue || editedJson, scrollOffset: jsonScrollOffset, width: editWidth, height: panelHeight, active: true })), sourceVisible && sourceWidth > 0 && (_jsxs(_Fragment, { children: [_jsx(Text, { children: " " }), _jsx(SourcePanel, { sourceCode: sourceCode, filePath: component.originalProposal.source, width: sourceWidth, height: panelHeight, scrollX: sourceScrollX, scrollY: sourceScrollY })] }))] }), !editMode && _jsx(Text, { dimColor: true, children: ' [a] accept [r] reject [e] edit [A] accept all [↑↓] scroll' })] }));
48
- }
@@ -1,125 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { PALETTE } from '../theme.js';
3
- import { Box, Text } from 'ink';
4
- const PLACEHOLDER = '(no rationale captured)';
5
- function wrapText(text, innerWidth) {
6
- if (!text)
7
- return [''];
8
- const width = Math.max(1, innerWidth);
9
- const words = text.split(/\s+/).filter((w) => w.length > 0);
10
- if (words.length === 0)
11
- return [''];
12
- const lines = [];
13
- let current = '';
14
- for (const w of words) {
15
- if (current.length === 0) {
16
- if (w.length > width) {
17
- let rest = w;
18
- while (rest.length > width) {
19
- lines.push(rest.slice(0, width));
20
- rest = rest.slice(width);
21
- }
22
- current = rest;
23
- }
24
- else {
25
- current = w;
26
- }
27
- continue;
28
- }
29
- if (current.length + 1 + w.length <= width) {
30
- current += ' ' + w;
31
- }
32
- else {
33
- lines.push(current);
34
- if (w.length > width) {
35
- let rest = w;
36
- while (rest.length > width) {
37
- lines.push(rest.slice(0, width));
38
- rest = rest.slice(width);
39
- }
40
- current = rest;
41
- }
42
- else {
43
- current = w;
44
- }
45
- }
46
- }
47
- if (current.length > 0)
48
- lines.push(current);
49
- return lines.length > 0 ? lines : [''];
50
- }
51
- export function renderComponentRationaleLines(data, innerWidth) {
52
- const out = [];
53
- const pushSection = (heading, body) => {
54
- out.push({ kind: 'heading', text: heading });
55
- const text = body && body.trim().length > 0 ? body : PLACEHOLDER;
56
- for (const ln of wrapText(text, Math.max(1, innerWidth - 2))) {
57
- out.push({ kind: 'text', text: ' ' + ln, dim: !body });
58
- }
59
- out.push({ kind: 'blank' });
60
- };
61
- out.push({ kind: 'heading', text: 'Description' });
62
- const descBody = data.description && data.description.trim().length > 0 ? data.description : PLACEHOLDER;
63
- for (const ln of wrapText(descBody, Math.max(1, innerWidth - 2))) {
64
- out.push({ kind: 'text', text: ' ' + ln, dim: !data.description });
65
- }
66
- if (data.descriptionRationale && data.descriptionRationale.trim().length > 0) {
67
- for (const ln of wrapText(`why: ${data.descriptionRationale}`, Math.max(1, innerWidth - 2))) {
68
- out.push({ kind: 'text', text: ' ' + ln, dim: true });
69
- }
70
- }
71
- out.push({ kind: 'blank' });
72
- pushSection('Why these props', data.propsRationale);
73
- pushSection('Why these slots', data.slotsRationale);
74
- out.push({ kind: 'heading', text: 'Props' });
75
- if (data.props.length === 0) {
76
- out.push({ kind: 'text', text: ' ' + PLACEHOLDER, dim: true });
77
- }
78
- else {
79
- for (const p of data.props) {
80
- const sub = p.category ? `(${p.category})` : undefined;
81
- out.push({ kind: 'list-name', text: p.name, sublabel: sub });
82
- const text = p.rationale && p.rationale.trim().length > 0 ? p.rationale : PLACEHOLDER;
83
- for (const ln of wrapText(text, Math.max(1, innerWidth - 4))) {
84
- out.push({ kind: 'text', text: ' ' + ln, dim: !p.rationale });
85
- }
86
- }
87
- }
88
- out.push({ kind: 'blank' });
89
- out.push({ kind: 'heading', text: 'Slots' });
90
- if (data.slots.length === 0) {
91
- out.push({ kind: 'text', text: ' ' + PLACEHOLDER, dim: true });
92
- }
93
- else {
94
- for (const s of data.slots) {
95
- out.push({ kind: 'list-name', text: s.name });
96
- const text = s.rationale && s.rationale.trim().length > 0 ? s.rationale : PLACEHOLDER;
97
- for (const ln of wrapText(text, Math.max(1, innerWidth - 4))) {
98
- out.push({ kind: 'text', text: ' ' + ln, dim: !s.rationale });
99
- }
100
- }
101
- }
102
- return out;
103
- }
104
- export function ComponentRationalePanel({ data, scrollOffset, width, height, active, }) {
105
- const innerWidth = Math.max(1, width - 2);
106
- const all = renderComponentRationaleLines(data, innerWidth);
107
- const totalLines = all.length;
108
- const contentHeight = Math.max(1, height - 1);
109
- const visible = all.slice(scrollOffset, scrollOffset + contentHeight);
110
- const overflowed = totalLines > contentHeight;
111
- const visibleStart = totalLines === 0 ? 0 : scrollOffset + 1;
112
- const visibleEnd = Math.min(totalLines, scrollOffset + contentHeight);
113
- return (_jsxs(Box, { flexDirection: "column", width: width, height: height + 2, borderStyle: "single", borderColor: active ? PALETTE.inverse : undefined, children: [_jsx(Box, { children: _jsx(Text, { bold: true, dimColor: !active, children: `Component rationale: ${data.name}` }) }), visible.map((line, i) => {
114
- if (line.kind === 'blank') {
115
- return (_jsx(Box, { children: _jsx(Text, { children: " " }) }, i));
116
- }
117
- if (line.kind === 'heading') {
118
- return (_jsx(Box, { children: _jsx(Text, { bold: true, color: PALETTE.info, dimColor: !active, children: line.text }) }, i));
119
- }
120
- if (line.kind === 'list-name') {
121
- return (_jsxs(Box, { children: [_jsx(Text, { children: ' - ' }), _jsx(Text, { bold: true, dimColor: !active, children: line.text }), line.sublabel ? _jsx(Text, { dimColor: true, children: ' ' + line.sublabel }) : null] }, i));
122
- }
123
- return (_jsx(Box, { children: _jsx(Text, { dimColor: !active || line.dim, children: line.text }) }, i));
124
- }), _jsx(Box, { children: overflowed ? (_jsx(Text, { dimColor: true, children: `${visibleStart}-${visibleEnd}/${totalLines} [j/k] scroll [I/Esc] close` })) : (_jsx(Text, { dimColor: true, children: '[I/Esc] close' })) })] }));
125
- }