@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,75 +0,0 @@
1
- import { createHash } from 'node:crypto';
2
- import { readFile, stat } from 'node:fs/promises';
3
- import { resolve } from 'node:path';
4
- function rowField(row, key) {
5
- const v = row[key];
6
- return typeof v === 'string' ? v : null;
7
- }
8
- export function sha256Hex(buf) {
9
- return createHash('sha256').update(buf).digest('hex');
10
- }
11
- /**
12
- * Build a per-file fingerprint of every source file that contributed to a
13
- * run. Stats each unique source_path once (first-seen component name wins),
14
- * and (optionally) hashes the raw tokens file too.
15
- *
16
- * Missing files do NOT throw — they're simply omitted. The read-side
17
- * staleness check re-stats from disk and surfaces missing files there so we
18
- * can report which one disappeared.
19
- */
20
- export async function buildSourceFingerprint(opts) {
21
- const rows = opts.db
22
- .prepare('SELECT name, source_path FROM raw_components WHERE session_id = ?')
23
- .all(opts.extractSessionId);
24
- const files = {};
25
- const seen = new Set();
26
- for (const row of rows) {
27
- const sourcePath = rowField(row, 'source_path');
28
- const name = rowField(row, 'name');
29
- if (!sourcePath)
30
- continue;
31
- const abs = resolve(sourcePath);
32
- if (seen.has(abs))
33
- continue;
34
- seen.add(abs);
35
- try {
36
- const st = await stat(abs);
37
- const entry = { mtime: st.mtime.toISOString() };
38
- if (name)
39
- entry.componentName = name;
40
- files[abs] = entry;
41
- }
42
- catch {
43
- // Source file missing at fingerprint time — skip silently. Staleness
44
- // can only fire on files we recorded; a file removed before save
45
- // simply isn't tracked. Operators usually re-extract in that case.
46
- }
47
- }
48
- let rawTokensPath = null;
49
- let rawTokensMtime = null;
50
- let rawTokensContentHash = null;
51
- if (opts.rawTokensPath) {
52
- const abs = resolve(opts.rawTokensPath);
53
- rawTokensPath = abs;
54
- try {
55
- const [st, buf] = await Promise.all([stat(abs), readFile(abs)]);
56
- rawTokensMtime = st.mtime.toISOString();
57
- rawTokensContentHash = sha256Hex(buf);
58
- }
59
- catch {
60
- // Missing raw tokens — record the path but leave mtime/hash null so
61
- // the staleness check can detect it as missing on read.
62
- }
63
- }
64
- return { files, rawTokensPath, rawTokensMtime, rawTokensContentHash };
65
- }
66
- /**
67
- * Hash the saved JSON contents the wizard just wrote. Caller passes the raw
68
- * bytes (or strings) so we hash exactly what landed on disk.
69
- */
70
- export function buildSavedFingerprint(input) {
71
- return {
72
- componentsJsonHash: input.componentsJson != null ? sha256Hex(input.componentsJson) : null,
73
- tokensJsonHash: input.tokensJson != null ? sha256Hex(input.tokensJson) : null,
74
- };
75
- }
@@ -1,137 +0,0 @@
1
- import { listRuns } from './store.js';
2
- import { resolveRunTarget } from './resolve-run-target.js';
3
- import { checkRunStaleness, shortStalenessSummary, formatStalenessDetail } from './staleness.js';
4
- function pad(value, width) {
5
- if (value.length >= width)
6
- return value;
7
- return value + ' '.repeat(width - value.length);
8
- }
9
- function formatCreated(iso) {
10
- // Drop ms + Z, render as `YYYY-MM-DD HH:MM`.
11
- const m = /^(\d{4}-\d{2}-\d{2})T(\d{2}:\d{2})/.exec(iso);
12
- return m ? `${m[1]} ${m[2]}` : iso;
13
- }
14
- function formatPushed(record) {
15
- if (!record.pushedTo)
16
- return '(not pushed)';
17
- return `${record.pushedTo.spaceId}/${record.pushedTo.environmentId}`;
18
- }
19
- function makeColumns(staleness) {
20
- return [
21
- { header: 'ID', get: (r) => r.id },
22
- { header: 'CREATED', get: (r) => formatCreated(r.createdAt) },
23
- { header: 'PROJECT', get: (r) => r.projectPath },
24
- { header: 'SAVED TO', get: (r) => r.savePath },
25
- { header: 'COMPONENTS', get: (r) => String(r.componentCount) },
26
- { header: 'PUSHED', get: formatPushed },
27
- { header: 'STALE', get: (_r, i) => shortStalenessSummary(staleness[i]) },
28
- ];
29
- }
30
- function renderFooter(runs, write) {
31
- if (runs.length === 0)
32
- return;
33
- const id = runs[0].id;
34
- write('\n');
35
- write(`Push run ${id}: experiences import --push-from-run ${id}\n`);
36
- write(`Modify run ${id}: experiences import --modify ${id}\n`);
37
- }
38
- async function renderDetail(run, write) {
39
- const lines = [
40
- `Run ${run.id}`,
41
- `Created: ${formatCreated(run.createdAt)}`,
42
- `Project: ${run.projectPath}`,
43
- `Saved: ${run.savePath}`,
44
- `Components: ${run.componentCount}`,
45
- `Tokens: ${run.tokenCount}`,
46
- ];
47
- if (run.tokensPath) {
48
- lines.push(`Tokens saved: ${run.tokensPath}`);
49
- }
50
- lines.push(`Agent: ${run.agent}`, `Pushed: ${formatPushed(run)}`, '');
51
- // Staleness status block. v2/v1 records (no sourceFingerprint) render as
52
- // UNKNOWN — the operator can re-extract for a fresh run.
53
- if (!run.sourceFingerprint) {
54
- lines.push('Status: UNKNOWN (run pre-dates the staleness fingerprint).');
55
- }
56
- else {
57
- const staleness = await checkRunStaleness(run);
58
- lines.push(...formatStalenessDetail(staleness));
59
- }
60
- lines.push('', `Push to Contentful: experiences import --push-from-run ${run.id}`, `Modify in wizard: experiences import --modify ${run.id}`, '');
61
- write(lines.join('\n'));
62
- }
63
- export async function runLsCommand(opts = {}) {
64
- const write = opts.write ?? ((s) => process.stdout.write(s));
65
- if (opts.pushed && opts.notPushed) {
66
- throw new Error('--pushed and --not-pushed are mutually exclusive');
67
- }
68
- if (opts.target) {
69
- const run = await resolveRunTarget(opts.target);
70
- if (opts.json) {
71
- write(JSON.stringify(run, null, 2) + '\n');
72
- return;
73
- }
74
- await renderDetail(run, write);
75
- return;
76
- }
77
- let runs = await listRuns({
78
- ...(opts.projectPath ? { projectPath: opts.projectPath } : {}),
79
- ...(typeof opts.limit === 'number' ? { limit: opts.limit } : {}),
80
- });
81
- if (opts.pushed)
82
- runs = runs.filter((r) => r.pushedTo !== null);
83
- if (opts.notPushed)
84
- runs = runs.filter((r) => r.pushedTo === null);
85
- if (opts.json) {
86
- write(JSON.stringify(runs, null, 2) + '\n');
87
- return;
88
- }
89
- if (runs.length === 0) {
90
- write('No runs recorded yet. Run `experiences import` to create one.\n');
91
- return;
92
- }
93
- // Compute staleness once per row so the table is consistent across the
94
- // STALE column and any future detail-equivalent surfaces.
95
- const stalenessByIdx = await Promise.all(runs.map(async (r) => (r.sourceFingerprint ? checkRunStaleness(r) : null)));
96
- const stalenessForCol = stalenessByIdx.map((s) => s ?? {
97
- stale: false,
98
- staleComponents: [],
99
- staleTokens: false,
100
- savedComponentsEdited: false,
101
- savedTokensEdited: false,
102
- missingSourceFiles: [],
103
- });
104
- const columns = makeColumns(stalenessForCol);
105
- // Auto-expand each column to max(header, max(row value)) so long paths
106
- // aren't silently truncated.
107
- const widths = columns.map((c) => Math.max(c.header.length, ...runs.map((r, i) => c.get(r, i).length)));
108
- const headerRow = columns.map((c, i) => pad(c.header, widths[i])).join(' ');
109
- write(headerRow + '\n');
110
- for (let i = 0; i < runs.length; i++) {
111
- const r = runs[i];
112
- const row = columns.map((c, ci) => pad(c.get(r, i), widths[ci])).join(' ');
113
- write(row + '\n');
114
- }
115
- renderFooter(runs, write);
116
- }
117
- export function registerRunsCommand(program) {
118
- program
119
- .command('runs [target]')
120
- .alias('ls')
121
- .description('List recorded import runs from ~/.config/experiences/runs.json, or show one run when [target] (id or path) is given')
122
- .option('--project <path>', 'Filter by source project path (absolute)')
123
- .option('--limit <n>', 'Limit the number of rows', (v) => parseInt(v, 10))
124
- .option('--json', 'Emit RunRecord JSON to stdout (array, or single object with [target])')
125
- .option('--pushed', 'Only show runs that have been pushed to Contentful')
126
- .option('--not-pushed', 'Only show runs that have not been pushed')
127
- .action(async (target, options) => {
128
- await runLsCommand({
129
- ...(target ? { target } : {}),
130
- ...(options.project ? { projectPath: options.project } : {}),
131
- ...(typeof options.limit === 'number' && !Number.isNaN(options.limit) ? { limit: options.limit } : {}),
132
- ...(options.json ? { json: true } : {}),
133
- ...(options.pushed ? { pushed: true } : {}),
134
- ...(options.notPushed ? { notPushed: true } : {}),
135
- });
136
- });
137
- }
@@ -1,42 +0,0 @@
1
- /**
2
- * Thin indirection so `runModifyCommand` can be unit-tested without spinning
3
- * up the real Ink wizard. The production implementation lives here.
4
- */
5
- export async function launchModifyWizard(input) {
6
- const { render } = await import('ink');
7
- const { createElement } = await import('react');
8
- const { WizardApp } = await import('../import/tui/WizardApp.js');
9
- // Modify entry: re-open the wizard with the prior run's sessions seeded so
10
- // extract + generate are skipped. The wizard short-circuits to `initialStep`
11
- // (typically `final-review`) using state derived from the seed IDs. Saved
12
- // credentials from the run record's `pushedTo` pre-fill the credentials
13
- // step (CMA token is never persisted, so it still falls through to the
14
- // env/credentials.json/prompt resolution path).
15
- const props = {
16
- initialProjectPath: input.projectPath,
17
- seedExtractSessionId: input.extractSessionId,
18
- initialStep: input.entryStep,
19
- };
20
- if (input.generateSessionId)
21
- props.seedGenerateSessionId = input.generateSessionId;
22
- if (input.tokenSessionId)
23
- props.seedTokenSessionId = input.tokenSessionId;
24
- if (input.compositionMode)
25
- props.compositionMode = input.compositionMode;
26
- if (input.saveMode === 'overwrite')
27
- props.outDirOverride = input.savePath;
28
- if (input.outDirOverride)
29
- props.outDirOverride = input.outDirOverride;
30
- if (input.initialSpaceId)
31
- props.initialSpaceId = input.initialSpaceId;
32
- if (input.initialEnvironmentId)
33
- props.initialEnvironmentId = input.initialEnvironmentId;
34
- if (input.initialHost)
35
- props.initialHost = input.initialHost;
36
- if (input.initialCmaToken)
37
- props.initialCmaToken = input.initialCmaToken;
38
- if (input.allowDeletions !== undefined)
39
- props.allowDeletions = input.allowDeletions;
40
- const { waitUntilExit } = render(createElement(WizardApp, props));
41
- await waitUntilExit();
42
- }
@@ -1,72 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useState, useEffect } from 'react';
3
- import { Box, Text } from 'ink';
4
- import { readdirSync } from 'node:fs';
5
- import { dirname, basename, join } from 'node:path';
6
- import { useImmediateInput } from '../analyze/select/tui/hooks/useImmediateInput.js';
7
- import { normalizePath } from '../import/path-utils.js';
8
- function autocomplete(partial) {
9
- if (!partial)
10
- return null;
11
- const normalized = normalizePath(partial);
12
- const dir = dirname(normalized);
13
- const base = basename(normalized);
14
- let entries;
15
- try {
16
- entries = readdirSync(dir);
17
- }
18
- catch {
19
- return null;
20
- }
21
- const matches = entries.filter((e) => e.startsWith(base));
22
- if (matches.length === 0)
23
- return null;
24
- if (matches.length === 1)
25
- return join(dir, matches[0]);
26
- // Common prefix
27
- let prefix = matches[0];
28
- for (const m of matches) {
29
- while (!m.startsWith(prefix))
30
- prefix = prefix.slice(0, -1);
31
- if (!prefix)
32
- break;
33
- }
34
- return prefix.length > base.length ? join(dir, prefix) : null;
35
- }
36
- export function PathPrompt({ defaultPath, onSubmit, onCancel, label = 'Save to', }) {
37
- const [input, setInput] = useState('');
38
- const [cursorVisible, setCursorVisible] = useState(true);
39
- useEffect(() => {
40
- const interval = setInterval(() => setCursorVisible((v) => !v), 500);
41
- return () => clearInterval(interval);
42
- }, []);
43
- useImmediateInput((rawInput, key) => {
44
- if (key.return) {
45
- const trimmed = input.trim();
46
- onSubmit(trimmed === '' ? defaultPath : normalizePath(trimmed));
47
- return;
48
- }
49
- if (key.escape) {
50
- onCancel();
51
- return;
52
- }
53
- if (key.tab) {
54
- const target = input.trim() || defaultPath;
55
- const completed = autocomplete(target);
56
- if (completed)
57
- setInput(completed);
58
- return;
59
- }
60
- if (key.backspace || key.delete) {
61
- setInput((v) => v.slice(0, -1));
62
- return;
63
- }
64
- if (rawInput && !key.ctrl && !key.meta) {
65
- setInput((v) => v + rawInput);
66
- }
67
- });
68
- const shown = input || defaultPath;
69
- const isPlaceholder = input === '';
70
- const cursor = cursorVisible ? '█' : ' ';
71
- return (_jsxs(Box, { flexDirection: "column", gap: 1, paddingX: 2, paddingY: 1, children: [_jsxs(Box, { gap: 1, children: [_jsx(Text, { color: "cyan", children: "?" }), _jsxs(Text, { bold: true, children: [label, ":"] }), _jsx(Text, { dimColor: isPlaceholder, children: shown }), _jsx(Text, { children: cursor })] }), _jsxs(Box, { gap: 3, children: [_jsx(Text, { dimColor: true, children: "[Enter] Confirm" }), _jsx(Text, { dimColor: true, children: "[Tab] Autocomplete" }), _jsx(Text, { dimColor: true, children: "[Esc] Cancel" })] })] }));
72
- }
@@ -1,39 +0,0 @@
1
- import React from 'react';
2
- export async function promptForPushCredentials(opts = {}) {
3
- const { render, Box, Text } = await import('ink');
4
- const { useState } = await import('react');
5
- const { CredentialsStep } = await import('../import/tui/steps/CredentialsStep.js');
6
- return new Promise((resolve, reject) => {
7
- let app = null;
8
- function App() {
9
- const [done, setDone] = useState(false);
10
- const handle = (spaceId, environmentId, cmaToken, host) => {
11
- if (done)
12
- return;
13
- setDone(true);
14
- // Defer unmount so Ink flushes the final render.
15
- queueMicrotask(() => {
16
- app?.unmount();
17
- resolve({ spaceId, environmentId, cmaToken, host });
18
- });
19
- };
20
- if (done) {
21
- return React.createElement(Box, null, React.createElement(Text, null, ''));
22
- }
23
- return React.createElement(CredentialsStep, {
24
- summary: opts.summary ?? 'Enter Contentful credentials to push this run. Press Enter on each field to advance.',
25
- ...(opts.initialSpaceId !== undefined ? { initialSpaceId: opts.initialSpaceId } : {}),
26
- ...(opts.initialEnvironmentId !== undefined ? { initialEnvironmentId: opts.initialEnvironmentId } : {}),
27
- ...(opts.initialCmaToken !== undefined ? { initialCmaToken: opts.initialCmaToken } : {}),
28
- ...(opts.initialHost !== undefined ? { initialHost: opts.initialHost } : {}),
29
- onConfirm: handle,
30
- onContinue: handle,
31
- onQuit: () => {
32
- app?.unmount();
33
- reject(new Error('Credentials entry cancelled.'));
34
- },
35
- });
36
- }
37
- app = render(React.createElement(App));
38
- });
39
- }
@@ -1,72 +0,0 @@
1
- import { execFile } from 'node:child_process';
2
- import { existsSync } from 'node:fs';
3
- import { dirname, join } from 'node:path';
4
- import { fileURLToPath } from 'node:url';
5
- /**
6
- * Resolve the package's CLI binary. Duplicates the walk from export-helpers
7
- * so push-helpers can be imported independently.
8
- */
9
- function findCliPath() {
10
- let dir = dirname(fileURLToPath(import.meta.url));
11
- for (let i = 0; i < 8; i++) {
12
- const candidate = join(dir, 'bin', 'cli.js');
13
- if (existsSync(candidate))
14
- return candidate;
15
- const parent = dirname(dir);
16
- if (parent === dir)
17
- break;
18
- dir = parent;
19
- }
20
- return join(fileURLToPath(import.meta.url), '..', '..', '..', '..', 'bin', 'cli.js');
21
- }
22
- function runCli(args) {
23
- const cliPath = findCliPath();
24
- if (!existsSync(cliPath)) {
25
- return Promise.resolve({
26
- exitCode: 1,
27
- stdout: '',
28
- stderr: `Cannot find CLI binary at ${cliPath}`,
29
- });
30
- }
31
- return new Promise((res) => {
32
- execFile('node', [cliPath, ...args], (err, stdout, stderr) => {
33
- res({
34
- exitCode: err && 'code' in err && typeof err.code === 'number' ? err.code : err ? 1 : 0,
35
- stdout,
36
- stderr,
37
- });
38
- });
39
- });
40
- }
41
- /**
42
- * Push a recorded pipeline.db session's components + tokens to Contentful by
43
- * shelling out to `experiences apply push --session <id>`. Does no local
44
- * file I/O — that is the whole point of --push-from-run.
45
- */
46
- export async function pushRunSession(opts) {
47
- const args = [
48
- 'apply',
49
- 'push',
50
- '--session',
51
- opts.sessionId,
52
- '--space-id',
53
- opts.spaceId,
54
- '--environment-id',
55
- opts.environmentId,
56
- '--cma-token',
57
- opts.cmaToken,
58
- '--yes',
59
- ];
60
- if (opts.host) {
61
- args.push('--host', opts.host);
62
- }
63
- if (opts.allowDeletions) {
64
- args.push('--allow-deletions');
65
- }
66
- const r = await runCli(args);
67
- if (r.exitCode === 0)
68
- return { ok: true };
69
- return { ok: false, error: r.stderr.trim() || r.stdout.trim() || `exit ${r.exitCode}` };
70
- }
71
- /** Internal test surface. Not part of the public API. */
72
- export const __testing = { findCliPath };
@@ -1,77 +0,0 @@
1
- /**
2
- * Push-from-picker launcher. When the operator selects "Push" from the
3
- * interactive run-picker, we mount the wizard with seeded session IDs and
4
- * `initialStep: 'push-from-picker'` so they see the same preview + push UX
5
- * as a fresh `experiences import` (preview → diff review → pushing progress
6
- * bars → done with view URL).
7
- *
8
- * This is deliberately parallel to `modify-launcher.ts`. The `--push-from-run`
9
- * CLI flag path (headless shell-out via `replayRun`) is preserved for
10
- * scripted / non-TTY use.
11
- */
12
- export async function launchPushWizard(input) {
13
- const { render } = await import('ink');
14
- const { createElement } = await import('react');
15
- const { WizardApp } = await import('../import/tui/WizardApp.js');
16
- const props = {
17
- initialProjectPath: input.projectPath,
18
- seedExtractSessionId: input.extractSessionId,
19
- initialStep: 'push-from-picker',
20
- };
21
- if (input.generateSessionId)
22
- props.seedGenerateSessionId = input.generateSessionId;
23
- if (input.tokenSessionId)
24
- props.seedTokenSessionId = input.tokenSessionId;
25
- if (input.tokensPath)
26
- props.seedTokensPath = input.tokensPath;
27
- if (input.initialSpaceId)
28
- props.initialSpaceId = input.initialSpaceId;
29
- if (input.initialEnvironmentId)
30
- props.initialEnvironmentId = input.initialEnvironmentId;
31
- if (input.initialHost)
32
- props.initialHost = input.initialHost;
33
- if (input.initialCmaToken)
34
- props.initialCmaToken = input.initialCmaToken;
35
- const { waitUntilExit } = render(createElement(WizardApp, props));
36
- await waitUntilExit();
37
- }
38
- /**
39
- * Interactive picker-Push entry point. Resolves the run record, applies the
40
- * staleness gate, layers credentials (flag → pushedTo → credentials.json),
41
- * and mounts the wizard via `launchPushWizard`.
42
- */
43
- export async function pickerPushRun(opts) {
44
- const { resolveRunTarget } = await import('./resolve-run-target.js');
45
- const { readExperiencesCredentials } = await import('../credentials-store.js');
46
- const { checkRunStaleness, formatStalenessDetail } = await import('./staleness.js');
47
- const run = await resolveRunTarget(opts.runIdOrPath);
48
- if (!opts.force) {
49
- const staleness = await checkRunStaleness(run);
50
- if (staleness.stale) {
51
- const detail = formatStalenessDetail(staleness);
52
- throw new Error([
53
- `Refusing to push run ${run.id} — source or saved files have drifted since the run was recorded.`,
54
- ...detail,
55
- '',
56
- 'Re-extract with `experiences import --project <path>` for a fresh run, or pass --force to bypass.',
57
- ].join('\n'));
58
- }
59
- }
60
- const stored = await readExperiencesCredentials();
61
- const spaceId = opts.spaceId || run.pushedTo?.spaceId || stored.spaceId || '';
62
- const environmentId = opts.environmentId || run.pushedTo?.environmentId || stored.environmentId || '';
63
- const cmaToken = opts.cmaToken || stored.cmaToken || '';
64
- const host = opts.host || run.pushedTo?.host || stored.host || '';
65
- await launchPushWizard({
66
- extractSessionId: run.extractSessionId,
67
- generateSessionId: run.generateSessionId,
68
- tokenSessionId: run.tokenSessionId,
69
- projectPath: run.projectPath,
70
- savePath: run.savePath,
71
- tokensPath: run.tokensPath,
72
- ...(spaceId ? { initialSpaceId: spaceId } : {}),
73
- ...(environmentId ? { initialEnvironmentId: environmentId } : {}),
74
- ...(host ? { initialHost: host } : {}),
75
- ...(cmaToken ? { initialCmaToken: cmaToken } : {}),
76
- });
77
- }