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