@contentful/experience-design-system-cli 2.37.1-dev-build-eeb53912.0 → 2.37.1-dev-build-6df388e4.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,147 @@ var init_src3 = __esm({
5246
4686
  }
5247
4687
  });
5248
4688
 
4689
+ // packages/experience-design-system-cli/src/tui/import/steps/03-path-validation/helpers/fold-svelte-and-md-into-other.ts
4690
+ function foldSvelteAndMdIntoOther(counts) {
4691
+ return {
4692
+ tsx: counts.tsx,
4693
+ ts: counts.ts,
4694
+ vue: counts.vue,
4695
+ astro: counts.astro,
4696
+ jsx: counts.jsx,
4697
+ js: counts.js,
4698
+ json: counts.json,
4699
+ other: counts.other + counts.svelte + counts.md,
4700
+ total: counts.total
4701
+ };
4702
+ }
4703
+ var init_fold_svelte_and_md_into_other = __esm({
4704
+ "packages/experience-design-system-cli/src/tui/import/steps/03-path-validation/helpers/fold-svelte-and-md-into-other.ts"() {
4705
+ "use strict";
4706
+ }
4707
+ });
4708
+
4709
+ // packages/experience-design-system-cli/src/tui/import/steps/03-path-validation/loader.ts
4710
+ async function scanProject(directory) {
4711
+ const outcome = collectFiles(directory);
4712
+ return toScanResult(outcome);
4713
+ }
4714
+ function toScanResult(outcome) {
4715
+ if (!outcome.ok) {
4716
+ return { ok: false, failure: outcome.failure };
4717
+ }
4718
+ return {
4719
+ ok: true,
4720
+ counts: foldSvelteAndMdIntoOther(outcome.result.counts),
4721
+ filePaths: outcome.result.filePaths,
4722
+ warnings: outcome.result.warnings
4723
+ };
4724
+ }
4725
+ var init_loader = __esm({
4726
+ "packages/experience-design-system-cli/src/tui/import/steps/03-path-validation/loader.ts"() {
4727
+ "use strict";
4728
+ init_src3();
4729
+ init_fold_svelte_and_md_into_other();
4730
+ }
4731
+ });
4732
+
4733
+ // packages/experience-design-system-cli/src/tui/import/steps/03-path-validation/screen.tsx
4734
+ import { useEffect as useEffect3, useMemo, useState as useState5 } from "react";
4735
+ import { Box as Box5, Text as Text6 } from "ink";
4736
+ import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
4737
+ function Row({ row }) {
4738
+ return /* @__PURE__ */ jsxs5(Text6, { color: row.tone === "accent" ? PALETTE.accent : void 0, dimColor: row.tone === "muted", children: [
4739
+ " \u2022 ",
4740
+ String(row.count).padStart(3),
4741
+ " ",
4742
+ row.label
4743
+ ] });
4744
+ }
4745
+ function Failure({ scan, path: path5 }) {
4746
+ const { headline, hints } = describeFailure(scan.failure, path5);
4747
+ return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
4748
+ /* @__PURE__ */ jsxs5(Text6, { color: PALETTE.error, children: [
4749
+ "\u2717 ",
4750
+ headline
4751
+ ] }),
4752
+ hints.map((hint) => /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: hint }, hint))
4753
+ ] });
4754
+ }
4755
+ function Summary({ scan, path: path5 }) {
4756
+ const { total, rows, warning } = summarize(scan.counts);
4757
+ return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", gap: 1, children: [
4758
+ /* @__PURE__ */ jsxs5(Text6, { children: [
4759
+ "Scanned ",
4760
+ /* @__PURE__ */ jsx6(Text6, { bold: true, children: path5 })
4761
+ ] }),
4762
+ /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
4763
+ /* @__PURE__ */ jsxs5(Text6, { color: PALETTE.success, children: [
4764
+ "\u2713 Found ",
4765
+ total,
4766
+ " files:"
4767
+ ] }),
4768
+ rows.map((row) => /* @__PURE__ */ jsx6(Row, { row }, row.label))
4769
+ ] }),
4770
+ warning && /* @__PURE__ */ jsxs5(Text6, { color: PALETTE.warning, children: [
4771
+ "\u26A0 ",
4772
+ warning
4773
+ ] }),
4774
+ /* @__PURE__ */ jsx6(Text6, { children: "Does this look right?" })
4775
+ ] });
4776
+ }
4777
+ function PathValidationScreen({
4778
+ projectPath,
4779
+ onConfirm,
4780
+ onChangePath,
4781
+ onBack
4782
+ }) {
4783
+ const resolvedPath = useMemo(() => resolveUserPath(projectPath), [projectPath]);
4784
+ const [scan, setScan] = useState5();
4785
+ useEffect3(() => {
4786
+ let cancelled = false;
4787
+ setScan(void 0);
4788
+ void scanProject(resolvedPath).then((result) => {
4789
+ if (!cancelled) setScan(result);
4790
+ });
4791
+ return () => {
4792
+ cancelled = true;
4793
+ };
4794
+ }, [resolvedPath]);
4795
+ const phase = phaseOf(scan);
4796
+ usePathValidationControls(phase, {
4797
+ onConfirm: () => {
4798
+ if (scan?.ok) onConfirm({ projectPath: resolvedPath, filePaths: scan.filePaths });
4799
+ },
4800
+ onChangePath,
4801
+ onBack
4802
+ });
4803
+ return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", gap: 1, paddingX: 2, paddingY: 1, children: [
4804
+ scan === void 0 && /* @__PURE__ */ jsxs5(Text6, { dimColor: true, children: [
4805
+ "Scanning ",
4806
+ /* @__PURE__ */ jsx6(Text6, { bold: true, children: resolvedPath }),
4807
+ "..."
4808
+ ] }),
4809
+ scan?.ok === false && /* @__PURE__ */ jsx6(Failure, { scan, path: resolvedPath }),
4810
+ scan?.ok === true && /* @__PURE__ */ jsx6(Summary, { scan, path: resolvedPath }),
4811
+ /* @__PURE__ */ jsx6(Box5, { marginTop: 1, gap: 3, children: controlsFor(phase).map((control) => /* @__PURE__ */ jsxs5(Text6, { dimColor: true, children: [
4812
+ "[",
4813
+ control.keys,
4814
+ "] ",
4815
+ control.label
4816
+ ] }, control.keys)) })
4817
+ ] });
4818
+ }
4819
+ var init_screen3 = __esm({
4820
+ "packages/experience-design-system-cli/src/tui/import/steps/03-path-validation/screen.tsx"() {
4821
+ "use strict";
4822
+ init_home_theme();
4823
+ init_resolve_user_path();
4824
+ init_controls3();
4825
+ init_loader();
4826
+ init_logic3();
4827
+ }
4828
+ });
4829
+
5249
4830
  // packages/experience-design-system-cli/src/tui/import/steps/04-credentials/logic.ts
5250
4831
  function keyAction2(input, key) {
5251
4832
  if (key.escape) return "back";
@@ -5256,12 +4837,21 @@ function keyAction2(input, key) {
5256
4837
  function nextField(field) {
5257
4838
  return FIELDS[(FIELDS.indexOf(field) + 1) % FIELDS.length];
5258
4839
  }
4840
+ function toConfiguredHost3(host) {
4841
+ const value = (host ?? "").trim().replace(/\/+$/, "");
4842
+ return value === "" ? DEFAULT_HOST : value.replace(/^https:\/\//i, "");
4843
+ }
4844
+ function toApiHost3(host) {
4845
+ const value = host.trim().replace(/\/+$/, "");
4846
+ if (value === "") return `https://${DEFAULT_HOST}`;
4847
+ return /^[a-z][a-z\d+\-.]*:\/\//i.test(value) ? value : `https://${value}`;
4848
+ }
5259
4849
  function normalize(values) {
5260
4850
  return {
5261
4851
  spaceId: values.spaceId.trim(),
5262
4852
  environmentId: values.environmentId.trim(),
5263
4853
  cmaToken: values.cmaToken.trim(),
5264
- host: toConfiguredHost2(values.host) ?? DEFAULT_CONFIGURED_HOST
4854
+ host: toConfiguredHost3(values.host)
5265
4855
  };
5266
4856
  }
5267
4857
  function missingField(values) {
@@ -5270,12 +4860,12 @@ function missingField(values) {
5270
4860
  function isUnchanged(current, initial) {
5271
4861
  return FIELDS.every((field) => current[field] === initial[field]);
5272
4862
  }
5273
- var FIELDS;
4863
+ var FIELDS, DEFAULT_HOST;
5274
4864
  var init_logic4 = __esm({
5275
4865
  "packages/experience-design-system-cli/src/tui/import/steps/04-credentials/logic.ts"() {
5276
4866
  "use strict";
5277
- init_src3();
5278
4867
  FIELDS = ["spaceId", "environmentId", "cmaToken", "host"];
4868
+ DEFAULT_HOST = "api.contentful.com";
5279
4869
  }
5280
4870
  });
5281
4871
 
@@ -5305,35 +4895,65 @@ var init_controls4 = __esm({
5305
4895
  });
5306
4896
 
5307
4897
  // packages/experience-design-system-cli/src/tui/import/steps/04-credentials/validate.ts
4898
+ function headers(token) {
4899
+ return { Authorization: `Bearer ${token}`, "X-Contentful-User-Agent": USER_AGENT2 };
4900
+ }
4901
+ function isApsDenial(body) {
4902
+ try {
4903
+ const id = JSON.parse(body).sys?.id;
4904
+ return id === "NotFound" || id === "AccessDenied";
4905
+ } catch {
4906
+ return false;
4907
+ }
4908
+ }
4909
+ function messageFrom(body) {
4910
+ try {
4911
+ const message = JSON.parse(body).message;
4912
+ return typeof message === "string" && message !== "" ? message : void 0;
4913
+ } catch {
4914
+ return void 0;
4915
+ }
4916
+ }
5308
4917
  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
- });
4918
+ const base = toApiHost3(values.host);
4919
+ let me;
5316
4920
  try {
5317
- await client2.validateToken();
5318
- return { ok: true };
4921
+ me = await fetch(`${base}/users/me`, { headers: headers(values.cmaToken) });
5319
4922
  } catch (error) {
5320
- return { ok: false, error: toUserError(error, host) };
4923
+ return { ok: false, error: `Could not reach ${base}: ${error instanceof Error ? error.message : String(error)}` };
5321
4924
  }
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 });
4925
+ if (me.status === 401) return { ok: false, error: "CMA token is invalid or revoked." };
4926
+ if (!me.ok) return { ok: false, error: `Unexpected error validating the token (${me.status}).` };
4927
+ let preflight;
4928
+ try {
4929
+ preflight = await fetch(
4930
+ `${base}/spaces/${values.spaceId}/environments/${values.environmentId}/design_systems/preflight`,
4931
+ { headers: headers(values.cmaToken) }
4932
+ );
4933
+ } catch {
4934
+ return { ok: true };
4935
+ }
4936
+ if (preflight.ok || preflight.status >= 500) return { ok: true };
4937
+ const body = await preflight.text();
4938
+ if (preflight.status === 404 && !isApsDenial(body)) return { ok: true };
4939
+ const detail = messageFrom(body);
4940
+ if (preflight.status === 403) {
4941
+ return { ok: false, error: `Access denied. ${detail ?? "Your token cannot write design system components here."}` };
4942
+ }
4943
+ if (preflight.status === 404) {
4944
+ return {
4945
+ ok: false,
4946
+ error: `Not found. Check the space ID, environment and API host.${detail ? ` (${detail})` : ""}`
4947
+ };
5329
4948
  }
5330
- if (error instanceof Error) return `Could not reach ${host}: ${error.message}`;
5331
- return String(error);
4949
+ return { ok: false, error: `Credential check failed (${preflight.status}).${detail ? ` ${detail}` : ""}` };
5332
4950
  }
4951
+ var USER_AGENT2;
5333
4952
  var init_validate4 = __esm({
5334
4953
  "packages/experience-design-system-cli/src/tui/import/steps/04-credentials/validate.ts"() {
5335
4954
  "use strict";
5336
- init_src3();
4955
+ init_logic4();
4956
+ USER_AGENT2 = "app contentful.experience-design-system-cli";
5337
4957
  }
5338
4958
  });
5339
4959
 
@@ -5408,7 +5028,7 @@ function CredentialsScreen({
5408
5028
  value: values[field],
5409
5029
  focus: active === field && !validating,
5410
5030
  mask: field === "cmaToken" ? "\u2022" : void 0,
5411
- placeholder: field === "host" ? DEFAULT_CONFIGURED_HOST : void 0,
5031
+ placeholder: field === "host" ? DEFAULT_HOST : void 0,
5412
5032
  onChange: change(field),
5413
5033
  onSubmit: () => void submit(field)
5414
5034
  }
@@ -5435,7 +5055,6 @@ var init_screen4 = __esm({
5435
5055
  "use strict";
5436
5056
  init_home_theme();
5437
5057
  init_controls4();
5438
- init_src3();
5439
5058
  init_logic4();
5440
5059
  init_validate4();
5441
5060
  LABELS = {
@@ -5462,8 +5081,8 @@ var init_steps = __esm({
5462
5081
  import { spawn as spawn3 } from "node:child_process";
5463
5082
  function buildArgs2(options) {
5464
5083
  const args = ["import"];
5465
- if (options.project) {
5466
- args.push("--project", options.project);
5084
+ if (options.projectPath) {
5085
+ args.push("--project", options.projectPath);
5467
5086
  }
5468
5087
  if (options.tokens) {
5469
5088
  args.push("--tokens", options.tokens);
@@ -5520,9 +5139,9 @@ var init_terminal_input = __esm({
5520
5139
  import { randomBytes } from "node:crypto";
5521
5140
  import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
5522
5141
  import { homedir as homedir2 } from "node:os";
5523
- import { dirname as dirname2, join as join6 } from "node:path";
5142
+ import { dirname as dirname2, join as join5 } from "node:path";
5524
5143
  function configRoot2() {
5525
- return process.env["EDS_HOME"] || join6(homedir2(), ".contentful", "experience-design-system-cli");
5144
+ return process.env["EDS_HOME"] || join5(homedir2(), ".contentful", "experience-design-system-cli");
5526
5145
  }
5527
5146
  async function readSettings2() {
5528
5147
  try {
@@ -5532,12 +5151,12 @@ async function readSettings2() {
5532
5151
  }
5533
5152
  }
5534
5153
  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`;
5154
+ const path5 = configFilePath2();
5155
+ await mkdir(dirname2(path5), { recursive: true });
5156
+ const tmp = `${path5}.${process.pid}.${randomBytes(4).toString("hex")}.tmp`;
5538
5157
  await writeFile(tmp, `${JSON.stringify(settings, null, 2)}
5539
5158
  `, { mode: 384 });
5540
- await rename(tmp, path);
5159
+ await rename(tmp, path5);
5541
5160
  }
5542
5161
  async function updateSettings2(patch) {
5543
5162
  await writeSettings2({ ...await readSettings2(), ...patch });
@@ -5546,10 +5165,10 @@ var configFilePath2, runsFilePath2, debugSessionsDir2, oldConfigDir2;
5546
5165
  var init_config = __esm({
5547
5166
  "packages/experience-design-system-types/dist/src/config/index.js"() {
5548
5167
  "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");
5168
+ configFilePath2 = () => join5(configRoot2(), "config.json");
5169
+ runsFilePath2 = () => join5(configRoot2(), "state", "runs.json");
5170
+ debugSessionsDir2 = () => join5(configRoot2(), "debug", "sessions");
5171
+ oldConfigDir2 = () => join5(homedir2(), ".config", "experiences");
5553
5172
  }
5554
5173
  });
5555
5174
 
@@ -5574,8 +5193,8 @@ var init_debug_mode_store = __esm({
5574
5193
 
5575
5194
  // packages/experience-design-system-cli/src/tui/debug-store.ts
5576
5195
  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";
5196
+ import { existsSync as existsSync4, readdirSync as readdirSync2 } from "node:fs";
5197
+ import { join as join6 } from "node:path";
5579
5198
  function generateRunId() {
5580
5199
  const now = /* @__PURE__ */ new Date();
5581
5200
  const pad = (n) => String(n).padStart(2, "0");
@@ -5591,7 +5210,7 @@ function slugify(value) {
5591
5210
  function generateSessionId3() {
5592
5211
  const today = datePrefix();
5593
5212
  const root = debugSessionsDir2();
5594
- const existing = existsSync4(root) ? readdirSync(root) : [];
5213
+ const existing = existsSync4(root) ? readdirSync2(root) : [];
5595
5214
  const seqPattern = new RegExp(`^${today}-session-(\\d+)$`);
5596
5215
  const maxSeq = existing.reduce((max, entry) => {
5597
5216
  const match = seqPattern.exec(entry);
@@ -5600,7 +5219,7 @@ function generateSessionId3() {
5600
5219
  return `${today}-session-${maxSeq + 1}`;
5601
5220
  }
5602
5221
  function sessionDebugDir() {
5603
- return join7(debugSessionsDir2(), SESSION_ID);
5222
+ return join6(debugSessionsDir2(), SESSION_ID);
5604
5223
  }
5605
5224
  function currentDebugSessionDir() {
5606
5225
  return sessionDebugDir();
@@ -5645,15 +5264,15 @@ async function finishDebugRun({
5645
5264
  const durationMs = Date.now() - run.startedAt;
5646
5265
  const content = renderMarkdown(run, { outputs: redact(outputs), status, exitMethod, durationMs });
5647
5266
  const flowSegments = run.flow.split("/");
5648
- const dir = join7(sessionDebugDir(), ...flowSegments);
5267
+ const dir = join6(sessionDebugDir(), ...flowSegments);
5649
5268
  await mkdir2(dir, { recursive: true });
5650
5269
  const filename = nextAttemptFilename(dir, run.menuOption);
5651
- await writeFile2(join7(dir, filename), content, { mode: 384 });
5270
+ await writeFile2(join6(dir, filename), content, { mode: 384 });
5652
5271
  }
5653
5272
  function nextAttemptFilename(dir, menuOption) {
5654
5273
  const today = datePrefix();
5655
5274
  const optionSlug = slugify(menuOption);
5656
- const existing = existsSync4(dir) ? readdirSync(dir) : [];
5275
+ const existing = existsSync4(dir) ? readdirSync2(dir) : [];
5657
5276
  const attemptPattern = new RegExp(`^${today}-${optionSlug}-attempt-(\\d+)\\.md$`);
5658
5277
  const maxAttempt = existing.reduce((max, entry) => {
5659
5278
  const match = attemptPattern.exec(entry);
@@ -6348,7 +5967,7 @@ function App({ onLaunchImport, importExitCode }) {
6348
5967
  const [showImportResult, setShowImportResult] = useState13(returnedFromImport);
6349
5968
  const [projectPath, setProjectPath] = useState13();
6350
5969
  const [tokensPath, setTokensPath] = useState13();
6351
- const [pathConfirmed, setPathConfirmed] = useState13(false);
5970
+ const [scannedFiles, setScannedFiles] = useState13();
6352
5971
  const [importDefaults, setImportDefaults] = useState13();
6353
5972
  useEffect9(() => {
6354
5973
  if (screen !== "import") {
@@ -6363,16 +5982,16 @@ function App({ onLaunchImport, importExitCode }) {
6363
5982
  })
6364
5983
  );
6365
5984
  }, [screen]);
6366
- const finishCredentials = async (result, project, tokens) => {
5985
+ const finishCredentials = async (result, projectPath2, tokens, filePaths) => {
6367
5986
  if (!result.skipped) await writeCredentials({ ...result.credentials });
6368
- onLaunchImport?.({ project, tokens, skipCredentials: result.skipped });
5987
+ onLaunchImport?.({ projectPath: projectPath2, tokens, filePaths, skipCredentials: result.skipped });
6369
5988
  };
6370
5989
  const goToStart = () => setScreen("start");
6371
5990
  const goToSettings = () => setScreen("settings");
6372
5991
  const resetImport = () => {
6373
5992
  setProjectPath(void 0);
6374
5993
  setTokensPath(void 0);
6375
- setPathConfirmed(false);
5994
+ setScannedFiles(void 0);
6376
5995
  };
6377
5996
  const finishImportResult = () => {
6378
5997
  setShowImportResult(false);
@@ -6400,12 +6019,12 @@ function App({ onLaunchImport, importExitCode }) {
6400
6019
  }
6401
6020
  );
6402
6021
  }
6403
- if (!pathConfirmed) {
6022
+ if (scannedFiles === void 0) {
6404
6023
  return /* @__PURE__ */ jsx14(
6405
6024
  PathValidationScreen,
6406
6025
  {
6407
6026
  projectPath,
6408
- onConfirm: () => setPathConfirmed(true),
6027
+ onConfirm: ({ filePaths }) => setScannedFiles(filePaths),
6409
6028
  onChangePath: resetImport,
6410
6029
  onBack: () => setTokensPath(void 0)
6411
6030
  }
@@ -6415,8 +6034,8 @@ function App({ onLaunchImport, importExitCode }) {
6415
6034
  CredentialsScreen,
6416
6035
  {
6417
6036
  initial: importDefaults.credentials,
6418
- onBack: () => setPathConfirmed(false),
6419
- onDone: (result) => void finishCredentials(result, projectPath, tokensPath)
6037
+ onBack: () => setScannedFiles(void 0),
6038
+ onDone: (result) => void finishCredentials(result, projectPath, tokensPath, scannedFiles)
6420
6039
  }
6421
6040
  );
6422
6041
  case "help":
@@ -6486,8 +6105,8 @@ var init_app = __esm({
6486
6105
  });
6487
6106
 
6488
6107
  // packages/experience-design-system-cli/program.ts
6489
- import { readFileSync as readFileSync3 } from "node:fs";
6490
- import { join as join8 } from "node:path";
6108
+ import { readFileSync as readFileSync4 } from "node:fs";
6109
+ import { join as join7 } from "node:path";
6491
6110
  import { Command } from "commander";
6492
6111
 
6493
6112
  // packages/experience-design-system-cli/src/legacy/run-legacy.ts
@@ -6588,8 +6207,8 @@ function registerImportCommand(program, openTui) {
6588
6207
  // packages/experience-design-system-cli/program.ts
6589
6208
  init_package_root();
6590
6209
  var pkg = JSON.parse(
6591
- readFileSync3(
6592
- join8(findPackageRoot(import.meta.url, "@contentful/experience-design-system-cli"), "package.json"),
6210
+ readFileSync4(
6211
+ join7(findPackageRoot(import.meta.url, "@contentful/experience-design-system-cli"), "package.json"),
6593
6212
  "utf8"
6594
6213
  )
6595
6214
  );
@@ -6609,20 +6228,20 @@ init_config();
6609
6228
  init_package_root();
6610
6229
  import { existsSync as existsSync5 } from "node:fs";
6611
6230
  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";
6231
+ import { dirname as dirname3, join as join8 } from "node:path";
6613
6232
  var PACKAGE_NAME4 = "@contentful/experience-design-system-cli";
6614
- async function readJson(path) {
6233
+ async function readJson(path5) {
6615
6234
  try {
6616
- return JSON.parse(await readFile2(path, "utf8"));
6235
+ return JSON.parse(await readFile2(path5, "utf8"));
6617
6236
  } catch {
6618
6237
  return void 0;
6619
6238
  }
6620
6239
  }
6621
6240
  async function migrateOldConfig() {
6622
6241
  try {
6623
- const oldCredentials = join9(oldConfigDir2(), "credentials.json");
6624
- const oldRuns = join9(oldConfigDir2(), "runs.json");
6625
- const oldDebugMode = join9(
6242
+ const oldCredentials = join8(oldConfigDir2(), "credentials.json");
6243
+ const oldRuns = join8(oldConfigDir2(), "runs.json");
6244
+ const oldDebugMode = join8(
6626
6245
  findPackageRoot(import.meta.url, PACKAGE_NAME4),
6627
6246
  ".contentful",
6628
6247
  "config",