@contentful/experience-design-system-cli 2.36.2-dev-build-a6f80ae6.0 → 2.36.2-dev-build-7907fec3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/app.js CHANGED
@@ -1,9 +1,9 @@
1
1
  // packages/experience-design-system-cli/app.tsx
2
- import { useState as useState8 } from "react";
2
+ import { useEffect as useEffect8, useState as useState11 } from "react";
3
3
 
4
4
  // packages/experience-design-system-cli/src/tui/home/home.tsx
5
5
  import { useEffect as useEffect2, useState as useState2 } from "react";
6
- import { Box, Text, useApp, useInput } from "ink";
6
+ import { Box, Text as Text2, useApp, useInput } from "ink";
7
7
 
8
8
  // packages/experience-design-system-cli/src/tui/home/home.theme.ts
9
9
  var BRAND = {
@@ -117,8 +117,15 @@ function useTerminalWidth() {
117
117
  return columns;
118
118
  }
119
119
 
120
+ // packages/experience-design-system-cli/src/tui/control-hints.tsx
121
+ import { Text } from "ink";
122
+ import { jsx } from "react/jsx-runtime";
123
+ function ControlHints({ hints }) {
124
+ return /* @__PURE__ */ jsx(Text, { color: PALETTE.muted, children: hints.map((hint) => `${hint.keys} ${hint.label}`).join(" \xB7 ") });
125
+ }
126
+
120
127
  // packages/experience-design-system-cli/src/tui/home/home.tsx
121
- import { jsx, jsxs } from "react/jsx-runtime";
128
+ import { jsx as jsx2, jsxs } from "react/jsx-runtime";
122
129
  var VERSION = readPackageVersion();
123
130
  var HEADING = "Contentful Experiences";
124
131
  var SUBTITLE = "Let's import your design system into Contentful";
@@ -171,27 +178,27 @@ function HomeScreen({ onNavigate }) {
171
178
  });
172
179
  if (tooNarrow) {
173
180
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [
174
- /* @__PURE__ */ jsx(Text, { bold: true, color: PALETTE.warning, children: "Terminal too small" }),
175
- /* @__PURE__ */ jsx(Text, { color: PALETTE.muted, children: "Press q to quit, make your terminal full screen, then run experiences import again." })
181
+ /* @__PURE__ */ jsx2(Text2, { bold: true, color: PALETTE.warning, children: "Terminal too small" }),
182
+ /* @__PURE__ */ jsx2(Text2, { color: PALETTE.muted, children: "Press q to quit, make your terminal full screen, then run experiences import again." })
176
183
  ] });
177
184
  }
178
185
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [
179
186
  /* @__PURE__ */ jsxs(Box, { flexDirection: "column", alignItems: "center", children: [
180
- /* @__PURE__ */ jsx(Text, { bold: true, color: PALETTE.heading, children: HEADING }),
181
- /* @__PURE__ */ jsx(Text, { children: brandBar(HEADING.length).map((segment, i) => /* @__PURE__ */ jsx(Text, { color: segment.color, children: segment.text }, i)) }),
182
- /* @__PURE__ */ jsx(Text, { color: PALETTE.muted, children: SUBTITLE }),
183
- /* @__PURE__ */ jsxs(Text, { color: PALETTE.muted, children: [
187
+ /* @__PURE__ */ jsx2(Text2, { bold: true, color: PALETTE.heading, children: HEADING }),
188
+ /* @__PURE__ */ jsx2(Text2, { children: brandBar(HEADING.length).map((segment, i) => /* @__PURE__ */ jsx2(Text2, { color: segment.color, children: segment.text }, i)) }),
189
+ /* @__PURE__ */ jsx2(Text2, { color: PALETTE.muted, children: SUBTITLE }),
190
+ /* @__PURE__ */ jsxs(Text2, { color: PALETTE.muted, children: [
184
191
  "v",
185
192
  VERSION
186
193
  ] })
187
194
  ] }),
188
- /* @__PURE__ */ jsx(Box, { marginTop: 1, justifyContent: "center", children: /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: START_ITEMS.map((item, i) => {
195
+ /* @__PURE__ */ jsx2(Box, { marginTop: 1, justifyContent: "center", children: /* @__PURE__ */ jsx2(Box, { flexDirection: "column", children: START_ITEMS.map((item, i) => {
189
196
  const focused = i === focusIdx;
190
197
  const isUpgradeItem = item.screen === "upgrade";
191
198
  const display = isUpgradeItem ? upgradeItemDisplay(upgradeCheck) : { label: item.label };
192
199
  const dimmed = isUpgradeItem && upgradeDisabled;
193
200
  return /* @__PURE__ */ jsxs(
194
- Text,
201
+ Text2,
195
202
  {
196
203
  bold: focused && !dimmed,
197
204
  dimColor: dimmed,
@@ -204,13 +211,22 @@ function HomeScreen({ onNavigate }) {
204
211
  item.label
205
212
  );
206
213
  }) }) }),
207
- /* @__PURE__ */ jsx(Box, { marginTop: 1, justifyContent: "center", children: /* @__PURE__ */ jsx(Text, { color: PALETTE.muted, children: "\u2191/\u2193 move \xB7 \u23CE select \xB7 q quit" }) })
214
+ /* @__PURE__ */ jsx2(Box, { marginTop: 1, justifyContent: "center", children: /* @__PURE__ */ jsx2(
215
+ ControlHints,
216
+ {
217
+ hints: [
218
+ { keys: "\u2191/\u2193", label: "move" },
219
+ { keys: "\u23CE", label: "select" },
220
+ { keys: "q", label: "quit" }
221
+ ]
222
+ }
223
+ ) })
208
224
  ] });
209
225
  }
210
226
 
211
227
  // packages/experience-design-system-cli/src/tui/import/PageContainer.tsx
212
- import { Box as Box2, Text as Text2, useInput as useInput2 } from "ink";
213
- import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
228
+ import { Box as Box2, Text as Text3, useInput as useInput2 } from "ink";
229
+ import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
214
230
  function ImportScreen({ exitCode, onDone }) {
215
231
  useInput2((input, key) => {
216
232
  if (key.return || key.escape || input === "q") {
@@ -219,14 +235,210 @@ function ImportScreen({ exitCode, onDone }) {
219
235
  });
220
236
  const isSuccess = exitCode === 0;
221
237
  return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [
222
- /* @__PURE__ */ jsx2(Text2, { bold: true, children: "Import" }),
223
- /* @__PURE__ */ jsx2(Text2, { children: " " }),
224
- isSuccess ? /* @__PURE__ */ jsx2(Text2, { color: PALETTE.success, children: "\u2713 Import complete" }) : /* @__PURE__ */ jsxs2(Text2, { color: PALETTE.error, children: [
238
+ /* @__PURE__ */ jsx3(Text3, { bold: true, children: "Import" }),
239
+ /* @__PURE__ */ jsx3(Text3, { children: " " }),
240
+ isSuccess ? /* @__PURE__ */ jsx3(Text3, { color: PALETTE.success, children: "\u2713 Import complete" }) : /* @__PURE__ */ jsxs2(Text3, { color: PALETTE.error, children: [
225
241
  "\u2717 Import failed: process exited with code ",
226
242
  exitCode ?? "unknown"
227
243
  ] }),
228
- /* @__PURE__ */ jsx2(Text2, { children: " " }),
229
- /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "[Enter] Back to Start" })
244
+ /* @__PURE__ */ jsx3(Text3, { children: " " }),
245
+ /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "[Enter] Back to Start" })
246
+ ] });
247
+ }
248
+
249
+ // packages/experience-design-system-cli/src/tui/import/steps/01-welcome/screen.tsx
250
+ import { useState as useState3 } from "react";
251
+ import { Box as Box3, Text as Text4 } from "ink";
252
+ import TextInput from "ink-text-input";
253
+
254
+ // packages/experience-design-system-cli/src/tui/import/steps/01-welcome/controls.ts
255
+ import { useInput as useInput3 } from "ink";
256
+
257
+ // packages/experience-design-system-cli/src/tui/import/steps/01-welcome/logic.ts
258
+ function shouldQuit(value, input, key) {
259
+ if (key.escape) return true;
260
+ return value === "" && input === "q" && !key.ctrl && !key.meta;
261
+ }
262
+ function toProjectPath(value) {
263
+ const projectPath = value.trim();
264
+ return projectPath === "" ? null : projectPath;
265
+ }
266
+
267
+ // packages/experience-design-system-cli/src/tui/import/steps/01-welcome/controls.ts
268
+ var WELCOME_CONTROLS = [
269
+ { keys: "Enter", label: "Continue" },
270
+ { keys: "Esc/q", label: "Back to menu" }
271
+ ];
272
+ function useWelcomeControls(projectPath, onQuit) {
273
+ useInput3((input, key) => {
274
+ if (shouldQuit(projectPath, input, key)) onQuit();
275
+ });
276
+ }
277
+
278
+ // packages/experience-design-system-cli/src/tui/import/steps/01-welcome/screen.tsx
279
+ import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
280
+ var RULE = "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500";
281
+ var OVERVIEW = [
282
+ { label: "Step 1", description: "Extract components from your codebase" },
283
+ { label: "Step 2", description: "Review what was extracted" },
284
+ { label: "Step 3", description: "Generate CDF definitions with Claude" },
285
+ { label: "Step 4", description: "Review generated definitions" },
286
+ { label: "Step 5", description: "Push to Contentful" }
287
+ ];
288
+ function WelcomeScreen({ onContinue, onQuit, initialPath = "" }) {
289
+ const [projectPath, setProjectPath] = useState3(initialPath);
290
+ useWelcomeControls(projectPath, onQuit);
291
+ const submit = (value) => {
292
+ const path = toProjectPath(value);
293
+ if (path) onContinue(path);
294
+ };
295
+ return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", gap: 1, paddingX: 2, paddingY: 1, children: [
296
+ /* @__PURE__ */ jsx4(Text4, { bold: true, color: PALETTE.success, children: "\u{1F44B} Hey! Let's import your design system into Contentful." }),
297
+ /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: "I'll walk you through 5 steps to get your components into Contentful ExO." }),
298
+ /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", marginTop: 1, children: [
299
+ /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: RULE }),
300
+ OVERVIEW.map((item) => /* @__PURE__ */ jsxs3(Box3, { gap: 1, children: [
301
+ /* @__PURE__ */ jsx4(Text4, { bold: true, children: item.label }),
302
+ /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: item.description })
303
+ ] }, item.label)),
304
+ /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: RULE })
305
+ ] }),
306
+ /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", marginTop: 1, children: [
307
+ /* @__PURE__ */ jsx4(Text4, { children: "Where is your component library?" }),
308
+ /* @__PURE__ */ jsxs3(Box3, { gap: 1, children: [
309
+ /* @__PURE__ */ jsx4(Text4, { color: PALETTE.accent, children: "?" }),
310
+ /* @__PURE__ */ jsx4(Text4, { children: "Project path:" }),
311
+ /* @__PURE__ */ jsx4(TextInput, { value: projectPath, onChange: setProjectPath, onSubmit: submit })
312
+ ] })
313
+ ] }),
314
+ /* @__PURE__ */ jsx4(Box3, { marginTop: 1, gap: 3, children: WELCOME_CONTROLS.map((control) => /* @__PURE__ */ jsxs3(Text4, { dimColor: true, children: [
315
+ "[",
316
+ control.keys,
317
+ "] ",
318
+ control.label
319
+ ] }, control.keys)) })
320
+ ] });
321
+ }
322
+
323
+ // packages/experience-design-system-cli/src/tui/import/steps/02-token-input/screen.tsx
324
+ import { useState as useState4 } from "react";
325
+ import { Box as Box4, Text as Text5 } from "ink";
326
+ import TextInput2 from "ink-text-input";
327
+
328
+ // packages/experience-design-system-cli/src/tui/import/steps/02-token-input/controls.ts
329
+ import { useInput as useInput4 } from "ink";
330
+
331
+ // packages/experience-design-system-cli/src/tui/import/steps/02-token-input/logic.ts
332
+ function isPlainKeyOnEmptyField(value, input, key, expected) {
333
+ return value === "" && input === expected && !key.ctrl && !key.meta;
334
+ }
335
+ function shouldGoBack(value, input, key) {
336
+ return key.escape || isPlainKeyOnEmptyField(value, input, key, "q");
337
+ }
338
+ function shouldSkip(value, input, key) {
339
+ return isPlainKeyOnEmptyField(value, input, key, "s");
340
+ }
341
+ function toTokenPath(value) {
342
+ const tokenPath = value.trim();
343
+ return tokenPath === "" ? null : tokenPath;
344
+ }
345
+
346
+ // packages/experience-design-system-cli/src/tui/import/steps/02-token-input/controls.ts
347
+ var TOKEN_INPUT_CONTROLS = [
348
+ { keys: "Enter", label: "Continue (skips if empty)" },
349
+ { keys: "s", label: "Skip" },
350
+ { keys: "Esc/q", label: "Back" }
351
+ ];
352
+ function useTokenInputControls(tokenPath, onSkip, onBack) {
353
+ useInput4((input, key) => {
354
+ if (shouldGoBack(tokenPath, input, key)) onBack();
355
+ else if (shouldSkip(tokenPath, input, key)) onSkip();
356
+ });
357
+ }
358
+
359
+ // packages/experience-design-system-cli/src/tui/import/steps/02-token-input/validate-path.ts
360
+ import { statSync } from "node:fs";
361
+ import { homedir } from "node:os";
362
+ import { resolve } from "node:path";
363
+ function stripQuotes(value) {
364
+ const quoted = value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'");
365
+ return value.length >= 2 && quoted ? value.slice(1, -1) : value;
366
+ }
367
+ function expandHome(value) {
368
+ return value === "~" || value.startsWith("~/") || value.startsWith("~\\") ? homedir() + value.slice(1) : value;
369
+ }
370
+ function validateTokenPath(rawPath) {
371
+ const path = resolve(expandHome(stripQuotes(rawPath.trim())));
372
+ let stats;
373
+ try {
374
+ stats = statSync(path);
375
+ } catch {
376
+ return { ok: false, error: `Path not found: ${path}`, resolvedPath: path };
377
+ }
378
+ if (stats.isDirectory()) {
379
+ return {
380
+ ok: false,
381
+ error: "That's a directory \u2014 provide a path to a token file (e.g. tokens.json), not a folder.",
382
+ resolvedPath: path
383
+ };
384
+ }
385
+ if (!stats.isFile()) {
386
+ return { ok: false, error: `Not a regular file: ${path}`, resolvedPath: path };
387
+ }
388
+ return { ok: true, path };
389
+ }
390
+
391
+ // packages/experience-design-system-cli/src/tui/import/steps/02-token-input/screen.tsx
392
+ import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
393
+ function TokenInputScreen({
394
+ onConfirm,
395
+ onSkip,
396
+ onBack,
397
+ initialPath = ""
398
+ }) {
399
+ const [tokenPath, setTokenPath] = useState4(initialPath);
400
+ const [failure, setFailure] = useState4(null);
401
+ useTokenInputControls(tokenPath, onSkip, onBack);
402
+ const change = (value) => {
403
+ setTokenPath(value);
404
+ setFailure(null);
405
+ };
406
+ const submit = (value) => {
407
+ const rawPath = toTokenPath(value);
408
+ if (!rawPath) {
409
+ onSkip();
410
+ return;
411
+ }
412
+ const check = validateTokenPath(rawPath);
413
+ if (check.ok) onConfirm(check.path);
414
+ else setFailure({ error: check.error, resolvedPath: check.resolvedPath });
415
+ };
416
+ return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", gap: 1, paddingX: 2, paddingY: 1, children: [
417
+ /* @__PURE__ */ jsx5(Text5, { bold: true, children: "Design tokens" }),
418
+ /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "Point me to your raw token file (e.g. ~/design-tokens/tokens.json). You can use ~, relative, or absolute paths. Claude will map it to DTCG format." }),
419
+ /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", marginTop: 1, children: [
420
+ /* @__PURE__ */ jsxs4(Box4, { gap: 1, children: [
421
+ /* @__PURE__ */ jsx5(Text5, { color: PALETTE.accent, children: "?" }),
422
+ /* @__PURE__ */ jsx5(Text5, { children: "Token path:" }),
423
+ /* @__PURE__ */ jsx5(TextInput2, { value: tokenPath, onChange: change, onSubmit: submit })
424
+ ] }),
425
+ failure && /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
426
+ /* @__PURE__ */ jsxs4(Text5, { color: PALETTE.error, children: [
427
+ "\u2717 ",
428
+ failure.error
429
+ ] }),
430
+ /* @__PURE__ */ jsxs4(Text5, { dimColor: true, children: [
431
+ " Resolved to: ",
432
+ failure.resolvedPath
433
+ ] })
434
+ ] })
435
+ ] }),
436
+ /* @__PURE__ */ jsx5(Box4, { marginTop: 1, gap: 3, children: TOKEN_INPUT_CONTROLS.map((control) => /* @__PURE__ */ jsxs4(Text5, { dimColor: true, children: [
437
+ "[",
438
+ control.keys,
439
+ "] ",
440
+ control.label
441
+ ] }, control.keys)) })
230
442
  ] });
231
443
  }
232
444
 
@@ -257,6 +469,9 @@ function buildArgs(options) {
257
469
  if (options.project) {
258
470
  args.push("--project", options.project);
259
471
  }
472
+ if (options.tokens) {
473
+ args.push("--tokens", options.tokens);
474
+ }
260
475
  return args;
261
476
  }
262
477
  async function spawnV1Import(options = {}) {
@@ -280,7 +495,7 @@ function getTerminalHandle() {
280
495
  return process.stdin._handle;
281
496
  }
282
497
  async function stopReadingTerminal() {
283
- await new Promise((resolve) => setImmediate(resolve));
498
+ await new Promise((resolve2) => setImmediate(resolve2));
284
499
  const handle = getTerminalHandle();
285
500
  if (!handle?.readStop) return;
286
501
  handle.reading = false;
@@ -294,43 +509,281 @@ function startReadingTerminal() {
294
509
  }
295
510
 
296
511
  // packages/experience-design-system-cli/src/tui/help/PageContainer.tsx
297
- import { Box as Box3, Text as Text3, useInput as useInput3 } from "ink";
298
- import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
512
+ import { useEffect as useEffect3, useState as useState5 } from "react";
513
+ import { Box as Box5, Text as Text6, useInput as useInput5 } from "ink";
514
+
515
+ // packages/experience-design-system-cli/src/tui/debug-store.ts
516
+ import { mkdir as mkdir2, writeFile as writeFile2 } from "node:fs/promises";
517
+ import { existsSync as existsSync3, readdirSync } from "node:fs";
518
+ import { join as join5 } from "node:path";
519
+
520
+ // packages/experience-design-system-types/dist/src/config/index.js
521
+ import { randomBytes } from "node:crypto";
522
+ import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
523
+ import { homedir as homedir2 } from "node:os";
524
+ import { dirname as dirname2, join as join4 } from "node:path";
525
+ function configRoot() {
526
+ return process.env["EDS_HOME"] || join4(homedir2(), ".contentful", "experience-design-system-cli");
527
+ }
528
+ var configFilePath = () => join4(configRoot(), "config.json");
529
+ var debugSessionsDir = () => join4(configRoot(), "debug", "sessions");
530
+ async function readSettings() {
531
+ try {
532
+ return JSON.parse(await readFile(configFilePath(), "utf8"));
533
+ } catch {
534
+ return {};
535
+ }
536
+ }
537
+ async function writeSettings(settings) {
538
+ const path = configFilePath();
539
+ await mkdir(dirname2(path), { recursive: true });
540
+ const tmp = `${path}.${process.pid}.${randomBytes(4).toString("hex")}.tmp`;
541
+ await writeFile(tmp, `${JSON.stringify(settings, null, 2)}
542
+ `, { mode: 384 });
543
+ await rename(tmp, path);
544
+ }
545
+ async function updateSettings(patch) {
546
+ await writeSettings({ ...await readSettings(), ...patch });
547
+ }
548
+
549
+ // packages/experience-design-system-cli/src/tui/settings/debug-mode/debug-mode-store.ts
550
+ var DEFAULT_DEBUG_MODE_SETTING = {
551
+ enabled: true
552
+ };
553
+ async function readDebugModeSetting() {
554
+ const { debugMode } = await readSettings();
555
+ return { ...DEFAULT_DEBUG_MODE_SETTING, ...debugMode };
556
+ }
557
+ async function writeDebugModeSetting(setting) {
558
+ await updateSettings({ debugMode: setting });
559
+ }
560
+
561
+ // packages/experience-design-system-cli/src/tui/debug-store.ts
562
+ var pendingRun;
563
+ function generateRunId() {
564
+ const now = /* @__PURE__ */ new Date();
565
+ const pad = (n) => String(n).padStart(2, "0");
566
+ return `${now.getFullYear()}${pad(now.getMonth() + 1)}${pad(now.getDate())}-${pad(now.getHours())}${pad(now.getMinutes())}${pad(now.getSeconds())}`;
567
+ }
568
+ function datePrefix(now = /* @__PURE__ */ new Date()) {
569
+ const pad = (n) => String(n).padStart(2, "0");
570
+ return `${pad(now.getMonth() + 1)}-${pad(now.getDate())}-${now.getFullYear()}`;
571
+ }
572
+ function slugify(value) {
573
+ return value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
574
+ }
575
+ function generateSessionId() {
576
+ const today = datePrefix();
577
+ const root = debugSessionsDir();
578
+ const existing = existsSync3(root) ? readdirSync(root) : [];
579
+ const seqPattern = new RegExp(`^${today}-session-(\\d+)$`);
580
+ const maxSeq = existing.reduce((max, entry) => {
581
+ const match = seqPattern.exec(entry);
582
+ return match ? Math.max(max, Number(match[1])) : max;
583
+ }, 0);
584
+ return `${today}-session-${maxSeq + 1}`;
585
+ }
586
+ var SESSION_ID = generateSessionId();
587
+ function sessionDebugDir() {
588
+ return join5(debugSessionsDir(), SESSION_ID);
589
+ }
590
+ function currentDebugSessionDir() {
591
+ return sessionDebugDir();
592
+ }
593
+ void isDebugModeEnabled().then((enabled) => {
594
+ if (!enabled) return void 0;
595
+ return mkdir2(sessionDebugDir(), { recursive: true });
596
+ });
597
+ async function isDebugModeEnabled() {
598
+ try {
599
+ return (await readDebugModeSetting()).enabled;
600
+ } catch {
601
+ return true;
602
+ }
603
+ }
604
+ function redact(value) {
605
+ const clone = { ...value };
606
+ if ("cma_token" in clone) {
607
+ const raw = clone.cma_token;
608
+ clone.cma_token = typeof raw === "string" && raw.length > 0 ? `[present, ${raw.length} chars]` : "[not set]";
609
+ }
610
+ return clone;
611
+ }
612
+ function startDebugRun({
613
+ flow,
614
+ step,
615
+ menuOption,
616
+ inputs
617
+ }) {
618
+ const runId = generateRunId();
619
+ const startedAt = Date.now();
620
+ const redactedInputs = redact(inputs);
621
+ isDebugModeEnabled().then((enabled) => {
622
+ if (!enabled) return;
623
+ pendingRun = { flow, step, runId, menuOption, inputs: redactedInputs, startedAt };
624
+ });
625
+ }
626
+ async function finishDebugRun({
627
+ outputs,
628
+ status,
629
+ exitMethod
630
+ }) {
631
+ const run = pendingRun;
632
+ if (!run) return;
633
+ pendingRun = void 0;
634
+ const durationMs = Date.now() - run.startedAt;
635
+ const content = renderMarkdown(run, { outputs: redact(outputs), status, exitMethod, durationMs });
636
+ const flowSegments = run.flow.split("/");
637
+ const dir = join5(sessionDebugDir(), ...flowSegments);
638
+ await mkdir2(dir, { recursive: true });
639
+ const filename = nextAttemptFilename(dir, run.menuOption);
640
+ await writeFile2(join5(dir, filename), content, { mode: 384 });
641
+ }
642
+ function nextAttemptFilename(dir, menuOption) {
643
+ const today = datePrefix();
644
+ const optionSlug = slugify(menuOption);
645
+ const existing = existsSync3(dir) ? readdirSync(dir) : [];
646
+ const attemptPattern = new RegExp(`^${today}-${optionSlug}-attempt-(\\d+)\\.md$`);
647
+ const maxAttempt = existing.reduce((max, entry) => {
648
+ const match = attemptPattern.exec(entry);
649
+ return match ? Math.max(max, Number(match[1])) : max;
650
+ }, 0);
651
+ return `${today}-${optionSlug}-attempt-${maxAttempt + 1}.md`;
652
+ }
653
+ function renderMarkdown(run, finish) {
654
+ const stepMatch = /^(\d+)-(.+)$/.exec(run.step);
655
+ const stepLabel = stepMatch ? `${stepMatch[1]} - ${stepMatch[2]}` : run.step;
656
+ const flowSlug = run.flow.split("/").join("-");
657
+ return `# Debug Log
658
+
659
+ - Run ID: ${run.runId}
660
+ - Flow: ${flowSlug}
661
+ - Step: ${stepLabel}
662
+ - Menu option: ${run.menuOption}
663
+ - Date: ${(/* @__PURE__ */ new Date()).toISOString()}
664
+ - CLI version: ${readPackageVersion()}
665
+ - Platform: ${process.platform} / Node ${process.version}
666
+ - Duration on screen: ${finish.durationMs}ms
667
+ - Status: ${finish.status}
668
+ - Exit method: ${finish.exitMethod}
669
+
670
+ ## Inputs
671
+ \`\`\`json
672
+ ${JSON.stringify(run.inputs, null, 2)}
673
+ \`\`\`
674
+
675
+ ## Outputs
676
+ \`\`\`json
677
+ ${JSON.stringify(finish.outputs, null, 2)}
678
+ \`\`\`
679
+ `;
680
+ }
681
+ function handleCrash() {
682
+ return finishDebugRun({ outputs: {}, status: "error", exitMethod: "crashed" });
683
+ }
684
+ process.once("uncaughtException", (err) => {
685
+ void handleCrash().finally(() => {
686
+ throw err;
687
+ });
688
+ });
689
+ process.once("unhandledRejection", (reason) => {
690
+ void handleCrash().finally(() => {
691
+ throw reason;
692
+ });
693
+ });
694
+ process.once("SIGINT", () => {
695
+ void handleCrash().finally(() => {
696
+ process.exit(130);
697
+ });
698
+ });
699
+
700
+ // packages/experience-design-system-cli/src/tui/help/help-info.ts
701
+ async function readHelpInfo() {
702
+ const debugMode = await readDebugModeSetting();
703
+ return {
704
+ storage: [
705
+ { label: "Config folder", value: configRoot() },
706
+ { label: "Settings file", value: configFilePath() },
707
+ { label: "Debug logs", value: debugSessionsDir() }
708
+ ],
709
+ troubleshooting: [
710
+ { label: "CLI version", value: readPackageVersion() },
711
+ { label: "Node", value: process.version },
712
+ { label: "Platform", value: `${process.platform} ${process.arch}` },
713
+ { label: "Debug Mode", value: debugMode.enabled ? "on" : "off" },
714
+ {
715
+ label: "This session",
716
+ value: debugMode.enabled ? currentDebugSessionDir() : "no logs written while Debug Mode is off"
717
+ }
718
+ ]
719
+ };
720
+ }
721
+
722
+ // packages/experience-design-system-cli/src/tui/help/PageContainer.tsx
723
+ import { Fragment, jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
724
+ function Section({ title, rows }) {
725
+ return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
726
+ /* @__PURE__ */ jsx6(Text6, { bold: true, color: PALETTE.accent, children: title }),
727
+ rows.map((row) => /* @__PURE__ */ jsxs5(Box5, { gap: 1, children: [
728
+ /* @__PURE__ */ jsx6(Box5, { width: 14, flexShrink: 0, children: /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: row.label }) }),
729
+ /* @__PURE__ */ jsx6(Text6, { children: row.value })
730
+ ] }, row.label))
731
+ ] });
732
+ }
299
733
  function HelpScreen({ onDone }) {
300
- useInput3((input, key) => {
734
+ const [info, setInfo] = useState5();
735
+ useEffect3(() => {
736
+ startDebugRun({ flow: "help", step: "01-help", menuOption: "Help", inputs: {} });
737
+ void readHelpInfo().then(setInfo);
738
+ }, []);
739
+ const leave = (exitMethod) => {
740
+ void finishDebugRun({ outputs: {}, status: "success", exitMethod });
741
+ onDone();
742
+ };
743
+ useInput5((input, key) => {
301
744
  if (key.return) {
302
- onDone();
745
+ leave("saved");
303
746
  return;
304
747
  }
305
748
  if (key.escape || input === "q") {
306
- onDone();
749
+ leave("discarded");
307
750
  return;
308
751
  }
309
752
  });
310
- return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [
311
- /* @__PURE__ */ jsx3(Text3, { bold: true, children: "Help" }),
312
- /* @__PURE__ */ jsx3(Text3, { children: " " }),
313
- /* @__PURE__ */ jsx3(Text3, { children: "This is a placeholder screen for v2 help content." }),
314
- /* @__PURE__ */ jsx3(Text3, { children: " " }),
315
- /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "[Enter] Complete [Esc/q] Exit \u2014 both return to Start" })
753
+ return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", paddingX: 2, paddingY: 1, gap: 1, children: [
754
+ /* @__PURE__ */ jsx6(Text6, { bold: true, children: "Help" }),
755
+ info ? /* @__PURE__ */ jsxs5(Fragment, { children: [
756
+ /* @__PURE__ */ jsx6(Section, { title: "Where things are stored", rows: info.storage }),
757
+ /* @__PURE__ */ jsx6(Section, { title: "Troubleshooting", rows: info.troubleshooting }),
758
+ /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "Hit a problem? Turn on Debug Mode in Settings, reproduce it, then share the session folder above. The CMA token is redacted from those logs." })
759
+ ] }) : /* @__PURE__ */ jsx6(Text6, { color: PALETTE.accent, children: "Loading..." }),
760
+ /* @__PURE__ */ jsx6(
761
+ ControlHints,
762
+ {
763
+ hints: [
764
+ { keys: "\u23CE", label: "done" },
765
+ { keys: "Esc/q", label: "back" }
766
+ ]
767
+ }
768
+ )
316
769
  ] });
317
770
  }
318
771
 
319
772
  // packages/experience-design-system-cli/src/tui/settings/PageContainer.tsx
320
- import { useState as useState3 } from "react";
321
- import { Box as Box4, Text as Text4, useInput as useInput4 } from "ink";
322
- import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
773
+ import { useState as useState6 } from "react";
774
+ import { Box as Box6, Text as Text7, useInput as useInput6 } from "ink";
775
+ import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
323
776
  function SettingsScreen({
324
777
  onNavigate,
325
778
  onBack
326
779
  }) {
327
- const [focusIdx, setFocusIdx] = useState3(0);
780
+ const [focusIdx, setFocusIdx] = useState6(0);
328
781
  const items = [
329
782
  { label: "Configuration", screen: "settings-configuration" },
330
783
  { label: "Opt-in Analytics", screen: "settings-opt-in-analytics" },
331
784
  { label: "Debug Mode", screen: "settings-debug-mode" }
332
785
  ];
333
- useInput4((input, key) => {
786
+ useInput6((input, key) => {
334
787
  if (key.upArrow) {
335
788
  setFocusIdx((i) => (i - 1 + items.length) % items.length);
336
789
  return;
@@ -350,40 +803,35 @@ function SettingsScreen({
350
803
  onBack();
351
804
  }
352
805
  });
353
- return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [
354
- /* @__PURE__ */ jsx4(Text4, { bold: true, children: "Settings" }),
355
- /* @__PURE__ */ jsx4(Text4, { children: " " }),
356
- items.map((item, i) => /* @__PURE__ */ jsxs4(Text4, { color: i === focusIdx ? "cyan" : void 0, children: [
806
+ return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [
807
+ /* @__PURE__ */ jsx7(Text7, { bold: true, children: "Settings" }),
808
+ /* @__PURE__ */ jsx7(Text7, { children: " " }),
809
+ items.map((item, i) => /* @__PURE__ */ jsxs6(Text7, { color: i === focusIdx ? "cyan" : void 0, children: [
357
810
  i === focusIdx ? "> " : " ",
358
811
  item.label
359
812
  ] }, item.label)),
360
- /* @__PURE__ */ jsx4(Text4, { children: " " }),
361
- /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: "[\u2191/\u2193] Navigate [Enter] Select [Esc/q] Back to Start" })
813
+ /* @__PURE__ */ jsx7(Text7, { children: " " }),
814
+ /* @__PURE__ */ jsx7(
815
+ ControlHints,
816
+ {
817
+ hints: [
818
+ { keys: "\u2191/\u2193", label: "move" },
819
+ { keys: "\u23CE", label: "select" },
820
+ { keys: "Esc/q", label: "back" }
821
+ ]
822
+ }
823
+ )
362
824
  ] });
363
825
  }
364
826
 
365
827
  // packages/experience-design-system-cli/src/tui/settings/contentful-configuration/ContentfulConfigScreen.tsx
366
- import { useEffect as useEffect3, useState as useState4 } from "react";
367
- import { Box as Box5, Text as Text5, useInput as useInput5 } from "ink";
828
+ import { useEffect as useEffect4, useState as useState7 } from "react";
829
+ import { Box as Box7, Text as Text8, useInput as useInput7 } from "ink";
830
+ import TextInput3 from "ink-text-input";
368
831
 
369
832
  // packages/experience-design-system-cli/src/tui/settings/utils/v1-store.ts
370
- import { readFile, writeFile, mkdir } from "node:fs/promises";
371
- import { join as join4 } from "node:path";
372
- import { homedir } from "node:os";
373
- var V1_STORE_PATH = join4(homedir(), ".config", "experiences", "credentials.json");
374
- async function readV1Store() {
375
- try {
376
- const raw = await readFile(V1_STORE_PATH, "utf8");
377
- return JSON.parse(raw);
378
- } catch {
379
- return {};
380
- }
381
- }
382
- async function writeV1Store(data) {
383
- await mkdir(join4(homedir(), ".config", "experiences"), { recursive: true });
384
- await writeFile(V1_STORE_PATH, `${JSON.stringify(data, null, 2)}
385
- `, { mode: 384 });
386
- }
833
+ var readV1Store = readSettings;
834
+ var writeV1Store = writeSettings;
387
835
 
388
836
  // packages/experience-design-system-cli/src/tui/settings/contentful-configuration/config-store.ts
389
837
  async function readCredentials() {
@@ -392,7 +840,9 @@ async function readCredentials() {
392
840
  spaceId: store.spaceId || "",
393
841
  environmentId: store.environmentId || "",
394
842
  cmaToken: store.cmaToken || "",
395
- host: store.host || ""
843
+ host: store.host || "",
844
+ defaultComponentDir: store.defaultComponentDir || "",
845
+ defaultTokenFile: store.defaultTokenFile || ""
396
846
  };
397
847
  }
398
848
  async function writeCredentials(config) {
@@ -408,23 +858,51 @@ async function writeCredentials(config) {
408
858
  }
409
859
 
410
860
  // packages/experience-design-system-cli/src/tui/settings/contentful-configuration/ContentfulConfigScreen.tsx
411
- import { Fragment, jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
412
- var FIELD_ORDER = ["spaceId", "environmentId", "cmaToken", "host"];
861
+ import { Fragment as Fragment2, jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
862
+ var FIELD_ORDER = [
863
+ "spaceId",
864
+ "environmentId",
865
+ "cmaToken",
866
+ "host",
867
+ "defaultComponentDir",
868
+ "defaultTokenFile"
869
+ ];
870
+ function debugFields(config) {
871
+ return {
872
+ space_id: config?.spaceId ?? "",
873
+ environment_id: config?.environmentId ?? "",
874
+ cma_token: config?.cmaToken ?? "",
875
+ host: config?.host ?? "",
876
+ default_component_dir: config?.defaultComponentDir ?? "",
877
+ default_token_file: config?.defaultTokenFile ?? ""
878
+ };
879
+ }
413
880
  var FIELD_LABELS = {
414
881
  spaceId: "Space ID",
415
882
  environmentId: "Environment ID",
416
883
  cmaToken: "CMA Token",
417
- host: "API Host (optional)"
884
+ host: "API Host (optional)",
885
+ defaultComponentDir: "Default component directory (optional)",
886
+ defaultTokenFile: "Default token file (optional)"
418
887
  };
419
888
  function ConfigurationScreen({ onDone }) {
420
- const [stage, setStage] = useState4("loading");
421
- const [config, setConfig] = useState4(null);
422
- const [activeField, setActiveField] = useState4("spaceId");
423
- const [message, setMessage] = useState4(null);
424
- useEffect3(() => {
889
+ const [stage, setStage] = useState7("loading");
890
+ const [config, setConfig] = useState7(null);
891
+ const [activeField, setActiveField] = useState7("spaceId");
892
+ const [notice, setNotice] = useState7(null);
893
+ const [lastSaved, setLastSaved] = useState7(null);
894
+ const [editing, setEditing] = useState7(false);
895
+ const [valueBeforeEdit, setValueBeforeEdit] = useState7("");
896
+ useEffect4(() => {
425
897
  readCredentials().then((cfg) => {
426
898
  setConfig(cfg);
427
899
  setStage("form");
900
+ startDebugRun({
901
+ flow: "settings/contentful-configuration",
902
+ step: "01-configuration",
903
+ menuOption: "Configuration",
904
+ inputs: debugFields(cfg)
905
+ });
428
906
  });
429
907
  }, []);
430
908
  function fieldValue(field) {
@@ -434,29 +912,46 @@ function ConfigurationScreen({ onDone }) {
434
912
  function setFieldValue(field, value) {
435
913
  if (!config) return;
436
914
  setConfig({ ...config, [field]: value });
915
+ setNotice(null);
437
916
  }
438
917
  function handleSave() {
439
918
  if (!config) return;
440
919
  setStage("saving");
441
- setMessage(null);
920
+ setNotice(null);
442
921
  writeCredentials(config).then(() => {
443
- setStage("saved");
444
- setMessage("Configuration saved");
922
+ setLastSaved(config);
923
+ setNotice({ kind: "success", text: "Configuration saved" });
924
+ setStage("form");
445
925
  }).catch((err) => {
446
- setMessage(err instanceof Error ? err.message : "Failed to save");
926
+ setNotice({ kind: "error", text: err instanceof Error ? err.message : "Failed to save" });
447
927
  setStage("form");
448
928
  });
449
929
  }
450
- useInput5((input, key) => {
930
+ function quit() {
931
+ void finishDebugRun(
932
+ lastSaved ? { outputs: debugFields(lastSaved), status: "success", exitMethod: "saved" } : { outputs: {}, status: "success", exitMethod: "discarded" }
933
+ );
934
+ onDone();
935
+ }
936
+ useInput7((input, key) => {
451
937
  if (stage === "loading" || stage === "saving") return;
452
- if (stage === "saved") {
453
- if (key.return || key.escape || input === "q") {
454
- onDone();
938
+ if (editing) {
939
+ if (key.escape) {
940
+ setFieldValue(activeField, valueBeforeEdit);
941
+ setEditing(false);
455
942
  }
456
943
  return;
457
944
  }
458
945
  if (key.escape || input === "q") {
459
- onDone();
946
+ quit();
947
+ return;
948
+ }
949
+ if (input === "s") {
950
+ handleSave();
951
+ return;
952
+ }
953
+ if (input === "c") {
954
+ setFieldValue(activeField, "");
460
955
  return;
461
956
  }
462
957
  if (key.tab || key.downArrow) {
@@ -470,75 +965,73 @@ function ConfigurationScreen({ onDone }) {
470
965
  return;
471
966
  }
472
967
  if (key.return) {
473
- const idx = FIELD_ORDER.indexOf(activeField);
474
- if (idx < FIELD_ORDER.length - 1) {
475
- setActiveField(FIELD_ORDER[idx + 1]);
476
- } else {
477
- handleSave();
478
- }
479
- return;
480
- }
481
- if (key.backspace || key.delete) {
482
- const current = fieldValue(activeField);
483
- setFieldValue(activeField, current.slice(0, -1));
484
- return;
485
- }
486
- if (input && !key.ctrl && !key.meta) {
487
- setFieldValue(activeField, fieldValue(activeField) + input);
968
+ setValueBeforeEdit(fieldValue(activeField));
969
+ setEditing(true);
488
970
  }
489
971
  });
490
972
  if (stage === "loading") {
491
- return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [
492
- /* @__PURE__ */ jsx5(Text5, { bold: true, children: "Configuration" }),
493
- /* @__PURE__ */ jsx5(Text5, { children: " " }),
494
- /* @__PURE__ */ jsx5(Text5, { color: PALETTE.accent, children: "Loading..." })
495
- ] });
496
- }
497
- if (stage === "saved") {
498
- return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [
499
- /* @__PURE__ */ jsx5(Text5, { bold: true, children: "Configuration" }),
500
- /* @__PURE__ */ jsx5(Text5, { children: " " }),
501
- /* @__PURE__ */ jsxs5(Text5, { color: PALETTE.success, children: [
502
- "\u2713 ",
503
- message
504
- ] }),
505
- /* @__PURE__ */ jsx5(Text5, { children: " " }),
506
- /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "[Enter] Back to Settings" })
973
+ return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [
974
+ /* @__PURE__ */ jsx8(Text8, { bold: true, children: "Configuration" }),
975
+ /* @__PURE__ */ jsx8(Text8, { children: " " }),
976
+ /* @__PURE__ */ jsx8(Text8, { color: PALETTE.accent, children: "Loading..." })
507
977
  ] });
508
978
  }
509
- return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [
510
- /* @__PURE__ */ jsx5(Text5, { bold: true, children: "Configuration" }),
511
- /* @__PURE__ */ jsx5(Text5, { children: " " }),
512
- /* @__PURE__ */ jsx5(Text5, { children: "Contentful API Credentials" }),
513
- /* @__PURE__ */ jsx5(Text5, { children: " " }),
514
- /* @__PURE__ */ jsx5(Box5, { flexDirection: "column", children: FIELD_ORDER.map((field) => {
979
+ return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [
980
+ /* @__PURE__ */ jsx8(Text8, { bold: true, children: "Configuration" }),
981
+ /* @__PURE__ */ jsx8(Text8, { children: " " }),
982
+ /* @__PURE__ */ jsx8(Box7, { flexDirection: "column", children: FIELD_ORDER.map((field) => {
515
983
  const isActive = activeField === field;
516
984
  const value = fieldValue(field);
517
985
  const display = field === "cmaToken" ? "\u2022".repeat(value.length) : value;
518
- return /* @__PURE__ */ jsxs5(Box5, { gap: 1, children: [
519
- /* @__PURE__ */ jsx5(Text5, { color: isActive ? PALETTE.accent : void 0, children: isActive ? "\u276F" : " " }),
520
- /* @__PURE__ */ jsxs5(Text5, { bold: isActive, children: [
986
+ return /* @__PURE__ */ jsxs7(Box7, { gap: 1, children: [
987
+ /* @__PURE__ */ jsx8(Text8, { color: isActive ? PALETTE.accent : void 0, children: isActive ? "\u276F" : " " }),
988
+ /* @__PURE__ */ jsxs7(Text8, { bold: isActive, children: [
521
989
  FIELD_LABELS[field],
522
990
  ":"
523
991
  ] }),
524
- /* @__PURE__ */ jsx5(Text5, { children: display || /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "(empty)" }) })
992
+ isActive && editing ? /* @__PURE__ */ jsx8(
993
+ TextInput3,
994
+ {
995
+ value,
996
+ onChange: (next) => setFieldValue(field, next),
997
+ onSubmit: () => setEditing(false),
998
+ mask: field === "cmaToken" ? "\u2022" : void 0
999
+ }
1000
+ ) : /* @__PURE__ */ jsx8(Text8, { children: display || /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: "(empty)" }) })
525
1001
  ] }, field);
526
1002
  }) }),
527
- message && /* @__PURE__ */ jsxs5(Fragment, { children: [
528
- /* @__PURE__ */ jsx5(Text5, { children: " " }),
529
- /* @__PURE__ */ jsxs5(Text5, { color: PALETTE.error, children: [
530
- "\u2717 ",
531
- message
1003
+ notice && /* @__PURE__ */ jsxs7(Fragment2, { children: [
1004
+ /* @__PURE__ */ jsx8(Text8, { children: " " }),
1005
+ /* @__PURE__ */ jsxs7(Text8, { color: notice.kind === "success" ? PALETTE.success : PALETTE.error, children: [
1006
+ notice.kind === "success" ? "\u2713" : "\u2717",
1007
+ " ",
1008
+ notice.text
532
1009
  ] })
533
1010
  ] }),
534
- /* @__PURE__ */ jsx5(Text5, { children: " " }),
535
- /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "[\u2191/\u2193] Switch field \xB7 [Enter] Save/Next \xB7 [Esc/q] Back" })
1011
+ /* @__PURE__ */ jsx8(Text8, { children: " " }),
1012
+ /* @__PURE__ */ jsx8(
1013
+ ControlHints,
1014
+ {
1015
+ hints: editing ? [
1016
+ { keys: "type", label: "edit" },
1017
+ { keys: "\u2190/\u2192", label: "move cursor" },
1018
+ { keys: "\u23CE", label: "done" },
1019
+ { keys: "Esc", label: "cancel edit" }
1020
+ ] : [
1021
+ { keys: "\u2191/\u2193", label: "move" },
1022
+ { keys: "\u23CE", label: "edit" },
1023
+ { keys: "c", label: "clear" },
1024
+ { keys: "s", label: "save" },
1025
+ { keys: "Esc/q", label: "quit without saving" }
1026
+ ]
1027
+ }
1028
+ )
536
1029
  ] });
537
1030
  }
538
1031
 
539
1032
  // packages/experience-design-system-cli/src/tui/settings/opt-in-analytics/screen.tsx
540
- import { useEffect as useEffect4, useState as useState5 } from "react";
541
- import { Box as Box6, Text as Text6, useInput as useInput6 } from "ink";
1033
+ import { useEffect as useEffect5, useState as useState8 } from "react";
1034
+ import { Box as Box8, Text as Text9, useInput as useInput8 } from "ink";
542
1035
 
543
1036
  // packages/experience-design-system-cli/src/tui/settings/opt-in-analytics/analytics-store.ts
544
1037
  async function readAnalyticsSetting() {
@@ -556,17 +1049,23 @@ async function writeAnalyticsSetting(setting) {
556
1049
  }
557
1050
 
558
1051
  // packages/experience-design-system-cli/src/tui/settings/opt-in-analytics/screen.tsx
559
- import { Fragment as Fragment2, jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
1052
+ import { Fragment as Fragment3, jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
560
1053
  function OptInAnalyticsScreen({ onDone }) {
561
- const [loading, setLoading] = useState5(true);
562
- const [enabled, setEnabled] = useState5(true);
563
- useEffect4(() => {
1054
+ const [loading, setLoading] = useState8(true);
1055
+ const [enabled, setEnabled] = useState8(true);
1056
+ useEffect5(() => {
564
1057
  readAnalyticsSetting().then((setting) => {
565
1058
  setEnabled(setting.enabled);
566
1059
  setLoading(false);
1060
+ startDebugRun({
1061
+ flow: "settings/opt-in-analytics",
1062
+ step: "01-opt-in-analytics",
1063
+ menuOption: "Opt-in Analytics",
1064
+ inputs: { enabled: setting.enabled }
1065
+ });
567
1066
  });
568
1067
  }, []);
569
- useInput6((input, key) => {
1068
+ useInput8((input, key) => {
570
1069
  if (loading) return;
571
1070
  if (key.return || input === " ") {
572
1071
  setEnabled((current) => {
@@ -577,208 +1076,44 @@ function OptInAnalyticsScreen({ onDone }) {
577
1076
  return;
578
1077
  }
579
1078
  if (key.escape || input === "q") {
1079
+ void finishDebugRun({ outputs: { enabled }, status: "success", exitMethod: "saved" });
580
1080
  onDone();
581
1081
  }
582
1082
  });
583
- return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [
584
- /* @__PURE__ */ jsx6(Text6, { bold: true, children: "Settings \u203A Opt-in Analytics" }),
585
- /* @__PURE__ */ jsx6(Text6, { children: " " }),
586
- loading ? /* @__PURE__ */ jsx6(Text6, { color: PALETTE.muted, children: "Loading\u2026" }) : /* @__PURE__ */ jsxs6(Fragment2, { children: [
587
- /* @__PURE__ */ jsxs6(Text6, { children: [
1083
+ return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [
1084
+ /* @__PURE__ */ jsx9(Text9, { bold: true, children: "Settings \u203A Opt-in Analytics" }),
1085
+ /* @__PURE__ */ jsx9(Text9, { children: " " }),
1086
+ loading ? /* @__PURE__ */ jsx9(Text9, { color: PALETTE.muted, children: "Loading\u2026" }) : /* @__PURE__ */ jsxs8(Fragment3, { children: [
1087
+ /* @__PURE__ */ jsxs8(Text9, { children: [
588
1088
  "Share anonymous usage data:",
589
1089
  " ",
590
- /* @__PURE__ */ jsx6(Text6, { bold: true, color: enabled ? PALETTE.success : PALETTE.muted, children: enabled ? "On" : "Off" })
1090
+ /* @__PURE__ */ jsx9(Text9, { bold: true, color: enabled ? PALETTE.success : PALETTE.muted, children: enabled ? "On" : "Off" })
591
1091
  ] }),
592
- /* @__PURE__ */ jsx6(Text6, { children: " " }),
593
- /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "Shares which CLI commands are used and where imports succeed or fail." }),
594
- /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "Never includes source code, file paths, credentials, or authored content." })
1092
+ /* @__PURE__ */ jsx9(Text9, { children: " " }),
1093
+ /* @__PURE__ */ jsx9(Text9, { dimColor: true, children: "Shares which CLI commands are used and where imports succeed or fail." }),
1094
+ /* @__PURE__ */ jsx9(Text9, { dimColor: true, children: "Never includes source code, file paths, credentials, or authored content." })
595
1095
  ] }),
596
- /* @__PURE__ */ jsx6(Text6, { children: " " }),
597
- /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "[Enter/Space] Toggle [Esc/q] Back to Settings" })
1096
+ /* @__PURE__ */ jsx9(Text9, { children: " " }),
1097
+ /* @__PURE__ */ jsx9(
1098
+ ControlHints,
1099
+ {
1100
+ hints: [
1101
+ { keys: "\u23CE/Space", label: "toggle" },
1102
+ { keys: "Esc/q", label: "back" }
1103
+ ]
1104
+ }
1105
+ )
598
1106
  ] });
599
1107
  }
600
1108
 
601
1109
  // packages/experience-design-system-cli/src/tui/upgrade/PageContainer.tsx
602
- import { useEffect as useEffect5, useState as useState6 } from "react";
603
- import { Box as Box7, Text as Text7, useInput as useInput7 } from "ink";
604
-
605
- // packages/experience-design-system-cli/src/tui/debug-store.ts
606
- import { mkdir as mkdir3, writeFile as writeFile3 } from "node:fs/promises";
607
- import { existsSync as existsSync3, readdirSync } from "node:fs";
608
- import { join as join6 } from "node:path";
609
-
610
- // packages/experience-design-system-cli/src/tui/settings/debug-mode/debug-mode-store.ts
611
- import { mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "node:fs/promises";
612
- import { dirname as dirname2, join as join5 } from "node:path";
613
- var PACKAGE_NAME3 = "@contentful/experience-design-system-cli";
614
- var DEFAULT_DEBUG_MODE_SETTING = {
615
- enabled: true
616
- };
617
- function debugModeSettingPath() {
618
- return join5(findPackageRoot(import.meta.url, PACKAGE_NAME3), ".contentful", "config", "debug_mode.json");
619
- }
620
- async function readDebugModeSetting() {
621
- try {
622
- const raw = await readFile2(debugModeSettingPath(), "utf8");
623
- const parsed = JSON.parse(raw);
624
- return { ...DEFAULT_DEBUG_MODE_SETTING, ...parsed };
625
- } catch {
626
- return { ...DEFAULT_DEBUG_MODE_SETTING };
627
- }
628
- }
629
- async function writeDebugModeSetting(setting) {
630
- const path = debugModeSettingPath();
631
- await mkdir2(dirname2(path), { recursive: true });
632
- await writeFile2(path, `${JSON.stringify(setting, null, 2)}
633
- `, { mode: 384 });
634
- }
635
-
636
- // packages/experience-design-system-cli/src/tui/debug-store.ts
637
- var PACKAGE_NAME4 = "@contentful/experience-design-system-cli";
638
- var pendingRun;
639
- function generateRunId() {
640
- const now = /* @__PURE__ */ new Date();
641
- const pad = (n) => String(n).padStart(2, "0");
642
- return `${now.getFullYear()}${pad(now.getMonth() + 1)}${pad(now.getDate())}-${pad(now.getHours())}${pad(now.getMinutes())}${pad(now.getSeconds())}`;
643
- }
644
- function sessionsRootDir() {
645
- return join6(findPackageRoot(import.meta.url, PACKAGE_NAME4), ".contentful", "debug", "sessions");
646
- }
647
- function datePrefix(now = /* @__PURE__ */ new Date()) {
648
- const pad = (n) => String(n).padStart(2, "0");
649
- return `${pad(now.getMonth() + 1)}-${pad(now.getDate())}-${now.getFullYear()}`;
650
- }
651
- function slugify(value) {
652
- return value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
653
- }
654
- function generateSessionId() {
655
- const today = datePrefix();
656
- const root = sessionsRootDir();
657
- const existing = existsSync3(root) ? readdirSync(root) : [];
658
- const seqPattern = new RegExp(`^${today}-session-(\\d+)$`);
659
- const maxSeq = existing.reduce((max, entry) => {
660
- const match = seqPattern.exec(entry);
661
- return match ? Math.max(max, Number(match[1])) : max;
662
- }, 0);
663
- return `${today}-session-${maxSeq + 1}`;
664
- }
665
- var SESSION_ID = generateSessionId();
666
- function sessionDebugDir() {
667
- return join6(sessionsRootDir(), SESSION_ID);
668
- }
669
- void isDebugModeEnabled().then((enabled) => {
670
- if (!enabled) return void 0;
671
- return mkdir3(sessionDebugDir(), { recursive: true });
672
- });
673
- async function isDebugModeEnabled() {
674
- try {
675
- return (await readDebugModeSetting()).enabled;
676
- } catch {
677
- return true;
678
- }
679
- }
680
- function redact(value) {
681
- const clone = { ...value };
682
- if ("cma_token" in clone) {
683
- const raw = clone.cma_token;
684
- clone.cma_token = typeof raw === "string" && raw.length > 0 ? `[present, ${raw.length} chars]` : "[not set]";
685
- }
686
- return clone;
687
- }
688
- function startDebugRun({
689
- flow,
690
- step,
691
- menuOption,
692
- inputs
693
- }) {
694
- const runId = generateRunId();
695
- const startedAt = Date.now();
696
- const redactedInputs = redact(inputs);
697
- isDebugModeEnabled().then((enabled) => {
698
- if (!enabled) return;
699
- pendingRun = { flow, step, runId, menuOption, inputs: redactedInputs, startedAt };
700
- });
701
- }
702
- async function finishDebugRun({
703
- outputs,
704
- status,
705
- exitMethod
706
- }) {
707
- const run = pendingRun;
708
- if (!run) return;
709
- pendingRun = void 0;
710
- const durationMs = Date.now() - run.startedAt;
711
- const content = renderMarkdown(run, { outputs: redact(outputs), status, exitMethod, durationMs });
712
- const flowSegments = run.flow.split("/");
713
- const dir = join6(sessionDebugDir(), ...flowSegments);
714
- await mkdir3(dir, { recursive: true });
715
- const filename = nextAttemptFilename(dir, run.menuOption);
716
- await writeFile3(join6(dir, filename), content, { mode: 384 });
717
- }
718
- function nextAttemptFilename(dir, menuOption) {
719
- const today = datePrefix();
720
- const optionSlug = slugify(menuOption);
721
- const existing = existsSync3(dir) ? readdirSync(dir) : [];
722
- const attemptPattern = new RegExp(`^${today}-${optionSlug}-attempt-(\\d+)\\.md$`);
723
- const maxAttempt = existing.reduce((max, entry) => {
724
- const match = attemptPattern.exec(entry);
725
- return match ? Math.max(max, Number(match[1])) : max;
726
- }, 0);
727
- return `${today}-${optionSlug}-attempt-${maxAttempt + 1}.md`;
728
- }
729
- function renderMarkdown(run, finish) {
730
- const stepMatch = /^(\d+)-(.+)$/.exec(run.step);
731
- const stepLabel = stepMatch ? `${stepMatch[1]} - ${stepMatch[2]}` : run.step;
732
- const flowSlug = run.flow.split("/").join("-");
733
- return `# Debug Log
734
-
735
- - Run ID: ${run.runId}
736
- - Flow: ${flowSlug}
737
- - Step: ${stepLabel}
738
- - Menu option: ${run.menuOption}
739
- - Date: ${(/* @__PURE__ */ new Date()).toISOString()}
740
- - CLI version: ${readPackageVersion()}
741
- - Platform: ${process.platform} / Node ${process.version}
742
- - Duration on screen: ${finish.durationMs}ms
743
- - Status: ${finish.status}
744
- - Exit method: ${finish.exitMethod}
745
-
746
- ## Inputs
747
- \`\`\`json
748
- ${JSON.stringify(run.inputs, null, 2)}
749
- \`\`\`
750
-
751
- ## Outputs
752
- \`\`\`json
753
- ${JSON.stringify(finish.outputs, null, 2)}
754
- \`\`\`
755
- `;
756
- }
757
- function handleCrash() {
758
- return finishDebugRun({ outputs: {}, status: "error", exitMethod: "crashed" });
759
- }
760
- process.once("uncaughtException", (err) => {
761
- void handleCrash().finally(() => {
762
- throw err;
763
- });
764
- });
765
- process.once("unhandledRejection", (reason) => {
766
- void handleCrash().finally(() => {
767
- throw reason;
768
- });
769
- });
770
- process.once("SIGINT", () => {
771
- void handleCrash().finally(() => {
772
- process.exit(130);
773
- });
774
- });
775
-
776
- // packages/experience-design-system-cli/src/tui/upgrade/PageContainer.tsx
777
- import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
1110
+ import { useEffect as useEffect6, useState as useState9 } from "react";
1111
+ import { Box as Box9, Text as Text10, useInput as useInput9 } from "ink";
1112
+ import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
778
1113
  var UPGRADE_COMMANDS = ["git pull", "pnpm install", "pnpm build"];
779
1114
  function UpgradeScreen({ onDone }) {
780
- const [upgradeCheck, setUpgradeCheck] = useState6();
781
- useEffect5(() => {
1115
+ const [upgradeCheck, setUpgradeCheck] = useState9();
1116
+ useEffect6(() => {
782
1117
  startDebugRun({
783
1118
  flow: "upgrade",
784
1119
  step: "01-upgrade",
@@ -787,7 +1122,7 @@ function UpgradeScreen({ onDone }) {
787
1122
  });
788
1123
  checkForUpgrade().then(setUpgradeCheck).catch(() => setUpgradeCheck({ status: "error" }));
789
1124
  }, []);
790
- useInput7((_input, key) => {
1125
+ useInput9((_input, key) => {
791
1126
  if (key.return) {
792
1127
  void finishDebugRun({
793
1128
  outputs: upgradeCheck ?? {},
@@ -798,12 +1133,12 @@ function UpgradeScreen({ onDone }) {
798
1133
  return;
799
1134
  }
800
1135
  });
801
- return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [
802
- /* @__PURE__ */ jsx7(Text7, { bold: true, children: "Upgrade" }),
803
- /* @__PURE__ */ jsx7(Text7, { children: " " }),
1136
+ return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [
1137
+ /* @__PURE__ */ jsx10(Text10, { bold: true, children: "Upgrade" }),
1138
+ /* @__PURE__ */ jsx10(Text10, { children: " " }),
804
1139
  renderBody(upgradeCheck),
805
- /* @__PURE__ */ jsx7(Text7, { children: " " }),
806
- /* @__PURE__ */ jsxs7(Text7, { bold: true, color: PALETTE.accent, children: [
1140
+ /* @__PURE__ */ jsx10(Text10, { children: " " }),
1141
+ /* @__PURE__ */ jsxs9(Text10, { bold: true, color: PALETTE.accent, children: [
807
1142
  FOCUS_MARKER,
808
1143
  " Go Back"
809
1144
  ] })
@@ -811,51 +1146,57 @@ function UpgradeScreen({ onDone }) {
811
1146
  }
812
1147
  function renderBody(upgradeCheck) {
813
1148
  if (!upgradeCheck) {
814
- return /* @__PURE__ */ jsx7(Text7, { color: PALETTE.muted, children: "Checking for updates\u2026" });
1149
+ return /* @__PURE__ */ jsx10(Text10, { color: PALETTE.muted, children: "Checking for updates\u2026" });
815
1150
  }
816
1151
  if (upgradeCheck.status === "error") {
817
- return /* @__PURE__ */ jsx7(Text7, { color: PALETTE.warning, children: "Couldn't check for updates \u2014 check your network connection and try again." });
1152
+ return /* @__PURE__ */ jsx10(Text10, { color: PALETTE.warning, children: "Couldn't check for updates \u2014 check your network connection and try again." });
818
1153
  }
819
1154
  if (upgradeCheck.status === "up-to-date") {
820
- return /* @__PURE__ */ jsxs7(Text7, { color: PALETTE.success, children: [
1155
+ return /* @__PURE__ */ jsxs9(Text10, { color: PALETTE.success, children: [
821
1156
  "You're already on the latest version (v",
822
1157
  upgradeCheck.current,
823
1158
  ")."
824
1159
  ] });
825
1160
  }
826
- return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
827
- /* @__PURE__ */ jsxs7(Text7, { color: PALETTE.muted, children: [
828
- /* @__PURE__ */ jsxs7(Text7, { bold: true, color: PALETTE.success, children: [
1161
+ return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", children: [
1162
+ /* @__PURE__ */ jsxs9(Text10, { color: PALETTE.muted, children: [
1163
+ /* @__PURE__ */ jsxs9(Text10, { bold: true, color: PALETTE.success, children: [
829
1164
  "v",
830
1165
  upgradeCheck.latest
831
1166
  ] }),
832
1167
  " ",
833
1168
  "is available (you're on ",
834
- /* @__PURE__ */ jsxs7(Text7, { bold: true, children: [
1169
+ /* @__PURE__ */ jsxs9(Text10, { bold: true, children: [
835
1170
  "v",
836
1171
  upgradeCheck.current
837
1172
  ] }),
838
1173
  "). Exit this program, cd into the root of your local clone of contentful/experience-design-system-sdk-public, then run:"
839
1174
  ] }),
840
- /* @__PURE__ */ jsx7(Text7, { children: " " }),
841
- /* @__PURE__ */ jsx7(Box7, { flexDirection: "column", borderStyle: "round", borderColor: PALETTE.border, paddingX: 1, children: UPGRADE_COMMANDS.map((cmd) => /* @__PURE__ */ jsx7(Text7, { bold: true, children: cmd }, cmd)) })
1175
+ /* @__PURE__ */ jsx10(Text10, { children: " " }),
1176
+ /* @__PURE__ */ jsx10(Box9, { flexDirection: "column", borderStyle: "round", borderColor: PALETTE.border, paddingX: 1, children: UPGRADE_COMMANDS.map((cmd) => /* @__PURE__ */ jsx10(Text10, { bold: true, children: cmd }, cmd)) })
842
1177
  ] });
843
1178
  }
844
1179
 
845
1180
  // packages/experience-design-system-cli/src/tui/settings/debug-mode/screen.tsx
846
- import { useEffect as useEffect6, useState as useState7 } from "react";
847
- import { Box as Box8, Text as Text8, useInput as useInput8 } from "ink";
848
- import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
1181
+ import { useEffect as useEffect7, useState as useState10 } from "react";
1182
+ import { Box as Box10, Text as Text11, useInput as useInput10 } from "ink";
1183
+ import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
849
1184
  function DebugModeScreen({ onDone }) {
850
- const [loading, setLoading] = useState7(true);
851
- const [enabled, setEnabled] = useState7(true);
852
- useEffect6(() => {
1185
+ const [loading, setLoading] = useState10(true);
1186
+ const [enabled, setEnabled] = useState10(true);
1187
+ useEffect7(() => {
853
1188
  readDebugModeSetting().then((setting) => {
854
1189
  setEnabled(setting.enabled);
855
1190
  setLoading(false);
1191
+ startDebugRun({
1192
+ flow: "settings/debug-mode",
1193
+ step: "01-debug-mode",
1194
+ menuOption: "Debug Mode",
1195
+ inputs: { enabled: setting.enabled }
1196
+ });
856
1197
  });
857
1198
  }, []);
858
- useInput8((input, key) => {
1199
+ useInput10((input, key) => {
859
1200
  if (loading) return;
860
1201
  if (key.return || input === " ") {
861
1202
  setEnabled((current) => {
@@ -866,64 +1207,100 @@ function DebugModeScreen({ onDone }) {
866
1207
  return;
867
1208
  }
868
1209
  if (key.escape || input === "q") {
1210
+ void finishDebugRun({ outputs: { enabled }, status: "success", exitMethod: "saved" });
869
1211
  onDone();
870
1212
  }
871
1213
  });
872
- return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [
873
- /* @__PURE__ */ jsx8(Text8, { bold: true, children: "Settings \u203A Debug Mode" }),
874
- /* @__PURE__ */ jsx8(Text8, { children: " " }),
875
- loading ? /* @__PURE__ */ jsx8(Text8, { color: PALETTE.muted, children: "Loading\u2026" }) : /* @__PURE__ */ jsxs8(Text8, { children: [
1214
+ return /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [
1215
+ /* @__PURE__ */ jsx11(Text11, { bold: true, children: "Settings \u203A Debug Mode" }),
1216
+ /* @__PURE__ */ jsx11(Text11, { children: " " }),
1217
+ loading ? /* @__PURE__ */ jsx11(Text11, { color: PALETTE.muted, children: "Loading\u2026" }) : /* @__PURE__ */ jsxs10(Text11, { children: [
876
1218
  "Debug logging:",
877
1219
  " ",
878
- /* @__PURE__ */ jsx8(Text8, { bold: true, color: enabled ? PALETTE.success : PALETTE.muted, children: enabled ? "On" : "Off" })
1220
+ /* @__PURE__ */ jsx11(Text11, { bold: true, color: enabled ? PALETTE.success : PALETTE.muted, children: enabled ? "On" : "Off" })
879
1221
  ] }),
880
- /* @__PURE__ */ jsx8(Text8, { children: " " }),
881
- /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: "[Enter/Space] Toggle [Esc/q] Back to Settings" })
1222
+ /* @__PURE__ */ jsx11(Text11, { children: " " }),
1223
+ /* @__PURE__ */ jsx11(
1224
+ ControlHints,
1225
+ {
1226
+ hints: [
1227
+ { keys: "\u23CE/Space", label: "toggle" },
1228
+ { keys: "Esc/q", label: "back" }
1229
+ ]
1230
+ }
1231
+ )
882
1232
  ] });
883
1233
  }
884
1234
 
885
1235
  // packages/experience-design-system-cli/app.tsx
886
- import { jsx as jsx9 } from "react/jsx-runtime";
1236
+ import { Fragment as Fragment4, jsx as jsx12 } from "react/jsx-runtime";
887
1237
  function App({ onLaunchImport, importExitCode }) {
888
1238
  const returnedFromImport = importExitCode !== void 0;
889
- const [screen, setScreen] = useState8(returnedFromImport ? "import" : "start");
890
- const goToStart = () => setScreen("start");
891
- const goToSettings = () => setScreen("settings");
892
- const navigateFromHome = (next) => {
893
- if (next === "import" && onLaunchImport) {
894
- onLaunchImport();
1239
+ const [screen, setScreen] = useState11(returnedFromImport ? "import" : "start");
1240
+ const [showImportResult, setShowImportResult] = useState11(returnedFromImport);
1241
+ const [projectPath, setProjectPath] = useState11();
1242
+ const [importDefaults, setImportDefaults] = useState11();
1243
+ useEffect8(() => {
1244
+ if (screen !== "import") {
1245
+ setImportDefaults(void 0);
895
1246
  return;
896
1247
  }
897
- setScreen(next);
1248
+ void readCredentials().then(
1249
+ (saved) => setImportDefaults({ componentDir: saved.defaultComponentDir ?? "", tokenFile: saved.defaultTokenFile ?? "" })
1250
+ );
1251
+ }, [screen]);
1252
+ const goToStart = () => setScreen("start");
1253
+ const goToSettings = () => setScreen("settings");
1254
+ const finishImportResult = () => {
1255
+ setShowImportResult(false);
1256
+ setProjectPath(void 0);
1257
+ goToStart();
1258
+ };
1259
+ const leaveImport = () => {
1260
+ setProjectPath(void 0);
1261
+ goToStart();
898
1262
  };
899
1263
  switch (screen) {
900
1264
  case "import":
901
- return /* @__PURE__ */ jsx9(ImportScreen, { exitCode: importExitCode, onDone: goToStart });
1265
+ if (showImportResult) return /* @__PURE__ */ jsx12(ImportScreen, { exitCode: importExitCode, onDone: finishImportResult });
1266
+ if (importDefaults === void 0) return /* @__PURE__ */ jsx12(Fragment4, {});
1267
+ if (projectPath === void 0) {
1268
+ return /* @__PURE__ */ jsx12(WelcomeScreen, { onContinue: setProjectPath, onQuit: leaveImport, initialPath: importDefaults.componentDir });
1269
+ }
1270
+ return /* @__PURE__ */ jsx12(
1271
+ TokenInputScreen,
1272
+ {
1273
+ initialPath: importDefaults.tokenFile,
1274
+ onConfirm: (tokens) => onLaunchImport?.({ project: projectPath, tokens }),
1275
+ onSkip: () => onLaunchImport?.({ project: projectPath }),
1276
+ onBack: () => setProjectPath(void 0)
1277
+ }
1278
+ );
902
1279
  case "help":
903
- return /* @__PURE__ */ jsx9(HelpScreen, { onDone: goToStart });
1280
+ return /* @__PURE__ */ jsx12(HelpScreen, { onDone: goToStart });
904
1281
  case "upgrade":
905
- return /* @__PURE__ */ jsx9(UpgradeScreen, { onDone: goToStart });
1282
+ return /* @__PURE__ */ jsx12(UpgradeScreen, { onDone: goToStart });
906
1283
  case "settings":
907
- return /* @__PURE__ */ jsx9(SettingsScreen, { onNavigate: setScreen, onBack: goToStart });
1284
+ return /* @__PURE__ */ jsx12(SettingsScreen, { onNavigate: setScreen, onBack: goToStart });
908
1285
  case "settings-configuration":
909
- return /* @__PURE__ */ jsx9(ConfigurationScreen, { onDone: goToSettings });
1286
+ return /* @__PURE__ */ jsx12(ConfigurationScreen, { onDone: goToSettings });
910
1287
  case "settings-opt-in-analytics":
911
- return /* @__PURE__ */ jsx9(OptInAnalyticsScreen, { onDone: goToSettings });
1288
+ return /* @__PURE__ */ jsx12(OptInAnalyticsScreen, { onDone: goToSettings });
912
1289
  case "settings-debug-mode":
913
- return /* @__PURE__ */ jsx9(DebugModeScreen, { onDone: goToSettings });
1290
+ return /* @__PURE__ */ jsx12(DebugModeScreen, { onDone: goToSettings });
914
1291
  case "start":
915
- return /* @__PURE__ */ jsx9(HomeScreen, { onNavigate: navigateFromHome });
1292
+ return /* @__PURE__ */ jsx12(HomeScreen, { onNavigate: setScreen });
916
1293
  }
917
1294
  }
918
1295
  async function renderUntilImportRequestedOrExit(renderApp, importExitCode) {
919
- let importRequested = false;
1296
+ let requestedImport;
920
1297
  const instance = renderApp(
921
- /* @__PURE__ */ jsx9(
1298
+ /* @__PURE__ */ jsx12(
922
1299
  App,
923
1300
  {
924
1301
  importExitCode,
925
- onLaunchImport: () => {
926
- importRequested = true;
1302
+ onLaunchImport: (options) => {
1303
+ requestedImport = options;
927
1304
  instance.unmount();
928
1305
  }
929
1306
  }
@@ -931,13 +1308,15 @@ async function renderUntilImportRequestedOrExit(renderApp, importExitCode) {
931
1308
  );
932
1309
  await instance.waitUntilExit();
933
1310
  await stopReadingTerminal();
934
- return importRequested;
1311
+ return requestedImport;
935
1312
  }
936
1313
  async function runApp(renderApp) {
937
1314
  let importExitCode;
938
- while (await renderUntilImportRequestedOrExit(renderApp, importExitCode)) {
939
- importExitCode = (await spawnV1Import({})).exitCode;
1315
+ let requestedImport = await renderUntilImportRequestedOrExit(renderApp, importExitCode);
1316
+ while (requestedImport !== void 0) {
1317
+ importExitCode = (await spawnV1Import(requestedImport)).exitCode;
940
1318
  startReadingTerminal();
1319
+ requestedImport = await renderUntilImportRequestedOrExit(renderApp, importExitCode);
941
1320
  }
942
1321
  }
943
1322
  export {