@contentful/experience-design-system-cli 2.37.1-dev-build-eeb53912.0 → 2.37.1-dev-build-df3fca68.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/index.js CHANGED
@@ -356,8 +356,8 @@ function WelcomeScreen({ onContinue, onQuit, initialPath = "" }) {
356
356
  const [projectPath, setProjectPath] = useState3(initialPath);
357
357
  useWelcomeControls(onQuit);
358
358
  const submit = (value) => {
359
- const path = toProjectPath(value);
360
- if (path) onContinue(path);
359
+ const path5 = toProjectPath(value);
360
+ if (path5) onContinue(path5);
361
361
  };
362
362
  return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", gap: 1, paddingX: 2, paddingY: 1, children: [
363
363
  /* @__PURE__ */ jsx4(Text4, { bold: true, color: PALETTE.success, children: "\u{1F44B} Hey! Let's import your design system into Contentful." }),
@@ -459,24 +459,24 @@ var init_resolve_user_path = __esm({
459
459
  // packages/experience-design-system-cli/src/tui/import/steps/02-token-input/validate-path.ts
460
460
  import { statSync } from "node:fs";
461
461
  function validateTokenPath(rawPath) {
462
- const path = resolveUserPath(rawPath);
462
+ const path5 = resolveUserPath(rawPath);
463
463
  let stats;
464
464
  try {
465
- stats = statSync(path);
465
+ stats = statSync(path5);
466
466
  } catch {
467
- return { ok: false, error: `Path not found: ${path}`, resolvedPath: path };
467
+ return { ok: false, error: `Path not found: ${path5}`, resolvedPath: path5 };
468
468
  }
469
469
  if (stats.isDirectory()) {
470
470
  return {
471
471
  ok: false,
472
472
  error: "That's a directory \u2014 provide a path to a token file (e.g. tokens.json), not a folder.",
473
- resolvedPath: path
473
+ resolvedPath: path5
474
474
  };
475
475
  }
476
476
  if (!stats.isFile()) {
477
- return { ok: false, error: `Not a regular file: ${path}`, resolvedPath: path };
477
+ return { ok: false, error: `Not a regular file: ${path5}`, resolvedPath: path5 };
478
478
  }
479
- return { ok: true, path };
479
+ return { ok: true, path: path5 };
480
480
  }
481
481
  var init_validate_path = __esm({
482
482
  "packages/experience-design-system-cli/src/tui/import/steps/02-token-input/validate-path.ts"() {
@@ -547,38 +547,7 @@ var init_screen2 = __esm({
547
547
  });
548
548
 
549
549
  // packages/experience-design-system-cli/src/tui/import/steps/03-path-validation/logic.ts
550
- function categorize(fileName) {
551
- if (fileName.endsWith(".d.ts")) return "other";
552
- const dot = fileName.lastIndexOf(".");
553
- const extension = dot === -1 ? "" : fileName.slice(dot + 1);
554
- return CATEGORY_BY_EXTENSION.get(extension) ?? "other";
555
- }
556
- function emptyCounts() {
557
- return { tsx: 0, ts: 0, vue: 0, astro: 0, jsx: 0, js: 0, json: 0, other: 0, total: 0 };
558
- }
559
- function addFile(counts, fileName) {
560
- const category = categorize(fileName);
561
- return { ...counts, [category]: counts[category] + 1, total: counts.total + 1 };
562
- }
563
- function mergeCounts(a, b) {
564
- return {
565
- tsx: a.tsx + b.tsx,
566
- ts: a.ts + b.ts,
567
- vue: a.vue + b.vue,
568
- astro: a.astro + b.astro,
569
- jsx: a.jsx + b.jsx,
570
- js: a.js + b.js,
571
- json: a.json + b.json,
572
- other: a.other + b.other,
573
- total: a.total + b.total
574
- };
575
- }
576
- function failureFromErrorCode(code) {
577
- if (code === "ENOENT") return "not-found";
578
- if (code === "EACCES") return "permission-denied";
579
- return "unreadable";
580
- }
581
- function describeFailure(failure, path) {
550
+ function describeFailure(failure, path5) {
582
551
  switch (failure) {
583
552
  case "is-file":
584
553
  return {
@@ -590,18 +559,18 @@ function describeFailure(failure, path) {
590
559
  };
591
560
  case "not-found":
592
561
  return {
593
- headline: `Directory not found: ${path}`,
562
+ headline: `Directory not found: ${path5}`,
594
563
  hints: ["Double-check the path and try again. Tip: you can use ~, relative, or absolute paths."]
595
564
  };
596
565
  case "permission-denied":
597
566
  return {
598
- headline: `Permission denied: ${path}`,
567
+ headline: `Permission denied: ${path5}`,
599
568
  hints: ["You don't have read access to this directory."]
600
569
  };
601
570
  case "not-directory":
602
- return { headline: `Not a directory: ${path}`, hints: [] };
571
+ return { headline: `Not a directory: ${path5}`, hints: [] };
603
572
  case "unreadable":
604
- return { headline: `Cannot access: ${path}`, hints: [] };
573
+ return { headline: `Cannot access: ${path5}`, hints: [] };
605
574
  }
606
575
  }
607
576
  function summarize(counts) {
@@ -633,30 +602,10 @@ function keyAction(phase, input, key) {
633
602
  if (phase === "failed" && (key.return || input === "e")) return "change-path";
634
603
  return void 0;
635
604
  }
636
- var IGNORED_DIRECTORIES, CATEGORY_BY_EXTENSION, COMPONENT_CATEGORIES, ROW_LABELS, ROW_ORDER;
605
+ var COMPONENT_CATEGORIES, ROW_LABELS, ROW_ORDER;
637
606
  var init_logic3 = __esm({
638
607
  "packages/experience-design-system-cli/src/tui/import/steps/03-path-validation/logic.ts"() {
639
608
  "use strict";
640
- IGNORED_DIRECTORIES = /* @__PURE__ */ new Set([
641
- "node_modules",
642
- "dist",
643
- "build",
644
- ".next",
645
- ".nuxt",
646
- "coverage",
647
- "storybook-static",
648
- "out",
649
- ".git"
650
- ]);
651
- CATEGORY_BY_EXTENSION = /* @__PURE__ */ new Map([
652
- ["tsx", "tsx"],
653
- ["ts", "ts"],
654
- ["vue", "vue"],
655
- ["astro", "astro"],
656
- ["jsx", "jsx"],
657
- ["js", "js"],
658
- ["json", "json"]
659
- ]);
660
609
  COMPONENT_CATEGORIES = ["tsx", "ts", "vue", "astro", "jsx", "js"];
661
610
  ROW_LABELS = {
662
611
  tsx: ".tsx files",
@@ -705,142 +654,6 @@ var init_controls3 = __esm({
705
654
  }
706
655
  });
707
656
 
708
- // packages/experience-design-system-cli/src/tui/import/steps/03-path-validation/loader.ts
709
- import { readdir, stat } from "node:fs/promises";
710
- import { join as join5 } from "node:path";
711
- async function isFile(path) {
712
- try {
713
- return (await stat(path)).isFile();
714
- } catch {
715
- return false;
716
- }
717
- }
718
- async function countEntry(directory, entry) {
719
- const path = join5(directory, entry.name);
720
- if (entry.isDirectory()) return countFiles(path);
721
- if (entry.isFile() || entry.isSymbolicLink() && await isFile(path)) return addFile(emptyCounts(), entry.name);
722
- return emptyCounts();
723
- }
724
- async function countFiles(directory) {
725
- let entries;
726
- try {
727
- entries = await readdir(directory, { withFileTypes: true });
728
- } catch {
729
- return emptyCounts();
730
- }
731
- const counts = await Promise.all(
732
- entries.filter((entry) => !IGNORED_DIRECTORIES.has(entry.name)).map((entry) => countEntry(directory, entry))
733
- );
734
- return counts.reduce(mergeCounts, emptyCounts());
735
- }
736
- async function scanProject(directory) {
737
- try {
738
- const stats = await stat(directory);
739
- if (stats.isFile()) return { ok: false, failure: "is-file" };
740
- if (!stats.isDirectory()) return { ok: false, failure: "not-directory" };
741
- } catch (error) {
742
- return { ok: false, failure: failureFromErrorCode(error.code) };
743
- }
744
- return { ok: true, counts: await countFiles(directory) };
745
- }
746
- var init_loader = __esm({
747
- "packages/experience-design-system-cli/src/tui/import/steps/03-path-validation/loader.ts"() {
748
- "use strict";
749
- init_logic3();
750
- }
751
- });
752
-
753
- // packages/experience-design-system-cli/src/tui/import/steps/03-path-validation/screen.tsx
754
- import { useEffect as useEffect3, useMemo, useState as useState5 } from "react";
755
- import { Box as Box5, Text as Text6 } from "ink";
756
- import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
757
- function Row({ row }) {
758
- return /* @__PURE__ */ jsxs5(Text6, { color: row.tone === "accent" ? PALETTE.accent : void 0, dimColor: row.tone === "muted", children: [
759
- " \u2022 ",
760
- String(row.count).padStart(3),
761
- " ",
762
- row.label
763
- ] });
764
- }
765
- function Failure({ scan, path }) {
766
- const { headline, hints } = describeFailure(scan.failure, path);
767
- return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
768
- /* @__PURE__ */ jsxs5(Text6, { color: PALETTE.error, children: [
769
- "\u2717 ",
770
- headline
771
- ] }),
772
- hints.map((hint) => /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: hint }, hint))
773
- ] });
774
- }
775
- function Summary({ scan, path }) {
776
- const { total, rows, warning } = summarize(scan.counts);
777
- return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", gap: 1, children: [
778
- /* @__PURE__ */ jsxs5(Text6, { children: [
779
- "Scanned ",
780
- /* @__PURE__ */ jsx6(Text6, { bold: true, children: path })
781
- ] }),
782
- /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
783
- /* @__PURE__ */ jsxs5(Text6, { color: PALETTE.success, children: [
784
- "\u2713 Found ",
785
- total,
786
- " files:"
787
- ] }),
788
- rows.map((row) => /* @__PURE__ */ jsx6(Row, { row }, row.label))
789
- ] }),
790
- warning && /* @__PURE__ */ jsxs5(Text6, { color: PALETTE.warning, children: [
791
- "\u26A0 ",
792
- warning
793
- ] }),
794
- /* @__PURE__ */ jsx6(Text6, { children: "Does this look right?" })
795
- ] });
796
- }
797
- function PathValidationScreen({
798
- projectPath,
799
- onConfirm,
800
- onChangePath,
801
- onBack
802
- }) {
803
- const resolvedPath = useMemo(() => resolveUserPath(projectPath), [projectPath]);
804
- const [scan, setScan] = useState5();
805
- useEffect3(() => {
806
- let cancelled = false;
807
- setScan(void 0);
808
- void scanProject(resolvedPath).then((result) => {
809
- if (!cancelled) setScan(result);
810
- });
811
- return () => {
812
- cancelled = true;
813
- };
814
- }, [resolvedPath]);
815
- const phase = phaseOf(scan);
816
- usePathValidationControls(phase, { onConfirm: () => onConfirm(resolvedPath), onChangePath, onBack });
817
- return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", gap: 1, paddingX: 2, paddingY: 1, children: [
818
- scan === void 0 && /* @__PURE__ */ jsxs5(Text6, { dimColor: true, children: [
819
- "Scanning ",
820
- /* @__PURE__ */ jsx6(Text6, { bold: true, children: resolvedPath }),
821
- "..."
822
- ] }),
823
- scan?.ok === false && /* @__PURE__ */ jsx6(Failure, { scan, path: resolvedPath }),
824
- scan?.ok === true && /* @__PURE__ */ jsx6(Summary, { scan, path: resolvedPath }),
825
- /* @__PURE__ */ jsx6(Box5, { marginTop: 1, gap: 3, children: controlsFor(phase).map((control) => /* @__PURE__ */ jsxs5(Text6, { dimColor: true, children: [
826
- "[",
827
- control.keys,
828
- "] ",
829
- control.label
830
- ] }, control.keys)) })
831
- ] });
832
- }
833
- var init_screen3 = __esm({
834
- "packages/experience-design-system-cli/src/tui/import/steps/03-path-validation/screen.tsx"() {
835
- "use strict";
836
- init_home_theme();
837
- init_resolve_user_path();
838
- init_controls3();
839
- init_loader();
840
- init_logic3();
841
- }
842
- });
843
-
844
657
  // packages/experience-design-system-backend-pipeline/dist/src/persistence/src/session/helpers/config-root.js
845
658
  var init_config_root = __esm({
846
659
  "packages/experience-design-system-backend-pipeline/dist/src/persistence/src/session/helpers/config-root.js"() {
@@ -2825,6 +2638,18 @@ var init_reject_components_by_name = __esm({
2825
2638
  });
2826
2639
 
2827
2640
  // packages/experience-design-system-backend-pipeline/dist/src/persistence/src/helpers/collect-files/build-scan-warnings.js
2641
+ function buildScanWarnings(counts) {
2642
+ const warnings = [];
2643
+ if (counts.total === 0) {
2644
+ warnings.push("No source files found. Double-check the path points at your component code.");
2645
+ return warnings;
2646
+ }
2647
+ const frameworkFiles = counts.tsx + counts.ts + counts.jsx + counts.js + counts.vue + counts.astro + counts.svelte;
2648
+ if (frameworkFiles === 0) {
2649
+ warnings.push("No framework source files found (.tsx, .ts, .vue, .svelte, .astro, .jsx, .js).");
2650
+ }
2651
+ return warnings;
2652
+ }
2828
2653
  var init_build_scan_warnings = __esm({
2829
2654
  "packages/experience-design-system-backend-pipeline/dist/src/persistence/src/helpers/collect-files/build-scan-warnings.js"() {
2830
2655
  "use strict";
@@ -2832,6 +2657,17 @@ var init_build_scan_warnings = __esm({
2832
2657
  });
2833
2658
 
2834
2659
  // packages/experience-design-system-backend-pipeline/dist/src/persistence/src/helpers/collect-files/classify-stat-error.js
2660
+ function classifyStatError(code) {
2661
+ switch (code) {
2662
+ case "ENOENT":
2663
+ return "not-found";
2664
+ case "EACCES":
2665
+ case "EPERM":
2666
+ return "permission-denied";
2667
+ default:
2668
+ return "unreadable";
2669
+ }
2670
+ }
2835
2671
  var init_classify_stat_error = __esm({
2836
2672
  "packages/experience-design-system-backend-pipeline/dist/src/persistence/src/helpers/collect-files/classify-stat-error.js"() {
2837
2673
  "use strict";
@@ -2839,6 +2675,9 @@ var init_classify_stat_error = __esm({
2839
2675
  });
2840
2676
 
2841
2677
  // packages/experience-design-system-backend-pipeline/dist/src/persistence/src/helpers/collect-files/empty-file-counts.js
2678
+ function emptyFileCounts() {
2679
+ return { tsx: 0, ts: 0, vue: 0, astro: 0, svelte: 0, jsx: 0, js: 0, json: 0, md: 0, other: 0, total: 0 };
2680
+ }
2842
2681
  var init_empty_file_counts = __esm({
2843
2682
  "packages/experience-design-system-backend-pipeline/dist/src/persistence/src/helpers/collect-files/empty-file-counts.js"() {
2844
2683
  "use strict";
@@ -2846,20 +2685,93 @@ var init_empty_file_counts = __esm({
2846
2685
  });
2847
2686
 
2848
2687
  // packages/experience-design-system-backend-pipeline/dist/src/persistence/src/constants/file-patterns.js
2688
+ var INCLUDED_EXTENSIONS, DENYLIST_GATED_EXTENSIONS, EXCLUDED_SUFFIXES, IGNORED_DIRS, DENYLISTED_EXACT_FILE_NAMES, DENYLISTED_FILE_NAME_PATTERNS;
2849
2689
  var init_file_patterns = __esm({
2850
2690
  "packages/experience-design-system-backend-pipeline/dist/src/persistence/src/constants/file-patterns.js"() {
2851
2691
  "use strict";
2692
+ INCLUDED_EXTENSIONS = /* @__PURE__ */ new Set([".astro", ".js", ".jsx", ".svelte", ".ts", ".tsx", ".vue"]);
2693
+ DENYLIST_GATED_EXTENSIONS = /* @__PURE__ */ new Set([".json", ".md"]);
2694
+ EXCLUDED_SUFFIXES = [
2695
+ ".d.ts",
2696
+ ".stories.ts",
2697
+ ".stories.tsx",
2698
+ ".stories.js",
2699
+ ".stories.jsx",
2700
+ ".story.ts",
2701
+ ".story.tsx",
2702
+ ".story.js",
2703
+ ".story.jsx",
2704
+ ".spec.ts",
2705
+ ".spec.tsx",
2706
+ ".test.ts",
2707
+ ".test.tsx"
2708
+ ];
2709
+ IGNORED_DIRS = /* @__PURE__ */ new Set([
2710
+ ".changeset",
2711
+ ".git",
2712
+ ".github",
2713
+ ".idea",
2714
+ ".next",
2715
+ ".nuxt",
2716
+ ".nx",
2717
+ ".vscode",
2718
+ "build",
2719
+ "coverage",
2720
+ "demo",
2721
+ "demos",
2722
+ "dist",
2723
+ "example",
2724
+ "examples",
2725
+ "node_modules",
2726
+ "out",
2727
+ "storybook-static"
2728
+ ]);
2729
+ DENYLISTED_EXACT_FILE_NAMES = /* @__PURE__ */ new Set([
2730
+ "package.json",
2731
+ "package-lock.json",
2732
+ "npm-shrinkwrap.json",
2733
+ "nx.json",
2734
+ "project.json",
2735
+ "turbo.json",
2736
+ "lerna.json",
2737
+ "jsconfig.json"
2738
+ ]);
2739
+ DENYLISTED_FILE_NAME_PATTERNS = [
2740
+ /^tsconfig(\..+)?\.json$/,
2741
+ /^\.?eslintrc(\..+)?\.json$/,
2742
+ /^\.?prettierrc(\..+)?\.json$/,
2743
+ /^(readme|changelog|contributing|code_of_conduct|license|security)(\..+)?\.md$/i
2744
+ ];
2852
2745
  }
2853
2746
  });
2854
2747
 
2855
2748
  // packages/experience-design-system-backend-pipeline/dist/src/persistence/src/constants/file-categories.js
2749
+ var CATEGORY_BY_EXTENSION;
2856
2750
  var init_file_categories = __esm({
2857
2751
  "packages/experience-design-system-backend-pipeline/dist/src/persistence/src/constants/file-categories.js"() {
2858
2752
  "use strict";
2753
+ CATEGORY_BY_EXTENSION = {
2754
+ ".tsx": "tsx",
2755
+ ".ts": "ts",
2756
+ ".vue": "vue",
2757
+ ".astro": "astro",
2758
+ ".svelte": "svelte",
2759
+ ".jsx": "jsx",
2760
+ ".js": "js",
2761
+ ".json": "json",
2762
+ ".md": "md"
2763
+ };
2859
2764
  }
2860
2765
  });
2861
2766
 
2862
2767
  // packages/experience-design-system-backend-pipeline/dist/src/persistence/src/helpers/collect-files/categorize-file.js
2768
+ import path from "node:path";
2769
+ function categorizeFile(name) {
2770
+ if (name.endsWith(".d.ts"))
2771
+ return "other";
2772
+ const ext = path.extname(name);
2773
+ return CATEGORY_BY_EXTENSION[ext] ?? "other";
2774
+ }
2863
2775
  var init_categorize_file = __esm({
2864
2776
  "packages/experience-design-system-backend-pipeline/dist/src/persistence/src/helpers/collect-files/categorize-file.js"() {
2865
2777
  "use strict";
@@ -2868,6 +2780,9 @@ var init_categorize_file = __esm({
2868
2780
  });
2869
2781
 
2870
2782
  // packages/experience-design-system-backend-pipeline/dist/src/persistence/src/helpers/collect-files/is-noise-config-file.js
2783
+ function isNoiseConfigFile(name) {
2784
+ return DENYLISTED_EXACT_FILE_NAMES.has(name) || DENYLISTED_FILE_NAME_PATTERNS.some((pattern) => pattern.test(name));
2785
+ }
2871
2786
  var init_is_noise_config_file = __esm({
2872
2787
  "packages/experience-design-system-backend-pipeline/dist/src/persistence/src/helpers/collect-files/is-noise-config-file.js"() {
2873
2788
  "use strict";
@@ -2876,6 +2791,19 @@ var init_is_noise_config_file = __esm({
2876
2791
  });
2877
2792
 
2878
2793
  // packages/experience-design-system-backend-pipeline/dist/src/persistence/src/helpers/collect-files/is-source-file.js
2794
+ import path2 from "node:path";
2795
+ function isSourceFile(name) {
2796
+ if (name.endsWith(".d.ts"))
2797
+ return false;
2798
+ if (EXCLUDED_SUFFIXES.some((suffix) => name.endsWith(suffix)))
2799
+ return false;
2800
+ const ext = path2.extname(name);
2801
+ if (INCLUDED_EXTENSIONS.has(ext))
2802
+ return true;
2803
+ if (DENYLIST_GATED_EXTENSIONS.has(ext) && !isNoiseConfigFile(name))
2804
+ return true;
2805
+ return false;
2806
+ }
2879
2807
  var init_is_source_file = __esm({
2880
2808
  "packages/experience-design-system-backend-pipeline/dist/src/persistence/src/helpers/collect-files/is-source-file.js"() {
2881
2809
  "use strict";
@@ -2885,6 +2813,14 @@ var init_is_source_file = __esm({
2885
2813
  });
2886
2814
 
2887
2815
  // packages/experience-design-system-backend-pipeline/dist/src/persistence/src/helpers/collect-files/read-dir-safely.js
2816
+ import { readdirSync } from "node:fs";
2817
+ function readDirSafely(dir) {
2818
+ try {
2819
+ return readdirSync(dir, { withFileTypes: true });
2820
+ } catch {
2821
+ return "unreadable";
2822
+ }
2823
+ }
2888
2824
  var init_read_dir_safely = __esm({
2889
2825
  "packages/experience-design-system-backend-pipeline/dist/src/persistence/src/helpers/collect-files/read-dir-safely.js"() {
2890
2826
  "use strict";
@@ -2892,6 +2828,38 @@ var init_read_dir_safely = __esm({
2892
2828
  });
2893
2829
 
2894
2830
  // packages/experience-design-system-backend-pipeline/dist/src/persistence/src/helpers/collect-files/walk-project-tree.js
2831
+ import { readFileSync as readFileSync3 } from "node:fs";
2832
+ import path3 from "node:path";
2833
+ function walkProjectTree(dir, result, includeContent) {
2834
+ const entries = readDirSafely(dir);
2835
+ if (entries === "unreadable") {
2836
+ result.warnings.push(`Could not read directory: ${dir}`);
2837
+ return;
2838
+ }
2839
+ for (const entry of entries) {
2840
+ const full = path3.join(dir, entry.name);
2841
+ if (entry.isDirectory()) {
2842
+ if (!IGNORED_DIRS.has(entry.name))
2843
+ walkProjectTree(full, result, includeContent);
2844
+ continue;
2845
+ }
2846
+ if (!entry.isFile())
2847
+ continue;
2848
+ if (!isSourceFile(entry.name))
2849
+ continue;
2850
+ const category = categorizeFile(entry.name);
2851
+ result.counts[category] += 1;
2852
+ result.counts.total += 1;
2853
+ result.filePaths.push(full);
2854
+ if (includeContent) {
2855
+ try {
2856
+ const content = readFileSync3(full, "utf8");
2857
+ (result.candidateFiles ??= []).push({ path: full, content });
2858
+ } catch {
2859
+ }
2860
+ }
2861
+ }
2862
+ }
2895
2863
  var init_walk_project_tree = __esm({
2896
2864
  "packages/experience-design-system-backend-pipeline/dist/src/persistence/src/helpers/collect-files/walk-project-tree.js"() {
2897
2865
  "use strict";
@@ -2903,6 +2871,35 @@ var init_walk_project_tree = __esm({
2903
2871
  });
2904
2872
 
2905
2873
  // packages/experience-design-system-backend-pipeline/dist/src/persistence/src/helpers/collect-files/collect-files.js
2874
+ import { statSync as statSync2 } from "node:fs";
2875
+ import path4 from "node:path";
2876
+ function collectFiles(root, options = {}) {
2877
+ const resolved = path4.resolve(root);
2878
+ let stat;
2879
+ try {
2880
+ stat = statSync2(resolved);
2881
+ } catch (err) {
2882
+ return { ok: false, failure: classifyStatError(err.code), rootPath: resolved };
2883
+ }
2884
+ if (stat.isFile())
2885
+ return { ok: false, failure: "is-file", rootPath: resolved };
2886
+ if (!stat.isDirectory())
2887
+ return { ok: false, failure: "not-directory", rootPath: resolved };
2888
+ const result = {
2889
+ filePaths: [],
2890
+ counts: emptyFileCounts(),
2891
+ warnings: [],
2892
+ rootPath: resolved
2893
+ };
2894
+ if (options.includeContent)
2895
+ result.candidateFiles = [];
2896
+ walkProjectTree(resolved, result, options.includeContent === true);
2897
+ result.filePaths.sort();
2898
+ if (result.candidateFiles)
2899
+ result.candidateFiles.sort((a, b) => a.path.localeCompare(b.path));
2900
+ result.warnings.push(...buildScanWarnings(result.counts));
2901
+ return { ok: true, result };
2902
+ }
2906
2903
  var init_collect_files = __esm({
2907
2904
  "packages/experience-design-system-backend-pipeline/dist/src/persistence/src/helpers/collect-files/collect-files.js"() {
2908
2905
  "use strict";
@@ -3205,11 +3202,9 @@ var init_resolve_session_id = __esm({
3205
3202
  });
3206
3203
 
3207
3204
  // packages/experience-design-system-backend-pipeline/dist/src/persistence/src/credentials/helpers/host-utils.js
3208
- var DEFAULT_CONFIGURED_HOST;
3209
3205
  var init_host_utils = __esm({
3210
3206
  "packages/experience-design-system-backend-pipeline/dist/src/persistence/src/credentials/helpers/host-utils.js"() {
3211
3207
  "use strict";
3212
- DEFAULT_CONFIGURED_HOST = "api.contentful.com";
3213
3208
  }
3214
3209
  });
3215
3210
 
@@ -3497,7 +3492,7 @@ var init_utils_gen = __esm({
3497
3492
  init_bodySerializer_gen();
3498
3493
  init_pathSerializer_gen();
3499
3494
  PATH_PARAM_RE = /\{[^{}]+\}/g;
3500
- defaultPathSerializer = ({ path, url: _url }) => {
3495
+ defaultPathSerializer = ({ path: path5, url: _url }) => {
3501
3496
  let url = _url;
3502
3497
  const matches = _url.match(PATH_PARAM_RE);
3503
3498
  if (matches) {
@@ -3516,7 +3511,7 @@ var init_utils_gen = __esm({
3516
3511
  name = name.substring(1);
3517
3512
  style = "matrix";
3518
3513
  }
3519
- const value = path[name];
3514
+ const value = path5[name];
3520
3515
  if (value === void 0 || value === null) {
3521
3516
  continue;
3522
3517
  }
@@ -3661,11 +3656,11 @@ var init_utils_gen = __esm({
3661
3656
  });
3662
3657
  return url;
3663
3658
  };
3664
- getUrl = ({ baseUrl, path, query, querySerializer, url: _url }) => {
3659
+ getUrl = ({ baseUrl, path: path5, query, querySerializer, url: _url }) => {
3665
3660
  const pathUrl = _url.startsWith("/") ? _url : `/${_url}`;
3666
3661
  let url = (baseUrl ?? "") + pathUrl;
3667
- if (path) {
3668
- url = defaultPathSerializer({ path, url });
3662
+ if (path5) {
3663
+ url = defaultPathSerializer({ path: path5, url });
3669
3664
  }
3670
3665
  let search = query ? querySerializer(query) : "";
3671
3666
  if (search.startsWith("?")) {
@@ -3684,9 +3679,9 @@ var init_utils_gen = __esm({
3684
3679
  config.headers = mergeHeaders(a.headers, b.headers);
3685
3680
  return config;
3686
3681
  };
3687
- mergeHeaders = (...headers) => {
3682
+ mergeHeaders = (...headers2) => {
3688
3683
  const mergedHeaders = new Headers();
3689
- for (const header of headers) {
3684
+ for (const header of headers2) {
3690
3685
  if (!header || typeof header !== "object") {
3691
3686
  continue;
3692
3687
  }
@@ -3933,37 +3928,10 @@ var init_client_gen2 = __esm({
3933
3928
  });
3934
3929
 
3935
3930
  // packages/experience-design-system-client/dist/src/generated/sdk.gen.js
3936
- var designSystemImportSourcelessPreview, designSystemImportApply, designSystemImportGetOperation;
3937
3931
  var init_sdk_gen = __esm({
3938
3932
  "packages/experience-design-system-client/dist/src/generated/sdk.gen.js"() {
3939
3933
  "use strict";
3940
3934
  init_client_gen2();
3941
- designSystemImportSourcelessPreview = (options) => {
3942
- return (options.client ?? client).post({
3943
- url: "/spaces/{spaceId}/environments/{environmentId}/design_systems/imports/preview",
3944
- ...options,
3945
- headers: {
3946
- "Content-Type": "application/json",
3947
- ...options.headers
3948
- }
3949
- });
3950
- };
3951
- designSystemImportApply = (options) => {
3952
- return (options.client ?? client).post({
3953
- url: "/spaces/{spaceId}/environments/{environmentId}/design_systems/imports/apply",
3954
- ...options,
3955
- headers: {
3956
- "Content-Type": "application/json",
3957
- ...options.headers
3958
- }
3959
- });
3960
- };
3961
- designSystemImportGetOperation = (options) => {
3962
- return (options.client ?? client).get({
3963
- url: "/spaces/{spaceId}/environments/{environmentId}/design_systems/imports/apply/{operationId}",
3964
- ...options
3965
- });
3966
- };
3967
3935
  }
3968
3936
  });
3969
3937
 
@@ -3986,13 +3954,9 @@ var init_src2 = __esm({
3986
3954
  });
3987
3955
 
3988
3956
  // packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/constants/api.js
3989
- var PREVIEW_ERROR_PREFIX, APPLY_ERROR_PREFIX, USER_AGENT;
3990
3957
  var init_api = __esm({
3991
3958
  "packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/constants/api.js"() {
3992
3959
  "use strict";
3993
- PREVIEW_ERROR_PREFIX = "preview failed:";
3994
- APPLY_ERROR_PREFIX = "apply failed:";
3995
- USER_AGENT = "experience-design-system-backend-pipeline";
3996
3960
  }
3997
3961
  });
3998
3962
 
@@ -4005,153 +3969,34 @@ var init_constants5 = __esm({
4005
3969
  });
4006
3970
 
4007
3971
  // packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/http-utils.js
4008
- function isTransientStatus(status) {
4009
- return status >= 500 && status <= 599;
4010
- }
4011
- function retryAfterMs(response) {
4012
- const value = response.headers?.get("retry-after")?.trim();
4013
- if (!value)
4014
- return void 0;
4015
- const seconds = Number(value);
4016
- const delayMs = Number.isFinite(seconds) ? seconds * 1e3 : Date.parse(value) - Date.now();
4017
- if (!Number.isFinite(delayMs) || delayMs < 0 || delayMs > MAX_RETRY_AFTER_MS)
4018
- return void 0;
4019
- return Math.round(delayMs);
4020
- }
4021
- function isApsDenialBody(body) {
4022
- if (!body)
4023
- return false;
4024
- try {
4025
- const parsed = JSON.parse(body);
4026
- const id = parsed?.sys?.id;
4027
- return id === "NotFound" || id === "AccessDenied";
4028
- } catch {
4029
- return false;
4030
- }
4031
- }
4032
- function stringifyError(error) {
4033
- return typeof error === "string" ? error : JSON.stringify(error ?? {});
4034
- }
4035
- function errorMessage(error) {
4036
- return error instanceof Error && error.message ? error.message : String(error);
4037
- }
4038
- function defaultSleep(delayMs) {
4039
- return new Promise((resolve2) => setTimeout(resolve2, delayMs));
4040
- }
4041
- var MAX_RETRY_AFTER_MS;
4042
3972
  var init_http_utils = __esm({
4043
3973
  "packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/http-utils.js"() {
4044
3974
  "use strict";
4045
- MAX_RETRY_AFTER_MS = 6e4;
4046
3975
  }
4047
3976
  });
4048
3977
 
4049
3978
  // packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/sanitize-preview.js
4050
- function sanitizeBreakingChanges(raw) {
4051
- if (!Array.isArray(raw))
4052
- return [];
4053
- const out = [];
4054
- for (const bc of raw) {
4055
- if (typeof bc !== "object" || bc === null)
4056
- continue;
4057
- const reason = bc.reason;
4058
- if (typeof reason !== "string")
4059
- continue;
4060
- if ("propertyId" in bc && typeof bc.propertyId === "string") {
4061
- if (PROPERTY_BREAKING_REASONS.has(reason))
4062
- out.push(bc);
4063
- continue;
4064
- }
4065
- if ("slotId" in bc && typeof bc.slotId === "string") {
4066
- if (SLOT_BREAKING_REASONS.has(reason))
4067
- out.push(bc);
4068
- continue;
4069
- }
4070
- }
4071
- return out;
4072
- }
4073
- function sanitizePreviewResponse(res) {
4074
- for (const item of res.components?.changed ?? []) {
4075
- const cc = item.changeClassification;
4076
- if (cc && Array.isArray(cc.breakingChanges)) {
4077
- cc.breakingChanges = sanitizeBreakingChanges(cc.breakingChanges);
4078
- }
4079
- }
4080
- return res;
4081
- }
4082
- var PROPERTY_BREAKING_REASONS, SLOT_BREAKING_REASONS;
4083
3979
  var init_sanitize_preview = __esm({
4084
3980
  "packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/sanitize-preview.js"() {
4085
3981
  "use strict";
4086
- PROPERTY_BREAKING_REASONS = /* @__PURE__ */ new Set([
4087
- "removed",
4088
- "added_required_no_default",
4089
- "type_changed",
4090
- "validation_narrowed"
4091
- ]);
4092
- SLOT_BREAKING_REASONS = /* @__PURE__ */ new Set(["slot_removed", "slot_allowed_components_narrowed"]);
4093
3982
  }
4094
3983
  });
4095
3984
 
4096
3985
  // packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/host-utils.js
4097
- function trimTrailingSlashes(value) {
4098
- return value.replace(/\/+$/, "");
4099
- }
4100
- function normalizeHostInput(host) {
4101
- const value = host?.trim();
4102
- if (!value)
4103
- return void 0;
4104
- return trimTrailingSlashes(value);
4105
- }
4106
- function toConfiguredHost2(host) {
4107
- const normalized = normalizeHostInput(host);
4108
- if (!normalized)
4109
- return void 0;
4110
- return normalized.replace(/^https:\/\//i, "");
4111
- }
4112
- function toApiHost2(host) {
4113
- const normalized = normalizeHostInput(host);
4114
- if (!normalized)
4115
- return DEFAULT_API_HOST;
4116
- if (/^[a-z][a-z\d+\-.]*:\/\//i.test(normalized))
4117
- return normalized;
4118
- return `https://${normalized}`;
4119
- }
4120
- var DEFAULT_API_HOST;
4121
3986
  var init_host_utils2 = __esm({
4122
3987
  "packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/host-utils.js"() {
4123
3988
  "use strict";
4124
- DEFAULT_API_HOST = "https://api.contentful.com";
4125
3989
  }
4126
3990
  });
4127
3991
 
4128
3992
  // packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/types/api-error.js
4129
- var ERROR_BODY_LOG_CAP, ApiError;
4130
3993
  var init_api_error = __esm({
4131
3994
  "packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/types/api-error.js"() {
4132
3995
  "use strict";
4133
- ERROR_BODY_LOG_CAP = 16384;
4134
- ApiError = class extends Error {
4135
- status;
4136
- body;
4137
- guidance;
4138
- constructor(message, status, body, guidance) {
4139
- super(message);
4140
- this.status = status;
4141
- this.body = body;
4142
- this.guidance = guidance;
4143
- if (body) {
4144
- const trimmed = body.length > ERROR_BODY_LOG_CAP ? body.slice(0, ERROR_BODY_LOG_CAP) + "\u2026" : body;
4145
- this.message = `${message}
4146
- ${trimmed}`;
4147
- }
4148
- }
4149
- };
4150
3996
  }
4151
3997
  });
4152
3998
 
4153
3999
  // packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/api-client/api-client.js
4154
- var ApiClient;
4155
4000
  var init_api_client = __esm({
4156
4001
  "packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/api-client/api-client.js"() {
4157
4002
  "use strict";
@@ -4161,161 +4006,6 @@ var init_api_client = __esm({
4161
4006
  init_sanitize_preview();
4162
4007
  init_host_utils2();
4163
4008
  init_api_error();
4164
- ApiClient = class {
4165
- host;
4166
- token;
4167
- spaceId;
4168
- environmentId;
4169
- retry;
4170
- lastRequestId;
4171
- constructor(opts) {
4172
- this.host = toApiHost2(opts.host);
4173
- this.token = opts.cmaToken;
4174
- this.spaceId = opts.spaceId;
4175
- this.environmentId = opts.environmentId;
4176
- const initialDelayMs = Math.max(0, opts.retry?.initialDelayMs ?? 250);
4177
- this.retry = {
4178
- maxAttempts: Math.max(1, Math.floor(opts.retry?.maxAttempts ?? 3)),
4179
- initialDelayMs,
4180
- maxDelayMs: Math.max(initialDelayMs, opts.retry?.maxDelayMs ?? 2e3),
4181
- sleep: opts.retry?.sleep ?? defaultSleep
4182
- };
4183
- }
4184
- getLastRequestId() {
4185
- return this.lastRequestId;
4186
- }
4187
- noteRequestId(response) {
4188
- const id = response.headers.get("x-contentful-request-id");
4189
- if (id)
4190
- this.lastRequestId = id;
4191
- }
4192
- headers() {
4193
- return {
4194
- Authorization: `Bearer ${this.token}`,
4195
- "Content-Type": "application/json",
4196
- "X-Contentful-User-Agent": USER_AGENT
4197
- };
4198
- }
4199
- async requestWithRetry(phase, errorPrefix, makeCall) {
4200
- for (let attempt = 1; attempt <= this.retry.maxAttempts; attempt++) {
4201
- let result;
4202
- try {
4203
- result = await makeCall();
4204
- } catch (error) {
4205
- if (attempt === this.retry.maxAttempts) {
4206
- const body = `The request failed after ${attempt} attempts because of a network error: ${errorMessage(error)}. Check your connection and try again.`;
4207
- throw new ApiError(`${errorPrefix} 0`, 0, body);
4208
- }
4209
- await this.retry.sleep(Math.min(this.retry.initialDelayMs * 2 ** (attempt - 1), this.retry.maxDelayMs));
4210
- continue;
4211
- }
4212
- if (!isTransientStatus(result.response.status)) {
4213
- this.noteRequestId(result.response);
4214
- return result;
4215
- }
4216
- if (attempt === this.retry.maxAttempts) {
4217
- const body = stringifyError(result.error);
4218
- const guidance = `The ${phase} request failed after ${attempt} attempts because the service remained unavailable. Wait a moment and try again.`;
4219
- throw new ApiError(`${errorPrefix} ${result.response.status}`, result.response.status, body, guidance);
4220
- }
4221
- const backoffMs = Math.min(this.retry.initialDelayMs * 2 ** (attempt - 1), this.retry.maxDelayMs);
4222
- await this.retry.sleep(retryAfterMs(result.response) ?? backoffMs);
4223
- }
4224
- throw new Error("Retry attempts exhausted");
4225
- }
4226
- async validateToken() {
4227
- const res = await fetch(`${this.host}/users/me`, { headers: this.headers() });
4228
- this.noteRequestId(res);
4229
- if (res.status === 401) {
4230
- throw new ApiError("CMA token is invalid or revoked", res.status, await res.text());
4231
- }
4232
- if (!res.ok) {
4233
- throw new ApiError(`unexpected error validating token: ${res.status}`, res.status, await res.text());
4234
- }
4235
- await this.checkPreflight();
4236
- }
4237
- async checkPreflight() {
4238
- const url = `${this.host}/spaces/${this.spaceId}/environments/${this.environmentId}/design_systems/preflight`;
4239
- let res;
4240
- try {
4241
- res = await fetch(url, { headers: this.headers() });
4242
- } catch {
4243
- return;
4244
- }
4245
- this.noteRequestId(res);
4246
- if (res.ok)
4247
- return;
4248
- if (res.status >= 500)
4249
- return;
4250
- const body = await res.text();
4251
- if (res.status === 404 && !isApsDenialBody(body))
4252
- return;
4253
- throw new ApiError(`preflight failed: ${res.status}`, res.status, body);
4254
- }
4255
- async previewImport(cdf) {
4256
- const result = await this.requestWithRetry("preview", PREVIEW_ERROR_PREFIX, () => designSystemImportSourcelessPreview({
4257
- baseUrl: this.host,
4258
- headers: this.headers(),
4259
- path: { spaceId: this.spaceId, environmentId: this.environmentId },
4260
- body: cdf,
4261
- parseAs: "json"
4262
- }));
4263
- if (!result.response.ok) {
4264
- throw new ApiError(`${PREVIEW_ERROR_PREFIX} ${result.response.status}`, result.response.status, stringifyError(result.error));
4265
- }
4266
- return sanitizePreviewResponse(result.data);
4267
- }
4268
- async applyImport(cdf, opts) {
4269
- let result;
4270
- try {
4271
- result = await designSystemImportApply({
4272
- baseUrl: this.host,
4273
- headers: this.headers(),
4274
- path: { spaceId: this.spaceId, environmentId: this.environmentId },
4275
- body: { ...cdf, acknowledgeBreakingChanges: opts.acknowledgeBreakingChanges },
4276
- parseAs: "json"
4277
- });
4278
- } catch (error) {
4279
- const body = `The apply request was not retried because its outcome is unknown and retrying could start a duplicate operation. Cause: ${errorMessage(error)}`;
4280
- throw new ApiError(`${APPLY_ERROR_PREFIX} 0`, 0, body);
4281
- }
4282
- if (!result.response.ok) {
4283
- const body = stringifyError(result.error);
4284
- const guidance = isTransientStatus(result.response.status) ? "The apply request was not retried because the server may already have started an operation and retrying could create a duplicate." : void 0;
4285
- throw new ApiError(`${APPLY_ERROR_PREFIX} ${result.response.status}`, result.response.status, body, guidance);
4286
- }
4287
- this.noteRequestId(result.response);
4288
- return result.data;
4289
- }
4290
- async pollOperation(operationId, opts = {}) {
4291
- const intervalMs = opts.intervalMs ?? 2e3;
4292
- const maxIntervalMs = opts.maxIntervalMs ?? Math.round(intervalMs * 2.5);
4293
- const maxAttempts = opts.maxAttempts ?? 150;
4294
- const terminalStatuses = /* @__PURE__ */ new Set(["succeeded", "partial", "failed"]);
4295
- for (let attempt = 0; attempt < maxAttempts; attempt++) {
4296
- const result = await this.requestWithRetry("poll", "poll failed:", () => designSystemImportGetOperation({
4297
- baseUrl: this.host,
4298
- headers: this.headers(),
4299
- path: { spaceId: this.spaceId, environmentId: this.environmentId, operationId },
4300
- parseAs: "json"
4301
- }));
4302
- if (!result.response.ok) {
4303
- throw new ApiError(`poll failed: ${result.response.status}`, result.response.status, stringifyError(result.error));
4304
- }
4305
- const op = result.data;
4306
- opts.onProgress?.(op);
4307
- if (terminalStatuses.has(op.sys.status))
4308
- return op;
4309
- if (attempt < maxAttempts - 1) {
4310
- const progress = maxAttempts > 1 ? attempt / (maxAttempts - 1) : 0;
4311
- const baseDelay = intervalMs + (maxIntervalMs - intervalMs) * progress;
4312
- const jitter = Math.random() * baseDelay * 0.15;
4313
- await new Promise((resolve2) => setTimeout(resolve2, baseDelay + jitter));
4314
- }
4315
- }
4316
- throw new Error(`Operation ${operationId} timed out after ${maxAttempts} attempts`);
4317
- }
4318
- };
4319
4009
  }
4320
4010
  });
4321
4011
 
@@ -4518,25 +4208,6 @@ var init_annotate_preview2 = __esm({
4518
4208
  });
4519
4209
 
4520
4210
  // packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/edsi-errors/parse-binding-diagnostics.js
4521
- function parseBindingDiagnostics(body) {
4522
- if (!/binding configurations are invalid|Pointer path does not exist/i.test(body))
4523
- return null;
4524
- const locationMatches = [...body.matchAll(/(?:^|\.\s)([A-Za-z0-9_$-]+(?:\s*›\s*[A-Za-z0-9_$-]+){2,})/g)];
4525
- const location = locationMatches.at(-1)?.[1];
4526
- const pointerMessage = body.match(/Pointer path does not exist for '\[object Object\]':\s*(.+?)(?=\.\s*Default\s*›|$)/i)?.[1];
4527
- const graphQlMessage = body.match(/return GraphQL validation error:\s*(.+?)(?=\.\s*Default\s*›|$)/i)?.[1];
4528
- const heading = body.match(/^(.*?)(?=\.?\s*Pointer path does not exist|\.?\s*Default\s*›)/i)?.[1]?.trim();
4529
- const diagnostics = [];
4530
- if (pointerMessage)
4531
- diagnostics.push({ message: pointerMessage.trim(), ...location ? { path: location } : {} });
4532
- if (graphQlMessage)
4533
- diagnostics.push({ message: graphQlMessage.trim(), ...location ? { path: location } : {} });
4534
- return {
4535
- code: "BindingValidationFailed",
4536
- message: heading || "One or more binding configurations are invalid.",
4537
- ...diagnostics.length > 0 ? { diagnostics } : {}
4538
- };
4539
- }
4540
4211
  var init_parse_binding_diagnostics = __esm({
4541
4212
  "packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/edsi-errors/parse-binding-diagnostics.js"() {
4542
4213
  "use strict";
@@ -4544,76 +4215,6 @@ var init_parse_binding_diagnostics = __esm({
4544
4215
  });
4545
4216
 
4546
4217
  // packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/edsi-errors/helpers.js
4547
- function asRecord(value) {
4548
- return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
4549
- }
4550
- function displayValue(value) {
4551
- if (typeof value === "string")
4552
- return value;
4553
- if (typeof value === "number" || typeof value === "boolean")
4554
- return String(value);
4555
- if (value === null || value === void 0)
4556
- return null;
4557
- try {
4558
- return JSON.stringify(value);
4559
- } catch {
4560
- return null;
4561
- }
4562
- }
4563
- function isPathSegment(value) {
4564
- return typeof value === "string" || typeof value === "number" && Number.isFinite(value);
4565
- }
4566
- function formatPath(value) {
4567
- if (isPathSegment(value))
4568
- return String(value) ? { path: String(value) } : { path: null };
4569
- if (Array.isArray(value)) {
4570
- const parts = value.filter(isPathSegment);
4571
- return parts.length > 0 ? { path: parts.join(" \u203A ") } : { path: null };
4572
- }
4573
- return {};
4574
- }
4575
- function componentFromPath(path) {
4576
- if (!path)
4577
- return void 0;
4578
- const manifestMatch = path.match(/manifest:components\/([^/›]+)/);
4579
- if (manifestMatch?.[1])
4580
- return manifestMatch[1];
4581
- const parts = path.split(/[›/]/).map((part) => part.trim()).filter(Boolean);
4582
- const componentsIndex = parts.findIndex((part) => part === "components");
4583
- return componentsIndex === -1 ? void 0 : parts[componentsIndex + 1];
4584
- }
4585
- function diagnosticMessage(error) {
4586
- const candidates = [
4587
- ["message", error.message],
4588
- ["details", error.details],
4589
- ["error", error.error],
4590
- ["name", error.name]
4591
- ];
4592
- for (const [messageSource, value] of candidates) {
4593
- const message = displayValue(value);
4594
- if (message !== null)
4595
- return { message, messageSource };
4596
- }
4597
- return { message: "Validation failed" };
4598
- }
4599
- function parseObjectLiteralTail(body) {
4600
- const braceStart = body.lastIndexOf("{");
4601
- if (braceStart === -1)
4602
- return null;
4603
- const tail = body.slice(braceStart);
4604
- const codeMatch = tail.match(/code:\s*['"]([^'"]+)['"]/);
4605
- const cycleMatch = tail.match(/cycle:\s*\[\s*([^\]]*)\s*\]/);
4606
- if (!codeMatch && !cycleMatch)
4607
- return null;
4608
- const code = codeMatch ? codeMatch[1] : null;
4609
- let cycle = null;
4610
- if (cycleMatch) {
4611
- cycle = cycleMatch[1].split(",").map((s) => s.trim().replace(/^['"]|['"]$/g, "")).filter((s) => s.length > 0);
4612
- if (cycle.length === 0)
4613
- cycle = null;
4614
- }
4615
- return { code, cycle };
4616
- }
4617
4218
  var init_helpers3 = __esm({
4618
4219
  "packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/edsi-errors/helpers.js"() {
4619
4220
  "use strict";
@@ -4621,50 +4222,6 @@ var init_helpers3 = __esm({
4621
4222
  });
4622
4223
 
4623
4224
  // packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/edsi-errors/parse-json-body.js
4624
- function parseValidationDiagnostics(details) {
4625
- if (!Array.isArray(details.errors))
4626
- return [];
4627
- const diagnostics = [];
4628
- for (const rawError of details.errors) {
4629
- const error = asRecord(rawError);
4630
- if (!error)
4631
- continue;
4632
- const location = formatPath(error.path);
4633
- const component = displayValue(error.component ?? error.componentName ?? error.componentId) ?? componentFromPath(location.path);
4634
- diagnostics.push({ ...diagnosticMessage(error), ...location, ...component ? { component } : {} });
4635
- }
4636
- return diagnostics;
4637
- }
4638
- function parseJsonBody(body) {
4639
- let parsed;
4640
- try {
4641
- parsed = JSON.parse(body);
4642
- } catch {
4643
- return null;
4644
- }
4645
- const p = asRecord(parsed);
4646
- if (!p)
4647
- return null;
4648
- const details = asRecord(p.details) ?? {};
4649
- const pick = (k) => p[k] !== void 0 ? p[k] : details[k];
4650
- const codeRaw = pick("code") ?? asRecord(p.sys)?.id;
4651
- const messageRaw = pick("message");
4652
- const cycleRaw = pick("cycle");
4653
- const out = {};
4654
- if (typeof codeRaw === "string")
4655
- out.code = codeRaw;
4656
- if (typeof messageRaw === "string")
4657
- out.message = messageRaw;
4658
- if (Array.isArray(cycleRaw)) {
4659
- const strs = cycleRaw.filter((x) => typeof x === "string");
4660
- if (strs.length > 0)
4661
- out.cycle = strs;
4662
- }
4663
- const diagnostics = parseValidationDiagnostics(details);
4664
- if (diagnostics.length > 0)
4665
- out.diagnostics = diagnostics;
4666
- return out;
4667
- }
4668
4225
  var init_parse_json_body = __esm({
4669
4226
  "packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/edsi-errors/parse-json-body.js"() {
4670
4227
  "use strict";
@@ -4673,72 +4230,13 @@ var init_parse_json_body = __esm({
4673
4230
  });
4674
4231
 
4675
4232
  // packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/edsi-errors/strip-lambda-log-prefix.js
4676
- function stripLambdaLogPrefix(body) {
4677
- return body.replace(LAMBDA_LOG_PREFIX_RE, "").replace(DD_TAG_RE, "").trim();
4678
- }
4679
- var LAMBDA_LOG_PREFIX_RE, DD_TAG_RE;
4680
4233
  var init_strip_lambda_log_prefix = __esm({
4681
4234
  "packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/edsi-errors/strip-lambda-log-prefix.js"() {
4682
4235
  "use strict";
4683
- LAMBDA_LOG_PREFIX_RE = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z\s+[0-9a-f-]+\s+ERROR\s+(?:\[dd\.[^\]]*\]\s*)?/;
4684
- DD_TAG_RE = /\[dd\.(?:trace_id|span_id)=[^\]]*\]\s*/g;
4685
4236
  }
4686
4237
  });
4687
4238
 
4688
4239
  // packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/edsi-errors/parse-edsi-error.js
4689
- function parseEdsiError(rawInput) {
4690
- if (!rawInput)
4691
- return { code: null, message: "", cycle: null, raw: true };
4692
- const { body, prefix } = splitPhasePrefix(rawInput);
4693
- const cleaned = stripLambdaLogPrefix(body);
4694
- const json = parseJsonBody(cleaned) ?? parseJsonBody(body);
4695
- const bindingFromJson = typeof json?.message === "string" ? parseBindingDiagnostics(json.message) : null;
4696
- if (bindingFromJson) {
4697
- return {
4698
- code: bindingFromJson.code ?? json?.code ?? null,
4699
- message: bindingFromJson.message ?? cleaned,
4700
- cycle: null,
4701
- raw: false,
4702
- ...bindingFromJson.diagnostics ? { diagnostics: bindingFromJson.diagnostics } : {}
4703
- };
4704
- }
4705
- if (json && (json.code || json.message || json.cycle)) {
4706
- return {
4707
- code: json.code ?? null,
4708
- message: json.message ?? (cleaned || prefix),
4709
- cycle: json.cycle ?? null,
4710
- raw: false,
4711
- ...json.diagnostics ? { diagnostics: json.diagnostics } : {}
4712
- };
4713
- }
4714
- const binding = parseBindingDiagnostics(cleaned);
4715
- if (binding) {
4716
- return {
4717
- code: binding.code ?? null,
4718
- message: binding.message ?? cleaned,
4719
- cycle: null,
4720
- raw: false,
4721
- ...binding.diagnostics ? { diagnostics: binding.diagnostics } : {}
4722
- };
4723
- }
4724
- const literal2 = parseObjectLiteralTail(cleaned);
4725
- if (literal2 && (literal2.code || literal2.cycle)) {
4726
- const braceStart = cleaned.lastIndexOf("{");
4727
- const head = braceStart === -1 ? cleaned : cleaned.slice(0, braceStart).trim();
4728
- return { code: literal2.code ?? null, message: head || cleaned, cycle: literal2.cycle ?? null, raw: false };
4729
- }
4730
- return { code: null, message: cleaned || prefix || rawInput, cycle: null, raw: true };
4731
- }
4732
- function splitPhasePrefix(input) {
4733
- const nlIndex = input.indexOf("\n");
4734
- if (nlIndex === -1)
4735
- return { body: input, prefix: "" };
4736
- const firstLine = input.slice(0, nlIndex);
4737
- if (!API_ERROR_PREFIX_RE.test(firstLine))
4738
- return { body: input, prefix: "" };
4739
- return { body: input.slice(nlIndex + 1), prefix: firstLine };
4740
- }
4741
- var API_ERROR_PREFIX_RE;
4742
4240
  var init_parse_edsi_error = __esm({
4743
4241
  "packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/edsi-errors/parse-edsi-error.js"() {
4744
4242
  "use strict";
@@ -4746,51 +4244,10 @@ var init_parse_edsi_error = __esm({
4746
4244
  init_parse_json_body();
4747
4245
  init_helpers3();
4748
4246
  init_strip_lambda_log_prefix();
4749
- API_ERROR_PREFIX_RE = /^(?:apply|preview|poll) failed: \d+$/;
4750
4247
  }
4751
4248
  });
4752
4249
 
4753
4250
  // packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/edsi-errors/format-parsed-edsi-error.js
4754
- function formatParsedEdsiError(parsed, opts = {}) {
4755
- const lines = [];
4756
- if (parsed.code)
4757
- lines.push(`[${parsed.code}]`);
4758
- if (parsed.message)
4759
- lines.push(parsed.message);
4760
- for (const diagnostic of parsed.diagnostics ?? []) {
4761
- const context = [
4762
- diagnostic.component ? `Component: ${diagnostic.component}` : null,
4763
- diagnostic.path ? `Path: ${diagnostic.path}` : null
4764
- ].filter(Boolean);
4765
- lines.push(`- ${diagnostic.message}${context.length > 0 ? ` (${context.join("; ")})` : ""}`);
4766
- if (diagnostic.path === null) {
4767
- lines.push(" Location: not provided by the server. Review the submitted CDF file; no component or field was identified.");
4768
- }
4769
- if (opts.verbose && diagnostic.messageSource) {
4770
- lines.push(` Message field: ${diagnostic.messageSource}`);
4771
- }
4772
- }
4773
- if (parsed.code === "BindingValidationFailed") {
4774
- const location = parsed.diagnostics?.find((d) => d.path)?.path;
4775
- lines.push(location ? `Next action: review the binding at ${location} and correct its pointer or GraphQL selection.` : "Next action: review the binding pointer and GraphQL selection.");
4776
- }
4777
- if (parsed.code === "AccessDenied") {
4778
- lines.push("Next action: this operation requires DesignToken and Component permissions in this environment. Ask a Contentful admin to grant both on your role.");
4779
- }
4780
- if (parsed.code === "NotFound") {
4781
- lines.push("Next action: verify the resource id is correct. If it should exist, your role may lack read permission on DesignToken or Component.");
4782
- }
4783
- if (parsed.cycle && parsed.cycle.length > 0) {
4784
- lines.push(`Cycle: ${parsed.cycle.join(" \u2192 ")} \u2192 ${parsed.cycle[0]}`);
4785
- lines.push("Break the cycle by removing at least one $allowedComponents entry.");
4786
- }
4787
- if (opts.verbose && opts.raw) {
4788
- lines.push("");
4789
- lines.push("--- raw ---");
4790
- lines.push(opts.raw);
4791
- }
4792
- return lines.filter(Boolean).join("\n");
4793
- }
4794
4251
  var init_format_parsed_edsi_error = __esm({
4795
4252
  "packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/edsi-errors/format-parsed-edsi-error.js"() {
4796
4253
  "use strict";
@@ -4798,12 +4255,6 @@ var init_format_parsed_edsi_error = __esm({
4798
4255
  });
4799
4256
 
4800
4257
  // packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/edsi-errors/format-edsi-error.js
4801
- function formatEdsiError(raw, opts = {}) {
4802
- const input = typeof raw === "string" ? raw : displayValue(raw);
4803
- if (!input)
4804
- return "";
4805
- return formatParsedEdsiError(parseEdsiError(input), { ...opts, raw: opts.raw ?? input });
4806
- }
4807
4258
  var init_format_edsi_error = __esm({
4808
4259
  "packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/edsi-errors/format-edsi-error.js"() {
4809
4260
  "use strict";
@@ -4814,14 +4265,6 @@ var init_format_edsi_error = __esm({
4814
4265
  });
4815
4266
 
4816
4267
  // packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/edsi-errors/format-api-error.js
4817
- function formatApiError(error, verbose = false) {
4818
- const formatted = formatEdsiError(error.body || error.message, { verbose, raw: error.body }) || error.message;
4819
- const phase = error.message.split("\n", 1)[0];
4820
- const withPhase = /^(?:apply|preview|poll) failed: \d+$/.test(phase) && formatted !== phase ? `${phase}
4821
- ${formatted}` : formatted;
4822
- return error.guidance ? `${withPhase}
4823
- ${error.guidance}` : withPhase;
4824
- }
4825
4268
  var init_format_api_error = __esm({
4826
4269
  "packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/edsi-errors/format-api-error.js"() {
4827
4270
  "use strict";
@@ -4858,9 +4301,6 @@ var init_format_edsi_error2 = __esm({
4858
4301
  });
4859
4302
 
4860
4303
  // packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/controller/errors/format-api-error.js
4861
- function formatApiError2(request) {
4862
- return formatApiError(request.error, request.verbose ?? false);
4863
- }
4864
4304
  var init_format_api_error2 = __esm({
4865
4305
  "packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/controller/errors/format-api-error.js"() {
4866
4306
  "use strict";
@@ -5246,6 +4686,120 @@ var init_src3 = __esm({
5246
4686
  }
5247
4687
  });
5248
4688
 
4689
+ // packages/experience-design-system-cli/src/tui/import/steps/03-path-validation/helpers/scan-files.ts
4690
+ function scanFiles(directory) {
4691
+ return toScanResult(collectFiles(directory));
4692
+ }
4693
+ function toScanResult(outcome) {
4694
+ if (!outcome.ok) return { ok: false, failure: outcome.failure };
4695
+ return {
4696
+ ok: true,
4697
+ counts: foldSvelteAndMdIntoOther(outcome.result.counts),
4698
+ filePaths: outcome.result.filePaths,
4699
+ warnings: outcome.result.warnings
4700
+ };
4701
+ }
4702
+ function foldSvelteAndMdIntoOther(counts) {
4703
+ const { svelte, md, ...rest } = counts;
4704
+ return { ...rest, other: rest.other + svelte + md };
4705
+ }
4706
+ var init_scan_files = __esm({
4707
+ "packages/experience-design-system-cli/src/tui/import/steps/03-path-validation/helpers/scan-files.ts"() {
4708
+ "use strict";
4709
+ init_src3();
4710
+ }
4711
+ });
4712
+
4713
+ // packages/experience-design-system-cli/src/tui/import/steps/03-path-validation/screen.tsx
4714
+ import { useEffect as useEffect3, useMemo, useState as useState5 } from "react";
4715
+ import { Box as Box5, Text as Text6 } from "ink";
4716
+ import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
4717
+ function Row({ row }) {
4718
+ return /* @__PURE__ */ jsxs5(Text6, { color: row.tone === "accent" ? PALETTE.accent : void 0, dimColor: row.tone === "muted", children: [
4719
+ " \u2022 ",
4720
+ String(row.count).padStart(3),
4721
+ " ",
4722
+ row.label
4723
+ ] });
4724
+ }
4725
+ function Failure({ scan, path: path5 }) {
4726
+ const { headline, hints } = describeFailure(scan.failure, path5);
4727
+ return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
4728
+ /* @__PURE__ */ jsxs5(Text6, { color: PALETTE.error, children: [
4729
+ "\u2717 ",
4730
+ headline
4731
+ ] }),
4732
+ hints.map((hint) => /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: hint }, hint))
4733
+ ] });
4734
+ }
4735
+ function Summary({ scan, path: path5 }) {
4736
+ const { total, rows, warning } = summarize(scan.counts);
4737
+ return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", gap: 1, children: [
4738
+ /* @__PURE__ */ jsxs5(Text6, { children: [
4739
+ "Scanned ",
4740
+ /* @__PURE__ */ jsx6(Text6, { bold: true, children: path5 })
4741
+ ] }),
4742
+ /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
4743
+ /* @__PURE__ */ jsxs5(Text6, { color: PALETTE.success, children: [
4744
+ "\u2713 Found ",
4745
+ total,
4746
+ " files:"
4747
+ ] }),
4748
+ rows.map((row) => /* @__PURE__ */ jsx6(Row, { row }, row.label))
4749
+ ] }),
4750
+ warning && /* @__PURE__ */ jsxs5(Text6, { color: PALETTE.warning, children: [
4751
+ "\u26A0 ",
4752
+ warning
4753
+ ] }),
4754
+ /* @__PURE__ */ jsx6(Text6, { children: "Does this look right?" })
4755
+ ] });
4756
+ }
4757
+ function PathValidationScreen({
4758
+ projectPath,
4759
+ onConfirm,
4760
+ onChangePath,
4761
+ onBack
4762
+ }) {
4763
+ const resolvedPath = useMemo(() => resolveUserPath(projectPath), [projectPath]);
4764
+ const [scan, setScan] = useState5();
4765
+ useEffect3(() => {
4766
+ setScan(scanFiles(resolvedPath));
4767
+ }, [resolvedPath]);
4768
+ const phase = phaseOf(scan);
4769
+ usePathValidationControls(phase, {
4770
+ onConfirm: () => {
4771
+ if (scan?.ok) onConfirm({ projectPath: resolvedPath, filePaths: scan.filePaths });
4772
+ },
4773
+ onChangePath,
4774
+ onBack
4775
+ });
4776
+ return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", gap: 1, paddingX: 2, paddingY: 1, children: [
4777
+ scan === void 0 && /* @__PURE__ */ jsxs5(Text6, { dimColor: true, children: [
4778
+ "Scanning ",
4779
+ /* @__PURE__ */ jsx6(Text6, { bold: true, children: resolvedPath }),
4780
+ "..."
4781
+ ] }),
4782
+ scan?.ok === false && /* @__PURE__ */ jsx6(Failure, { scan, path: resolvedPath }),
4783
+ scan?.ok === true && /* @__PURE__ */ jsx6(Summary, { scan, path: resolvedPath }),
4784
+ /* @__PURE__ */ jsx6(Box5, { marginTop: 1, gap: 3, children: controlsFor(phase).map((control) => /* @__PURE__ */ jsxs5(Text6, { dimColor: true, children: [
4785
+ "[",
4786
+ control.keys,
4787
+ "] ",
4788
+ control.label
4789
+ ] }, control.keys)) })
4790
+ ] });
4791
+ }
4792
+ var init_screen3 = __esm({
4793
+ "packages/experience-design-system-cli/src/tui/import/steps/03-path-validation/screen.tsx"() {
4794
+ "use strict";
4795
+ init_home_theme();
4796
+ init_resolve_user_path();
4797
+ init_controls3();
4798
+ init_scan_files();
4799
+ init_logic3();
4800
+ }
4801
+ });
4802
+
5249
4803
  // packages/experience-design-system-cli/src/tui/import/steps/04-credentials/logic.ts
5250
4804
  function keyAction2(input, key) {
5251
4805
  if (key.escape) return "back";
@@ -5256,12 +4810,21 @@ function keyAction2(input, key) {
5256
4810
  function nextField(field) {
5257
4811
  return FIELDS[(FIELDS.indexOf(field) + 1) % FIELDS.length];
5258
4812
  }
4813
+ function toConfiguredHost3(host) {
4814
+ const value = (host ?? "").trim().replace(/\/+$/, "");
4815
+ return value === "" ? DEFAULT_HOST : value.replace(/^https:\/\//i, "");
4816
+ }
4817
+ function toApiHost3(host) {
4818
+ const value = host.trim().replace(/\/+$/, "");
4819
+ if (value === "") return `https://${DEFAULT_HOST}`;
4820
+ return /^[a-z][a-z\d+\-.]*:\/\//i.test(value) ? value : `https://${value}`;
4821
+ }
5259
4822
  function normalize(values) {
5260
4823
  return {
5261
4824
  spaceId: values.spaceId.trim(),
5262
4825
  environmentId: values.environmentId.trim(),
5263
4826
  cmaToken: values.cmaToken.trim(),
5264
- host: toConfiguredHost2(values.host) ?? DEFAULT_CONFIGURED_HOST
4827
+ host: toConfiguredHost3(values.host)
5265
4828
  };
5266
4829
  }
5267
4830
  function missingField(values) {
@@ -5270,12 +4833,12 @@ function missingField(values) {
5270
4833
  function isUnchanged(current, initial) {
5271
4834
  return FIELDS.every((field) => current[field] === initial[field]);
5272
4835
  }
5273
- var FIELDS;
4836
+ var FIELDS, DEFAULT_HOST;
5274
4837
  var init_logic4 = __esm({
5275
4838
  "packages/experience-design-system-cli/src/tui/import/steps/04-credentials/logic.ts"() {
5276
4839
  "use strict";
5277
- init_src3();
5278
4840
  FIELDS = ["spaceId", "environmentId", "cmaToken", "host"];
4841
+ DEFAULT_HOST = "api.contentful.com";
5279
4842
  }
5280
4843
  });
5281
4844
 
@@ -5305,35 +4868,65 @@ var init_controls4 = __esm({
5305
4868
  });
5306
4869
 
5307
4870
  // packages/experience-design-system-cli/src/tui/import/steps/04-credentials/validate.ts
4871
+ function headers(token) {
4872
+ return { Authorization: `Bearer ${token}`, "X-Contentful-User-Agent": USER_AGENT2 };
4873
+ }
4874
+ function isApsDenial(body) {
4875
+ try {
4876
+ const id = JSON.parse(body).sys?.id;
4877
+ return id === "NotFound" || id === "AccessDenied";
4878
+ } catch {
4879
+ return false;
4880
+ }
4881
+ }
4882
+ function messageFrom(body) {
4883
+ try {
4884
+ const message = JSON.parse(body).message;
4885
+ return typeof message === "string" && message !== "" ? message : void 0;
4886
+ } catch {
4887
+ return void 0;
4888
+ }
4889
+ }
5308
4890
  async function validateCredentials(values) {
5309
- const host = toApiHost2(values.host);
5310
- const client2 = new ApiClient({
5311
- host,
5312
- spaceId: values.spaceId,
5313
- environmentId: values.environmentId,
5314
- cmaToken: values.cmaToken
5315
- });
4891
+ const base = toApiHost3(values.host);
4892
+ let me;
5316
4893
  try {
5317
- await client2.validateToken();
5318
- return { ok: true };
4894
+ me = await fetch(`${base}/users/me`, { headers: headers(values.cmaToken) });
5319
4895
  } catch (error) {
5320
- return { ok: false, error: toUserError(error, host) };
4896
+ return { ok: false, error: `Could not reach ${base}: ${error instanceof Error ? error.message : String(error)}` };
5321
4897
  }
5322
- }
5323
- function toUserError(error, host) {
5324
- if (error instanceof ApiError) {
5325
- if (error.status === 404 && error.message.startsWith("preflight failed:")) {
5326
- return "Not found. Check the space ID, environment and API host.";
5327
- }
5328
- return formatApiError2({ error });
4898
+ if (me.status === 401) return { ok: false, error: "CMA token is invalid or revoked." };
4899
+ if (!me.ok) return { ok: false, error: `Unexpected error validating the token (${me.status}).` };
4900
+ let preflight;
4901
+ try {
4902
+ preflight = await fetch(
4903
+ `${base}/spaces/${values.spaceId}/environments/${values.environmentId}/design_systems/preflight`,
4904
+ { headers: headers(values.cmaToken) }
4905
+ );
4906
+ } catch {
4907
+ return { ok: true };
4908
+ }
4909
+ if (preflight.ok || preflight.status >= 500) return { ok: true };
4910
+ const body = await preflight.text();
4911
+ if (preflight.status === 404 && !isApsDenial(body)) return { ok: true };
4912
+ const detail = messageFrom(body);
4913
+ if (preflight.status === 403) {
4914
+ return { ok: false, error: `Access denied. ${detail ?? "Your token cannot write design system components here."}` };
4915
+ }
4916
+ if (preflight.status === 404) {
4917
+ return {
4918
+ ok: false,
4919
+ error: `Not found. Check the space ID, environment and API host.${detail ? ` (${detail})` : ""}`
4920
+ };
5329
4921
  }
5330
- if (error instanceof Error) return `Could not reach ${host}: ${error.message}`;
5331
- return String(error);
4922
+ return { ok: false, error: `Credential check failed (${preflight.status}).${detail ? ` ${detail}` : ""}` };
5332
4923
  }
4924
+ var USER_AGENT2;
5333
4925
  var init_validate4 = __esm({
5334
4926
  "packages/experience-design-system-cli/src/tui/import/steps/04-credentials/validate.ts"() {
5335
4927
  "use strict";
5336
- init_src3();
4928
+ init_logic4();
4929
+ USER_AGENT2 = "app contentful.experience-design-system-cli";
5337
4930
  }
5338
4931
  });
5339
4932
 
@@ -5408,7 +5001,7 @@ function CredentialsScreen({
5408
5001
  value: values[field],
5409
5002
  focus: active === field && !validating,
5410
5003
  mask: field === "cmaToken" ? "\u2022" : void 0,
5411
- placeholder: field === "host" ? DEFAULT_CONFIGURED_HOST : void 0,
5004
+ placeholder: field === "host" ? DEFAULT_HOST : void 0,
5412
5005
  onChange: change(field),
5413
5006
  onSubmit: () => void submit(field)
5414
5007
  }
@@ -5435,7 +5028,6 @@ var init_screen4 = __esm({
5435
5028
  "use strict";
5436
5029
  init_home_theme();
5437
5030
  init_controls4();
5438
- init_src3();
5439
5031
  init_logic4();
5440
5032
  init_validate4();
5441
5033
  LABELS = {
@@ -5462,8 +5054,8 @@ var init_steps = __esm({
5462
5054
  import { spawn as spawn3 } from "node:child_process";
5463
5055
  function buildArgs2(options) {
5464
5056
  const args = ["import"];
5465
- if (options.project) {
5466
- args.push("--project", options.project);
5057
+ if (options.projectPath) {
5058
+ args.push("--project", options.projectPath);
5467
5059
  }
5468
5060
  if (options.tokens) {
5469
5061
  args.push("--tokens", options.tokens);
@@ -5520,9 +5112,9 @@ var init_terminal_input = __esm({
5520
5112
  import { randomBytes } from "node:crypto";
5521
5113
  import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
5522
5114
  import { homedir as homedir2 } from "node:os";
5523
- import { dirname as dirname2, join as join6 } from "node:path";
5115
+ import { dirname as dirname2, join as join5 } from "node:path";
5524
5116
  function configRoot2() {
5525
- return process.env["EDS_HOME"] || join6(homedir2(), ".contentful", "experience-design-system-cli");
5117
+ return process.env["EDS_HOME"] || join5(homedir2(), ".contentful", "experience-design-system-cli");
5526
5118
  }
5527
5119
  async function readSettings2() {
5528
5120
  try {
@@ -5532,12 +5124,12 @@ async function readSettings2() {
5532
5124
  }
5533
5125
  }
5534
5126
  async function writeSettings2(settings) {
5535
- const path = configFilePath2();
5536
- await mkdir(dirname2(path), { recursive: true });
5537
- const tmp = `${path}.${process.pid}.${randomBytes(4).toString("hex")}.tmp`;
5127
+ const path5 = configFilePath2();
5128
+ await mkdir(dirname2(path5), { recursive: true });
5129
+ const tmp = `${path5}.${process.pid}.${randomBytes(4).toString("hex")}.tmp`;
5538
5130
  await writeFile(tmp, `${JSON.stringify(settings, null, 2)}
5539
5131
  `, { mode: 384 });
5540
- await rename(tmp, path);
5132
+ await rename(tmp, path5);
5541
5133
  }
5542
5134
  async function updateSettings2(patch) {
5543
5135
  await writeSettings2({ ...await readSettings2(), ...patch });
@@ -5546,10 +5138,10 @@ var configFilePath2, runsFilePath2, debugSessionsDir2, oldConfigDir2;
5546
5138
  var init_config = __esm({
5547
5139
  "packages/experience-design-system-types/dist/src/config/index.js"() {
5548
5140
  "use strict";
5549
- configFilePath2 = () => join6(configRoot2(), "config.json");
5550
- runsFilePath2 = () => join6(configRoot2(), "state", "runs.json");
5551
- debugSessionsDir2 = () => join6(configRoot2(), "debug", "sessions");
5552
- oldConfigDir2 = () => join6(homedir2(), ".config", "experiences");
5141
+ configFilePath2 = () => join5(configRoot2(), "config.json");
5142
+ runsFilePath2 = () => join5(configRoot2(), "state", "runs.json");
5143
+ debugSessionsDir2 = () => join5(configRoot2(), "debug", "sessions");
5144
+ oldConfigDir2 = () => join5(homedir2(), ".config", "experiences");
5553
5145
  }
5554
5146
  });
5555
5147
 
@@ -5574,8 +5166,8 @@ var init_debug_mode_store = __esm({
5574
5166
 
5575
5167
  // packages/experience-design-system-cli/src/tui/debug-store.ts
5576
5168
  import { mkdir as mkdir2, writeFile as writeFile2 } from "node:fs/promises";
5577
- import { existsSync as existsSync4, readdirSync } from "node:fs";
5578
- import { join as join7 } from "node:path";
5169
+ import { existsSync as existsSync4, readdirSync as readdirSync2 } from "node:fs";
5170
+ import { join as join6 } from "node:path";
5579
5171
  function generateRunId() {
5580
5172
  const now = /* @__PURE__ */ new Date();
5581
5173
  const pad = (n) => String(n).padStart(2, "0");
@@ -5591,7 +5183,7 @@ function slugify(value) {
5591
5183
  function generateSessionId3() {
5592
5184
  const today = datePrefix();
5593
5185
  const root = debugSessionsDir2();
5594
- const existing = existsSync4(root) ? readdirSync(root) : [];
5186
+ const existing = existsSync4(root) ? readdirSync2(root) : [];
5595
5187
  const seqPattern = new RegExp(`^${today}-session-(\\d+)$`);
5596
5188
  const maxSeq = existing.reduce((max, entry) => {
5597
5189
  const match = seqPattern.exec(entry);
@@ -5600,7 +5192,7 @@ function generateSessionId3() {
5600
5192
  return `${today}-session-${maxSeq + 1}`;
5601
5193
  }
5602
5194
  function sessionDebugDir() {
5603
- return join7(debugSessionsDir2(), SESSION_ID);
5195
+ return join6(debugSessionsDir2(), SESSION_ID);
5604
5196
  }
5605
5197
  function currentDebugSessionDir() {
5606
5198
  return sessionDebugDir();
@@ -5645,15 +5237,15 @@ async function finishDebugRun({
5645
5237
  const durationMs = Date.now() - run.startedAt;
5646
5238
  const content = renderMarkdown(run, { outputs: redact(outputs), status, exitMethod, durationMs });
5647
5239
  const flowSegments = run.flow.split("/");
5648
- const dir = join7(sessionDebugDir(), ...flowSegments);
5240
+ const dir = join6(sessionDebugDir(), ...flowSegments);
5649
5241
  await mkdir2(dir, { recursive: true });
5650
5242
  const filename = nextAttemptFilename(dir, run.menuOption);
5651
- await writeFile2(join7(dir, filename), content, { mode: 384 });
5243
+ await writeFile2(join6(dir, filename), content, { mode: 384 });
5652
5244
  }
5653
5245
  function nextAttemptFilename(dir, menuOption) {
5654
5246
  const today = datePrefix();
5655
5247
  const optionSlug = slugify(menuOption);
5656
- const existing = existsSync4(dir) ? readdirSync(dir) : [];
5248
+ const existing = existsSync4(dir) ? readdirSync2(dir) : [];
5657
5249
  const attemptPattern = new RegExp(`^${today}-${optionSlug}-attempt-(\\d+)\\.md$`);
5658
5250
  const maxAttempt = existing.reduce((max, entry) => {
5659
5251
  const match = attemptPattern.exec(entry);
@@ -6348,7 +5940,7 @@ function App({ onLaunchImport, importExitCode }) {
6348
5940
  const [showImportResult, setShowImportResult] = useState13(returnedFromImport);
6349
5941
  const [projectPath, setProjectPath] = useState13();
6350
5942
  const [tokensPath, setTokensPath] = useState13();
6351
- const [pathConfirmed, setPathConfirmed] = useState13(false);
5943
+ const [scannedFiles, setScannedFiles] = useState13();
6352
5944
  const [importDefaults, setImportDefaults] = useState13();
6353
5945
  useEffect9(() => {
6354
5946
  if (screen !== "import") {
@@ -6363,16 +5955,16 @@ function App({ onLaunchImport, importExitCode }) {
6363
5955
  })
6364
5956
  );
6365
5957
  }, [screen]);
6366
- const finishCredentials = async (result, project, tokens) => {
5958
+ const finishCredentials = async (result, projectPath2, tokens, filePaths) => {
6367
5959
  if (!result.skipped) await writeCredentials({ ...result.credentials });
6368
- onLaunchImport?.({ project, tokens, skipCredentials: result.skipped });
5960
+ onLaunchImport?.({ projectPath: projectPath2, tokens, filePaths, skipCredentials: result.skipped });
6369
5961
  };
6370
5962
  const goToStart = () => setScreen("start");
6371
5963
  const goToSettings = () => setScreen("settings");
6372
5964
  const resetImport = () => {
6373
5965
  setProjectPath(void 0);
6374
5966
  setTokensPath(void 0);
6375
- setPathConfirmed(false);
5967
+ setScannedFiles(void 0);
6376
5968
  };
6377
5969
  const finishImportResult = () => {
6378
5970
  setShowImportResult(false);
@@ -6400,12 +5992,12 @@ function App({ onLaunchImport, importExitCode }) {
6400
5992
  }
6401
5993
  );
6402
5994
  }
6403
- if (!pathConfirmed) {
5995
+ if (scannedFiles === void 0) {
6404
5996
  return /* @__PURE__ */ jsx14(
6405
5997
  PathValidationScreen,
6406
5998
  {
6407
5999
  projectPath,
6408
- onConfirm: () => setPathConfirmed(true),
6000
+ onConfirm: ({ filePaths }) => setScannedFiles(filePaths),
6409
6001
  onChangePath: resetImport,
6410
6002
  onBack: () => setTokensPath(void 0)
6411
6003
  }
@@ -6415,8 +6007,8 @@ function App({ onLaunchImport, importExitCode }) {
6415
6007
  CredentialsScreen,
6416
6008
  {
6417
6009
  initial: importDefaults.credentials,
6418
- onBack: () => setPathConfirmed(false),
6419
- onDone: (result) => void finishCredentials(result, projectPath, tokensPath)
6010
+ onBack: () => setScannedFiles(void 0),
6011
+ onDone: (result) => void finishCredentials(result, projectPath, tokensPath, scannedFiles)
6420
6012
  }
6421
6013
  );
6422
6014
  case "help":
@@ -6486,8 +6078,8 @@ var init_app = __esm({
6486
6078
  });
6487
6079
 
6488
6080
  // packages/experience-design-system-cli/program.ts
6489
- import { readFileSync as readFileSync3 } from "node:fs";
6490
- import { join as join8 } from "node:path";
6081
+ import { readFileSync as readFileSync4 } from "node:fs";
6082
+ import { join as join7 } from "node:path";
6491
6083
  import { Command } from "commander";
6492
6084
 
6493
6085
  // packages/experience-design-system-cli/src/legacy/run-legacy.ts
@@ -6588,8 +6180,8 @@ function registerImportCommand(program, openTui) {
6588
6180
  // packages/experience-design-system-cli/program.ts
6589
6181
  init_package_root();
6590
6182
  var pkg = JSON.parse(
6591
- readFileSync3(
6592
- join8(findPackageRoot(import.meta.url, "@contentful/experience-design-system-cli"), "package.json"),
6183
+ readFileSync4(
6184
+ join7(findPackageRoot(import.meta.url, "@contentful/experience-design-system-cli"), "package.json"),
6593
6185
  "utf8"
6594
6186
  )
6595
6187
  );
@@ -6609,20 +6201,20 @@ init_config();
6609
6201
  init_package_root();
6610
6202
  import { existsSync as existsSync5 } from "node:fs";
6611
6203
  import { mkdir as mkdir3, readFile as readFile2, rename as rename2, rmdir, unlink } from "node:fs/promises";
6612
- import { dirname as dirname3, join as join9 } from "node:path";
6204
+ import { dirname as dirname3, join as join8 } from "node:path";
6613
6205
  var PACKAGE_NAME4 = "@contentful/experience-design-system-cli";
6614
- async function readJson(path) {
6206
+ async function readJson(path5) {
6615
6207
  try {
6616
- return JSON.parse(await readFile2(path, "utf8"));
6208
+ return JSON.parse(await readFile2(path5, "utf8"));
6617
6209
  } catch {
6618
6210
  return void 0;
6619
6211
  }
6620
6212
  }
6621
6213
  async function migrateOldConfig() {
6622
6214
  try {
6623
- const oldCredentials = join9(oldConfigDir2(), "credentials.json");
6624
- const oldRuns = join9(oldConfigDir2(), "runs.json");
6625
- const oldDebugMode = join9(
6215
+ const oldCredentials = join8(oldConfigDir2(), "credentials.json");
6216
+ const oldRuns = join8(oldConfigDir2(), "runs.json");
6217
+ const oldDebugMode = join8(
6626
6218
  findPackageRoot(import.meta.url, PACKAGE_NAME4),
6627
6219
  ".contentful",
6628
6220
  "config",