@contentful/experience-design-system-cli 2.39.1-dev-build-cac1a211.0 → 2.39.1-dev-build-4580d8be.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
@@ -19407,6 +19407,325 @@ var init_PageContainer = __esm({
19407
19407
  }
19408
19408
  });
19409
19409
 
19410
+ // packages/experience-design-system-cli/src/tui/settings/debug-mode/debug-mode-store.ts
19411
+ function toRetentionDays(value) {
19412
+ return RETENTION_CHOICES.find((choice) => choice === value) ?? DEFAULT_RETENTION_DAYS;
19413
+ }
19414
+ async function readDebugModeSetting() {
19415
+ const { debugMode } = await readSettings2();
19416
+ const saved = debugMode ?? {};
19417
+ return {
19418
+ enabled: typeof saved.enabled === "boolean" ? saved.enabled : true,
19419
+ retentionDays: toRetentionDays(saved.retentionDays)
19420
+ };
19421
+ }
19422
+ async function writeDebugModeSetting(change) {
19423
+ await updateSettings2({ debugMode: { ...await readDebugModeSetting(), ...change } });
19424
+ }
19425
+ var RETENTION_CHOICES, DEFAULT_RETENTION_DAYS;
19426
+ var init_debug_mode_store = __esm({
19427
+ "packages/experience-design-system-cli/src/tui/settings/debug-mode/debug-mode-store.ts"() {
19428
+ "use strict";
19429
+ init_config();
19430
+ RETENTION_CHOICES = [7, 14, 30];
19431
+ DEFAULT_RETENTION_DAYS = 30;
19432
+ }
19433
+ });
19434
+
19435
+ // packages/experience-design-system-cli/src/tui/debug-prune.ts
19436
+ import { readdir as readdir2, rm, rmdir, stat as stat4 } from "node:fs/promises";
19437
+ import { dirname as dirname15, join as join18 } from "node:path";
19438
+ async function logFilesIn(dir) {
19439
+ const entries = await readdir2(dir, { withFileTypes: true });
19440
+ const nested = await Promise.all(
19441
+ entries.map(async (entry) => {
19442
+ const path5 = join18(dir, entry.name);
19443
+ if (entry.isDirectory()) return logFilesIn(path5);
19444
+ return entry.isFile() && entry.name.endsWith(".md") ? [path5] : [];
19445
+ })
19446
+ );
19447
+ return nested.flat();
19448
+ }
19449
+ async function removeEmptyFolders(from, stop) {
19450
+ let dir = from;
19451
+ let removed = 0;
19452
+ for (; ; ) {
19453
+ try {
19454
+ await rmdir(dir);
19455
+ } catch {
19456
+ return removed;
19457
+ }
19458
+ removed += 1;
19459
+ if (dir === stop) return removed;
19460
+ dir = dirname15(dir);
19461
+ }
19462
+ }
19463
+ async function pruneExpiredLogs(base, retentionDays, now = Date.now()) {
19464
+ const cutoff = now - retentionDays * DAY_MS;
19465
+ const contentfulDir = join18(base, ".contentful");
19466
+ const result = { logs: 0, folders: 0 };
19467
+ try {
19468
+ const sessions = (await readdir2(contentfulDir)).filter((name) => SESSION_FOLDER.test(name));
19469
+ for (const session of sessions) {
19470
+ const files = await logFilesIn(join18(contentfulDir, session, "debug")).catch(() => []);
19471
+ for (const file of files) {
19472
+ try {
19473
+ if ((await stat4(file)).mtimeMs >= cutoff) continue;
19474
+ await rm(file);
19475
+ result.logs += 1;
19476
+ result.folders += await removeEmptyFolders(dirname15(file), join18(contentfulDir, session));
19477
+ } catch {
19478
+ }
19479
+ }
19480
+ }
19481
+ } catch {
19482
+ }
19483
+ return result;
19484
+ }
19485
+ var DAY_MS, SESSION_FOLDER;
19486
+ var init_debug_prune = __esm({
19487
+ "packages/experience-design-system-cli/src/tui/debug-prune.ts"() {
19488
+ "use strict";
19489
+ DAY_MS = 24 * 60 * 60 * 1e3;
19490
+ SESSION_FOLDER = /^\d{2}-\d{2}-\d{4}-session-\d+$/;
19491
+ }
19492
+ });
19493
+
19494
+ // packages/experience-design-system-cli/src/tui/debug-store.ts
19495
+ var debug_store_exports = {};
19496
+ __export(debug_store_exports, {
19497
+ currentDebugSessionDir: () => currentDebugSessionDir,
19498
+ currentSessionDir: () => currentSessionDir,
19499
+ finishDebugRun: () => finishDebugRun,
19500
+ startDebugRun: () => startDebugRun,
19501
+ startDebugSessionIn: () => startDebugSessionIn,
19502
+ startImportRun: () => startImportRun
19503
+ });
19504
+ import { mkdir as mkdir7, writeFile as writeFile7 } from "node:fs/promises";
19505
+ import { existsSync as existsSync9, readdirSync as readdirSync3 } from "node:fs";
19506
+ import { join as join19, resolve as resolve20 } from "node:path";
19507
+ function generateRunId() {
19508
+ const now = /* @__PURE__ */ new Date();
19509
+ const pad = (n) => String(n).padStart(2, "0");
19510
+ return `${now.getFullYear()}${pad(now.getMonth() + 1)}${pad(now.getDate())}-${pad(now.getHours())}${pad(now.getMinutes())}${pad(now.getSeconds())}`;
19511
+ }
19512
+ function datePrefix(now = /* @__PURE__ */ new Date()) {
19513
+ const pad = (n) => String(n).padStart(2, "0");
19514
+ return `${pad(now.getMonth() + 1)}-${pad(now.getDate())}-${now.getFullYear()}`;
19515
+ }
19516
+ function slugify(value) {
19517
+ return value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
19518
+ }
19519
+ async function readBaseDir() {
19520
+ try {
19521
+ const dir = (await readSettings2())["contentfulBaseDir"];
19522
+ return typeof dir === "string" && dir !== "" ? resolve20(dir) : void 0;
19523
+ } catch {
19524
+ return void 0;
19525
+ }
19526
+ }
19527
+ function nextSessionId(contentfulDir) {
19528
+ const today = datePrefix();
19529
+ const existing = existsSync9(contentfulDir) ? readdirSync3(contentfulDir) : [];
19530
+ const seqPattern = new RegExp(`^${today}-session-(\\d+)$`);
19531
+ const maxSeq = existing.reduce((max, entry) => {
19532
+ const match2 = seqPattern.exec(entry);
19533
+ return match2 ? Math.max(max, Number(match2[1])) : max;
19534
+ }, 0);
19535
+ return `${today}-session-${maxSeq + 1}`;
19536
+ }
19537
+ function startSession(base, { replace }) {
19538
+ const contentfulDir = join19(base, ".contentful");
19539
+ if (replace || !sessionDir) sessionDir = join19(contentfulDir, nextSessionId(contentfulDir));
19540
+ return sessionDir;
19541
+ }
19542
+ function currentDebugSessionDir() {
19543
+ return sessionDir && join19(sessionDir, "debug");
19544
+ }
19545
+ function currentSessionDir() {
19546
+ return sessionDir;
19547
+ }
19548
+ async function startDebugSessionIn(base, { replace = false } = {}) {
19549
+ try {
19550
+ if (!await isDebugModeEnabled()) return;
19551
+ await mkdir7(join19(startSession(resolve20(base), { replace }), "debug"), { recursive: true });
19552
+ await writeWaitingLogs();
19553
+ } catch {
19554
+ }
19555
+ }
19556
+ function nextImportRunDir(session) {
19557
+ const existing = existsSync9(session) ? readdirSync3(session) : [];
19558
+ const maxRun = existing.reduce((max, entry) => {
19559
+ const match2 = /^dsi-import-(\d+)$/.exec(entry);
19560
+ return match2 ? Math.max(max, Number(match2[1])) : max;
19561
+ }, 0);
19562
+ return join19(session, `dsi-import-${maxRun + 1}`);
19563
+ }
19564
+ async function startImportRun(projectPath) {
19565
+ await startDebugSessionIn(projectPath);
19566
+ if (!sessionDir) return join19(resolve20(projectPath), ".contentful");
19567
+ const dir = nextImportRunDir(sessionDir);
19568
+ await mkdir7(dir, { recursive: true });
19569
+ return dir;
19570
+ }
19571
+ async function isDebugModeEnabled() {
19572
+ try {
19573
+ return (await readDebugModeSetting()).enabled;
19574
+ } catch {
19575
+ return true;
19576
+ }
19577
+ }
19578
+ function redact(value) {
19579
+ const clone = { ...value };
19580
+ if ("cma_token" in clone) {
19581
+ const raw = clone.cma_token;
19582
+ clone.cma_token = typeof raw === "string" && raw.length > 0 ? `[present, ${raw.length} chars]` : "[not set]";
19583
+ }
19584
+ return clone;
19585
+ }
19586
+ function startDebugRun({
19587
+ flow,
19588
+ step,
19589
+ menuOption,
19590
+ inputs
19591
+ }) {
19592
+ const runId = generateRunId();
19593
+ const startedAt = Date.now();
19594
+ const redactedInputs = redact(inputs);
19595
+ isDebugModeEnabled().then((enabled) => {
19596
+ if (!enabled) return;
19597
+ pendingRun = { flow, step, runId, menuOption, inputs: redactedInputs, startedAt };
19598
+ });
19599
+ }
19600
+ async function finishDebugRun({
19601
+ outputs,
19602
+ status,
19603
+ exitMethod
19604
+ }) {
19605
+ const run = pendingRun;
19606
+ if (!run) return;
19607
+ pendingRun = void 0;
19608
+ const durationMs = Date.now() - run.startedAt;
19609
+ const log = {
19610
+ flow: run.flow,
19611
+ menuOption: run.menuOption,
19612
+ content: renderMarkdown(run, { outputs: redact(outputs), status, exitMethod, durationMs })
19613
+ };
19614
+ const root = currentDebugSessionDir();
19615
+ if (!root) {
19616
+ if (waiting.length < WAITING_LIMIT) waiting.push(log);
19617
+ return;
19618
+ }
19619
+ await writeLog(root, log);
19620
+ }
19621
+ async function writeLog(root, log) {
19622
+ const dir = join19(root, ...log.flow.split("/"));
19623
+ await mkdir7(dir, { recursive: true });
19624
+ const filename = nextAttemptFilename(dir, log.menuOption);
19625
+ await writeFile7(join19(dir, filename), log.content, { mode: 384 });
19626
+ }
19627
+ async function writeWaitingLogs() {
19628
+ const root = currentDebugSessionDir();
19629
+ if (!root) return;
19630
+ for (const log of waiting.splice(0)) {
19631
+ try {
19632
+ await writeLog(root, log);
19633
+ } catch {
19634
+ }
19635
+ }
19636
+ }
19637
+ function nextAttemptFilename(dir, menuOption) {
19638
+ const today = datePrefix();
19639
+ const optionSlug = slugify(menuOption);
19640
+ const existing = existsSync9(dir) ? readdirSync3(dir) : [];
19641
+ const attemptPattern = new RegExp(`^${today}-${optionSlug}-attempt-(\\d+)\\.md$`);
19642
+ const maxAttempt = existing.reduce((max, entry) => {
19643
+ const match2 = attemptPattern.exec(entry);
19644
+ return match2 ? Math.max(max, Number(match2[1])) : max;
19645
+ }, 0);
19646
+ return `${today}-${optionSlug}-attempt-${maxAttempt + 1}.md`;
19647
+ }
19648
+ function renderMarkdown(run, finish) {
19649
+ const stepMatch = /^(\d+)-(.+)$/.exec(run.step);
19650
+ const stepLabel = stepMatch ? `${stepMatch[1]} - ${stepMatch[2]}` : run.step;
19651
+ const flowSlug = run.flow.split("/").join("-");
19652
+ return `# Debug Log
19653
+
19654
+ - Run ID: ${run.runId}
19655
+ - Flow: ${flowSlug}
19656
+ - Step: ${stepLabel}
19657
+ - Menu option: ${run.menuOption}
19658
+ - Date: ${(/* @__PURE__ */ new Date()).toISOString()}
19659
+ - CLI version: ${readPackageVersion()}
19660
+ - Platform: ${process.platform} / Node ${process.version}
19661
+ - Duration on screen: ${finish.durationMs}ms
19662
+ - Status: ${finish.status}
19663
+ - Exit method: ${finish.exitMethod}
19664
+
19665
+ ## Inputs
19666
+ \`\`\`json
19667
+ ${JSON.stringify(run.inputs, null, 2)}
19668
+ \`\`\`
19669
+
19670
+ ## Outputs
19671
+ \`\`\`json
19672
+ ${JSON.stringify(finish.outputs, null, 2)}
19673
+ \`\`\`
19674
+ `;
19675
+ }
19676
+ function handleCrash() {
19677
+ return finishDebugRun({ outputs: {}, status: "error", exitMethod: "crashed" });
19678
+ }
19679
+ var pendingRun, sessionDir, WAITING_LIMIT, waiting;
19680
+ var init_debug_store = __esm({
19681
+ "packages/experience-design-system-cli/src/tui/debug-store.ts"() {
19682
+ "use strict";
19683
+ init_config();
19684
+ init_version();
19685
+ init_debug_mode_store();
19686
+ init_debug_prune();
19687
+ void Promise.all([isDebugModeEnabled(), readBaseDir()]).then(async ([enabled, base]) => {
19688
+ if (!base) return;
19689
+ const retention = await readDebugModeSetting().catch(() => void 0);
19690
+ const pruned = retention ? await pruneExpiredLogs(base, retention.retentionDays).catch(() => void 0) : void 0;
19691
+ if (!enabled) return;
19692
+ const debugDir = join19(startSession(base, { replace: false }), "debug");
19693
+ await mkdir7(debugDir, { recursive: true });
19694
+ await writeWaitingLogs();
19695
+ if (retention && pruned && pruned.logs + pruned.folders > 0) {
19696
+ await writeFile7(
19697
+ join19(debugDir, `${datePrefix()}-cleanup-${generateRunId()}.md`),
19698
+ `# Debug Log Cleanup
19699
+
19700
+ - Date: ${(/* @__PURE__ */ new Date()).toISOString()}
19701
+ - Retention: ${retention.retentionDays} days
19702
+ - Logs deleted: ${pruned.logs}
19703
+ - Empty folders removed: ${pruned.folders}
19704
+ `,
19705
+ { mode: 384 }
19706
+ );
19707
+ }
19708
+ });
19709
+ WAITING_LIMIT = 50;
19710
+ waiting = [];
19711
+ process.once("uncaughtException", (err) => {
19712
+ void handleCrash().finally(() => {
19713
+ throw err;
19714
+ });
19715
+ });
19716
+ process.once("unhandledRejection", (reason) => {
19717
+ void handleCrash().finally(() => {
19718
+ throw reason;
19719
+ });
19720
+ });
19721
+ process.once("SIGINT", () => {
19722
+ void handleCrash().finally(() => {
19723
+ process.exit(130);
19724
+ });
19725
+ });
19726
+ }
19727
+ });
19728
+
19410
19729
  // packages/experience-design-system-cli/src/tui/import/steps/00-preflight/logic.ts
19411
19730
  function overviewFor(target) {
19412
19731
  return target === "tokens" ? TOKENS_ONLY_OVERVIEW : COMPONENTS_OVERVIEW;
@@ -19916,12 +20235,37 @@ var init_shared2 = __esm({
19916
20235
  });
19917
20236
 
19918
20237
  // packages/experience-design-system-cli/src/tui/import/steps/00-preflight/screen.tsx
19919
- import { useState as useState4 } from "react";
20238
+ import { useEffect as useEffect4, useRef, useState as useState4 } from "react";
19920
20239
  import { Box as Box9, Text as Text9 } from "ink";
19921
20240
  import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
19922
20241
  function PreflightScreen({ onChoose, onQuit }) {
19923
20242
  const [focus, setFocus] = useState4(0);
19924
- usePreflightControls({ focus, onFocus: setFocus, onChoose, onQuit });
20243
+ const viewed = useRef([optionAt(0)]).current;
20244
+ useEffect4(() => {
20245
+ startDebugRun({
20246
+ flow: "import/preflight",
20247
+ step: "00-preflight",
20248
+ menuOption: "Preflight",
20249
+ inputs: { options: IMPORT_TARGET_OPTIONS.map((option) => option.target), initial_focus: optionAt(0) }
20250
+ });
20251
+ }, []);
20252
+ const moveTo = (next) => {
20253
+ setFocus(next);
20254
+ if (viewed[viewed.length - 1] !== optionAt(next)) viewed.push(optionAt(next));
20255
+ };
20256
+ const choose = (target) => {
20257
+ void finishDebugRun({
20258
+ outputs: { chosen: target, viewed, steps_that_will_run: overviewFor(target).map((step) => step.description) },
20259
+ status: "success",
20260
+ exitMethod: "saved"
20261
+ });
20262
+ onChoose(target);
20263
+ };
20264
+ const quit = () => {
20265
+ void finishDebugRun({ outputs: { chosen: null, viewed }, status: "success", exitMethod: "discarded" });
20266
+ onQuit();
20267
+ };
20268
+ usePreflightControls({ focus, onFocus: moveTo, onChoose: choose, onQuit: quit });
19925
20269
  return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", children: [
19926
20270
  /* @__PURE__ */ jsx9(StepHeader, { step: "setup" }),
19927
20271
  /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", gap: 1, paddingX: 2, paddingBottom: 1, children: [
@@ -19933,25 +20277,28 @@ function PreflightScreen({ onChoose, onQuit }) {
19933
20277
  /* @__PURE__ */ jsx9(Text9, { bold: focused, color: focused ? PALETTE.accent : void 0, children: option.label })
19934
20278
  ] }, option.target);
19935
20279
  }) }),
19936
- /* @__PURE__ */ jsx9(OverviewBox, { steps: overviewFor(IMPORT_TARGET_OPTIONS[focus].target) }),
20280
+ /* @__PURE__ */ jsx9(OverviewBox, { steps: overviewFor(optionAt(focus)) }),
19937
20281
  /* @__PURE__ */ jsx9(ControlHints, { hints: PREFLIGHT_CONTROLS })
19938
20282
  ] })
19939
20283
  ] });
19940
20284
  }
20285
+ var optionAt;
19941
20286
  var init_screen = __esm({
19942
20287
  "packages/experience-design-system-cli/src/tui/import/steps/00-preflight/screen.tsx"() {
19943
20288
  "use strict";
19944
20289
  init_theme();
20290
+ init_debug_store();
19945
20291
  init_controls();
19946
20292
  init_logic();
19947
20293
  init_shared2();
19948
20294
  init_ControlHints();
19949
20295
  init_StepHeader();
20296
+ optionAt = (index) => IMPORT_TARGET_OPTIONS[index].target;
19950
20297
  }
19951
20298
  });
19952
20299
 
19953
20300
  // packages/experience-design-system-cli/src/tui/shared/components/ClearableTextInput.tsx
19954
- import { useRef } from "react";
20301
+ import { useRef as useRef2 } from "react";
19955
20302
  import { useInput as useInput6 } from "ink";
19956
20303
  import TextInput from "ink-text-input";
19957
20304
  import { jsx as jsx10 } from "react/jsx-runtime";
@@ -19959,7 +20306,7 @@ function isClearKey(input, key) {
19959
20306
  return key.ctrl && input === "d";
19960
20307
  }
19961
20308
  function ClearableTextInput({ onChange, ...props }) {
19962
- const justCleared = useRef(false);
20309
+ const justCleared = useRef2(false);
19963
20310
  useInput6((input, key) => {
19964
20311
  if (!isClearKey(input, key)) return;
19965
20312
  justCleared.current = true;
@@ -20092,7 +20439,7 @@ var init_controls5 = __esm({
20092
20439
 
20093
20440
  // packages/experience-design-system-cli/src/tui/import/resolve-user-path.ts
20094
20441
  import { homedir as homedir3 } from "node:os";
20095
- import { resolve as resolve20 } from "node:path";
20442
+ import { resolve as resolve21 } from "node:path";
20096
20443
  function stripQuotes(value) {
20097
20444
  const quoted = value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'");
20098
20445
  return value.length >= 2 && quoted ? value.slice(1, -1) : value;
@@ -20101,7 +20448,7 @@ function expandHome(value) {
20101
20448
  return value === "~" || value.startsWith("~/") || value.startsWith("~\\") ? homedir3() + value.slice(1) : value;
20102
20449
  }
20103
20450
  function resolveUserPath(raw) {
20104
- return resolve20(expandHome(stripQuotes(raw.trim())));
20451
+ return resolve21(expandHome(stripQuotes(raw.trim())));
20105
20452
  }
20106
20453
  var init_resolve_user_path = __esm({
20107
20454
  "packages/experience-design-system-cli/src/tui/import/resolve-user-path.ts"() {
@@ -20333,7 +20680,7 @@ var init_scan_files = __esm({
20333
20680
  });
20334
20681
 
20335
20682
  // packages/experience-design-system-cli/src/tui/import/steps/03-path-validation/screen.tsx
20336
- import { useEffect as useEffect4, useMemo, useState as useState7 } from "react";
20683
+ import { useEffect as useEffect5, useMemo, useState as useState7 } from "react";
20337
20684
  import { Box as Box12, Text as Text12 } from "ink";
20338
20685
  import { jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
20339
20686
  function Row({ row }) {
@@ -20389,7 +20736,7 @@ function PathValidationScreen({
20389
20736
  }) {
20390
20737
  const resolvedPath = useMemo(() => resolveUserPath(projectPath), [projectPath]);
20391
20738
  const [scan, setScan] = useState7();
20392
- useEffect4(() => {
20739
+ useEffect5(() => {
20393
20740
  setScan(scanFiles(resolvedPath));
20394
20741
  }, [resolvedPath]);
20395
20742
  const phase = phaseOf(scan);
@@ -20686,7 +21033,7 @@ var init_validate4 = __esm({
20686
21033
  });
20687
21034
 
20688
21035
  // packages/experience-design-system-cli/src/tui/import/steps/04-credentials/screen.tsx
20689
- import { useRef as useRef2, useState as useState9 } from "react";
21036
+ import { useRef as useRef3, useState as useState9 } from "react";
20690
21037
  import { Box as Box14, Text as Text14, useInput as useInput11 } from "ink";
20691
21038
  import { Fragment as Fragment2, jsx as jsx15, jsxs as jsxs14 } from "react/jsx-runtime";
20692
21039
  function CredentialsScreen({
@@ -20696,7 +21043,7 @@ function CredentialsScreen({
20696
21043
  validate: validate3 = validateCredentials,
20697
21044
  tokensOnly = false
20698
21045
  }) {
20699
- const initialValues = useRef2(
21046
+ const initialValues = useRef3(
20700
21047
  normalize({
20701
21048
  spaceId: initial.spaceId ?? "",
20702
21049
  environmentId: initial.environmentId || "master",
@@ -21144,16 +21491,16 @@ var init_steps = __esm({
21144
21491
  });
21145
21492
 
21146
21493
  // packages/experience-design-system-cli/src/tui/import/steps/06-extraction/find-skill-path.ts
21147
- import { existsSync as existsSync9 } from "node:fs";
21148
- import { dirname as dirname15, join as join18, resolve as resolve21 } from "node:path";
21494
+ import { existsSync as existsSync10 } from "node:fs";
21495
+ import { dirname as dirname16, join as join20, resolve as resolve22 } from "node:path";
21149
21496
  import { fileURLToPath as fileURLToPath4 } from "node:url";
21150
21497
  function findSkillPath(fileName) {
21151
- const thisDir = dirname15(fileURLToPath4(import.meta.url));
21498
+ const thisDir = dirname16(fileURLToPath4(import.meta.url));
21152
21499
  let dir = thisDir;
21153
21500
  for (; ; ) {
21154
- const candidate = join18(dir, "skills", fileName);
21155
- if (existsSync9(candidate)) return candidate;
21156
- const parent = resolve21(dir, "..");
21501
+ const candidate = join20(dir, "skills", fileName);
21502
+ if (existsSync10(candidate)) return candidate;
21503
+ const parent = resolve22(dir, "..");
21157
21504
  if (parent === dir) {
21158
21505
  throw new Error(`skill file not found (looked for skills/${fileName} from ${thisDir})`);
21159
21506
  }
@@ -21167,9 +21514,9 @@ var init_find_skill_path = __esm({
21167
21514
  });
21168
21515
 
21169
21516
  // packages/experience-design-system-cli/src/tui/import/steps/06-extraction/selection.ts
21170
- import { resolve as resolve22 } from "node:path";
21517
+ import { resolve as resolve23 } from "node:path";
21171
21518
  async function hashSelectPrompt(options) {
21172
- const promptHash = options.promptText ? hashContent(options.promptText) : options.promptPath ? await hashFile(resolve22(options.promptPath)) : await hashFile(SELECT_SKILL_PATH);
21519
+ const promptHash = options.promptText ? hashContent(options.promptText) : options.promptPath ? await hashFile(resolve23(options.promptPath)) : await hashFile(SELECT_SKILL_PATH);
21173
21520
  return hashContent(`${promptHash}|${options.agent}|${options.model ?? ""}`);
21174
21521
  }
21175
21522
  async function runSelection(options) {
@@ -21263,10 +21610,10 @@ var init_selection2 = __esm({
21263
21610
  });
21264
21611
 
21265
21612
  // packages/experience-design-system-cli/src/tui/import/steps/06-extraction/run.ts
21266
- import { mkdir as mkdir7 } from "node:fs/promises";
21267
- import { join as join19, resolve as resolve23 } from "node:path";
21613
+ import { mkdir as mkdir8 } from "node:fs/promises";
21614
+ import { join as join21, resolve as resolve24 } from "node:path";
21268
21615
  async function runExtraction(input, onProgress, deps = realDeps) {
21269
- const outDir = input.outDir ?? join19(resolve23(input.projectPath), ".contentful");
21616
+ const outDir = input.outDir ?? join21(resolve24(input.projectPath), ".contentful");
21270
21617
  let progress = initialProgress({
21271
21618
  hasCredentials: input.credentials !== null,
21272
21619
  hasRawTokens: input.rawTokensPath !== ""
@@ -21370,7 +21717,7 @@ async function runExtraction(input, onProgress, deps = realDeps) {
21370
21717
  }
21371
21718
  async function fetchEntities(credentials, outDir) {
21372
21719
  try {
21373
- await mkdir7(outDir, { recursive: true });
21720
+ await mkdir8(outDir, { recursive: true });
21374
21721
  const result = await fetchAndPersistExistingContentfulEntities({
21375
21722
  spaceId: credentials.spaceId,
21376
21723
  environmentId: credentials.environmentId,
@@ -21390,7 +21737,7 @@ async function resolveSelectionPrompt(overrides) {
21390
21737
  if (select?.kind === "text") return { promptText: select.value };
21391
21738
  if (select?.kind === "path") {
21392
21739
  await resolvePromptOverride(select);
21393
- return { promptPath: resolve23(select.value) };
21740
+ return { promptPath: resolve24(select.value) };
21394
21741
  }
21395
21742
  return {};
21396
21743
  }
@@ -21416,11 +21763,11 @@ var init_run = __esm({
21416
21763
  });
21417
21764
 
21418
21765
  // packages/experience-design-system-cli/src/tui/import/steps/06-extraction/use-extraction.ts
21419
- import { useEffect as useEffect5, useRef as useRef3, useState as useState11 } from "react";
21766
+ import { useEffect as useEffect6, useRef as useRef4, useState as useState11 } from "react";
21420
21767
  function useExtraction(input) {
21421
21768
  const [state2, setState] = useState11();
21422
- const current = useRef3();
21423
- useEffect5(() => {
21769
+ const current = useRef4();
21770
+ useEffect6(() => {
21424
21771
  current.current = input;
21425
21772
  if (!input) {
21426
21773
  setState(void 0);
@@ -21491,11 +21838,11 @@ var init_run_tokens_only = __esm({
21491
21838
  });
21492
21839
 
21493
21840
  // packages/experience-design-system-cli/src/tui/import/steps/06-extraction/use-tokens-only.ts
21494
- import { useEffect as useEffect6, useRef as useRef4, useState as useState12 } from "react";
21841
+ import { useEffect as useEffect7, useRef as useRef5, useState as useState12 } from "react";
21495
21842
  function useTokensOnly(input) {
21496
21843
  const [state2, setState] = useState12();
21497
- const current = useRef4();
21498
- useEffect6(() => {
21844
+ const current = useRef5();
21845
+ useEffect7(() => {
21499
21846
  current.current = input;
21500
21847
  if (!input) {
21501
21848
  setState(void 0);
@@ -22319,11 +22666,11 @@ function buildVisibleRows(props) {
22319
22666
  if (!expanded) continue;
22320
22667
  const subtree = computeCycleMemberSubtree(key);
22321
22668
  const isLastAtDepthSubtree = (idx) => {
22322
- const own = subtree[idx].depth;
22669
+ const own2 = subtree[idx].depth;
22323
22670
  for (let j = idx + 1; j < subtree.length; j++) {
22324
22671
  const d = subtree[j].depth;
22325
- if (d < own) return true;
22326
- if (d === own) return false;
22672
+ if (d < own2) return true;
22673
+ if (d === own2) return false;
22327
22674
  }
22328
22675
  return true;
22329
22676
  };
@@ -22443,11 +22790,11 @@ function buildVisibleRows(props) {
22443
22790
  injectedChildren.push({ name: c2.name, depth: c2.depth, isCycleChild: false });
22444
22791
  }
22445
22792
  const isLastAtDepth = (idx) => {
22446
- const own = injectedChildren[idx].depth;
22793
+ const own2 = injectedChildren[idx].depth;
22447
22794
  for (let j = idx + 1; j < injectedChildren.length; j++) {
22448
22795
  const d = injectedChildren[j].depth;
22449
- if (d < own) return true;
22450
- if (d === own) return false;
22796
+ if (d < own2) return true;
22797
+ if (d === own2) return false;
22451
22798
  }
22452
22799
  return true;
22453
22800
  };
@@ -22692,7 +23039,7 @@ var init_GroupedSidebar = __esm({
22692
23039
  });
22693
23040
 
22694
23041
  // packages/experience-design-system-cli/src/tui/import/steps/07-scope-gate/sidebar/hooks/useImmediateInput.ts
22695
- import { useLayoutEffect, useRef as useRef5 } from "react";
23042
+ import { useLayoutEffect, useRef as useRef6 } from "react";
22696
23043
  import { useStdin } from "ink";
22697
23044
  function parseInput(data) {
22698
23045
  const isShiftTab = data === "\x1B[Z";
@@ -22754,7 +23101,7 @@ function registerInputHandler(stdin, setRawMode, handler) {
22754
23101
  }
22755
23102
  function useImmediateInput(handler, enabled = true) {
22756
23103
  const { stdin, setRawMode } = useStdin();
22757
- const handlerRef = useRef5(handler);
23104
+ const handlerRef = useRef6(handler);
22758
23105
  handlerRef.current = handler;
22759
23106
  useLayoutEffect(() => {
22760
23107
  if (!enabled) return;
@@ -22772,7 +23119,7 @@ var init_useImmediateInput = __esm({
22772
23119
 
22773
23120
  // packages/experience-design-system-cli/src/tui/import/steps/07-scope-gate/sidebar/hooks/use-terminal-size.ts
22774
23121
  import { useStdout as useStdout2 } from "ink";
22775
- import { useEffect as useEffect7, useState as useState13 } from "react";
23122
+ import { useEffect as useEffect8, useState as useState13 } from "react";
22776
23123
  function readTerminalSize(stdout) {
22777
23124
  return {
22778
23125
  columns: stdout?.columns ?? 80,
@@ -22782,7 +23129,7 @@ function readTerminalSize(stdout) {
22782
23129
  function useTerminalSize() {
22783
23130
  const { stdout } = useStdout2();
22784
23131
  const [size, setSize] = useState13(() => readTerminalSize(stdout));
22785
- useEffect7(() => {
23132
+ useEffect8(() => {
22786
23133
  const updateSize = () => setSize(readTerminalSize(stdout));
22787
23134
  stdout?.on("resize", updateSize);
22788
23135
  updateSize();
@@ -23784,7 +24131,7 @@ var init_state = __esm({
23784
24131
  });
23785
24132
 
23786
24133
  // packages/experience-design-system-cli/src/tui/import/steps/07-scope-gate/use-scope-gate.ts
23787
- import { useEffect as useEffect8, useMemo as useMemo3, useRef as useRef6, useState as useState16 } from "react";
24134
+ import { useEffect as useEffect9, useMemo as useMemo3, useRef as useRef7, useState as useState16 } from "react";
23788
24135
  function useScopeGate({ components, tokenCount, tokensWidth, onConfirm, onQuit }) {
23789
24136
  const { columns: totalWidth, rows: terminalRows } = useTerminalSize();
23790
24137
  const columnPlan = useMemo3(
@@ -23830,8 +24177,8 @@ function useScopeGate({ components, tokenCount, tokensWidth, onConfirm, onQuit }
23830
24177
  for (const p of cycleParticipants) seed.add(p);
23831
24178
  return seed;
23832
24179
  });
23833
- const seededGroupsRef = useRef6(closures.size > 0 || cycleParticipants.size > 0);
23834
- useEffect8(() => {
24180
+ const seededGroupsRef = useRef7(closures.size > 0 || cycleParticipants.size > 0);
24181
+ useEffect9(() => {
23835
24182
  if (seededGroupsRef.current) return;
23836
24183
  if (closures.size === 0 && cycleParticipants.size === 0) return;
23837
24184
  seededGroupsRef.current = true;
@@ -23922,7 +24269,7 @@ function useScopeGate({ components, tokenCount, tokensWidth, onConfirm, onQuit }
23922
24269
  entryCount: 0
23923
24270
  });
23924
24271
  const panelLayout = useMemo3(() => computePanelLayout(visibleCount), [visibleCount]);
23925
- useEffect8(() => {
24272
+ useEffect9(() => {
23926
24273
  setNav((prev) => {
23927
24274
  const maxIdx = Math.max(0, visibleRows.length - 1);
23928
24275
  const nextCursor = Math.min(prev.cursor, maxIdx);
@@ -24495,13 +24842,13 @@ var init_load2 = __esm({
24495
24842
  });
24496
24843
 
24497
24844
  // packages/experience-design-system-cli/src/tui/import/steps/07-scope-gate/use-scope-gate-flow.ts
24498
- import { useEffect as useEffect9, useMemo as useMemo5, useRef as useRef7, useState as useState17 } from "react";
24845
+ import { useEffect as useEffect10, useMemo as useMemo5, useRef as useRef8, useState as useState17 } from "react";
24499
24846
  function useScopeGateFlow(input, deps = realDeps3) {
24500
24847
  const sessionId = input?.sessionId;
24501
24848
  const loaded = useMemo5(() => sessionId ? deps.load(sessionId) : void 0, [sessionId]);
24502
- const cacheCheck = useRef7(void 0);
24849
+ const cacheCheck = useRef8(void 0);
24503
24850
  const [confirmed, setConfirmed] = useState17();
24504
- useEffect9(() => {
24851
+ useEffect10(() => {
24505
24852
  if (!input || !loaded?.ok || cacheCheck.current) return;
24506
24853
  cacheCheck.current = deps.checkCache(input.cache);
24507
24854
  }, [input, loaded]);
@@ -24639,7 +24986,7 @@ var init_save_decisions = __esm({
24639
24986
  });
24640
24987
 
24641
24988
  // packages/experience-design-system-cli/src/tui/import/steps/08-generation/run.ts
24642
- import { resolve as resolve24 } from "node:path";
24989
+ import { resolve as resolve25 } from "node:path";
24643
24990
  async function runGeneration(input, onProgress, deps = realDeps4) {
24644
24991
  let progress = { components: null, mapTokens: "idle", mapTokensEligible: null };
24645
24992
  const update = (change) => {
@@ -24725,7 +25072,7 @@ async function buildMapTokensOptions(input) {
24725
25072
  if (mapOverride?.kind === "text") prompt.skillContentOverride = mapOverride.value;
24726
25073
  if (mapOverride?.kind === "path") {
24727
25074
  await resolvePromptOverride(mapOverride);
24728
- prompt.skillPathOverride = resolve24(mapOverride.value);
25075
+ prompt.skillPathOverride = resolve25(mapOverride.value);
24729
25076
  }
24730
25077
  if (input.existingEntitiesPath) {
24731
25078
  const entities = await readExistingContentfulEntitiesFromSession({ path: input.existingEntitiesPath });
@@ -24772,11 +25119,11 @@ var init_run2 = __esm({
24772
25119
  });
24773
25120
 
24774
25121
  // packages/experience-design-system-cli/src/tui/import/steps/08-generation/use-generation.ts
24775
- import { useEffect as useEffect10, useRef as useRef8, useState as useState18 } from "react";
25122
+ import { useEffect as useEffect11, useRef as useRef9, useState as useState18 } from "react";
24776
25123
  function useGeneration(input) {
24777
25124
  const [state2, setState] = useState18();
24778
- const current = useRef8();
24779
- useEffect10(() => {
25125
+ const current = useRef9();
25126
+ useEffect11(() => {
24780
25127
  current.current = input;
24781
25128
  if (!input) {
24782
25129
  setState(void 0);
@@ -24803,7 +25150,7 @@ var init_use_generation = __esm({
24803
25150
  });
24804
25151
 
24805
25152
  // packages/experience-design-system-cli/src/tui/import/steps/10-flow/flow/build-flow-start.ts
24806
- import { join as join20 } from "node:path";
25153
+ import { join as join22 } from "node:path";
24807
25154
  function buildFlowStart(input) {
24808
25155
  const { extraction, handoff, saved, generatePromptPath, tokensOnly } = input;
24809
25156
  const credentials = extraction.credentials ?? {
@@ -24816,7 +25163,7 @@ function buildFlowStart(input) {
24816
25163
  handoff,
24817
25164
  agent: extraction.agent,
24818
25165
  projectPath: extraction.projectPath,
24819
- outDir: extraction.projectPath ? join20(extraction.projectPath, ".contentful") : "",
25166
+ outDir: extraction.projectPath ? join22(extraction.projectPath, ".contentful") : "",
24820
25167
  rawTokensPath: extraction.rawTokensPath,
24821
25168
  credentials: {
24822
25169
  spaceId: credentials.spaceId,
@@ -25204,12 +25551,141 @@ var init_dtcg2 = __esm({
25204
25551
  }
25205
25552
  });
25206
25553
 
25554
+ // packages/experience-design-system-types/dist/src/property-contract/json-value.js
25555
+ var nodeTypes;
25556
+ var init_json_value = __esm({
25557
+ "packages/experience-design-system-types/dist/src/property-contract/json-value.js"() {
25558
+ "use strict";
25559
+ nodeTypes = globalThis.process?.getBuiltinModule?.("node:util")?.types;
25560
+ }
25561
+ });
25562
+
25563
+ // packages/experience-design-system-types/dist/src/property-contract/date-time-value.js
25564
+ import * as z5 from "zod/mini";
25565
+ var dateTimeValueSchema;
25566
+ var init_date_time_value = __esm({
25567
+ "packages/experience-design-system-types/dist/src/property-contract/date-time-value.js"() {
25568
+ "use strict";
25569
+ dateTimeValueSchema = z5.iso.datetime({ offset: true });
25570
+ }
25571
+ });
25572
+
25573
+ // packages/experience-design-system-types/dist/src/property-contract/discriminated-union.js
25574
+ var init_discriminated_union = __esm({
25575
+ "packages/experience-design-system-types/dist/src/property-contract/discriminated-union.js"() {
25576
+ "use strict";
25577
+ init_json_value();
25578
+ }
25579
+ });
25580
+
25581
+ // packages/experience-design-system-types/dist/src/property-contract/target-definition.js
25582
+ var TARGET_PROPERTY_TYPES, SAME_SPACE_RESOURCE_SOURCE, targetDefinitionJsonSchema;
25583
+ var init_target_definition = __esm({
25584
+ "packages/experience-design-system-types/dist/src/property-contract/target-definition.js"() {
25585
+ "use strict";
25586
+ init_json_value();
25587
+ init_date_time_value();
25588
+ init_discriminated_union();
25589
+ TARGET_PROPERTY_TYPES = [
25590
+ "String",
25591
+ "Number",
25592
+ "Boolean",
25593
+ "Array",
25594
+ "Record",
25595
+ "Integer",
25596
+ "DateTime",
25597
+ "RichText",
25598
+ "JSON",
25599
+ "ResourceLink",
25600
+ "Literal",
25601
+ "DiscriminatedUnion"
25602
+ ];
25603
+ SAME_SPACE_RESOURCE_SOURCE = "crn:contentful:::content:spaces/$self/environments/$self";
25604
+ targetDefinitionJsonSchema = {
25605
+ $schema: "http://json-schema.org/draft-07/schema#",
25606
+ $ref: "#/definitions/target",
25607
+ definitions: {
25608
+ target: {
25609
+ type: "object",
25610
+ required: ["type"],
25611
+ properties: {
25612
+ type: { enum: [...TARGET_PROPERTY_TYPES] },
25613
+ id: { type: "string" },
25614
+ name: { type: "string" },
25615
+ description: { type: "string" },
25616
+ required: { type: "boolean" },
25617
+ values: { type: "array", minItems: 1 },
25618
+ defaultValue: {},
25619
+ items: { $ref: "#/definitions/target" },
25620
+ fields: { type: "object", minProperties: 1, additionalProperties: { $ref: "#/definitions/target" } },
25621
+ allowedResources: {
25622
+ type: "array",
25623
+ minItems: 1,
25624
+ items: {
25625
+ type: "object",
25626
+ required: ["type", "source"],
25627
+ properties: {
25628
+ type: { enum: ["Contentful:Entry", "Contentful:Asset"] },
25629
+ source: { const: SAME_SPACE_RESOURCE_SOURCE },
25630
+ allowedTypes: { type: "array", items: { type: "string" } }
25631
+ },
25632
+ allOf: [
25633
+ {
25634
+ if: { properties: { type: { const: "Contentful:Entry" } } },
25635
+ then: { required: ["allowedTypes"] },
25636
+ else: { not: { required: ["allowedTypes"] } }
25637
+ }
25638
+ ],
25639
+ additionalProperties: false
25640
+ }
25641
+ },
25642
+ value: {},
25643
+ valueType: { $ref: "#/definitions/target" },
25644
+ discriminator: { type: "string", minLength: 1 },
25645
+ members: {
25646
+ type: "array",
25647
+ minItems: 2,
25648
+ uniqueItems: true,
25649
+ items: {
25650
+ allOf: [
25651
+ { $ref: "#/definitions/target" },
25652
+ { type: "object", properties: { type: { const: "Record" } }, required: ["type", "fields"] }
25653
+ ]
25654
+ }
25655
+ }
25656
+ },
25657
+ allOf: [
25658
+ {
25659
+ if: { properties: { type: { const: "DiscriminatedUnion" } } },
25660
+ then: { required: ["discriminator", "members"] },
25661
+ else: { not: { anyOf: [{ required: ["discriminator"] }, { required: ["members"] }] } }
25662
+ }
25663
+ ],
25664
+ additionalProperties: false
25665
+ }
25666
+ }
25667
+ };
25668
+ }
25669
+ });
25670
+
25671
+ // packages/experience-design-system-types/dist/src/property-contract/index.js
25672
+ var init_property_contract = __esm({
25673
+ "packages/experience-design-system-types/dist/src/property-contract/index.js"() {
25674
+ "use strict";
25675
+ init_json_value();
25676
+ init_date_time_value();
25677
+ init_discriminated_union();
25678
+ init_target_definition();
25679
+ }
25680
+ });
25681
+
25207
25682
  // packages/experience-design-system-types/dist/src/index.js
25208
25683
  var init_src4 = __esm({
25209
25684
  "packages/experience-design-system-types/dist/src/index.js"() {
25210
25685
  "use strict";
25211
25686
  init_cdf2();
25212
25687
  init_dtcg2();
25688
+ init_property_contract();
25213
25689
  }
25214
25690
  });
25215
25691
 
@@ -25349,14 +25825,14 @@ function computeRenderStatuses(closure, directIssues) {
25349
25825
  for (const node of closure.nodes) {
25350
25826
  nodesByName.set(node.name, { name: node.name, path: node.path });
25351
25827
  }
25352
- const own = /* @__PURE__ */ new Map();
25828
+ const own2 = /* @__PURE__ */ new Map();
25353
25829
  for (const node of closure.nodes) {
25354
25830
  const s = directIssues.get(node.name);
25355
- if (s && s !== "ok") own.set(node.name, s);
25831
+ if (s && s !== "ok") own2.set(node.name, s);
25356
25832
  }
25357
25833
  const inheritedSources = /* @__PURE__ */ new Map();
25358
25834
  for (const node of closure.nodes) {
25359
- const ownStatus = own.get(node.name);
25835
+ const ownStatus = own2.get(node.name);
25360
25836
  if (!ownStatus) continue;
25361
25837
  for (let i = 0; i < node.path.length - 1; i++) {
25362
25838
  const ancestor = node.path[i];
@@ -25364,7 +25840,7 @@ function computeRenderStatuses(closure, directIssues) {
25364
25840
  inheritedSources.get(ancestor).set(node.name, ownStatus);
25365
25841
  }
25366
25842
  }
25367
- for (const [name, status] of own.entries()) {
25843
+ for (const [name, status] of own2.entries()) {
25368
25844
  out.set(name, {
25369
25845
  status,
25370
25846
  isOwn: true,
@@ -25634,7 +26110,7 @@ var init_scroll_offset = __esm({
25634
26110
  });
25635
26111
 
25636
26112
  // packages/experience-design-system-cli/src/tui/import/steps/09-review/components/FieldEditor.tsx
25637
- import React13, { useEffect as useEffect11, useLayoutEffect as useLayoutEffect2, useState as useState19 } from "react";
26113
+ import React13, { useEffect as useEffect12, useLayoutEffect as useLayoutEffect2, useState as useState19 } from "react";
25638
26114
  import figures6 from "figures";
25639
26115
  import { Box as Box26, measureElement, Text as Text27 } from "ink";
25640
26116
  import { Fragment as Fragment6, jsx as jsx32, jsxs as jsxs26 } from "react/jsx-runtime";
@@ -27161,7 +27637,7 @@ function FieldEditor({
27161
27637
  }
27162
27638
  return Math.max(start + 1, end2);
27163
27639
  };
27164
- useEffect11(() => {
27640
+ useEffect12(() => {
27165
27641
  if (focusLevel === "field" || selectedRowIdx < 0) return;
27166
27642
  setListScrollStart((previous) => {
27167
27643
  if (initialFocusTarget && !initialFocusScrollApplied.current) {
@@ -28556,7 +29032,7 @@ var init_FinalizeDialog = __esm({
28556
29032
  });
28557
29033
 
28558
29034
  // packages/experience-design-system-cli/src/tui/import/steps/09-review/use-finalize-preview.ts
28559
- import { useEffect as useEffect12, useRef as useRef9, useState as useState20 } from "react";
29035
+ import { useEffect as useEffect13, useRef as useRef10, useState as useState20 } from "react";
28560
29036
  function useReviewFinalizePreview({
28561
29037
  components,
28562
29038
  ...options
@@ -28571,9 +29047,9 @@ function useFinalizePreview(opts) {
28571
29047
  const [status, setStatus] = useState20("idle");
28572
29048
  const [removed, setRemoved] = useState20([]);
28573
29049
  const [scrollOffset, setScrollOffset] = useState20(0);
28574
- const generationRef = useRef9(0);
29050
+ const generationRef = useRef10(0);
28575
29051
  const acceptedKey = [...acceptedKeys].sort().join("\0");
28576
- useEffect12(() => {
29052
+ useEffect13(() => {
28577
29053
  if (!open) {
28578
29054
  setStatus("idle");
28579
29055
  setRemoved([]);
@@ -28625,7 +29101,7 @@ var init_use_finalize_preview = __esm({
28625
29101
  });
28626
29102
 
28627
29103
  // packages/experience-design-system-cli/src/tui/import/steps/09-review/use-review-session.ts
28628
- import { useCallback as useCallback2, useEffect as useEffect13, useRef as useRef10, useState as useState21 } from "react";
29104
+ import { useCallback as useCallback2, useEffect as useEffect14, useRef as useRef11, useState as useState21 } from "react";
28629
29105
  function useReviewSession({
28630
29106
  loadSession,
28631
29107
  tokensPath,
@@ -28644,7 +29120,7 @@ function useReviewSession({
28644
29120
  }));
28645
29121
  return { result, catalog };
28646
29122
  }, [loadSession, tokensPath]);
28647
- useEffect13(() => {
29123
+ useEffect14(() => {
28648
29124
  let disposed = false;
28649
29125
  void (async () => {
28650
29126
  try {
@@ -28697,7 +29173,7 @@ function useReviewSession({
28697
29173
  function useReviewMetadata({ components, selectedIdx, extractSessionId }) {
28698
29174
  const [reviewMetadata, setReviewMetadata] = useState21(null);
28699
29175
  const [componentRationale, setComponentRationale] = useState21(null);
28700
- useEffect13(() => {
29176
+ useEffect14(() => {
28701
29177
  const current = components[selectedIdx];
28702
29178
  if (!current) {
28703
29179
  setReviewMetadata(null);
@@ -28727,9 +29203,9 @@ function useReviewMetadata({ components, selectedIdx, extractSessionId }) {
28727
29203
  return { reviewMetadata, componentRationale };
28728
29204
  }
28729
29205
  function useReviewHistory({ loading, components, createSnapshot, applySnapshot }) {
28730
- const historyRef = useRef10(null);
28731
- const historySeededRef = useRef10(false);
28732
- useEffect13(() => {
29206
+ const historyRef = useRef11(null);
29207
+ const historySeededRef = useRef11(false);
29208
+ useEffect14(() => {
28733
29209
  if (loading || historySeededRef.current) return;
28734
29210
  historySeededRef.current = true;
28735
29211
  historyRef.current = createHistoryStack(createSnapshot(components));
@@ -28811,7 +29287,7 @@ var init_token_suggestions = __esm({
28811
29287
  });
28812
29288
 
28813
29289
  // packages/experience-design-system-cli/src/tui/import/steps/09-review/use-review-editor.ts
28814
- import { useEffect as useEffect14, useRef as useRef11, useState as useState22 } from "react";
29290
+ import { useEffect as useEffect15, useRef as useRef12, useState as useState22 } from "react";
28815
29291
  function parseReviewEntry(draftValue) {
28816
29292
  const parsed = JSON.parse(draftValue);
28817
29293
  const keys = Object.keys(parsed);
@@ -28843,9 +29319,9 @@ function useReviewEditor({
28843
29319
  const [tokenReviewEditing, setTokenReviewEditing] = useState22(false);
28844
29320
  const [tokenReviewEditCursor, setTokenReviewEditCursor] = useState22(0);
28845
29321
  const [tokenReviewEditSelection, setTokenReviewEditSelection] = useState22(/* @__PURE__ */ new Set());
28846
- const tokenReviewSuggestedRef = useRef11(/* @__PURE__ */ new Map());
28847
- const pendingGRef = useRef11(false);
28848
- useEffect14(() => {
29322
+ const tokenReviewSuggestedRef = useRef12(/* @__PURE__ */ new Map());
29323
+ const pendingGRef = useRef12(false);
29324
+ useEffect15(() => {
28849
29325
  setTokenReviewRow(0);
28850
29326
  setTokenReviewEditing(false);
28851
29327
  setTokenReviewEditCursor(0);
@@ -29327,24 +29803,24 @@ var init_preview_annotations = __esm({
29327
29803
  });
29328
29804
 
29329
29805
  // packages/experience-design-system-cli/src/tui/import/steps/09-review/use-live-preview.ts
29330
- import { useCallback as useCallback3, useEffect as useEffect15, useRef as useRef12, useState as useState24 } from "react";
29806
+ import { useCallback as useCallback3, useEffect as useEffect16, useRef as useRef13, useState as useState24 } from "react";
29331
29807
  function useLivePreview(opts) {
29332
29808
  const debounceMs = opts.debounceMs ?? DEFAULT_DEBOUNCE_MS;
29333
29809
  const [status, setStatus] = useState24("idle");
29334
29810
  const [disabled, setDisabled] = useState24(false);
29335
- const timerRef = useRef12(null);
29336
- const generationRef = useRef12(0);
29337
- const latestRef = useRef12(0);
29338
- const inflightRef = useRef12(0);
29339
- const optsRef = useRef12(opts);
29340
- useEffect15(() => {
29811
+ const timerRef = useRef13(null);
29812
+ const generationRef = useRef13(0);
29813
+ const latestRef = useRef13(0);
29814
+ const inflightRef = useRef13(0);
29815
+ const optsRef = useRef13(opts);
29816
+ useEffect16(() => {
29341
29817
  optsRef.current = opts;
29342
29818
  });
29343
- const disabledRef = useRef12(disabled);
29344
- useEffect15(() => {
29819
+ const disabledRef = useRef13(disabled);
29820
+ useEffect16(() => {
29345
29821
  disabledRef.current = disabled;
29346
29822
  }, [disabled]);
29347
- useEffect15(() => {
29823
+ useEffect16(() => {
29348
29824
  return () => {
29349
29825
  if (timerRef.current) {
29350
29826
  clearTimeout(timerRef.current);
@@ -29425,7 +29901,7 @@ var init_use_live_preview = __esm({
29425
29901
  });
29426
29902
 
29427
29903
  // packages/experience-design-system-cli/src/tui/import/steps/09-review/use-review-preview.ts
29428
- import { useCallback as useCallback4, useEffect as useEffect16, useState as useState25 } from "react";
29904
+ import { useCallback as useCallback4, useEffect as useEffect17, useState as useState25 } from "react";
29429
29905
  function useReviewPreview({
29430
29906
  components,
29431
29907
  loading,
@@ -29467,13 +29943,13 @@ function useReviewPreview({
29467
29943
  deleteAllComponents
29468
29944
  });
29469
29945
  const [spinnerTick, setSpinnerTick] = useState25(0);
29470
- useEffect16(() => {
29946
+ useEffect17(() => {
29471
29947
  if (livePreviewHook.status !== "running") return;
29472
29948
  const id = setInterval(() => setSpinnerTick((tick) => tick + 1), 80);
29473
29949
  return () => clearInterval(id);
29474
29950
  }, [livePreviewHook.status]);
29475
29951
  const livePreviewSpinner = SPINNER_FRAMES[spinnerTick % SPINNER_FRAMES.length];
29476
- useEffect16(() => {
29952
+ useEffect17(() => {
29477
29953
  if (loading) return;
29478
29954
  if (!livePreview) return;
29479
29955
  if (components.length === 0) return;
@@ -29530,7 +30006,7 @@ var init_LivePreviewSummary = __esm({
29530
30006
  });
29531
30007
 
29532
30008
  // packages/experience-design-system-cli/src/tui/import/steps/09-review/generate-review-step.tsx
29533
- import { useCallback as useCallback5, useEffect as useEffect17, useMemo as useMemo6, useRef as useRef13, useState as useState26 } from "react";
30009
+ import { useCallback as useCallback5, useEffect as useEffect18, useMemo as useMemo6, useRef as useRef14, useState as useState26 } from "react";
29534
30010
  import figures8 from "figures";
29535
30011
  import { Box as Box38, Text as Text40 } from "ink";
29536
30012
  import { Fragment as Fragment14, jsx as jsx48, jsxs as jsxs38 } from "react/jsx-runtime";
@@ -29744,7 +30220,7 @@ function GenerateReviewStepView({
29744
30220
  setFinalizeError
29745
30221
  } = reviewSurface;
29746
30222
  const [removedBannerCollapsed, setRemovedBannerCollapsed] = useState26(false);
29747
- const removedBannerDefaultedRef = useRef13(false);
30223
+ const removedBannerDefaultedRef = useRef14(false);
29748
30224
  const [cyclePanelScroll, setCyclePanelScroll] = useState26(0);
29749
30225
  const [cyclesCursor, setCyclesCursor] = useState26(0);
29750
30226
  const cyclePanel = useOverlayPanel({
@@ -29764,7 +30240,7 @@ function GenerateReviewStepView({
29764
30240
  const [breakCursor, setBreakCursor] = useState26(0);
29765
30241
  const [breakConfirm, setBreakConfirm] = useState26(false);
29766
30242
  const [expandedGroups, setExpandedGroups] = useState26(/* @__PURE__ */ new Set());
29767
- const seededGroupsRef = useRef13(false);
30243
+ const seededGroupsRef = useRef14(false);
29768
30244
  const {
29769
30245
  searchOpen,
29770
30246
  setSearchOpen,
@@ -29788,7 +30264,7 @@ function GenerateReviewStepView({
29788
30264
  const [pendingEditorFocus, setPendingEditorFocus] = useState26(null);
29789
30265
  const [autoRejected, setAutoRejected] = useState26([]);
29790
30266
  const [undoSnapshot, setUndoSnapshot] = useState26(null);
29791
- const autoRejectFiredRef = useRef13(false);
30267
+ const autoRejectFiredRef = useRef14(false);
29792
30268
  const [showReloadDialog, setShowReloadDialog] = useState26(false);
29793
30269
  const acceptedCountForPreview = components.filter((c2) => c2.status === "accepted").length;
29794
30270
  const { previewAnnotations, removedComponents, livePreviewHook, livePreviewSpinner } = useReviewPreview({
@@ -29851,7 +30327,7 @@ function GenerateReviewStepView({
29851
30327
  [components]
29852
30328
  );
29853
30329
  const closures = useMemo6(() => computeAllClosures(componentGraph), [componentGraph]);
29854
- useEffect17(() => {
30330
+ useEffect18(() => {
29855
30331
  if (seededGroupsRef.current) return;
29856
30332
  if (closures.size === 0 && slotCycles.length === 0) return;
29857
30333
  seededGroupsRef.current = true;
@@ -29878,7 +30354,7 @@ function GenerateReviewStepView({
29878
30354
  suggestedBreak: cycle.edges.length > 0 ? suggestCycleBreakEdge2(cycle, cycleView.pushBlocking) : null
29879
30355
  }));
29880
30356
  }, [slotCycles, cycleView]);
29881
- useEffect17(() => {
30357
+ useEffect18(() => {
29882
30358
  const decision = computeAutoRejectDecision({
29883
30359
  loading,
29884
30360
  autoRejectFired: autoRejectFiredRef.current,
@@ -29921,8 +30397,8 @@ function GenerateReviewStepView({
29921
30397
  }),
29922
30398
  applySnapshot: applyHistorySnapshot
29923
30399
  });
29924
- const autoRejectPushedRef = useRef13(false);
29925
- useEffect17(() => {
30400
+ const autoRejectPushedRef = useRef14(false);
30401
+ useEffect18(() => {
29926
30402
  if (loading) return;
29927
30403
  if (!historySeededRef.current) return;
29928
30404
  if (!autoRejectFiredRef.current) return;
@@ -30006,7 +30482,7 @@ function GenerateReviewStepView({
30006
30482
  const panelHeight = leftPanelHeight + 2;
30007
30483
  const panelContentHeight = Math.max(1, panelHeight - 3);
30008
30484
  const cycleViewportHeight = Math.max(1, panelHeight - 4);
30009
- useEffect17(() => {
30485
+ useEffect18(() => {
30010
30486
  if (selectableRowPositions.length === 0) return;
30011
30487
  const cursorInRange = selectableRowPositions.includes(cursorRowIdx);
30012
30488
  const maxScroll = Math.max(0, visibleRowsMemo.length - visibleCount);
@@ -31065,7 +31541,7 @@ var init_DoneStep = __esm({
31065
31541
  });
31066
31542
 
31067
31543
  // packages/experience-design-system-cli/src/tui/import/steps/10-flow/support/path-utils.ts
31068
- import { resolve as resolve25 } from "node:path";
31544
+ import { resolve as resolve26 } from "node:path";
31069
31545
  import { homedir as homedir4 } from "node:os";
31070
31546
  function expandTilde(input) {
31071
31547
  if (input === "~" || input.startsWith("~/") || input.startsWith("~\\")) {
@@ -31079,7 +31555,7 @@ function normalizePath(input) {
31079
31555
  p = p.slice(1, -1);
31080
31556
  }
31081
31557
  p = expandTilde(p);
31082
- return resolve25(p);
31558
+ return resolve26(p);
31083
31559
  }
31084
31560
  var init_path_utils = __esm({
31085
31561
  "packages/experience-design-system-cli/src/tui/import/steps/10-flow/support/path-utils.ts"() {
@@ -31088,10 +31564,10 @@ var init_path_utils = __esm({
31088
31564
  });
31089
31565
 
31090
31566
  // packages/experience-design-system-cli/src/tui/import/steps/10-flow/support/use-blinking-cursor.ts
31091
- import { useEffect as useEffect18, useState as useState27 } from "react";
31567
+ import { useEffect as useEffect19, useState as useState27 } from "react";
31092
31568
  function useBlinkingCursor() {
31093
31569
  const [visible, setVisible] = useState27(true);
31094
- useEffect18(() => {
31570
+ useEffect19(() => {
31095
31571
  const interval = setInterval(() => setVisible((current) => !current), 500);
31096
31572
  return () => clearInterval(interval);
31097
31573
  }, []);
@@ -31106,29 +31582,29 @@ var init_use_blinking_cursor = __esm({
31106
31582
  // packages/experience-design-system-cli/src/tui/import/steps/10-flow/screens/PathPrompt.tsx
31107
31583
  import { useState as useState28 } from "react";
31108
31584
  import { Box as Box42, Text as Text44 } from "ink";
31109
- import { readdirSync as readdirSync3 } from "node:fs";
31110
- import { dirname as dirname16, basename as basename6, join as join21 } from "node:path";
31585
+ import { readdirSync as readdirSync4 } from "node:fs";
31586
+ import { dirname as dirname17, basename as basename6, join as join23 } from "node:path";
31111
31587
  import { jsx as jsx52, jsxs as jsxs42 } from "react/jsx-runtime";
31112
31588
  function autocomplete(partial) {
31113
31589
  if (!partial) return null;
31114
31590
  const normalized = normalizePath(partial);
31115
- const dir = dirname16(normalized);
31591
+ const dir = dirname17(normalized);
31116
31592
  const base = basename6(normalized);
31117
31593
  let entries;
31118
31594
  try {
31119
- entries = readdirSync3(dir);
31595
+ entries = readdirSync4(dir);
31120
31596
  } catch {
31121
31597
  return null;
31122
31598
  }
31123
31599
  const matches = entries.filter((e) => e.startsWith(base));
31124
31600
  if (matches.length === 0) return null;
31125
- if (matches.length === 1) return join21(dir, matches[0]);
31601
+ if (matches.length === 1) return join23(dir, matches[0]);
31126
31602
  let prefix = matches[0];
31127
31603
  for (const m of matches) {
31128
31604
  while (!m.startsWith(prefix)) prefix = prefix.slice(0, -1);
31129
31605
  if (!prefix) break;
31130
31606
  }
31131
- return prefix.length > base.length ? join21(dir, prefix) : null;
31607
+ return prefix.length > base.length ? join23(dir, prefix) : null;
31132
31608
  }
31133
31609
  function PathPrompt({
31134
31610
  defaultPath,
@@ -31228,12 +31704,12 @@ var init_produced = __esm({
31228
31704
  });
31229
31705
 
31230
31706
  // packages/experience-design-system-cli/src/tui/import/steps/10-flow/support/use-timed-spinner.tsx
31231
- import { useEffect as useEffect19, useState as useState29 } from "react";
31707
+ import { useEffect as useEffect20, useState as useState29 } from "react";
31232
31708
  import { Spinner as Spinner2 } from "@inkjs/ui";
31233
31709
  import { jsx as jsx53 } from "react/jsx-runtime";
31234
31710
  function useTimedSpinner() {
31235
31711
  const [elapsedSeconds, setElapsedSeconds] = useState29(0);
31236
- useEffect19(() => {
31712
+ useEffect20(() => {
31237
31713
  const timer = setInterval(() => setElapsedSeconds((current) => current + 1), 1e3);
31238
31714
  return () => {
31239
31715
  clearInterval(timer);
@@ -31502,7 +31978,7 @@ var init_preview_confirmation_input = __esm({
31502
31978
  });
31503
31979
 
31504
31980
  // packages/experience-design-system-cli/src/tui/import/steps/10-flow/screens/WizardPreviewStep.tsx
31505
- import { useEffect as useEffect20, useState as useState30, useMemo as useMemo7 } from "react";
31981
+ import { useEffect as useEffect21, useState as useState30, useMemo as useMemo7 } from "react";
31506
31982
  import { Box as Box44, Text as Text46 } from "ink";
31507
31983
  import { Fragment as Fragment16, jsx as jsx55, jsxs as jsxs44 } from "react/jsx-runtime";
31508
31984
  function buildPreviewSummaryLines(preview) {
@@ -31712,7 +32188,7 @@ function WizardPreviewStep({
31712
32188
  const activeLines = diffExpanded ? diffLines : summaryLines;
31713
32189
  const maxScroll = Math.max(0, activeLines.length - viewportHeight);
31714
32190
  const boundedScrollOffset = Math.min(scrollOffset, maxScroll);
31715
- useEffect20(() => {
32191
+ useEffect21(() => {
31716
32192
  setScrollOffset((previous) => Math.min(previous, maxScroll));
31717
32193
  }, [maxScroll]);
31718
32194
  useImmediateInput((input, key) => {
@@ -32348,8 +32824,8 @@ var init_run_print_files_helpers = __esm({
32348
32824
  });
32349
32825
 
32350
32826
  // packages/experience-design-system-cli/src/tui/import/steps/10-flow/flow/save.ts
32351
- import { writeFile as writeFile7 } from "node:fs/promises";
32352
- import { join as join22 } from "node:path";
32827
+ import { writeFile as writeFile8 } from "node:fs/promises";
32828
+ import { join as join24 } from "node:path";
32353
32829
  function buildSavedCDF(components, tokens, opts = {}) {
32354
32830
  const cdf = buildCDF2(components, toCdfTokens(tokens), opts);
32355
32831
  if (!cdf) throw new Error("nothing to save \u2014 no components or tokens resolved");
@@ -32361,7 +32837,7 @@ function buildSavedCDF(components, tokens, opts = {}) {
32361
32837
  }
32362
32838
  async function runPrintFiles(input, deps, onPatch) {
32363
32839
  onPatch({ step: "printing" });
32364
- const componentsPath = join22(input.outDir, "components.json");
32840
+ const componentsPath = join24(input.outDir, "components.json");
32365
32841
  try {
32366
32842
  const db = deps.openDb();
32367
32843
  let components = [];
@@ -32445,7 +32921,7 @@ var init_save = __esm({
32445
32921
  realSaveDeps = () => ({
32446
32922
  openDb: openPipelineDb,
32447
32923
  readTokens: (path5) => readTokensFromPath2({ flag: "tokens", path: path5 }),
32448
- writeFile: (path5, contents) => writeFile7(path5, contents),
32924
+ writeFile: (path5, contents) => writeFile8(path5, contents),
32449
32925
  appendRun,
32450
32926
  buildSourceFingerprint,
32451
32927
  sleep: (ms) => new Promise((resolve29) => setTimeout(resolve29, ms)),
@@ -32468,9 +32944,9 @@ var init_types9 = __esm({
32468
32944
 
32469
32945
  // packages/experience-design-system-cli/src/tui/import/steps/10-flow/flow/controller.ts
32470
32946
  import { appendFileSync, writeFileSync } from "node:fs";
32471
- import { mkdir as mkdir8 } from "node:fs/promises";
32947
+ import { mkdir as mkdir9 } from "node:fs/promises";
32472
32948
  import { tmpdir } from "node:os";
32473
- import { join as join23, resolve as resolve26 } from "node:path";
32949
+ import { join as join25, resolve as resolve27 } from "node:path";
32474
32950
  function appendWizardLog(entry) {
32475
32951
  appendFileSync(WIZARD_LOG, JSON.stringify({ ts: (/* @__PURE__ */ new Date()).toISOString(), ...entry }) + "\n");
32476
32952
  }
@@ -32493,7 +32969,7 @@ function realFlowDeps() {
32493
32969
  }
32494
32970
  },
32495
32971
  mkdir: async (path5) => {
32496
- await mkdir8(path5, { recursive: true });
32972
+ await mkdir9(path5, { recursive: true });
32497
32973
  },
32498
32974
  detectSaveConflict,
32499
32975
  buildTimestampedSubdir,
@@ -32723,367 +33199,71 @@ function createFlowController(start, deps) {
32723
33199
  },
32724
33200
  async submitPath(submitted) {
32725
33201
  await deps.mkdir(submitted);
32726
- if (resolve26(submitted) !== resolve26(state2.outDir) && await deps.detectSaveConflict(submitted)) {
33202
+ if (resolve27(submitted) !== resolve27(state2.outDir) && await deps.detectSaveConflict(submitted)) {
32727
33203
  const subdir = deps.buildTimestampedSubdir(submitted);
32728
33204
  await deps.mkdir(subdir);
32729
33205
  await proceedToWrite(subdir);
32730
33206
  return;
32731
33207
  }
32732
- await proceedToWrite(submitted);
32733
- },
32734
- confirmPreview: (acknowledge) => void push(acknowledge),
32735
- acknowledgeBreakingChanges: () => void push(true),
32736
- editDefinitions: () => update({ step: "final-review" }),
32737
- async skipValidationErrors() {
32738
- if (state2.extractSessionId) {
32739
- const names = namesToSkip(state2.previewValidationErrors);
32740
- if (names.length > 0) await deps.rejectComponentsByName(state2.extractSessionId, names);
32741
- }
32742
- await preview();
32743
- }
32744
- };
32745
- }
32746
- var WIZARD_LOG;
32747
- var init_controller = __esm({
32748
- "packages/experience-design-system-cli/src/tui/import/steps/10-flow/flow/controller.ts"() {
32749
- "use strict";
32750
- init_src3();
32751
- init_slot_graph();
32752
- init_cycle_detection();
32753
- init_wizard_state_transitions();
32754
- init_preview2();
32755
- init_push();
32756
- init_save();
32757
- init_types9();
32758
- WIZARD_LOG = join23(tmpdir(), "experiences-import-wizard.log");
32759
- }
32760
- });
32761
-
32762
- // packages/experience-design-system-cli/src/tui/import/steps/10-flow/flow/use-flow.ts
32763
- import { useEffect as useEffect21, useRef as useRef14, useSyncExternalStore } from "react";
32764
- function useFlow(start, options = {}) {
32765
- const controller = useRef14();
32766
- if (start && !controller.current) {
32767
- try {
32768
- startWizardLog();
32769
- } catch {
32770
- }
32771
- const flowDeps = (options.deps ?? realFlowDeps)();
32772
- controller.current = createFlowController(start, {
32773
- ...flowDeps,
32774
- ...options.beforeStepChange ? { beforeStepChange: options.beforeStepChange } : {}
32775
- });
32776
- }
32777
- const current = controller.current;
32778
- const state2 = useSyncExternalStore(
32779
- (listener) => current?.subscribe(listener) ?? (() => void 0),
32780
- () => current?.getState()
32781
- );
32782
- useEffect21(() => {
32783
- if (!start) controller.current = void 0;
32784
- }, [start]);
32785
- return current && state2 ? { controller: current, state: state2 } : void 0;
32786
- }
32787
- var init_use_flow = __esm({
32788
- "packages/experience-design-system-cli/src/tui/import/steps/10-flow/flow/use-flow.ts"() {
32789
- "use strict";
32790
- init_controller();
32791
- }
32792
- });
32793
-
32794
- // packages/experience-design-system-cli/src/tui/settings/debug-mode/debug-mode-store.ts
32795
- function toRetentionDays(value) {
32796
- return RETENTION_CHOICES.find((choice) => choice === value) ?? DEFAULT_RETENTION_DAYS;
32797
- }
32798
- async function readDebugModeSetting() {
32799
- const { debugMode } = await readSettings2();
32800
- const saved = debugMode ?? {};
32801
- return {
32802
- enabled: typeof saved.enabled === "boolean" ? saved.enabled : true,
32803
- retentionDays: toRetentionDays(saved.retentionDays)
32804
- };
32805
- }
32806
- async function writeDebugModeSetting(change) {
32807
- await updateSettings2({ debugMode: { ...await readDebugModeSetting(), ...change } });
32808
- }
32809
- var RETENTION_CHOICES, DEFAULT_RETENTION_DAYS;
32810
- var init_debug_mode_store = __esm({
32811
- "packages/experience-design-system-cli/src/tui/settings/debug-mode/debug-mode-store.ts"() {
32812
- "use strict";
32813
- init_config();
32814
- RETENTION_CHOICES = [7, 14, 30];
32815
- DEFAULT_RETENTION_DAYS = 30;
32816
- }
32817
- });
32818
-
32819
- // packages/experience-design-system-cli/src/tui/debug-prune.ts
32820
- import { readdir as readdir2, rm, rmdir, stat as stat4 } from "node:fs/promises";
32821
- import { dirname as dirname17, join as join24 } from "node:path";
32822
- async function logFilesIn(dir) {
32823
- const entries = await readdir2(dir, { withFileTypes: true });
32824
- const nested = await Promise.all(
32825
- entries.map(async (entry) => {
32826
- const path5 = join24(dir, entry.name);
32827
- if (entry.isDirectory()) return logFilesIn(path5);
32828
- return entry.isFile() && entry.name.endsWith(".md") ? [path5] : [];
32829
- })
32830
- );
32831
- return nested.flat();
32832
- }
32833
- async function removeEmptyFolders(from, stop) {
32834
- let dir = from;
32835
- let removed = 0;
32836
- for (; ; ) {
32837
- try {
32838
- await rmdir(dir);
32839
- } catch {
32840
- return removed;
32841
- }
32842
- removed += 1;
32843
- if (dir === stop) return removed;
32844
- dir = dirname17(dir);
32845
- }
32846
- }
32847
- async function pruneExpiredLogs(base, retentionDays, now = Date.now()) {
32848
- const cutoff = now - retentionDays * DAY_MS;
32849
- const contentfulDir = join24(base, ".contentful");
32850
- const result = { logs: 0, folders: 0 };
32851
- try {
32852
- const sessions = (await readdir2(contentfulDir)).filter((name) => SESSION_FOLDER.test(name));
32853
- for (const session of sessions) {
32854
- const files = await logFilesIn(join24(contentfulDir, session, "debug")).catch(() => []);
32855
- for (const file of files) {
32856
- try {
32857
- if ((await stat4(file)).mtimeMs >= cutoff) continue;
32858
- await rm(file);
32859
- result.logs += 1;
32860
- result.folders += await removeEmptyFolders(dirname17(file), join24(contentfulDir, session));
32861
- } catch {
32862
- }
32863
- }
33208
+ await proceedToWrite(submitted);
33209
+ },
33210
+ confirmPreview: (acknowledge) => void push(acknowledge),
33211
+ acknowledgeBreakingChanges: () => void push(true),
33212
+ editDefinitions: () => update({ step: "final-review" }),
33213
+ async skipValidationErrors() {
33214
+ if (state2.extractSessionId) {
33215
+ const names = namesToSkip(state2.previewValidationErrors);
33216
+ if (names.length > 0) await deps.rejectComponentsByName(state2.extractSessionId, names);
33217
+ }
33218
+ await preview();
32864
33219
  }
32865
- } catch {
32866
- }
32867
- return result;
33220
+ };
32868
33221
  }
32869
- var DAY_MS, SESSION_FOLDER;
32870
- var init_debug_prune = __esm({
32871
- "packages/experience-design-system-cli/src/tui/debug-prune.ts"() {
33222
+ var WIZARD_LOG;
33223
+ var init_controller = __esm({
33224
+ "packages/experience-design-system-cli/src/tui/import/steps/10-flow/flow/controller.ts"() {
32872
33225
  "use strict";
32873
- DAY_MS = 24 * 60 * 60 * 1e3;
32874
- SESSION_FOLDER = /^\d{2}-\d{2}-\d{4}-session-\d+$/;
33226
+ init_src3();
33227
+ init_slot_graph();
33228
+ init_cycle_detection();
33229
+ init_wizard_state_transitions();
33230
+ init_preview2();
33231
+ init_push();
33232
+ init_save();
33233
+ init_types9();
33234
+ WIZARD_LOG = join25(tmpdir(), "experiences-import-wizard.log");
32875
33235
  }
32876
33236
  });
32877
33237
 
32878
- // packages/experience-design-system-cli/src/tui/debug-store.ts
32879
- var debug_store_exports = {};
32880
- __export(debug_store_exports, {
32881
- currentDebugSessionDir: () => currentDebugSessionDir,
32882
- currentSessionDir: () => currentSessionDir,
32883
- finishDebugRun: () => finishDebugRun,
32884
- startDebugRun: () => startDebugRun,
32885
- startDebugSessionIn: () => startDebugSessionIn,
32886
- startImportRun: () => startImportRun
32887
- });
32888
- import { mkdir as mkdir9, writeFile as writeFile8 } from "node:fs/promises";
32889
- import { existsSync as existsSync10, readdirSync as readdirSync4 } from "node:fs";
32890
- import { join as join25, resolve as resolve27 } from "node:path";
32891
- function generateRunId() {
32892
- const now = /* @__PURE__ */ new Date();
32893
- const pad = (n) => String(n).padStart(2, "0");
32894
- return `${now.getFullYear()}${pad(now.getMonth() + 1)}${pad(now.getDate())}-${pad(now.getHours())}${pad(now.getMinutes())}${pad(now.getSeconds())}`;
32895
- }
32896
- function datePrefix(now = /* @__PURE__ */ new Date()) {
32897
- const pad = (n) => String(n).padStart(2, "0");
32898
- return `${pad(now.getMonth() + 1)}-${pad(now.getDate())}-${now.getFullYear()}`;
32899
- }
32900
- function slugify(value) {
32901
- return value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
32902
- }
32903
- async function readBaseDir() {
32904
- try {
32905
- const dir = (await readSettings2())["contentfulBaseDir"];
32906
- return typeof dir === "string" && dir !== "" ? resolve27(dir) : void 0;
32907
- } catch {
32908
- return void 0;
32909
- }
32910
- }
32911
- function nextSessionId(contentfulDir) {
32912
- const today = datePrefix();
32913
- const existing = existsSync10(contentfulDir) ? readdirSync4(contentfulDir) : [];
32914
- const seqPattern = new RegExp(`^${today}-session-(\\d+)$`);
32915
- const maxSeq = existing.reduce((max, entry) => {
32916
- const match2 = seqPattern.exec(entry);
32917
- return match2 ? Math.max(max, Number(match2[1])) : max;
32918
- }, 0);
32919
- return `${today}-session-${maxSeq + 1}`;
32920
- }
32921
- function startSession(base, { replace }) {
32922
- const contentfulDir = join25(base, ".contentful");
32923
- if (replace || !sessionDir) sessionDir = join25(contentfulDir, nextSessionId(contentfulDir));
32924
- return sessionDir;
32925
- }
32926
- function currentDebugSessionDir() {
32927
- return sessionDir && join25(sessionDir, "debug");
32928
- }
32929
- function currentSessionDir() {
32930
- return sessionDir;
32931
- }
32932
- async function startDebugSessionIn(base, { replace = false } = {}) {
32933
- try {
32934
- if (!await isDebugModeEnabled()) return;
32935
- await mkdir9(join25(startSession(resolve27(base), { replace }), "debug"), { recursive: true });
32936
- } catch {
32937
- }
32938
- }
32939
- function nextImportRunDir(session) {
32940
- const existing = existsSync10(session) ? readdirSync4(session) : [];
32941
- const maxRun = existing.reduce((max, entry) => {
32942
- const match2 = /^dsi-import-(\d+)$/.exec(entry);
32943
- return match2 ? Math.max(max, Number(match2[1])) : max;
32944
- }, 0);
32945
- return join25(session, `dsi-import-${maxRun + 1}`);
32946
- }
32947
- async function startImportRun(projectPath) {
32948
- await startDebugSessionIn(projectPath);
32949
- if (!sessionDir) return join25(resolve27(projectPath), ".contentful");
32950
- const dir = nextImportRunDir(sessionDir);
32951
- await mkdir9(dir, { recursive: true });
32952
- return dir;
32953
- }
32954
- async function isDebugModeEnabled() {
32955
- try {
32956
- return (await readDebugModeSetting()).enabled;
32957
- } catch {
32958
- return true;
32959
- }
32960
- }
32961
- function redact(value) {
32962
- const clone = { ...value };
32963
- if ("cma_token" in clone) {
32964
- const raw = clone.cma_token;
32965
- clone.cma_token = typeof raw === "string" && raw.length > 0 ? `[present, ${raw.length} chars]` : "[not set]";
33238
+ // packages/experience-design-system-cli/src/tui/import/steps/10-flow/flow/use-flow.ts
33239
+ import { useEffect as useEffect22, useRef as useRef15, useSyncExternalStore } from "react";
33240
+ function useFlow(start, options = {}) {
33241
+ const controller = useRef15();
33242
+ if (start && !controller.current) {
33243
+ try {
33244
+ startWizardLog();
33245
+ } catch {
33246
+ }
33247
+ const flowDeps = (options.deps ?? realFlowDeps)();
33248
+ controller.current = createFlowController(start, {
33249
+ ...flowDeps,
33250
+ ...options.beforeStepChange ? { beforeStepChange: options.beforeStepChange } : {}
33251
+ });
32966
33252
  }
32967
- return clone;
32968
- }
32969
- function startDebugRun({
32970
- flow,
32971
- step,
32972
- menuOption,
32973
- inputs
32974
- }) {
32975
- const runId = generateRunId();
32976
- const startedAt = Date.now();
32977
- const redactedInputs = redact(inputs);
32978
- isDebugModeEnabled().then((enabled) => {
32979
- if (!enabled) return;
32980
- pendingRun = { flow, step, runId, menuOption, inputs: redactedInputs, startedAt };
32981
- });
32982
- }
32983
- async function finishDebugRun({
32984
- outputs,
32985
- status,
32986
- exitMethod
32987
- }) {
32988
- const run = pendingRun;
32989
- if (!run) return;
32990
- pendingRun = void 0;
32991
- const durationMs = Date.now() - run.startedAt;
32992
- const content = renderMarkdown(run, { outputs: redact(outputs), status, exitMethod, durationMs });
32993
- const root = currentDebugSessionDir();
32994
- if (!root) return;
32995
- const flowSegments = run.flow.split("/");
32996
- const dir = join25(root, ...flowSegments);
32997
- await mkdir9(dir, { recursive: true });
32998
- const filename = nextAttemptFilename(dir, run.menuOption);
32999
- await writeFile8(join25(dir, filename), content, { mode: 384 });
33000
- }
33001
- function nextAttemptFilename(dir, menuOption) {
33002
- const today = datePrefix();
33003
- const optionSlug = slugify(menuOption);
33004
- const existing = existsSync10(dir) ? readdirSync4(dir) : [];
33005
- const attemptPattern = new RegExp(`^${today}-${optionSlug}-attempt-(\\d+)\\.md$`);
33006
- const maxAttempt = existing.reduce((max, entry) => {
33007
- const match2 = attemptPattern.exec(entry);
33008
- return match2 ? Math.max(max, Number(match2[1])) : max;
33009
- }, 0);
33010
- return `${today}-${optionSlug}-attempt-${maxAttempt + 1}.md`;
33011
- }
33012
- function renderMarkdown(run, finish) {
33013
- const stepMatch = /^(\d+)-(.+)$/.exec(run.step);
33014
- const stepLabel = stepMatch ? `${stepMatch[1]} - ${stepMatch[2]}` : run.step;
33015
- const flowSlug = run.flow.split("/").join("-");
33016
- return `# Debug Log
33017
-
33018
- - Run ID: ${run.runId}
33019
- - Flow: ${flowSlug}
33020
- - Step: ${stepLabel}
33021
- - Menu option: ${run.menuOption}
33022
- - Date: ${(/* @__PURE__ */ new Date()).toISOString()}
33023
- - CLI version: ${readPackageVersion()}
33024
- - Platform: ${process.platform} / Node ${process.version}
33025
- - Duration on screen: ${finish.durationMs}ms
33026
- - Status: ${finish.status}
33027
- - Exit method: ${finish.exitMethod}
33028
-
33029
- ## Inputs
33030
- \`\`\`json
33031
- ${JSON.stringify(run.inputs, null, 2)}
33032
- \`\`\`
33033
-
33034
- ## Outputs
33035
- \`\`\`json
33036
- ${JSON.stringify(finish.outputs, null, 2)}
33037
- \`\`\`
33038
- `;
33039
- }
33040
- function handleCrash() {
33041
- return finishDebugRun({ outputs: {}, status: "error", exitMethod: "crashed" });
33253
+ const current = controller.current;
33254
+ const state2 = useSyncExternalStore(
33255
+ (listener) => current?.subscribe(listener) ?? (() => void 0),
33256
+ () => current?.getState()
33257
+ );
33258
+ useEffect22(() => {
33259
+ if (!start) controller.current = void 0;
33260
+ }, [start]);
33261
+ return current && state2 ? { controller: current, state: state2 } : void 0;
33042
33262
  }
33043
- var pendingRun, sessionDir;
33044
- var init_debug_store = __esm({
33045
- "packages/experience-design-system-cli/src/tui/debug-store.ts"() {
33263
+ var init_use_flow = __esm({
33264
+ "packages/experience-design-system-cli/src/tui/import/steps/10-flow/flow/use-flow.ts"() {
33046
33265
  "use strict";
33047
- init_config();
33048
- init_version();
33049
- init_debug_mode_store();
33050
- init_debug_prune();
33051
- void Promise.all([isDebugModeEnabled(), readBaseDir()]).then(async ([enabled, base]) => {
33052
- if (!base) return;
33053
- const retention = await readDebugModeSetting().catch(() => void 0);
33054
- const pruned = retention ? await pruneExpiredLogs(base, retention.retentionDays).catch(() => void 0) : void 0;
33055
- if (!enabled) return;
33056
- const debugDir = join25(startSession(base, { replace: false }), "debug");
33057
- await mkdir9(debugDir, { recursive: true });
33058
- if (retention && pruned && pruned.logs + pruned.folders > 0) {
33059
- await writeFile8(
33060
- join25(debugDir, `${datePrefix()}-cleanup-${generateRunId()}.md`),
33061
- `# Debug Log Cleanup
33062
-
33063
- - Date: ${(/* @__PURE__ */ new Date()).toISOString()}
33064
- - Retention: ${retention.retentionDays} days
33065
- - Logs deleted: ${pruned.logs}
33066
- - Empty folders removed: ${pruned.folders}
33067
- `,
33068
- { mode: 384 }
33069
- );
33070
- }
33071
- });
33072
- process.once("uncaughtException", (err) => {
33073
- void handleCrash().finally(() => {
33074
- throw err;
33075
- });
33076
- });
33077
- process.once("unhandledRejection", (reason) => {
33078
- void handleCrash().finally(() => {
33079
- throw reason;
33080
- });
33081
- });
33082
- process.once("SIGINT", () => {
33083
- void handleCrash().finally(() => {
33084
- process.exit(130);
33085
- });
33086
- });
33266
+ init_controller();
33087
33267
  }
33088
33268
  });
33089
33269
 
@@ -33154,7 +33334,7 @@ var init_help_info = __esm({
33154
33334
  });
33155
33335
 
33156
33336
  // packages/experience-design-system-cli/src/tui/help/PageContainer.tsx
33157
- import { useEffect as useEffect22, useState as useState31 } from "react";
33337
+ import { useEffect as useEffect23, useState as useState31 } from "react";
33158
33338
  import { Box as Box46, Text as Text47, useInput as useInput13 } from "ink";
33159
33339
  import { Fragment as Fragment17, jsx as jsx57, jsxs as jsxs46 } from "react/jsx-runtime";
33160
33340
  function Section({ title, rows }) {
@@ -33168,7 +33348,7 @@ function Section({ title, rows }) {
33168
33348
  }
33169
33349
  function HelpScreen({ onDone }) {
33170
33350
  const [info, setInfo] = useState31();
33171
- useEffect22(() => {
33351
+ useEffect23(() => {
33172
33352
  startDebugRun({ flow: "help", step: "01-help", menuOption: "Help", inputs: {} });
33173
33353
  void readHelpInfo().then(setInfo);
33174
33354
  }, []);
@@ -33589,7 +33769,7 @@ var init_AgentStatusBadge = __esm({
33589
33769
  });
33590
33770
 
33591
33771
  // packages/experience-design-system-cli/src/tui/settings/configuration/agents/AgentDetail.tsx
33592
- import { useEffect as useEffect23, useState as useState33 } from "react";
33772
+ import { useEffect as useEffect24, useState as useState33 } from "react";
33593
33773
  import { Box as Box48, Text as Text50 } from "ink";
33594
33774
  import { jsx as jsx60, jsxs as jsxs48 } from "react/jsx-runtime";
33595
33775
  function StatusHeading() {
@@ -33610,7 +33790,7 @@ function AgentDetail({
33610
33790
  const [testing, setTesting] = useState33(false);
33611
33791
  const [notice, setNotice] = useState33(null);
33612
33792
  const [checks, setChecks] = useState33(void 0);
33613
- useEffect23(() => {
33793
+ useEffect24(() => {
33614
33794
  let active = true;
33615
33795
  setChecks(void 0);
33616
33796
  const timer = setTimeout(() => {
@@ -33702,7 +33882,7 @@ var init_AgentDetail = __esm({
33702
33882
  });
33703
33883
 
33704
33884
  // packages/experience-design-system-cli/src/tui/settings/configuration/agents/AgentsScreen.tsx
33705
- import { useEffect as useEffect24, useRef as useRef15, useState as useState34 } from "react";
33885
+ import { useEffect as useEffect25, useRef as useRef16, useState as useState34 } from "react";
33706
33886
  import { Box as Box49, Text as Text51, useInput as useInput15 } from "ink";
33707
33887
  import { Fragment as Fragment18, jsx as jsx61, jsxs as jsxs49 } from "react/jsx-runtime";
33708
33888
  function AgentsScreen({ onDone }) {
@@ -33713,7 +33893,7 @@ function AgentsScreen({ onDone }) {
33713
33893
  const [saving, setSaving] = useState34(false);
33714
33894
  const [loadError, setLoadError] = useState34(null);
33715
33895
  const [checks, setChecks] = useState34({});
33716
- const visit = useRef15({
33896
+ const visit = useRef16({
33717
33897
  trail: createTrail(),
33718
33898
  before: void 0,
33719
33899
  environment: void 0,
@@ -33726,7 +33906,7 @@ function AgentsScreen({ onDone }) {
33726
33906
  );
33727
33907
  }
33728
33908
  };
33729
- useEffect24(() => {
33909
+ useEffect25(() => {
33730
33910
  readAgentConfig().then((loaded) => {
33731
33911
  setConfig(loaded);
33732
33912
  inspectAll(loaded);
@@ -33952,7 +34132,7 @@ var init_project_store = __esm({
33952
34132
  });
33953
34133
 
33954
34134
  // packages/experience-design-system-cli/src/tui/settings/configuration/project/ProjectScreen.tsx
33955
- import { useEffect as useEffect25, useRef as useRef16, useState as useState35 } from "react";
34135
+ import { useEffect as useEffect26, useRef as useRef17, useState as useState35 } from "react";
33956
34136
  import { Box as Box50, Text as Text52, useInput as useInput16 } from "ink";
33957
34137
  import { Fragment as Fragment19, jsx as jsx62, jsxs as jsxs50 } from "react/jsx-runtime";
33958
34138
  function debugFields(config) {
@@ -33971,14 +34151,14 @@ function ProjectScreen({ onDone }) {
33971
34151
  const [saving, setSaving] = useState35(false);
33972
34152
  const [notice, setNotice] = useState35(null);
33973
34153
  const [loadError, setLoadError] = useState35(null);
33974
- const visit = useRef16({
34154
+ const visit = useRef17({
33975
34155
  trail: createTrail(),
33976
34156
  before: void 0,
33977
34157
  persisted: void 0,
33978
34158
  error: ""
33979
34159
  }).current;
33980
34160
  const scrub = (err) => scrubError(err, [config?.cmaToken ?? ""]);
33981
- useEffect25(() => {
34161
+ useEffect26(() => {
33982
34162
  readCredentials().then((cfg) => {
33983
34163
  setConfig(cfg);
33984
34164
  visit.before = snapshotOf(cfg);
@@ -34165,13 +34345,13 @@ var init_ConfigurationScreen = __esm({
34165
34345
  });
34166
34346
 
34167
34347
  // packages/experience-design-system-cli/src/tui/settings/opt-in-analytics/screen.tsx
34168
- import { useEffect as useEffect26, useState as useState37 } from "react";
34348
+ import { useEffect as useEffect27, useState as useState37 } from "react";
34169
34349
  import { Box as Box52, Text as Text54, useInput as useInput18 } from "ink";
34170
34350
  import { Fragment as Fragment20, jsx as jsx64, jsxs as jsxs52 } from "react/jsx-runtime";
34171
34351
  function OptInAnalyticsScreen({ onDone }) {
34172
34352
  const [loading, setLoading] = useState37(true);
34173
34353
  const [enabled, setEnabled] = useState37(true);
34174
- useEffect26(() => {
34354
+ useEffect27(() => {
34175
34355
  readAnalyticsSetting().then((setting) => {
34176
34356
  setEnabled(setting.enabled);
34177
34357
  setLoading(false);
@@ -34234,7 +34414,7 @@ var init_screen12 = __esm({
34234
34414
  });
34235
34415
 
34236
34416
  // packages/experience-design-system-cli/src/tui/settings/debug-mode/screen.tsx
34237
- import { useEffect as useEffect27, useRef as useRef17, useState as useState38 } from "react";
34417
+ import { useEffect as useEffect28, useRef as useRef18, useState as useState38 } from "react";
34238
34418
  import { Box as Box53, Text as Text55, useInput as useInput19 } from "ink";
34239
34419
  import { Fragment as Fragment21, jsx as jsx65, jsxs as jsxs53 } from "react/jsx-runtime";
34240
34420
  function DebugModeScreen({ onDone }) {
@@ -34244,8 +34424,8 @@ function DebugModeScreen({ onDone }) {
34244
34424
  RETENTION_CHOICES[RETENTION_CHOICES.length - 1]
34245
34425
  );
34246
34426
  const [notice, setNotice] = useState38(null);
34247
- const visit = useRef17({ trail: createTrail(), before: void 0, error: "" }).current;
34248
- useEffect27(() => {
34427
+ const visit = useRef18({ trail: createTrail(), before: void 0, error: "" }).current;
34428
+ useEffect28(() => {
34249
34429
  readDebugModeSetting().then((loaded) => {
34250
34430
  setSetting(loaded);
34251
34431
  setPending(loaded.retentionDays);
@@ -34386,7 +34566,7 @@ var app_exports = {};
34386
34566
  __export(app_exports, {
34387
34567
  runApp: () => runApp
34388
34568
  });
34389
- import { useEffect as useEffect28, useState as useState39 } from "react";
34569
+ import { useEffect as useEffect29, useState as useState39 } from "react";
34390
34570
  import { Fragment as Fragment22, jsx as jsx66 } from "react/jsx-runtime";
34391
34571
  function App({ importOptions, inkClear }) {
34392
34572
  const [screen, setScreen] = useState39("start");
@@ -34420,7 +34600,7 @@ function App({ importOptions, inkClear }) {
34420
34600
  const [flowStart, setFlowStart] = useState39();
34421
34601
  const flow = useFlow(flowStart, { beforeStepChange: inkClear });
34422
34602
  const [importDefaults, setImportDefaults] = useState39();
34423
- useEffect28(() => {
34603
+ useEffect29(() => {
34424
34604
  if (screen !== "import") {
34425
34605
  setImportDefaults(void 0);
34426
34606
  return;
@@ -34493,7 +34673,7 @@ function App({ importOptions, inkClear }) {
34493
34673
  }
34494
34674
  });
34495
34675
  };
34496
- useEffect28(() => {
34676
+ useEffect29(() => {
34497
34677
  if (!tokensOnlyRun || tokensOnly?.status !== "done" || !tokensOnly.result.ok) return;
34498
34678
  const { credentialsSkipped, input, tokens } = tokensOnlyRun;
34499
34679
  const { tokensPath, tokenSessionId, tokenCount } = tokensOnly.result;
@@ -34515,12 +34695,12 @@ function App({ importOptions, inkClear }) {
34515
34695
  }
34516
34696
  });
34517
34697
  }, [tokensOnly, tokensOnlyRun]);
34518
- useEffect28(() => {
34698
+ useEffect29(() => {
34519
34699
  if (!extractionRun || extraction?.status !== "done" || !extraction.result.ok) return;
34520
34700
  setExtractionRun(void 0);
34521
34701
  setScopeRun({ ...extractionRun, extraction: extraction.result.extraction });
34522
34702
  }, [extraction, extractionRun]);
34523
- useEffect28(() => {
34703
+ useEffect29(() => {
34524
34704
  if (!scopeRun || scopeFlow?.status !== "confirmed" || generationInput) return;
34525
34705
  const { extraction: produced, input, generatePromptPath } = scopeRun;
34526
34706
  setGenerationInput({
@@ -34538,7 +34718,7 @@ function App({ importOptions, inkClear }) {
34538
34718
  ...generatePromptPath ? { generatePromptPath } : {}
34539
34719
  });
34540
34720
  }, [scopeFlow, scopeRun, generationInput]);
34541
- useEffect28(() => {
34721
+ useEffect29(() => {
34542
34722
  if (!scopeRun || generation?.status !== "done" || !generation.result.ok) return;
34543
34723
  const { credentialsSkipped, extraction: produced, input, generatePromptPath } = scopeRun;
34544
34724
  inkClear();