@contentful/experience-design-system-cli 2.37.1-dev-build-4e7e3ced.0 → 2.37.1-dev-build-81dbe125.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/app.js CHANGED
@@ -2116,21 +2116,86 @@ var init_config = __esm({
2116
2116
  });
2117
2117
 
2118
2118
  // packages/experience-design-system-cli/src/tui/settings/debug-mode/debug-mode-store.ts
2119
+ function toRetentionDays(value) {
2120
+ return RETENTION_CHOICES.find((choice) => choice === value) ?? DEFAULT_RETENTION_DAYS;
2121
+ }
2119
2122
  async function readDebugModeSetting() {
2120
2123
  const { debugMode } = await readSettings2();
2121
- return { ...DEFAULT_DEBUG_MODE_SETTING, ...debugMode };
2124
+ const saved = debugMode ?? {};
2125
+ return {
2126
+ enabled: typeof saved.enabled === "boolean" ? saved.enabled : true,
2127
+ retentionDays: toRetentionDays(saved.retentionDays)
2128
+ };
2122
2129
  }
2123
- async function writeDebugModeSetting(setting) {
2124
- await updateSettings2({ debugMode: setting });
2130
+ async function writeDebugModeSetting(change) {
2131
+ await updateSettings2({ debugMode: { ...await readDebugModeSetting(), ...change } });
2125
2132
  }
2126
- var DEFAULT_DEBUG_MODE_SETTING;
2133
+ var RETENTION_CHOICES, DEFAULT_RETENTION_DAYS;
2127
2134
  var init_debug_mode_store = __esm({
2128
2135
  "packages/experience-design-system-cli/src/tui/settings/debug-mode/debug-mode-store.ts"() {
2129
2136
  "use strict";
2130
2137
  init_config();
2131
- DEFAULT_DEBUG_MODE_SETTING = {
2132
- enabled: true
2133
- };
2138
+ RETENTION_CHOICES = [7, 14, 30];
2139
+ DEFAULT_RETENTION_DAYS = 30;
2140
+ }
2141
+ });
2142
+
2143
+ // packages/experience-design-system-cli/src/tui/debug-prune.ts
2144
+ import { readdir as readdir3, rm, rmdir, stat as stat5 } from "node:fs/promises";
2145
+ import { dirname as dirname16, join as join24 } from "node:path";
2146
+ async function logFilesIn(dir) {
2147
+ const entries = await readdir3(dir, { withFileTypes: true });
2148
+ const nested = await Promise.all(
2149
+ entries.map(async (entry) => {
2150
+ const path5 = join24(dir, entry.name);
2151
+ if (entry.isDirectory()) return logFilesIn(path5);
2152
+ return entry.isFile() && entry.name.endsWith(".md") ? [path5] : [];
2153
+ })
2154
+ );
2155
+ return nested.flat();
2156
+ }
2157
+ async function removeEmptyFolders(from, stop) {
2158
+ let dir = from;
2159
+ let removed = 0;
2160
+ for (; ; ) {
2161
+ try {
2162
+ await rmdir(dir);
2163
+ } catch {
2164
+ return removed;
2165
+ }
2166
+ removed += 1;
2167
+ if (dir === stop) return removed;
2168
+ dir = dirname16(dir);
2169
+ }
2170
+ }
2171
+ async function pruneExpiredLogs(base, retentionDays, now = Date.now()) {
2172
+ const cutoff = now - retentionDays * DAY_MS;
2173
+ const contentfulDir = join24(base, ".contentful");
2174
+ const result = { logs: 0, folders: 0 };
2175
+ try {
2176
+ const sessions = (await readdir3(contentfulDir)).filter((name) => SESSION_FOLDER.test(name));
2177
+ for (const session of sessions) {
2178
+ const files = await logFilesIn(join24(contentfulDir, session, "debug")).catch(() => []);
2179
+ for (const file of files) {
2180
+ try {
2181
+ if ((await stat5(file)).mtimeMs >= cutoff) continue;
2182
+ await rm(file);
2183
+ result.logs += 1;
2184
+ result.folders += await removeEmptyFolders(dirname16(file), join24(contentfulDir, session));
2185
+ } catch {
2186
+ }
2187
+ }
2188
+ }
2189
+ } catch {
2190
+ }
2191
+ return result;
2192
+ }
2193
+ var DAY_MS, SESSION_FOLDER;
2194
+ var init_debug_prune = __esm({
2195
+ "packages/experience-design-system-cli/src/tui/debug-prune.ts"() {
2196
+ "use strict";
2197
+ DAY_MS = 24 * 60 * 60 * 1e3;
2198
+ SESSION_FOLDER = /^\d{2}-\d{2}-\d{4}-session-\d+$/;
2134
2199
  }
2135
2200
  });
2136
2201
 
@@ -2146,7 +2211,7 @@ __export(debug_store_exports, {
2146
2211
  });
2147
2212
  import { mkdir as mkdir9, writeFile as writeFile8 } from "node:fs/promises";
2148
2213
  import { existsSync as existsSync9, readdirSync as readdirSync4 } from "node:fs";
2149
- import { join as join24, resolve as resolve26 } from "node:path";
2214
+ import { join as join25, resolve as resolve26 } from "node:path";
2150
2215
  function generateRunId() {
2151
2216
  const now = /* @__PURE__ */ new Date();
2152
2217
  const pad = (n) => String(n).padStart(2, "0");
@@ -2178,12 +2243,12 @@ function nextSessionId(contentfulDir) {
2178
2243
  return `${today}-session-${maxSeq + 1}`;
2179
2244
  }
2180
2245
  function startSession(base, { replace }) {
2181
- const contentfulDir = join24(base, ".contentful");
2182
- if (replace || !sessionDir) sessionDir = join24(contentfulDir, nextSessionId(contentfulDir));
2246
+ const contentfulDir = join25(base, ".contentful");
2247
+ if (replace || !sessionDir) sessionDir = join25(contentfulDir, nextSessionId(contentfulDir));
2183
2248
  return sessionDir;
2184
2249
  }
2185
2250
  function currentDebugSessionDir() {
2186
- return sessionDir && join24(sessionDir, "debug");
2251
+ return sessionDir && join25(sessionDir, "debug");
2187
2252
  }
2188
2253
  function currentSessionDir() {
2189
2254
  return sessionDir;
@@ -2191,7 +2256,7 @@ function currentSessionDir() {
2191
2256
  async function startDebugSessionIn(base, { replace = false } = {}) {
2192
2257
  try {
2193
2258
  if (!await isDebugModeEnabled()) return;
2194
- await mkdir9(join24(startSession(resolve26(base), { replace }), "debug"), { recursive: true });
2259
+ await mkdir9(join25(startSession(resolve26(base), { replace }), "debug"), { recursive: true });
2195
2260
  } catch {
2196
2261
  }
2197
2262
  }
@@ -2201,11 +2266,11 @@ function nextImportRunDir(session) {
2201
2266
  const match2 = /^dsi-import-(\d+)$/.exec(entry);
2202
2267
  return match2 ? Math.max(max, Number(match2[1])) : max;
2203
2268
  }, 0);
2204
- return join24(session, `dsi-import-${maxRun + 1}`);
2269
+ return join25(session, `dsi-import-${maxRun + 1}`);
2205
2270
  }
2206
2271
  async function startImportRun(projectPath) {
2207
2272
  await startDebugSessionIn(projectPath);
2208
- if (!sessionDir) return join24(resolve26(projectPath), ".contentful");
2273
+ if (!sessionDir) return join25(resolve26(projectPath), ".contentful");
2209
2274
  const dir = nextImportRunDir(sessionDir);
2210
2275
  await mkdir9(dir, { recursive: true });
2211
2276
  return dir;
@@ -2252,10 +2317,10 @@ async function finishDebugRun({
2252
2317
  const root = currentDebugSessionDir();
2253
2318
  if (!root) return;
2254
2319
  const flowSegments = run.flow.split("/");
2255
- const dir = join24(root, ...flowSegments);
2320
+ const dir = join25(root, ...flowSegments);
2256
2321
  await mkdir9(dir, { recursive: true });
2257
2322
  const filename = nextAttemptFilename(dir, run.menuOption);
2258
- await writeFile8(join24(dir, filename), content, { mode: 384 });
2323
+ await writeFile8(join25(dir, filename), content, { mode: 384 });
2259
2324
  }
2260
2325
  function nextAttemptFilename(dir, menuOption) {
2261
2326
  const today = datePrefix();
@@ -2306,9 +2371,27 @@ var init_debug_store = __esm({
2306
2371
  init_config();
2307
2372
  init_version();
2308
2373
  init_debug_mode_store();
2309
- void Promise.all([isDebugModeEnabled(), readBaseDir()]).then(([enabled, base]) => {
2310
- if (!enabled || !base) return void 0;
2311
- return mkdir9(join24(startSession(base, { replace: false }), "debug"), { recursive: true });
2374
+ init_debug_prune();
2375
+ void Promise.all([isDebugModeEnabled(), readBaseDir()]).then(async ([enabled, base]) => {
2376
+ if (!base) return;
2377
+ const retention = await readDebugModeSetting().catch(() => void 0);
2378
+ const pruned = retention ? await pruneExpiredLogs(base, retention.retentionDays).catch(() => void 0) : void 0;
2379
+ if (!enabled) return;
2380
+ const debugDir = join25(startSession(base, { replace: false }), "debug");
2381
+ await mkdir9(debugDir, { recursive: true });
2382
+ if (retention && pruned && pruned.logs + pruned.folders > 0) {
2383
+ await writeFile8(
2384
+ join25(debugDir, `${datePrefix()}-cleanup-${generateRunId()}.md`),
2385
+ `# Debug Log Cleanup
2386
+
2387
+ - Date: ${(/* @__PURE__ */ new Date()).toISOString()}
2388
+ - Retention: ${retention.retentionDays} days
2389
+ - Logs deleted: ${pruned.logs}
2390
+ - Empty folders removed: ${pruned.folders}
2391
+ `,
2392
+ { mode: 384 }
2393
+ );
2394
+ }
2312
2395
  });
2313
2396
  process.once("uncaughtException", (err) => {
2314
2397
  void handleCrash().finally(() => {
@@ -2329,7 +2412,7 @@ var init_debug_store = __esm({
2329
2412
  });
2330
2413
 
2331
2414
  // packages/experience-design-system-cli/app.tsx
2332
- import { join as join26 } from "node:path";
2415
+ import { join as join27 } from "node:path";
2333
2416
  import { useEffect as useEffect27, useState as useState36 } from "react";
2334
2417
 
2335
2418
  // packages/experience-design-system-cli/src/tui/home/home.tsx
@@ -8809,8 +8892,8 @@ function getWorkspacePackageDirs(workspaceRoot) {
8809
8892
  continue;
8810
8893
  const entryPath = join7(dir, entry);
8811
8894
  try {
8812
- const stat5 = statSync3(entryPath);
8813
- if (stat5.isDirectory()) {
8895
+ const stat6 = statSync3(entryPath);
8896
+ if (stat6.isDirectory()) {
8814
8897
  scanDir(entryPath, depth + 1);
8815
8898
  }
8816
8899
  } catch {
@@ -12897,15 +12980,15 @@ function walkProjectTree(dir, result, includeContent) {
12897
12980
  // packages/experience-design-system-backend-pipeline/dist/src/persistence/src/helpers/collect-files/collect-files.js
12898
12981
  function collectFiles(root, options = {}) {
12899
12982
  const resolved = path4.resolve(root);
12900
- let stat5;
12983
+ let stat6;
12901
12984
  try {
12902
- stat5 = statSync4(resolved);
12985
+ stat6 = statSync4(resolved);
12903
12986
  } catch (err) {
12904
12987
  return { ok: false, failure: classifyStatError(err.code), rootPath: resolved };
12905
12988
  }
12906
- if (stat5.isFile())
12989
+ if (stat6.isFile())
12907
12990
  return { ok: false, failure: "is-file", rootPath: resolved };
12908
- if (!stat5.isDirectory())
12991
+ if (!stat6.isDirectory())
12909
12992
  return { ok: false, failure: "not-directory", rootPath: resolved };
12910
12993
  const result = {
12911
12994
  filePaths: [],
@@ -27947,7 +28030,7 @@ init_debug_mode_store();
27947
28030
  init_version();
27948
28031
 
27949
28032
  // packages/experience-design-system-cli/src/tui/help/file-locations.ts
27950
- import { join as join25, resolve as resolve27 } from "node:path";
28033
+ import { join as join26, resolve as resolve27 } from "node:path";
27951
28034
  function describeFileLocations({
27952
28035
  contentfulBaseDir,
27953
28036
  debugModeEnabled,
@@ -27956,14 +28039,14 @@ function describeFileLocations({
27956
28039
  if (!debugModeEnabled) {
27957
28040
  return {
27958
28041
  debugLogs: "none while Debug Mode is off",
27959
- importFiles: `${join25("<project>", ".contentful")}/ (tokens.json, components.json)`
28042
+ importFiles: `${join26("<project>", ".contentful")}/ (tokens.json, components.json)`
27960
28043
  };
27961
28044
  }
27962
28045
  const base = contentfulBaseDir ? resolve27(contentfulBaseDir) : "<project>";
27963
- const session = currentSessionDir2 ?? join25(base, ".contentful", "<date>-session-<n>");
28046
+ const session = currentSessionDir2 ?? join26(base, ".contentful", "<date>-session-<n>");
27964
28047
  return {
27965
- debugLogs: join25(session, "debug"),
27966
- importFiles: `${join25(session, "dsi-import-<n>")}/ (tokens.json, components.json)`
28048
+ debugLogs: join26(session, "debug"),
28049
+ importFiles: `${join26(session, "dsi-import-<n>")}/ (tokens.json, components.json)`
27967
28050
  };
27968
28051
  }
27969
28052
 
@@ -29212,55 +29295,137 @@ function OptInAnalyticsScreen({ onDone }) {
29212
29295
  }
29213
29296
 
29214
29297
  // packages/experience-design-system-cli/src/tui/settings/debug-mode/screen.tsx
29215
- import { useEffect as useEffect26, useState as useState35 } from "react";
29298
+ import { useEffect as useEffect26, useRef as useRef15, useState as useState35 } from "react";
29216
29299
  import { Box as Box50, Text as Text53, useInput as useInput16 } from "ink";
29217
29300
  init_debug_mode_store();
29218
29301
  init_debug_store();
29219
- import { jsx as jsx62, jsxs as jsxs51 } from "react/jsx-runtime";
29302
+ import { Fragment as Fragment21, jsx as jsx62, jsxs as jsxs51 } from "react/jsx-runtime";
29303
+ var ROWS = ["enabled", "retentionDays"];
29304
+ var snapshotOf2 = (setting) => ({
29305
+ enabled: String(setting.enabled),
29306
+ retentionDays: String(setting.retentionDays)
29307
+ });
29220
29308
  function DebugModeScreen({ onDone }) {
29221
- const [loading, setLoading] = useState35(true);
29222
- const [enabled, setEnabled] = useState35(true);
29309
+ const [setting, setSetting] = useState35(null);
29310
+ const [focus, setFocus] = useState35("enabled");
29311
+ const [pending, setPending] = useState35(
29312
+ RETENTION_CHOICES[RETENTION_CHOICES.length - 1]
29313
+ );
29314
+ const [notice, setNotice] = useState35(null);
29315
+ const visit = useRef15({ trail: createTrail(), before: void 0, error: "" }).current;
29223
29316
  useEffect26(() => {
29224
- readDebugModeSetting().then((setting) => {
29225
- setEnabled(setting.enabled);
29226
- setLoading(false);
29317
+ readDebugModeSetting().then((loaded) => {
29318
+ setSetting(loaded);
29319
+ setPending(loaded.retentionDays);
29320
+ visit.before = snapshotOf2(loaded);
29227
29321
  startDebugRun({
29228
29322
  flow: "settings/debug-mode",
29229
29323
  step: "01-debug-mode",
29230
29324
  menuOption: "Debug Mode",
29231
- inputs: { enabled: setting.enabled }
29325
+ inputs: { ...loaded }
29232
29326
  });
29233
29327
  });
29234
29328
  }, []);
29329
+ const save = (patch, saved) => {
29330
+ if (!setting) return;
29331
+ const fields2 = Object.keys(patch).join(", ");
29332
+ writeDebugModeSetting(patch).then(() => {
29333
+ setSetting({ ...setting, ...patch });
29334
+ visit.trail.record(`saved ${fields2}`);
29335
+ setNotice({ kind: "success", text: `Saved: ${saved}` });
29336
+ }).catch((err) => {
29337
+ visit.error = scrubError(err, []);
29338
+ visit.trail.record(`saving ${fields2} failed`);
29339
+ setNotice({ kind: "error", text: `Not saved: ${err instanceof Error ? err.message : String(err)}` });
29340
+ });
29341
+ };
29342
+ const endVisit = (current) => {
29343
+ const change = diffSnapshots(visit.before ?? snapshotOf2(current), snapshotOf2(current));
29344
+ void finishDebugRun({
29345
+ outputs: {
29346
+ ...current,
29347
+ ...change,
29348
+ ...pending !== current.retentionDays ? { unsaved_retention_days: pending } : {},
29349
+ actions: visit.trail.entries(),
29350
+ ...visit.error ? { error: visit.error } : {}
29351
+ },
29352
+ status: visit.error ? "error" : "success",
29353
+ exitMethod: change.changed ? "saved" : "discarded"
29354
+ });
29355
+ };
29235
29356
  useInput16((input, key) => {
29236
- if (loading) return;
29237
- if (key.return || input === " ") {
29238
- setEnabled((current) => {
29239
- const next = !current;
29240
- void writeDebugModeSetting({ enabled: next });
29241
- return next;
29242
- });
29357
+ if (!setting) return;
29358
+ if (key.upArrow || key.downArrow) {
29359
+ setFocus((current) => ROWS[(ROWS.indexOf(current) + (key.downArrow ? 1 : ROWS.length - 1)) % ROWS.length]);
29360
+ setNotice(null);
29361
+ return;
29362
+ }
29363
+ if ((key.leftArrow || key.rightArrow) && focus === "retentionDays") {
29364
+ const index = RETENTION_CHOICES.indexOf(pending) + (key.rightArrow ? 1 : -1);
29365
+ setPending(RETENTION_CHOICES[Math.min(Math.max(index, 0), RETENTION_CHOICES.length - 1)]);
29366
+ setNotice(null);
29367
+ return;
29368
+ }
29369
+ if (focus === "enabled" && (key.return || input === " ")) {
29370
+ const enabled = !setting.enabled;
29371
+ save({ enabled }, `debug logging is ${enabled ? "on" : "off"}`);
29372
+ return;
29373
+ }
29374
+ if (focus === "retentionDays" && key.return) {
29375
+ save({ retentionDays: pending }, `logs are deleted after ${pending} days`);
29243
29376
  return;
29244
29377
  }
29245
29378
  if (key.escape || input === "q") {
29246
- void finishDebugRun({ outputs: { enabled }, status: "success", exitMethod: "saved" });
29379
+ endVisit(setting);
29247
29380
  onDone();
29248
29381
  }
29249
29382
  });
29383
+ const marker = (row) => /* @__PURE__ */ jsx62(Text53, { color: focus === row ? PALETTE.accent : void 0, children: focus === row ? "\u276F" : " " });
29384
+ const label = (row, text) => /* @__PURE__ */ jsx62(Text53, { bold: focus === row, color: focus === row ? PALETTE.accent : PALETTE.muted, children: text });
29250
29385
  return /* @__PURE__ */ jsxs51(Box50, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [
29251
29386
  /* @__PURE__ */ jsx62(Text53, { bold: true, children: "Settings \u203A Debug Mode" }),
29252
29387
  /* @__PURE__ */ jsx62(Text53, { children: " " }),
29253
- loading ? /* @__PURE__ */ jsx62(Text53, { color: PALETTE.muted, children: "Loading\u2026" }) : /* @__PURE__ */ jsxs51(Text53, { children: [
29254
- "Debug logging:",
29255
- " ",
29256
- /* @__PURE__ */ jsx62(Text53, { bold: true, color: enabled ? PALETTE.success : PALETTE.muted, children: enabled ? "On" : "Off" })
29257
- ] }),
29388
+ setting ? /* @__PURE__ */ jsxs51(Fragment21, { children: [
29389
+ /* @__PURE__ */ jsxs51(Box50, { gap: 1, children: [
29390
+ marker("enabled"),
29391
+ label("enabled", "Debug logging:"),
29392
+ /* @__PURE__ */ jsx62(Text53, { bold: true, color: setting.enabled ? PALETTE.success : PALETTE.muted, children: setting.enabled ? "On" : "Off" })
29393
+ ] }),
29394
+ /* @__PURE__ */ jsxs51(Box50, { gap: 1, children: [
29395
+ marker("retentionDays"),
29396
+ label("retentionDays", "Delete logs after:"),
29397
+ RETENTION_CHOICES.map((days) => {
29398
+ const highlighted = focus === "retentionDays" && days === pending;
29399
+ const saved = days === setting.retentionDays;
29400
+ return /* @__PURE__ */ jsx62(
29401
+ Text53,
29402
+ {
29403
+ bold: highlighted || saved,
29404
+ underline: highlighted,
29405
+ color: highlighted ? PALETTE.accent : saved ? PALETTE.success : PALETTE.muted,
29406
+ children: `${saved ? "\u2713 " : ""}${days} days`
29407
+ },
29408
+ days
29409
+ );
29410
+ })
29411
+ ] }),
29412
+ /* @__PURE__ */ jsx62(Text53, { children: " " }),
29413
+ notice ? /* @__PURE__ */ jsxs51(Text53, { color: notice.kind === "success" ? PALETTE.success : PALETTE.error, children: [
29414
+ notice.kind === "success" ? "\u2713" : "\u2717",
29415
+ " ",
29416
+ notice.text
29417
+ ] }) : /* @__PURE__ */ jsx62(Text53, { color: PALETTE.muted, children: "\u2713 marks what is saved. Older logs are deleted the next time the CLI starts." })
29418
+ ] }) : /* @__PURE__ */ jsx62(Text53, { color: PALETTE.muted, children: "Loading\u2026" }),
29258
29419
  /* @__PURE__ */ jsx62(Text53, { children: " " }),
29259
29420
  /* @__PURE__ */ jsx62(
29260
29421
  ControlHints,
29261
29422
  {
29262
29423
  hints: [
29263
- { keys: "\u23CE/Space", label: "toggle" },
29424
+ { keys: "\u2191/\u2193", label: "move" },
29425
+ ...focus === "retentionDays" ? [
29426
+ { keys: "\u2190/\u2192", label: "choose" },
29427
+ { keys: "\u23CE", label: "save" }
29428
+ ] : [{ keys: "\u23CE/Space", label: "toggle" }],
29264
29429
  { keys: "Esc/q", label: "back" }
29265
29430
  ]
29266
29431
  }
@@ -29269,7 +29434,7 @@ function DebugModeScreen({ onDone }) {
29269
29434
  }
29270
29435
 
29271
29436
  // packages/experience-design-system-cli/app.tsx
29272
- import { Fragment as Fragment21, jsx as jsx63 } from "react/jsx-runtime";
29437
+ import { Fragment as Fragment22, jsx as jsx63 } from "react/jsx-runtime";
29273
29438
  function App({ importOptions, inkClear }) {
29274
29439
  const [screen, setScreen] = useState36("start");
29275
29440
  const [importExitCode, setImportExitCode] = useState36();
@@ -29318,7 +29483,7 @@ function App({ importOptions, inkClear }) {
29318
29483
  const launch = { projectPath: projectPath2, tokens, filePaths, ...importOptions };
29319
29484
  const state2 = await inspectTokens({
29320
29485
  rawTokensPath: tokens,
29321
- contentfulDir: join26(resolveUserPath(projectPath2), ".contentful"),
29486
+ contentfulDir: join27(resolveUserPath(projectPath2), ".contentful"),
29322
29487
  cache: importOptions.cache
29323
29488
  });
29324
29489
  if (state2.kind === "cached") {
@@ -29438,7 +29603,7 @@ function App({ importOptions, inkClear }) {
29438
29603
  }
29439
29604
  );
29440
29605
  }
29441
- if (importDefaults === void 0) return /* @__PURE__ */ jsx63(Fragment21, {});
29606
+ if (importDefaults === void 0) return /* @__PURE__ */ jsx63(Fragment22, {});
29442
29607
  if (projectPath === void 0) {
29443
29608
  return /* @__PURE__ */ jsx63(WelcomeScreen, { onContinue: setProjectPath, onQuit: leaveImport, initialPath: importDefaults.componentDir });
29444
29609
  }
@@ -29477,7 +29642,7 @@ function App({ importOptions, inkClear }) {
29477
29642
  }
29478
29643
  );
29479
29644
  }
29480
- return /* @__PURE__ */ jsx63(Fragment21, {});
29645
+ return /* @__PURE__ */ jsx63(Fragment22, {});
29481
29646
  }
29482
29647
  if (scopeRun && scopeFlow) {
29483
29648
  if (scopeFlow.status === "failed") {
@@ -29514,7 +29679,7 @@ function App({ importOptions, inkClear }) {
29514
29679
  }
29515
29680
  );
29516
29681
  }
29517
- return /* @__PURE__ */ jsx63(Fragment21, {});
29682
+ return /* @__PURE__ */ jsx63(Fragment22, {});
29518
29683
  }
29519
29684
  if (pendingLaunch?.cached) {
29520
29685
  return /* @__PURE__ */ jsx63(
package/dist/index.js CHANGED
@@ -8266,8 +8266,8 @@ function getWorkspacePackageDirs(workspaceRoot) {
8266
8266
  continue;
8267
8267
  const entryPath = join5(dir, entry);
8268
8268
  try {
8269
- const stat5 = statSync2(entryPath);
8270
- if (stat5.isDirectory()) {
8269
+ const stat6 = statSync2(entryPath);
8270
+ if (stat6.isDirectory()) {
8271
8271
  scanDir(entryPath, depth + 1);
8272
8272
  }
8273
8273
  } catch {
@@ -12911,15 +12911,15 @@ import { statSync as statSync3 } from "node:fs";
12911
12911
  import path4 from "node:path";
12912
12912
  function collectFiles(root, options = {}) {
12913
12913
  const resolved = path4.resolve(root);
12914
- let stat5;
12914
+ let stat6;
12915
12915
  try {
12916
- stat5 = statSync3(resolved);
12916
+ stat6 = statSync3(resolved);
12917
12917
  } catch (err) {
12918
12918
  return { ok: false, failure: classifyStatError(err.code), rootPath: resolved };
12919
12919
  }
12920
- if (stat5.isFile())
12920
+ if (stat6.isFile())
12921
12921
  return { ok: false, failure: "is-file", rootPath: resolved };
12922
- if (!stat5.isDirectory())
12922
+ if (!stat6.isDirectory())
12923
12923
  return { ok: false, failure: "not-directory", rootPath: resolved };
12924
12924
  const result = {
12925
12925
  filePaths: [],
@@ -31283,21 +31283,86 @@ var init_use_flow = __esm({
31283
31283
  });
31284
31284
 
31285
31285
  // packages/experience-design-system-cli/src/tui/settings/debug-mode/debug-mode-store.ts
31286
+ function toRetentionDays(value) {
31287
+ return RETENTION_CHOICES.find((choice) => choice === value) ?? DEFAULT_RETENTION_DAYS;
31288
+ }
31286
31289
  async function readDebugModeSetting() {
31287
31290
  const { debugMode } = await readSettings2();
31288
- return { ...DEFAULT_DEBUG_MODE_SETTING, ...debugMode };
31291
+ const saved = debugMode ?? {};
31292
+ return {
31293
+ enabled: typeof saved.enabled === "boolean" ? saved.enabled : true,
31294
+ retentionDays: toRetentionDays(saved.retentionDays)
31295
+ };
31289
31296
  }
31290
- async function writeDebugModeSetting(setting) {
31291
- await updateSettings2({ debugMode: setting });
31297
+ async function writeDebugModeSetting(change) {
31298
+ await updateSettings2({ debugMode: { ...await readDebugModeSetting(), ...change } });
31292
31299
  }
31293
- var DEFAULT_DEBUG_MODE_SETTING;
31300
+ var RETENTION_CHOICES, DEFAULT_RETENTION_DAYS;
31294
31301
  var init_debug_mode_store = __esm({
31295
31302
  "packages/experience-design-system-cli/src/tui/settings/debug-mode/debug-mode-store.ts"() {
31296
31303
  "use strict";
31297
31304
  init_config();
31298
- DEFAULT_DEBUG_MODE_SETTING = {
31299
- enabled: true
31300
- };
31305
+ RETENTION_CHOICES = [7, 14, 30];
31306
+ DEFAULT_RETENTION_DAYS = 30;
31307
+ }
31308
+ });
31309
+
31310
+ // packages/experience-design-system-cli/src/tui/debug-prune.ts
31311
+ import { readdir as readdir3, rm, rmdir, stat as stat5 } from "node:fs/promises";
31312
+ import { dirname as dirname16, join as join25 } from "node:path";
31313
+ async function logFilesIn(dir) {
31314
+ const entries = await readdir3(dir, { withFileTypes: true });
31315
+ const nested = await Promise.all(
31316
+ entries.map(async (entry) => {
31317
+ const path5 = join25(dir, entry.name);
31318
+ if (entry.isDirectory()) return logFilesIn(path5);
31319
+ return entry.isFile() && entry.name.endsWith(".md") ? [path5] : [];
31320
+ })
31321
+ );
31322
+ return nested.flat();
31323
+ }
31324
+ async function removeEmptyFolders(from, stop) {
31325
+ let dir = from;
31326
+ let removed = 0;
31327
+ for (; ; ) {
31328
+ try {
31329
+ await rmdir(dir);
31330
+ } catch {
31331
+ return removed;
31332
+ }
31333
+ removed += 1;
31334
+ if (dir === stop) return removed;
31335
+ dir = dirname16(dir);
31336
+ }
31337
+ }
31338
+ async function pruneExpiredLogs(base, retentionDays, now = Date.now()) {
31339
+ const cutoff = now - retentionDays * DAY_MS;
31340
+ const contentfulDir = join25(base, ".contentful");
31341
+ const result = { logs: 0, folders: 0 };
31342
+ try {
31343
+ const sessions = (await readdir3(contentfulDir)).filter((name) => SESSION_FOLDER.test(name));
31344
+ for (const session of sessions) {
31345
+ const files = await logFilesIn(join25(contentfulDir, session, "debug")).catch(() => []);
31346
+ for (const file of files) {
31347
+ try {
31348
+ if ((await stat5(file)).mtimeMs >= cutoff) continue;
31349
+ await rm(file);
31350
+ result.logs += 1;
31351
+ result.folders += await removeEmptyFolders(dirname16(file), join25(contentfulDir, session));
31352
+ } catch {
31353
+ }
31354
+ }
31355
+ }
31356
+ } catch {
31357
+ }
31358
+ return result;
31359
+ }
31360
+ var DAY_MS, SESSION_FOLDER;
31361
+ var init_debug_prune = __esm({
31362
+ "packages/experience-design-system-cli/src/tui/debug-prune.ts"() {
31363
+ "use strict";
31364
+ DAY_MS = 24 * 60 * 60 * 1e3;
31365
+ SESSION_FOLDER = /^\d{2}-\d{2}-\d{4}-session-\d+$/;
31301
31366
  }
31302
31367
  });
31303
31368
 
@@ -31313,7 +31378,7 @@ __export(debug_store_exports, {
31313
31378
  });
31314
31379
  import { mkdir as mkdir9, writeFile as writeFile8 } from "node:fs/promises";
31315
31380
  import { existsSync as existsSync10, readdirSync as readdirSync4 } from "node:fs";
31316
- import { join as join25, resolve as resolve26 } from "node:path";
31381
+ import { join as join26, resolve as resolve26 } from "node:path";
31317
31382
  function generateRunId() {
31318
31383
  const now = /* @__PURE__ */ new Date();
31319
31384
  const pad = (n) => String(n).padStart(2, "0");
@@ -31345,12 +31410,12 @@ function nextSessionId(contentfulDir) {
31345
31410
  return `${today}-session-${maxSeq + 1}`;
31346
31411
  }
31347
31412
  function startSession(base, { replace }) {
31348
- const contentfulDir = join25(base, ".contentful");
31349
- if (replace || !sessionDir) sessionDir = join25(contentfulDir, nextSessionId(contentfulDir));
31413
+ const contentfulDir = join26(base, ".contentful");
31414
+ if (replace || !sessionDir) sessionDir = join26(contentfulDir, nextSessionId(contentfulDir));
31350
31415
  return sessionDir;
31351
31416
  }
31352
31417
  function currentDebugSessionDir() {
31353
- return sessionDir && join25(sessionDir, "debug");
31418
+ return sessionDir && join26(sessionDir, "debug");
31354
31419
  }
31355
31420
  function currentSessionDir() {
31356
31421
  return sessionDir;
@@ -31358,7 +31423,7 @@ function currentSessionDir() {
31358
31423
  async function startDebugSessionIn(base, { replace = false } = {}) {
31359
31424
  try {
31360
31425
  if (!await isDebugModeEnabled()) return;
31361
- await mkdir9(join25(startSession(resolve26(base), { replace }), "debug"), { recursive: true });
31426
+ await mkdir9(join26(startSession(resolve26(base), { replace }), "debug"), { recursive: true });
31362
31427
  } catch {
31363
31428
  }
31364
31429
  }
@@ -31368,11 +31433,11 @@ function nextImportRunDir(session) {
31368
31433
  const match2 = /^dsi-import-(\d+)$/.exec(entry);
31369
31434
  return match2 ? Math.max(max, Number(match2[1])) : max;
31370
31435
  }, 0);
31371
- return join25(session, `dsi-import-${maxRun + 1}`);
31436
+ return join26(session, `dsi-import-${maxRun + 1}`);
31372
31437
  }
31373
31438
  async function startImportRun(projectPath) {
31374
31439
  await startDebugSessionIn(projectPath);
31375
- if (!sessionDir) return join25(resolve26(projectPath), ".contentful");
31440
+ if (!sessionDir) return join26(resolve26(projectPath), ".contentful");
31376
31441
  const dir = nextImportRunDir(sessionDir);
31377
31442
  await mkdir9(dir, { recursive: true });
31378
31443
  return dir;
@@ -31419,10 +31484,10 @@ async function finishDebugRun({
31419
31484
  const root = currentDebugSessionDir();
31420
31485
  if (!root) return;
31421
31486
  const flowSegments = run.flow.split("/");
31422
- const dir = join25(root, ...flowSegments);
31487
+ const dir = join26(root, ...flowSegments);
31423
31488
  await mkdir9(dir, { recursive: true });
31424
31489
  const filename = nextAttemptFilename(dir, run.menuOption);
31425
- await writeFile8(join25(dir, filename), content, { mode: 384 });
31490
+ await writeFile8(join26(dir, filename), content, { mode: 384 });
31426
31491
  }
31427
31492
  function nextAttemptFilename(dir, menuOption) {
31428
31493
  const today = datePrefix();
@@ -31473,9 +31538,27 @@ var init_debug_store = __esm({
31473
31538
  init_config();
31474
31539
  init_version();
31475
31540
  init_debug_mode_store();
31476
- void Promise.all([isDebugModeEnabled(), readBaseDir()]).then(([enabled, base]) => {
31477
- if (!enabled || !base) return void 0;
31478
- return mkdir9(join25(startSession(base, { replace: false }), "debug"), { recursive: true });
31541
+ init_debug_prune();
31542
+ void Promise.all([isDebugModeEnabled(), readBaseDir()]).then(async ([enabled, base]) => {
31543
+ if (!base) return;
31544
+ const retention = await readDebugModeSetting().catch(() => void 0);
31545
+ const pruned = retention ? await pruneExpiredLogs(base, retention.retentionDays).catch(() => void 0) : void 0;
31546
+ if (!enabled) return;
31547
+ const debugDir = join26(startSession(base, { replace: false }), "debug");
31548
+ await mkdir9(debugDir, { recursive: true });
31549
+ if (retention && pruned && pruned.logs + pruned.folders > 0) {
31550
+ await writeFile8(
31551
+ join26(debugDir, `${datePrefix()}-cleanup-${generateRunId()}.md`),
31552
+ `# Debug Log Cleanup
31553
+
31554
+ - Date: ${(/* @__PURE__ */ new Date()).toISOString()}
31555
+ - Retention: ${retention.retentionDays} days
31556
+ - Logs deleted: ${pruned.logs}
31557
+ - Empty folders removed: ${pruned.folders}
31558
+ `,
31559
+ { mode: 384 }
31560
+ );
31561
+ }
31479
31562
  });
31480
31563
  process.once("uncaughtException", (err) => {
31481
31564
  void handleCrash().finally(() => {
@@ -31496,7 +31579,7 @@ var init_debug_store = __esm({
31496
31579
  });
31497
31580
 
31498
31581
  // packages/experience-design-system-cli/src/tui/help/file-locations.ts
31499
- import { join as join26, resolve as resolve27 } from "node:path";
31582
+ import { join as join27, resolve as resolve27 } from "node:path";
31500
31583
  function describeFileLocations({
31501
31584
  contentfulBaseDir,
31502
31585
  debugModeEnabled,
@@ -31505,14 +31588,14 @@ function describeFileLocations({
31505
31588
  if (!debugModeEnabled) {
31506
31589
  return {
31507
31590
  debugLogs: "none while Debug Mode is off",
31508
- importFiles: `${join26("<project>", ".contentful")}/ (tokens.json, components.json)`
31591
+ importFiles: `${join27("<project>", ".contentful")}/ (tokens.json, components.json)`
31509
31592
  };
31510
31593
  }
31511
31594
  const base = contentfulBaseDir ? resolve27(contentfulBaseDir) : "<project>";
31512
- const session = currentSessionDir2 ?? join26(base, ".contentful", "<date>-session-<n>");
31595
+ const session = currentSessionDir2 ?? join27(base, ".contentful", "<date>-session-<n>");
31513
31596
  return {
31514
- debugLogs: join26(session, "debug"),
31515
- importFiles: `${join26(session, "dsi-import-<n>")}/ (tokens.json, components.json)`
31597
+ debugLogs: join27(session, "debug"),
31598
+ importFiles: `${join27(session, "dsi-import-<n>")}/ (tokens.json, components.json)`
31516
31599
  };
31517
31600
  }
31518
31601
  var init_file_locations = __esm({
@@ -32792,59 +32875,137 @@ var init_screen11 = __esm({
32792
32875
  });
32793
32876
 
32794
32877
  // packages/experience-design-system-cli/src/tui/settings/debug-mode/screen.tsx
32795
- import { useEffect as useEffect26, useState as useState35 } from "react";
32878
+ import { useEffect as useEffect26, useRef as useRef15, useState as useState35 } from "react";
32796
32879
  import { Box as Box50, Text as Text53, useInput as useInput16 } from "ink";
32797
- import { jsx as jsx62, jsxs as jsxs51 } from "react/jsx-runtime";
32880
+ import { Fragment as Fragment21, jsx as jsx62, jsxs as jsxs51 } from "react/jsx-runtime";
32798
32881
  function DebugModeScreen({ onDone }) {
32799
- const [loading, setLoading] = useState35(true);
32800
- const [enabled, setEnabled] = useState35(true);
32882
+ const [setting, setSetting] = useState35(null);
32883
+ const [focus, setFocus] = useState35("enabled");
32884
+ const [pending, setPending] = useState35(
32885
+ RETENTION_CHOICES[RETENTION_CHOICES.length - 1]
32886
+ );
32887
+ const [notice, setNotice] = useState35(null);
32888
+ const visit = useRef15({ trail: createTrail(), before: void 0, error: "" }).current;
32801
32889
  useEffect26(() => {
32802
- readDebugModeSetting().then((setting) => {
32803
- setEnabled(setting.enabled);
32804
- setLoading(false);
32890
+ readDebugModeSetting().then((loaded) => {
32891
+ setSetting(loaded);
32892
+ setPending(loaded.retentionDays);
32893
+ visit.before = snapshotOf2(loaded);
32805
32894
  startDebugRun({
32806
32895
  flow: "settings/debug-mode",
32807
32896
  step: "01-debug-mode",
32808
32897
  menuOption: "Debug Mode",
32809
- inputs: { enabled: setting.enabled }
32898
+ inputs: { ...loaded }
32810
32899
  });
32811
32900
  });
32812
32901
  }, []);
32902
+ const save = (patch, saved) => {
32903
+ if (!setting) return;
32904
+ const fields2 = Object.keys(patch).join(", ");
32905
+ writeDebugModeSetting(patch).then(() => {
32906
+ setSetting({ ...setting, ...patch });
32907
+ visit.trail.record(`saved ${fields2}`);
32908
+ setNotice({ kind: "success", text: `Saved: ${saved}` });
32909
+ }).catch((err) => {
32910
+ visit.error = scrubError(err, []);
32911
+ visit.trail.record(`saving ${fields2} failed`);
32912
+ setNotice({ kind: "error", text: `Not saved: ${err instanceof Error ? err.message : String(err)}` });
32913
+ });
32914
+ };
32915
+ const endVisit = (current) => {
32916
+ const change = diffSnapshots(visit.before ?? snapshotOf2(current), snapshotOf2(current));
32917
+ void finishDebugRun({
32918
+ outputs: {
32919
+ ...current,
32920
+ ...change,
32921
+ ...pending !== current.retentionDays ? { unsaved_retention_days: pending } : {},
32922
+ actions: visit.trail.entries(),
32923
+ ...visit.error ? { error: visit.error } : {}
32924
+ },
32925
+ status: visit.error ? "error" : "success",
32926
+ exitMethod: change.changed ? "saved" : "discarded"
32927
+ });
32928
+ };
32813
32929
  useInput16((input, key) => {
32814
- if (loading) return;
32815
- if (key.return || input === " ") {
32816
- setEnabled((current) => {
32817
- const next = !current;
32818
- void writeDebugModeSetting({ enabled: next });
32819
- return next;
32820
- });
32930
+ if (!setting) return;
32931
+ if (key.upArrow || key.downArrow) {
32932
+ setFocus((current) => ROWS[(ROWS.indexOf(current) + (key.downArrow ? 1 : ROWS.length - 1)) % ROWS.length]);
32933
+ setNotice(null);
32934
+ return;
32935
+ }
32936
+ if ((key.leftArrow || key.rightArrow) && focus === "retentionDays") {
32937
+ const index = RETENTION_CHOICES.indexOf(pending) + (key.rightArrow ? 1 : -1);
32938
+ setPending(RETENTION_CHOICES[Math.min(Math.max(index, 0), RETENTION_CHOICES.length - 1)]);
32939
+ setNotice(null);
32940
+ return;
32941
+ }
32942
+ if (focus === "enabled" && (key.return || input === " ")) {
32943
+ const enabled = !setting.enabled;
32944
+ save({ enabled }, `debug logging is ${enabled ? "on" : "off"}`);
32945
+ return;
32946
+ }
32947
+ if (focus === "retentionDays" && key.return) {
32948
+ save({ retentionDays: pending }, `logs are deleted after ${pending} days`);
32821
32949
  return;
32822
32950
  }
32823
32951
  if (key.escape || input === "q") {
32824
- void finishDebugRun({ outputs: { enabled }, status: "success", exitMethod: "saved" });
32952
+ endVisit(setting);
32825
32953
  onDone();
32826
32954
  }
32827
32955
  });
32956
+ const marker = (row) => /* @__PURE__ */ jsx62(Text53, { color: focus === row ? PALETTE.accent : void 0, children: focus === row ? "\u276F" : " " });
32957
+ const label = (row, text) => /* @__PURE__ */ jsx62(Text53, { bold: focus === row, color: focus === row ? PALETTE.accent : PALETTE.muted, children: text });
32828
32958
  return /* @__PURE__ */ jsxs51(Box50, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [
32829
32959
  /* @__PURE__ */ jsx62(Text53, { bold: true, children: "Settings \u203A Debug Mode" }),
32830
32960
  /* @__PURE__ */ jsx62(Text53, { children: " " }),
32831
- loading ? /* @__PURE__ */ jsx62(Text53, { color: PALETTE.muted, children: "Loading\u2026" }) : /* @__PURE__ */ jsxs51(Text53, { children: [
32832
- "Debug logging:",
32833
- " ",
32834
- /* @__PURE__ */ jsx62(Text53, { bold: true, color: enabled ? PALETTE.success : PALETTE.muted, children: enabled ? "On" : "Off" })
32835
- ] }),
32961
+ setting ? /* @__PURE__ */ jsxs51(Fragment21, { children: [
32962
+ /* @__PURE__ */ jsxs51(Box50, { gap: 1, children: [
32963
+ marker("enabled"),
32964
+ label("enabled", "Debug logging:"),
32965
+ /* @__PURE__ */ jsx62(Text53, { bold: true, color: setting.enabled ? PALETTE.success : PALETTE.muted, children: setting.enabled ? "On" : "Off" })
32966
+ ] }),
32967
+ /* @__PURE__ */ jsxs51(Box50, { gap: 1, children: [
32968
+ marker("retentionDays"),
32969
+ label("retentionDays", "Delete logs after:"),
32970
+ RETENTION_CHOICES.map((days) => {
32971
+ const highlighted = focus === "retentionDays" && days === pending;
32972
+ const saved = days === setting.retentionDays;
32973
+ return /* @__PURE__ */ jsx62(
32974
+ Text53,
32975
+ {
32976
+ bold: highlighted || saved,
32977
+ underline: highlighted,
32978
+ color: highlighted ? PALETTE.accent : saved ? PALETTE.success : PALETTE.muted,
32979
+ children: `${saved ? "\u2713 " : ""}${days} days`
32980
+ },
32981
+ days
32982
+ );
32983
+ })
32984
+ ] }),
32985
+ /* @__PURE__ */ jsx62(Text53, { children: " " }),
32986
+ notice ? /* @__PURE__ */ jsxs51(Text53, { color: notice.kind === "success" ? PALETTE.success : PALETTE.error, children: [
32987
+ notice.kind === "success" ? "\u2713" : "\u2717",
32988
+ " ",
32989
+ notice.text
32990
+ ] }) : /* @__PURE__ */ jsx62(Text53, { color: PALETTE.muted, children: "\u2713 marks what is saved. Older logs are deleted the next time the CLI starts." })
32991
+ ] }) : /* @__PURE__ */ jsx62(Text53, { color: PALETTE.muted, children: "Loading\u2026" }),
32836
32992
  /* @__PURE__ */ jsx62(Text53, { children: " " }),
32837
32993
  /* @__PURE__ */ jsx62(
32838
32994
  ControlHints,
32839
32995
  {
32840
32996
  hints: [
32841
- { keys: "\u23CE/Space", label: "toggle" },
32997
+ { keys: "\u2191/\u2193", label: "move" },
32998
+ ...focus === "retentionDays" ? [
32999
+ { keys: "\u2190/\u2192", label: "choose" },
33000
+ { keys: "\u23CE", label: "save" }
33001
+ ] : [{ keys: "\u23CE/Space", label: "toggle" }],
32842
33002
  { keys: "Esc/q", label: "back" }
32843
33003
  ]
32844
33004
  }
32845
33005
  )
32846
33006
  ] });
32847
33007
  }
33008
+ var ROWS, snapshotOf2;
32848
33009
  var init_screen12 = __esm({
32849
33010
  "packages/experience-design-system-cli/src/tui/settings/debug-mode/screen.tsx"() {
32850
33011
  "use strict";
@@ -32852,6 +33013,12 @@ var init_screen12 = __esm({
32852
33013
  init_debug_mode_store();
32853
33014
  init_debug_store();
32854
33015
  init_control_hints();
33016
+ init_debug_trail();
33017
+ ROWS = ["enabled", "retentionDays"];
33018
+ snapshotOf2 = (setting) => ({
33019
+ enabled: String(setting.enabled),
33020
+ retentionDays: String(setting.retentionDays)
33021
+ });
32855
33022
  }
32856
33023
  });
32857
33024
 
@@ -32860,9 +33027,9 @@ var app_exports = {};
32860
33027
  __export(app_exports, {
32861
33028
  runApp: () => runApp
32862
33029
  });
32863
- import { join as join27 } from "node:path";
33030
+ import { join as join28 } from "node:path";
32864
33031
  import { useEffect as useEffect27, useState as useState36 } from "react";
32865
- import { Fragment as Fragment21, jsx as jsx63 } from "react/jsx-runtime";
33032
+ import { Fragment as Fragment22, jsx as jsx63 } from "react/jsx-runtime";
32866
33033
  function App({ importOptions, inkClear }) {
32867
33034
  const [screen, setScreen] = useState36("start");
32868
33035
  const [importExitCode, setImportExitCode] = useState36();
@@ -32911,7 +33078,7 @@ function App({ importOptions, inkClear }) {
32911
33078
  const launch = { projectPath: projectPath2, tokens, filePaths, ...importOptions };
32912
33079
  const state2 = await inspectTokens({
32913
33080
  rawTokensPath: tokens,
32914
- contentfulDir: join27(resolveUserPath(projectPath2), ".contentful"),
33081
+ contentfulDir: join28(resolveUserPath(projectPath2), ".contentful"),
32915
33082
  cache: importOptions.cache
32916
33083
  });
32917
33084
  if (state2.kind === "cached") {
@@ -33031,7 +33198,7 @@ function App({ importOptions, inkClear }) {
33031
33198
  }
33032
33199
  );
33033
33200
  }
33034
- if (importDefaults === void 0) return /* @__PURE__ */ jsx63(Fragment21, {});
33201
+ if (importDefaults === void 0) return /* @__PURE__ */ jsx63(Fragment22, {});
33035
33202
  if (projectPath === void 0) {
33036
33203
  return /* @__PURE__ */ jsx63(WelcomeScreen, { onContinue: setProjectPath, onQuit: leaveImport, initialPath: importDefaults.componentDir });
33037
33204
  }
@@ -33070,7 +33237,7 @@ function App({ importOptions, inkClear }) {
33070
33237
  }
33071
33238
  );
33072
33239
  }
33073
- return /* @__PURE__ */ jsx63(Fragment21, {});
33240
+ return /* @__PURE__ */ jsx63(Fragment22, {});
33074
33241
  }
33075
33242
  if (scopeRun && scopeFlow) {
33076
33243
  if (scopeFlow.status === "failed") {
@@ -33107,7 +33274,7 @@ function App({ importOptions, inkClear }) {
33107
33274
  }
33108
33275
  );
33109
33276
  }
33110
- return /* @__PURE__ */ jsx63(Fragment21, {});
33277
+ return /* @__PURE__ */ jsx63(Fragment22, {});
33111
33278
  }
33112
33279
  if (pendingLaunch?.cached) {
33113
33280
  return /* @__PURE__ */ jsx63(
@@ -33182,7 +33349,7 @@ var init_app = __esm({
33182
33349
  // packages/experience-design-system-cli/program.ts
33183
33350
  init_src3();
33184
33351
  import { readFileSync as readFileSync9 } from "node:fs";
33185
- import { join as join28 } from "node:path";
33352
+ import { join as join29 } from "node:path";
33186
33353
  import { Command } from "commander";
33187
33354
 
33188
33355
  // packages/experience-design-system-cli/src/commands/import-options.ts
@@ -33248,7 +33415,7 @@ init_analytics_store();
33248
33415
  init_package_root();
33249
33416
  var pkg = JSON.parse(
33250
33417
  readFileSync9(
33251
- join28(findPackageRoot(import.meta.url, "@contentful/experience-design-system-cli"), "package.json"),
33418
+ join29(findPackageRoot(import.meta.url, "@contentful/experience-design-system-cli"), "package.json"),
33252
33419
  "utf8"
33253
33420
  )
33254
33421
  );
@@ -33288,8 +33455,8 @@ function createProgram() {
33288
33455
  init_config();
33289
33456
  init_package_root();
33290
33457
  import { existsSync as existsSync12 } from "node:fs";
33291
- import { mkdir as mkdir10, readFile as readFile19, rename as rename3, rmdir, unlink } from "node:fs/promises";
33292
- import { dirname as dirname16, join as join29 } from "node:path";
33458
+ import { mkdir as mkdir10, readFile as readFile19, rename as rename3, rmdir as rmdir2, unlink } from "node:fs/promises";
33459
+ import { dirname as dirname17, join as join30 } from "node:path";
33293
33460
  var PACKAGE_NAME3 = "@contentful/experience-design-system-cli";
33294
33461
  async function readJson(path5) {
33295
33462
  try {
@@ -33300,9 +33467,9 @@ async function readJson(path5) {
33300
33467
  }
33301
33468
  async function migrateOldConfig() {
33302
33469
  try {
33303
- const oldCredentials = join29(oldConfigDir2(), "credentials.json");
33304
- const oldRuns = join29(oldConfigDir2(), "runs.json");
33305
- const oldDebugMode = join29(
33470
+ const oldCredentials = join30(oldConfigDir2(), "credentials.json");
33471
+ const oldRuns = join30(oldConfigDir2(), "runs.json");
33472
+ const oldDebugMode = join30(
33306
33473
  findPackageRoot(import.meta.url, PACKAGE_NAME3),
33307
33474
  ".contentful",
33308
33475
  "config",
@@ -33315,14 +33482,14 @@ async function migrateOldConfig() {
33315
33482
  if (Object.keys(migrated).length > 0) await updateSettings2({ ...migrated, ...await readSettings2() });
33316
33483
  if (existsSync12(oldRuns)) {
33317
33484
  if (!existsSync12(runsFilePath2())) {
33318
- await mkdir10(dirname16(runsFilePath2()), { recursive: true });
33485
+ await mkdir10(dirname17(runsFilePath2()), { recursive: true });
33319
33486
  await rename3(oldRuns, runsFilePath2());
33320
33487
  } else {
33321
33488
  await unlink(oldRuns);
33322
33489
  }
33323
33490
  }
33324
33491
  await Promise.all([oldCredentials, oldDebugMode].map((f) => unlink(f).catch(() => void 0)));
33325
- await rmdir(oldConfigDir2()).catch(() => void 0);
33492
+ await rmdir2(oldConfigDir2()).catch(() => void 0);
33326
33493
  } catch {
33327
33494
  }
33328
33495
  }
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contentful/experience-design-system-cli",
3
- "version": "2.37.1-dev-build-4e7e3ced.0",
3
+ "version": "2.37.1-dev-build-81dbe125.0",
4
4
  "description": "Contentful Experiences design system import CLI",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -0,0 +1,12 @@
1
+ export type PruneResult = {
2
+ logs: number;
3
+ folders: number;
4
+ };
5
+ /**
6
+ * Deletes the debug logs under `<base>/.contentful` that are older than `retentionDays`. It only looks at `.md` files
7
+ * inside the `debug` folder of a session folder, so nothing the import produced or the user put there is touched. A file
8
+ * that cannot be read or deleted is skipped: this runs at startup and must never get in the user's way. A folder the
9
+ * deletion left empty is removed too, up to the session folder; one that still holds anything stays. Returns how many
10
+ * logs and folders it deleted.
11
+ */
12
+ export declare function pruneExpiredLogs(base: string, retentionDays: number, now?: number): Promise<PruneResult>;
@@ -1,5 +1,11 @@
1
+ /** How long a debug log is kept before the CLI deletes it. Only these values are offered. */
2
+ export declare const RETENTION_CHOICES: readonly [7, 14, 30];
3
+ type RetentionDays = (typeof RETENTION_CHOICES)[number];
1
4
  export type DebugModeSetting = {
2
5
  enabled: boolean;
6
+ retentionDays: RetentionDays;
3
7
  };
4
8
  export declare function readDebugModeSetting(): Promise<DebugModeSetting>;
5
- export declare function writeDebugModeSetting(setting: DebugModeSetting): Promise<void>;
9
+ /** Saves the given fields and keeps the others, so turning logging off does not forget the retention. */
10
+ export declare function writeDebugModeSetting(change: Partial<DebugModeSetting>): Promise<void>;
11
+ export {};
@@ -1,4 +1,8 @@
1
1
  import React from 'react';
2
+ /**
3
+ * Settings > Debug Mode. Logging is switched with Enter. The retention is chosen with ←/→, which only moves a highlight:
4
+ * nothing is saved until Enter, and then the screen says so.
5
+ */
2
6
  export declare function DebugModeScreen({ onDone }: {
3
7
  onDone: () => void;
4
8
  }): React.ReactElement;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contentful/experience-design-system-cli",
3
- "version": "2.37.1-dev-build-4e7e3ced.0",
3
+ "version": "2.37.1-dev-build-81dbe125.0",
4
4
  "description": "Contentful Experiences design system import CLI",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -45,8 +45,8 @@
45
45
  "ts-morph": "^27.0.2",
46
46
  "typescript": "^5.9.3",
47
47
  "zod": "^4.6.5",
48
- "@contentful/experience-design-system-backend-pipeline": "2.37.1-dev-build-4e7e3ced.0",
49
- "@contentful/experience-design-system-types": "2.37.1-dev-build-4e7e3ced.0"
48
+ "@contentful/experience-design-system-types": "2.37.1-dev-build-81dbe125.0",
49
+ "@contentful/experience-design-system-backend-pipeline": "2.37.1-dev-build-81dbe125.0"
50
50
  },
51
51
  "devDependencies": {
52
52
  "@tsconfig/node24": "^24.0.4",