@contentful/experience-design-system-cli 2.41.1-dev-build-699ca2d9.0 → 2.41.1-dev-build-06624ee7.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
@@ -197,6 +197,7 @@ __export(debug_store_exports, {
197
197
  currentDebugSessionDir: () => currentDebugSessionDir,
198
198
  currentSessionDir: () => currentSessionDir,
199
199
  finishDebugRun: () => finishDebugRun,
200
+ setDebugRunProgress: () => setDebugRunProgress,
200
201
  startDebugRun: () => startDebugRun,
201
202
  startDebugSessionIn: () => startDebugSessionIn,
202
203
  startImportRun: () => startImportRun
@@ -292,11 +293,15 @@ function startDebugRun({
292
293
  const runId = generateRunId();
293
294
  const startedAt = Date.now();
294
295
  const redactedInputs = redact(inputs);
295
- isDebugModeEnabled().then((enabled) => {
296
- if (!enabled) return;
297
- pendingRun = { flow, step, runId, menuOption, inputs: redactedInputs, startedAt };
296
+ const run = { flow, step, runId, menuOption, inputs: redactedInputs, startedAt };
297
+ pendingRun = run;
298
+ void isDebugModeEnabled().then((enabled) => {
299
+ if (!enabled && pendingRun === run) pendingRun = void 0;
298
300
  });
299
301
  }
302
+ function setDebugRunProgress(outputs) {
303
+ if (pendingRun) pendingRun.progress = outputs;
304
+ }
300
305
  async function finishDebugRun({
301
306
  outputs,
302
307
  status,
@@ -305,9 +310,10 @@ async function finishDebugRun({
305
310
  const run = pendingRun;
306
311
  if (!run) return;
307
312
  pendingRun = void 0;
313
+ if (!await isDebugModeEnabled()) return;
308
314
  const durationMs = Date.now() - run.startedAt;
309
315
  const log = {
310
- flow: run.flow,
316
+ flow: logFolder(run.flow, run.step),
311
317
  menuOption: run.menuOption,
312
318
  content: renderMarkdown(run, { outputs: redact(outputs), status, exitMethod, durationMs })
313
319
  };
@@ -318,6 +324,9 @@ async function finishDebugRun({
318
324
  }
319
325
  await writeLog(root, log);
320
326
  }
327
+ function logFolder(flow, step) {
328
+ return flow.startsWith("import/") && /^\d+-/.test(step) ? `import/${step}` : flow;
329
+ }
321
330
  async function writeLog(root, log) {
322
331
  const dir = join5(root, ...log.flow.split("/"));
323
332
  await mkdir2(dir, { recursive: true });
@@ -374,7 +383,7 @@ ${JSON.stringify(finish.outputs, null, 2)}
374
383
  `;
375
384
  }
376
385
  function handleCrash() {
377
- return finishDebugRun({ outputs: {}, status: "error", exitMethod: "crashed" });
386
+ return finishDebugRun({ outputs: pendingRun?.progress ?? {}, status: "error", exitMethod: "crashed" });
378
387
  }
379
388
  var pendingRun, sessionDir, WAITING_LIMIT, waiting;
380
389
  var init_debug_store = __esm({
@@ -418,11 +427,17 @@ var init_debug_store = __esm({
418
427
  throw reason;
419
428
  });
420
429
  });
421
- process.once("SIGINT", () => {
422
- void handleCrash().finally(() => {
423
- process.exit(130);
430
+ for (const [signal, exitCode] of [
431
+ ["SIGINT", 130],
432
+ ["SIGTERM", 143],
433
+ ["SIGHUP", 129]
434
+ ]) {
435
+ process.once(signal, () => {
436
+ void handleCrash().finally(() => {
437
+ process.exit(exitCode);
438
+ });
424
439
  });
425
- });
440
+ }
426
441
  }
427
442
  });
428
443
 
@@ -1676,12 +1691,9 @@ var init_schema = __esm({
1676
1691
  $required: { type: "boolean" },
1677
1692
  $default: {},
1678
1693
  $values: { type: "array", items: { type: "string" } },
1679
- "$token.kind": { type: "string", minLength: 1 },
1694
+ "$token.kind": { type: "string" },
1680
1695
  "$token.allowed": { type: "array", items: { type: "string" } }
1681
1696
  },
1682
- // The API rejects a token property that does not say which kind of token it takes.
1683
- if: { type: "object", properties: { $type: { const: "token" } }, required: ["$type"] },
1684
- then: { type: "object", required: ["$token.kind"] },
1685
1697
  additionalProperties: false
1686
1698
  },
1687
1699
  slot: {
@@ -2487,7 +2499,7 @@ var init_cache_keys = __esm({
2487
2499
  });
2488
2500
 
2489
2501
  // packages/experience-design-system-cli/app.tsx
2490
- import { useEffect as useEffect31, useState as useState39 } from "react";
2502
+ import { useEffect as useEffect36, useState as useState39 } from "react";
2491
2503
 
2492
2504
  // packages/experience-design-system-cli/src/tui/home/home.tsx
2493
2505
  import { useEffect as useEffect2, useState as useState2 } from "react";
@@ -3045,8 +3057,8 @@ function progressPercent(progress) {
3045
3057
  }
3046
3058
  function formatElapsed(totalSeconds) {
3047
3059
  const minutes = Math.floor(totalSeconds / 60);
3048
- const seconds = totalSeconds % 60;
3049
- return minutes > 0 ? `${minutes}m ${seconds}s` : `${seconds}s`;
3060
+ const seconds2 = totalSeconds % 60;
3061
+ return minutes > 0 ? `${minutes}m ${seconds2}s` : `${seconds2}s`;
3050
3062
  }
3051
3063
 
3052
3064
  // packages/experience-design-system-cli/src/tui/import/shared/running-step/theme.ts
@@ -3064,12 +3076,12 @@ var PROGRESS_THEME = extendTheme(defaultTheme, {
3064
3076
  // packages/experience-design-system-cli/src/tui/import/shared/running-step/use-elapsed.ts
3065
3077
  import { useEffect as useEffect3, useState as useState3 } from "react";
3066
3078
  function useElapsed() {
3067
- const [seconds, setSeconds] = useState3(0);
3079
+ const [seconds2, setSeconds] = useState3(0);
3068
3080
  useEffect3(() => {
3069
3081
  const timer = setInterval(() => setSeconds((current) => current + 1), 1e3);
3070
3082
  return () => clearInterval(timer);
3071
3083
  }, []);
3072
- return formatElapsed(seconds);
3084
+ return formatElapsed(seconds2);
3073
3085
  }
3074
3086
 
3075
3087
  // packages/experience-design-system-cli/src/tui/import/shared/running-step/running-step.tsx
@@ -15256,8 +15268,8 @@ function retryAfterMs(response) {
15256
15268
  const value = response.headers?.get("retry-after")?.trim();
15257
15269
  if (!value)
15258
15270
  return void 0;
15259
- const seconds = Number(value);
15260
- const delayMs = Number.isFinite(seconds) ? seconds * 1e3 : Date.parse(value) - Date.now();
15271
+ const seconds2 = Number(value);
15272
+ const delayMs = Number.isFinite(seconds2) ? seconds2 * 1e3 : Date.parse(value) - Date.now();
15261
15273
  if (!Number.isFinite(delayMs) || delayMs < 0 || delayMs > MAX_RETRY_AFTER_MS)
15262
15274
  return void 0;
15263
15275
  return Math.round(delayMs);
@@ -17405,10 +17417,10 @@ async function readCandidateFiles(components, extraFiles = []) {
17405
17417
  async function selectCompositionPromptFiles(components, sourceFiles) {
17406
17418
  const allFiles = await readCandidateFiles(components, sourceFiles);
17407
17419
  const selectedCandidates = selectCandidateFiles(allFiles).map((c2) => ({ path: c2.path, content: c2.content }));
17408
- const capped = capCandidatesToPromptBudget(selectedCandidates);
17409
- const promptFiles = capped.kept;
17420
+ const capped3 = capCandidatesToPromptBudget(selectedCandidates);
17421
+ const promptFiles = capped3.kept;
17410
17422
  const runtimeFiles = allFiles.map((c2) => ({ path: c2.path, content: c2.content }));
17411
- const droppedWarning = capped.dropped.length > 0 ? `composition \u2014 ${capped.dropped.length} candidate file(s) omitted from the agent prompt to fit the context budget; resolution runs on the ${promptFiles.length} highest-value files.` : void 0;
17423
+ const droppedWarning = capped3.dropped.length > 0 ? `composition \u2014 ${capped3.dropped.length} candidate file(s) omitted from the agent prompt to fit the context budget; resolution runs on the ${promptFiles.length} highest-value files.` : void 0;
17412
17424
  return { promptFiles, runtimeFiles, droppedWarning };
17413
17425
  }
17414
17426
 
@@ -18160,8 +18172,9 @@ function PathValidationScreen({
18160
18172
  }
18161
18173
 
18162
18174
  // packages/experience-design-system-cli/src/tui/import/steps/04-credentials/screen.tsx
18163
- import { useRef as useRef5, useState as useState9 } from "react";
18175
+ import { useEffect as useEffect8, useRef as useRef5, useState as useState9 } from "react";
18164
18176
  import { Box as Box14, Text as Text14, useInput as useInput11 } from "ink";
18177
+ init_debug_store();
18165
18178
 
18166
18179
  // packages/experience-design-system-cli/src/tui/shared/components/FieldForm.tsx
18167
18180
  import { useState as useState8 } from "react";
@@ -18338,6 +18351,39 @@ function FieldForm({
18338
18351
  ] });
18339
18352
  }
18340
18353
 
18354
+ // packages/experience-design-system-cli/src/tui/shared/debug-trail.ts
18355
+ init_config();
18356
+ import { existsSync as existsSync9 } from "node:fs";
18357
+ function diffSnapshots(before, after) {
18358
+ const names = [.../* @__PURE__ */ new Set([...Object.keys(before), ...Object.keys(after)])];
18359
+ const changed_fields = names.filter((name) => before[name] !== after[name]);
18360
+ return { changed: changed_fields.length > 0, changed_fields };
18361
+ }
18362
+ var DEFAULT_TRAIL_LIMIT = 30;
18363
+ function createTrail(limit = DEFAULT_TRAIL_LIMIT) {
18364
+ const actions = [];
18365
+ return {
18366
+ record(action) {
18367
+ actions.push(action);
18368
+ if (actions.length > limit) actions.shift();
18369
+ },
18370
+ entries: () => [...actions]
18371
+ };
18372
+ }
18373
+ var MIN_SECRET_LENGTH = 6;
18374
+ function scrubError(error, secrets) {
18375
+ let message = error instanceof Error ? error.message : String(error);
18376
+ for (const secret of secrets) {
18377
+ if (secret.length < MIN_SECRET_LENGTH) continue;
18378
+ for (const form of /* @__PURE__ */ new Set([secret, encodeURIComponent(secret)])) message = message.split(form).join("[redacted]");
18379
+ }
18380
+ return message;
18381
+ }
18382
+ function describeSettingsFile() {
18383
+ const path5 = configFilePath();
18384
+ return { path: path5, eds_home_set: Boolean(process.env["EDS_HOME"]), exists: existsSync9(path5) };
18385
+ }
18386
+
18341
18387
  // packages/experience-design-system-cli/src/tui/import/steps/04-credentials/logic.ts
18342
18388
  var FIELDS = ["spaceId", "environmentId", "cmaToken", "host"];
18343
18389
  function credentialsPurpose(tokensOnly) {
@@ -18352,12 +18398,36 @@ function normalize(values) {
18352
18398
  host: toConfiguredHost2(values.host) ?? DEFAULT_CONFIGURED_HOST
18353
18399
  };
18354
18400
  }
18355
- function missingField(values) {
18356
- return values.spaceId === "" || values.environmentId === "" || values.cmaToken === "";
18401
+ function missingFields(values) {
18402
+ return ["spaceId", "environmentId", "cmaToken"].filter((field) => values[field] === "");
18357
18403
  }
18358
18404
  function isUnchanged(current, initial) {
18359
18405
  return FIELDS.every((field) => current[field] === initial[field]);
18360
18406
  }
18407
+ function rejectedAttempt(reason, credentials) {
18408
+ return { host: credentials.host, reason: scrubError(reason, [credentials.cmaToken]) };
18409
+ }
18410
+ function credentialsLog(credentials) {
18411
+ return {
18412
+ space_id: credentials.spaceId,
18413
+ environment_id: credentials.environmentId,
18414
+ host: credentials.host,
18415
+ cma_token: credentials.cmaToken
18416
+ };
18417
+ }
18418
+ function credentialsOutputs({
18419
+ outcome,
18420
+ credentials,
18421
+ initial,
18422
+ attempts
18423
+ }) {
18424
+ return {
18425
+ outcome,
18426
+ ...credentialsLog(credentials),
18427
+ changed_fields: diffSnapshots(initial, credentials).changed_fields,
18428
+ rejected_attempts: attempts
18429
+ };
18430
+ }
18361
18431
 
18362
18432
  // packages/experience-design-system-cli/src/tui/user-agent.ts
18363
18433
  init_version();
@@ -18405,7 +18475,9 @@ var MENU = [
18405
18475
  { choice: "continue", label: "Continue", description: "Check the credentials and go on" },
18406
18476
  { choice: "edit", label: "Edit", description: "Change the credentials" }
18407
18477
  ];
18478
+ var MAX_LOGGED_ATTEMPTS2 = 10;
18408
18479
  function CredentialsScreen({
18480
+ mode,
18409
18481
  onDone,
18410
18482
  onBack,
18411
18483
  initial = {},
@@ -18428,17 +18500,64 @@ function CredentialsScreen({
18428
18500
  const [focus, setFocus] = useState9(0);
18429
18501
  const [active, setActive] = useState9(0);
18430
18502
  const [beforeEdit, setBeforeEdit] = useState9(initialValues);
18503
+ const visit = useRef5({ attempts: [], lastReason: "" }).current;
18504
+ useEffect8(() => {
18505
+ startDebugRun({
18506
+ flow: "import/credentials",
18507
+ step: "04-credentials",
18508
+ menuOption: "Credentials",
18509
+ inputs: { import_mode: mode, prefilled, ...credentialsLog(initialValues) }
18510
+ });
18511
+ }, []);
18512
+ const reject = (attempt, text) => {
18513
+ if (visit.attempts.length < MAX_LOGGED_ATTEMPTS2) visit.attempts.push(attempt);
18514
+ visit.lastReason = attempt.reason;
18515
+ setNotice({ kind: "error", text });
18516
+ };
18517
+ const leave = () => {
18518
+ void finishDebugRun({
18519
+ outputs: {
18520
+ ...credentialsOutputs({
18521
+ outcome: "back",
18522
+ credentials: normalize(values),
18523
+ initial: initialValues,
18524
+ attempts: visit.attempts
18525
+ }),
18526
+ ...notice ? { error: visit.lastReason } : {}
18527
+ },
18528
+ status: notice ? "error" : "success",
18529
+ exitMethod: "discarded"
18530
+ });
18531
+ onBack();
18532
+ };
18431
18533
  const submit = async () => {
18432
18534
  const credentials = normalize(values);
18433
- if (missingField(credentials)) {
18434
- setNotice({ kind: "error", text: "Space ID, environment and CMA token are all required." });
18535
+ const missing = missingFields(credentials);
18536
+ if (missing.length > 0) {
18537
+ reject(
18538
+ rejectedAttempt(`Missing required fields: ${missing.join(", ")}`, credentials),
18539
+ "Space ID, environment and CMA token are all required."
18540
+ );
18435
18541
  return;
18436
18542
  }
18437
18543
  setValidating(true);
18438
18544
  const result = await validate3(credentials);
18439
18545
  setValidating(false);
18440
- if (result.ok) onDone({ skipped: false, credentials });
18441
- else setNotice({ kind: "error", text: result.error });
18546
+ if (!result.ok) {
18547
+ reject(rejectedAttempt(result.error, credentials), result.error);
18548
+ return;
18549
+ }
18550
+ void finishDebugRun({
18551
+ outputs: credentialsOutputs({
18552
+ outcome: "validated",
18553
+ credentials,
18554
+ initial: initialValues,
18555
+ attempts: visit.attempts
18556
+ }),
18557
+ status: "success",
18558
+ exitMethod: "saved"
18559
+ });
18560
+ onDone({ skipped: false, credentials });
18442
18561
  };
18443
18562
  const choose = (choice) => {
18444
18563
  if (choice === "continue") void submit();
@@ -18447,7 +18566,7 @@ function CredentialsScreen({
18447
18566
  setBeforeEdit(values);
18448
18567
  setActive(0);
18449
18568
  setEditing(true);
18450
- } else onBack();
18569
+ } else leave();
18451
18570
  };
18452
18571
  const stopEditing = () => {
18453
18572
  setEditing(false);
@@ -18457,7 +18576,7 @@ function CredentialsScreen({
18457
18576
  if (validating) return;
18458
18577
  if (editing) {
18459
18578
  if (key.escape) {
18460
- if (!prefilled) onBack();
18579
+ if (!prefilled) leave();
18461
18580
  else {
18462
18581
  setValues(beforeEdit);
18463
18582
  setNotice(null);
@@ -18565,6 +18684,47 @@ function CredentialsScreen({
18565
18684
  }
18566
18685
 
18567
18686
  // packages/experience-design-system-cli/src/tui/import/steps/06-extraction/logic.ts
18687
+ function extractionLogInputs(input) {
18688
+ const { credentials } = input;
18689
+ return {
18690
+ project_path: input.projectPath,
18691
+ out_dir: input.outDir ?? "",
18692
+ files_to_scan: input.filePaths.length,
18693
+ raw_tokens_path: input.rawTokensPath,
18694
+ agent: input.agent,
18695
+ agent_model: input.agentModel ?? "",
18696
+ prompt_overrides: input.promptOverrides,
18697
+ cache: !input.noCache,
18698
+ has_credentials: credentials !== null,
18699
+ space_id: credentials?.spaceId ?? "",
18700
+ environment_id: credentials?.environmentId ?? "",
18701
+ host: credentials?.host ?? "",
18702
+ cma_token: credentials?.cmaToken ?? ""
18703
+ };
18704
+ }
18705
+ function extractionLogOutputs(result, progress, cmaToken) {
18706
+ const last = progress ? { final_progress: progress } : {};
18707
+ if (!result.ok) {
18708
+ return {
18709
+ outputs: { result: "failed", failed_step: result.step, error: scrubError(result.message, [cmaToken]), ...last },
18710
+ status: "error"
18711
+ };
18712
+ }
18713
+ const { extraction } = result;
18714
+ return {
18715
+ outputs: {
18716
+ result: "done",
18717
+ session_id: extraction.sessionId,
18718
+ out_dir: extraction.outDir,
18719
+ tokens_path: extraction.tokensPath,
18720
+ token_count: extraction.tokenCount,
18721
+ existing_entities_status: extraction.existingEntitiesStatus,
18722
+ composition_phase: extraction.compositionPhase,
18723
+ ...last
18724
+ },
18725
+ status: "success"
18726
+ };
18727
+ }
18568
18728
  function initialProgress(input) {
18569
18729
  return {
18570
18730
  scan: null,
@@ -18659,8 +18819,9 @@ function ExtractionScreen({ progress, agent }) {
18659
18819
  }
18660
18820
 
18661
18821
  // packages/experience-design-system-cli/src/tui/import/steps/05-token-review/screen.tsx
18662
- import { useMemo as useMemo2, useState as useState10 } from "react";
18822
+ import { useEffect as useEffect9, useMemo as useMemo2, useState as useState10 } from "react";
18663
18823
  import { Box as Box15, Text as Text15, useInput as useInput12 } from "ink";
18824
+ init_debug_store();
18664
18825
 
18665
18826
  // packages/experience-design-system-cli/src/tui/import/steps/05-token-review/load.ts
18666
18827
  import { readFileSync as readFileSync9 } from "node:fs";
@@ -18724,12 +18885,31 @@ function TokenReviewScreen({ tokensPath, onContinue, onQuit }) {
18724
18885
  const rows = loaded.ok ? loaded.rows : [];
18725
18886
  const columns = useTerminalWidth();
18726
18887
  const [selected, setSelected] = useState10(0);
18888
+ useEffect9(() => {
18889
+ startDebugRun({
18890
+ flow: "import/token-review",
18891
+ step: "05-token-review",
18892
+ menuOption: "Token review",
18893
+ inputs: { import_mode: "tokens", tokens_path: tokensPath }
18894
+ });
18895
+ }, []);
18896
+ const finish = (outcome) => {
18897
+ void finishDebugRun({
18898
+ outputs: { outcome, ...loaded.ok ? { tokens: rows.length } : { load_error: loaded.message } },
18899
+ status: loaded.ok ? "success" : "error",
18900
+ exitMethod: outcome === "continued" ? "saved" : "discarded"
18901
+ });
18902
+ };
18727
18903
  const move = (to) => setSelected(Math.max(0, Math.min(to, rows.length - 1)));
18728
18904
  const { start, end } = computeColumnWindow(rows.length, selected, VISIBLE_ROWS);
18729
18905
  useInput12((_input, key) => {
18730
- if (key.return) onContinue();
18731
- else if (key.escape) onQuit();
18732
- else if (key.upArrow) move(selected - 1);
18906
+ if (key.return) {
18907
+ finish("continued");
18908
+ onContinue();
18909
+ } else if (key.escape) {
18910
+ finish("back");
18911
+ onQuit();
18912
+ } else if (key.upArrow) move(selected - 1);
18733
18913
  else if (key.downArrow) move(selected + 1);
18734
18914
  else if (key.pageUp) move(selected - VISIBLE_ROWS);
18735
18915
  else if (key.pageDown) move(selected + VISIBLE_ROWS);
@@ -18793,14 +18973,15 @@ function TokenReviewScreen({ tokensPath, onContinue, onQuit }) {
18793
18973
  init_config();
18794
18974
 
18795
18975
  // packages/experience-design-system-cli/src/tui/import/steps/06-extraction/use-extraction.ts
18796
- import { useEffect as useEffect8, useRef as useRef6, useState as useState11 } from "react";
18976
+ init_debug_store();
18977
+ import { useEffect as useEffect10, useRef as useRef6, useState as useState11 } from "react";
18797
18978
 
18798
18979
  // packages/experience-design-system-cli/src/tui/import/steps/06-extraction/run.ts
18799
18980
  import { mkdir as mkdir8 } from "node:fs/promises";
18800
18981
  import { join as join20, resolve as resolve24 } from "node:path";
18801
18982
 
18802
18983
  // packages/experience-design-system-cli/src/tui/import/steps/06-extraction/find-skill-path.ts
18803
- import { existsSync as existsSync9 } from "node:fs";
18984
+ import { existsSync as existsSync10 } from "node:fs";
18804
18985
  import { dirname as dirname16, join as join19, resolve as resolve22 } from "node:path";
18805
18986
  import { fileURLToPath as fileURLToPath4 } from "node:url";
18806
18987
  function findSkillPath(fileName) {
@@ -18808,7 +18989,7 @@ function findSkillPath(fileName) {
18808
18989
  let dir = thisDir;
18809
18990
  for (; ; ) {
18810
18991
  const candidate = join19(dir, "skills", fileName);
18811
- if (existsSync9(candidate)) return candidate;
18992
+ if (existsSync10(candidate)) return candidate;
18812
18993
  const parent = resolve22(dir, "..");
18813
18994
  if (parent === dir) {
18814
18995
  throw new Error(`skill file not found (looked for skills/${fileName} from ${thisDir})`);
@@ -19050,7 +19231,7 @@ async function resolveSelectionPrompt(overrides) {
19050
19231
  function useExtraction(input) {
19051
19232
  const [state2, setState] = useState11();
19052
19233
  const current = useRef6();
19053
- useEffect8(() => {
19234
+ useEffect10(() => {
19054
19235
  current.current = input;
19055
19236
  if (!input) {
19056
19237
  setState(void 0);
@@ -19063,10 +19244,23 @@ function useExtraction(input) {
19063
19244
  hasRawTokens: input.rawTokensPath !== ""
19064
19245
  })
19065
19246
  });
19247
+ let lastProgress;
19248
+ startDebugRun({
19249
+ flow: "import/extraction",
19250
+ step: "06-extraction",
19251
+ menuOption: "Extraction",
19252
+ inputs: extractionLogInputs(input)
19253
+ });
19066
19254
  void runExtraction(input, (progress) => {
19255
+ lastProgress = progress;
19067
19256
  if (current.current === input) setState({ status: "running", progress });
19068
19257
  }).then((result) => {
19069
- if (current.current === input) setState({ status: "done", result });
19258
+ if (current.current !== input) return;
19259
+ void finishDebugRun({
19260
+ ...extractionLogOutputs(result, lastProgress, input.credentials?.cmaToken ?? ""),
19261
+ exitMethod: result.ok ? "saved" : "discarded"
19262
+ });
19263
+ setState({ status: "done", result });
19070
19264
  });
19071
19265
  return () => {
19072
19266
  if (current.current === input) current.current = void 0;
@@ -19076,7 +19270,7 @@ function useExtraction(input) {
19076
19270
  }
19077
19271
 
19078
19272
  // packages/experience-design-system-cli/src/tui/import/steps/06-extraction/use-tokens-only.ts
19079
- import { useEffect as useEffect9, useRef as useRef7, useState as useState12 } from "react";
19273
+ import { useEffect as useEffect11, useRef as useRef7, useState as useState12 } from "react";
19080
19274
 
19081
19275
  // packages/experience-design-system-cli/src/tui/import/steps/06-extraction/run-tokens-only.ts
19082
19276
  var TOKENS_SKILL_PATH2 = findSkillPath("generate-tokens.md");
@@ -19111,7 +19305,7 @@ async function runTokensOnly(input, deps = realDeps2) {
19111
19305
  function useTokensOnly(input) {
19112
19306
  const [state2, setState] = useState12();
19113
19307
  const current = useRef7();
19114
- useEffect9(() => {
19308
+ useEffect11(() => {
19115
19309
  current.current = input;
19116
19310
  if (!input) {
19117
19311
  setState(void 0);
@@ -19129,9 +19323,37 @@ function useTokensOnly(input) {
19129
19323
  }
19130
19324
 
19131
19325
  // packages/experience-design-system-cli/src/tui/import/steps/07-scope-gate/screen.tsx
19132
- import { useMemo as useMemo4 } from "react";
19326
+ init_debug_store();
19327
+ import { useEffect as useEffect14, useMemo as useMemo4 } from "react";
19133
19328
  import { Box as Box25, Text as Text26 } from "ink";
19134
19329
 
19330
+ // packages/experience-design-system-cli/src/tui/import/steps/07-scope-gate/log.ts
19331
+ var MAX_NAMES = 20;
19332
+ var capped = (names) => {
19333
+ const unique = [...new Set(names)];
19334
+ return { count: unique.length, names: unique.slice(0, MAX_NAMES) };
19335
+ };
19336
+ function scopeGateLogInputs(components, tokenCount) {
19337
+ const ai = { accepted: 0, rejected: 0, failed: 0, none: 0 };
19338
+ for (const component of components) ai[component.aiDecision ?? "none"] += 1;
19339
+ return {
19340
+ components_found: components.length,
19341
+ ai_suggestions: ai,
19342
+ needs_review: components.filter((component) => component.needsReview === true).length,
19343
+ tokens: tokenCount
19344
+ };
19345
+ }
19346
+ function scopeGateLogOutputs(components, decisions) {
19347
+ const suggested = new Map(components.map((component) => [component.name, component.aiDecision]));
19348
+ return {
19349
+ outcome: "continued",
19350
+ accepted: new Set(decisions.accepted).size,
19351
+ rejected: new Set(decisions.rejected).size,
19352
+ accepted_although_ai_rejected: capped(decisions.accepted.filter((name) => suggested.get(name) === "rejected")),
19353
+ not_accepted_although_ai_accepted: capped(decisions.rejected.filter((name) => suggested.get(name) === "accepted"))
19354
+ };
19355
+ }
19356
+
19135
19357
  // packages/experience-design-system-cli/src/tui/import/steps/07-scope-gate/panels/tokens-column.tsx
19136
19358
  import { Box as Box17, Text as Text17 } from "ink";
19137
19359
  import figures2 from "figures";
@@ -20315,7 +20537,7 @@ function useImmediateInput(handler, enabled = true) {
20315
20537
 
20316
20538
  // packages/experience-design-system-cli/src/tui/import/steps/07-scope-gate/sidebar/hooks/use-terminal-size.ts
20317
20539
  import { useStdout as useStdout2 } from "ink";
20318
- import { useEffect as useEffect10, useState as useState13 } from "react";
20540
+ import { useEffect as useEffect12, useState as useState13 } from "react";
20319
20541
  function readTerminalSize(stdout) {
20320
20542
  return {
20321
20543
  columns: stdout?.columns ?? 80,
@@ -20325,7 +20547,7 @@ function readTerminalSize(stdout) {
20325
20547
  function useTerminalSize() {
20326
20548
  const { stdout } = useStdout2();
20327
20549
  const [size, setSize] = useState13(() => readTerminalSize(stdout));
20328
- useEffect10(() => {
20550
+ useEffect12(() => {
20329
20551
  const updateSize = () => setSize(readTerminalSize(stdout));
20330
20552
  stdout?.on("resize", updateSize);
20331
20553
  updateSize();
@@ -20508,7 +20730,7 @@ function createSidebarViewsHelpSection(includeBreaking) {
20508
20730
  }
20509
20731
 
20510
20732
  // packages/experience-design-system-cli/src/tui/import/steps/07-scope-gate/use-scope-gate.ts
20511
- import { useEffect as useEffect11, useMemo as useMemo3, useRef as useRef9, useState as useState16 } from "react";
20733
+ import { useEffect as useEffect13, useMemo as useMemo3, useRef as useRef9, useState as useState16 } from "react";
20512
20734
 
20513
20735
  // packages/experience-design-system-cli/src/tui/import/steps/07-scope-gate/columns.ts
20514
20736
  var TWO_COLUMN_MIN_WIDTH = 100;
@@ -21245,7 +21467,7 @@ function useScopeGate({ components, tokenCount, tokensWidth, onConfirm, onQuit }
21245
21467
  return seed;
21246
21468
  });
21247
21469
  const seededGroupsRef = useRef9(closures.size > 0 || cycleParticipants.size > 0);
21248
- useEffect11(() => {
21470
+ useEffect13(() => {
21249
21471
  if (seededGroupsRef.current) return;
21250
21472
  if (closures.size === 0 && cycleParticipants.size === 0) return;
21251
21473
  seededGroupsRef.current = true;
@@ -21336,7 +21558,7 @@ function useScopeGate({ components, tokenCount, tokensWidth, onConfirm, onQuit }
21336
21558
  entryCount: 0
21337
21559
  });
21338
21560
  const panelLayout = useMemo3(() => computePanelLayout(visibleCount), [visibleCount]);
21339
- useEffect11(() => {
21561
+ useEffect13(() => {
21340
21562
  setNav((prev) => {
21341
21563
  const maxIdx = Math.max(0, visibleRows.length - 1);
21342
21564
  const nextCursor = Math.min(prev.cursor, maxIdx);
@@ -21697,23 +21919,55 @@ var HELP_SECTIONS = [
21697
21919
  }
21698
21920
  ];
21699
21921
  function ScopeGateScreen(props) {
21700
- if (props.components.length === 0) {
21701
- return /* @__PURE__ */ jsx29(Box25, { paddingX: 2, paddingY: 1, children: /* @__PURE__ */ jsx29(Text26, { color: PALETTE.error, children: "Error: no components found for this session \u2014 please re-run analyze extract." }) });
21702
- }
21922
+ if (props.components.length === 0) return /* @__PURE__ */ jsx29(NoComponents, {});
21703
21923
  return /* @__PURE__ */ jsx29(ScopeGateView, { ...props });
21704
21924
  }
21925
+ function NoComponents() {
21926
+ useEffect14(() => {
21927
+ startDebugRun({
21928
+ flow: "import/scope-gate",
21929
+ step: "07-scope-gate",
21930
+ menuOption: "Scope gate",
21931
+ inputs: scopeGateLogInputs([], 0)
21932
+ });
21933
+ void finishDebugRun({
21934
+ outputs: { outcome: "nothing to decide", error: "No components were found for this session." },
21935
+ status: "error",
21936
+ exitMethod: "discarded"
21937
+ });
21938
+ }, []);
21939
+ return /* @__PURE__ */ jsx29(Box25, { paddingX: 2, paddingY: 1, children: /* @__PURE__ */ jsx29(Text26, { color: PALETTE.error, children: "Error: no components found for this session \u2014 please re-run analyze extract." }) });
21940
+ }
21705
21941
  function ScopeGateView({ components, tokensPath, onConfirm, onQuit }) {
21706
21942
  const tokens = useMemo4(() => {
21707
21943
  const loaded = tokensPath ? loadTokenRows(tokensPath) : void 0;
21708
21944
  return loaded?.ok ? loaded.rows : [];
21709
21945
  }, [tokensPath]);
21710
21946
  const longest = useMemo4(() => longestEntries(tokens), [tokens]);
21947
+ useEffect14(() => {
21948
+ startDebugRun({
21949
+ flow: "import/scope-gate",
21950
+ step: "07-scope-gate",
21951
+ menuOption: "Scope gate",
21952
+ inputs: scopeGateLogInputs(components, tokens.length)
21953
+ });
21954
+ }, []);
21711
21955
  const gate = useScopeGate({
21712
21956
  components,
21713
21957
  tokenCount: tokens.length,
21714
21958
  tokensWidth: longest.path + longest.value + 10,
21715
- onConfirm,
21716
- onQuit
21959
+ onConfirm: (decisions) => {
21960
+ void finishDebugRun({
21961
+ outputs: scopeGateLogOutputs(components, decisions),
21962
+ status: "success",
21963
+ exitMethod: "saved"
21964
+ });
21965
+ onConfirm(decisions);
21966
+ },
21967
+ onQuit: () => {
21968
+ void finishDebugRun({ outputs: { outcome: "quit" }, status: "success", exitMethod: "discarded" });
21969
+ onQuit();
21970
+ }
21717
21971
  });
21718
21972
  const { search, graph, columnPlan, panelLayout, counters } = gate;
21719
21973
  if (gate.showHelp) {
@@ -21811,7 +22065,8 @@ function ScopeGateView({ components, tokensPath, onConfirm, onQuit }) {
21811
22065
  }
21812
22066
 
21813
22067
  // packages/experience-design-system-cli/src/tui/import/steps/07-scope-gate/use-scope-gate-flow.ts
21814
- import { useEffect as useEffect12, useMemo as useMemo5, useRef as useRef10, useState as useState17 } from "react";
22068
+ init_debug_store();
22069
+ import { useEffect as useEffect15, useMemo as useMemo5, useRef as useRef10, useState as useState17 } from "react";
21815
22070
 
21816
22071
  // packages/experience-design-system-cli/src/tui/import/steps/07-scope-gate/cache-check.ts
21817
22072
  async function checkGenerationCache(input) {
@@ -21860,7 +22115,21 @@ function useScopeGateFlow(input, deps = realDeps3) {
21860
22115
  const loaded = useMemo5(() => sessionId ? deps.load(sessionId) : void 0, [sessionId]);
21861
22116
  const cacheCheck = useRef10(void 0);
21862
22117
  const [confirmed, setConfirmed] = useState17();
21863
- useEffect12(() => {
22118
+ useEffect15(() => {
22119
+ if (!sessionId || !loaded || loaded.ok) return;
22120
+ startDebugRun({
22121
+ flow: "import/scope-gate",
22122
+ step: "07-scope-gate",
22123
+ menuOption: "Scope gate",
22124
+ inputs: { session_id: sessionId }
22125
+ });
22126
+ void finishDebugRun({
22127
+ outputs: { outcome: "could not load the components", error: loaded.message },
22128
+ status: "error",
22129
+ exitMethod: "discarded"
22130
+ });
22131
+ }, [sessionId, loaded]);
22132
+ useEffect15(() => {
21864
22133
  if (!input || !loaded?.ok || cacheCheck.current) return;
21865
22134
  cacheCheck.current = deps.checkCache(input.cache);
21866
22135
  }, [input, loaded]);
@@ -21872,6 +22141,41 @@ function useScopeGateFlow(input, deps = realDeps3) {
21872
22141
  }
21873
22142
 
21874
22143
  // packages/experience-design-system-cli/src/tui/import/steps/08-generation/logic.ts
22144
+ function generationLogInputs(input) {
22145
+ return {
22146
+ session_id: input.sessionId,
22147
+ accepted: input.decisions.accepted.length,
22148
+ rejected: input.decisions.rejected.length,
22149
+ tokens_path: input.tokensPath,
22150
+ token_session_id: input.tokenSessionId,
22151
+ existing_entities_path: input.existingEntitiesPath,
22152
+ agent: input.agent,
22153
+ agent_model: input.agentModel ?? "",
22154
+ prompt_overrides: input.promptOverrides,
22155
+ generate_prompt_path: input.generatePromptPath ?? "",
22156
+ cache: !input.noCache,
22157
+ has_tokens: input.hasTokens
22158
+ };
22159
+ }
22160
+ function generationLogOutputs(result, progress) {
22161
+ const last = progress ? { final_progress: progress } : {};
22162
+ if (!result.ok) {
22163
+ return { outputs: { result: "failed", failed_step: result.step, error: result.message, ...last }, status: "error" };
22164
+ }
22165
+ const { generation } = result;
22166
+ return {
22167
+ outputs: generation.route === "review" ? {
22168
+ result: "done",
22169
+ route: generation.route,
22170
+ session_id: generation.sessionId,
22171
+ accepted: generation.acceptedCount,
22172
+ generated: generation.generatedCount,
22173
+ map_tokens_eligible: generation.mapTokensEligible,
22174
+ ...last
22175
+ } : { result: "done", route: generation.route, accepted: generation.acceptedCount, ...last },
22176
+ status: "success"
22177
+ };
22178
+ }
21875
22179
  function initialProgress2() {
21876
22180
  return { components: null, mapTokens: "idle", mapTokensEligible: null };
21877
22181
  }
@@ -21927,7 +22231,8 @@ function GenerationScreen({
21927
22231
  }
21928
22232
 
21929
22233
  // packages/experience-design-system-cli/src/tui/import/steps/08-generation/use-generation.ts
21930
- import { useEffect as useEffect13, useRef as useRef11, useState as useState18 } from "react";
22234
+ init_debug_store();
22235
+ import { useEffect as useEffect16, useRef as useRef11, useState as useState18 } from "react";
21931
22236
 
21932
22237
  // packages/experience-design-system-cli/src/tui/import/steps/08-generation/run.ts
21933
22238
  import { resolve as resolve25 } from "node:path";
@@ -22093,17 +22398,30 @@ function applyProgressEvent2(event, previous, total) {
22093
22398
  function useGeneration(input) {
22094
22399
  const [state2, setState] = useState18();
22095
22400
  const current = useRef11();
22096
- useEffect13(() => {
22401
+ useEffect16(() => {
22097
22402
  current.current = input;
22098
22403
  if (!input) {
22099
22404
  setState(void 0);
22100
22405
  return;
22101
22406
  }
22102
22407
  setState({ status: "running", progress: initialProgress2() });
22408
+ let lastProgress;
22409
+ startDebugRun({
22410
+ flow: "import/generation",
22411
+ step: "08-generation",
22412
+ menuOption: "Generation",
22413
+ inputs: generationLogInputs(input)
22414
+ });
22103
22415
  void runGeneration(input, (progress) => {
22416
+ lastProgress = progress;
22104
22417
  if (current.current === input) setState({ status: "running", progress });
22105
22418
  }).then((result) => {
22106
- if (current.current === input) setState({ status: "done", result });
22419
+ if (current.current !== input) return;
22420
+ void finishDebugRun({
22421
+ ...generationLogOutputs(result, lastProgress),
22422
+ exitMethod: result.ok ? "saved" : "discarded"
22423
+ });
22424
+ setState({ status: "done", result });
22107
22425
  });
22108
22426
  return () => {
22109
22427
  if (current.current === input) current.current = void 0;
@@ -22218,12 +22536,9 @@ var cdfJsonSchema2 = {
22218
22536
  $required: { type: "boolean" },
22219
22537
  $default: {},
22220
22538
  $values: { type: "array", items: { type: "string" } },
22221
- "$token.kind": { type: "string", minLength: 1 },
22539
+ "$token.kind": { type: "string" },
22222
22540
  "$token.allowed": { type: "array", items: { type: "string" } }
22223
22541
  },
22224
- // The API rejects a token property that does not say which kind of token it takes.
22225
- if: { type: "object", properties: { $type: { const: "token" } }, required: ["$type"] },
22226
- then: { type: "object", required: ["$token.kind"] },
22227
22542
  additionalProperties: false
22228
22543
  },
22229
22544
  slot: {
@@ -22282,42 +22597,14 @@ function parseCDFComponents(obj, prefix = "") {
22282
22597
  }
22283
22598
  return { components, tokens };
22284
22599
  }
22285
- function entryValidator(name) {
22286
- const check = ajv2.getSchema(`${CDF_SCHEMA_URL2}#/definitions/${name}`);
22287
- if (!check)
22288
- throw new Error(`the CDF schema has no "${name}" definition`);
22289
- return check;
22290
- }
22291
- var validateComponentEntry = entryValidator("component");
22292
- var validateTokenEntry = entryValidator("token");
22293
- function toValidationErrors(errors, prefix = "") {
22294
- return (errors ?? []).filter((err) => err.keyword !== "if").map((err) => ({
22295
- path: `${prefix}${err.instancePath}` || "/",
22296
- message: err.message ?? "Unknown validation error",
22297
- expected: err.params ? JSON.stringify(err.params) : void 0
22298
- }));
22299
- }
22300
- function entryErrors(node, prefix) {
22301
- const errors = [];
22302
- for (const [key, value] of Object.entries(node)) {
22303
- if (key.startsWith("$") || typeof value !== "object" || value === null)
22304
- continue;
22305
- const path5 = `${prefix}/${key}`;
22306
- const type = value["$type"];
22307
- const check = type === "component" ? validateComponentEntry : TOKEN_TYPE_SET3.has(type) ? validateTokenEntry : void 0;
22308
- if (!check) {
22309
- errors.push(...entryErrors(value, path5));
22310
- } else if (!check(value)) {
22311
- errors.push(...toValidationErrors(check.errors, path5));
22312
- }
22313
- }
22314
- return errors;
22315
- }
22316
22600
  function validateCDF2(input) {
22317
22601
  const valid = validate2(input);
22318
22602
  if (!valid) {
22319
- const focused = typeof input === "object" && input !== null ? entryErrors(input, "") : [];
22320
- const errors = focused.length > 0 ? focused : toValidationErrors(validate2.errors);
22603
+ const errors = (validate2.errors ?? []).map((err) => ({
22604
+ path: err.instancePath || "/",
22605
+ message: err.message ?? "Unknown validation error",
22606
+ expected: err.params ? JSON.stringify(err.params) : void 0
22607
+ }));
22321
22608
  return { valid: false, errors, components: [], tokens: [] };
22322
22609
  }
22323
22610
  const file = input;
@@ -22369,45 +22656,6 @@ var CDFTokenSchema2 = z3.strictObject({
22369
22656
  $description: z3.optional(z3.string())
22370
22657
  });
22371
22658
 
22372
- // packages/experience-design-system-types/dist/src/cdf/repair-token-kinds.js
22373
- var UNRESOLVED_WARNING = /\s*WARNING: token_kind unknown[^\n]*/;
22374
- function inferTokenKind(propName, prop, tokens) {
22375
- const bound = typeof prop.$default === "string" ? tokens.find(({ path: path5 }) => path5 === prop.$default) : void 0;
22376
- if (bound)
22377
- return bound.entry.$type;
22378
- const name = propName.toLowerCase();
22379
- const kinds = new Set(tokens.filter(({ path: path5 }) => path5.toLowerCase().split(".").includes(name)).map(({ entry }) => entry.$type));
22380
- return kinds.size === 1 ? [...kinds][0] : void 0;
22381
- }
22382
- function withoutWarning(prop) {
22383
- if (prop.$description === void 0)
22384
- return prop;
22385
- const description = prop.$description.replace(UNRESOLVED_WARNING, "").trim();
22386
- const { $description: _stale, ...rest } = prop;
22387
- return description ? { ...rest, $description: description } : rest;
22388
- }
22389
- function repairTokenKinds(entry, componentKey, tokens, note) {
22390
- const properties = { ...entry.$properties };
22391
- let repaired = false;
22392
- for (const [name, prop] of Object.entries(entry.$properties)) {
22393
- if (prop.$type !== "token" || prop["$token.kind"])
22394
- continue;
22395
- repaired = true;
22396
- const kind = inferTokenKind(name, prop, tokens);
22397
- if (kind) {
22398
- properties[name] = { ...withoutWarning(prop), "$token.kind": kind };
22399
- note?.(`${componentKey}.${name} had no token kind, so "${kind}" was taken from the token file`);
22400
- } else {
22401
- const plain = { ...withoutWarning(prop), $type: "string" };
22402
- delete plain["$token.allowed"];
22403
- delete plain.$default;
22404
- properties[name] = plain;
22405
- note?.(`${componentKey}.${name} had no token kind and none could be told, so it was saved as a string property`);
22406
- }
22407
- }
22408
- return repaired ? { ...entry, $properties: properties } : entry;
22409
- }
22410
-
22411
22659
  // packages/experience-design-system-types/dist/src/cdf/build.js
22412
22660
  function stripUnsupportedSlotFields(entry) {
22413
22661
  if (!entry.$slots)
@@ -22444,7 +22692,7 @@ function buildCDF2(components, tokens, opts = {}) {
22444
22692
  return void 0;
22445
22693
  const doc = { $schema: CDF_SCHEMA_URL2 };
22446
22694
  for (const { key, entry } of components) {
22447
- setAtPath(doc, key, stripUnsupportedSlotFields(repairTokenKinds(entry, key, tokens, opts.onRepair)));
22695
+ setAtPath(doc, key, stripUnsupportedSlotFields(entry));
22448
22696
  }
22449
22697
  for (const { path: path5, entry } of resolveTokenPathCollisions(tokens)) {
22450
22698
  setAtPath(doc, path5, entry);
@@ -22644,7 +22892,7 @@ function PreviewValidationErrorScreen({
22644
22892
  }
22645
22893
 
22646
22894
  // packages/experience-design-system-cli/src/tui/import/steps/09-review/generate-review-step.tsx
22647
- import { useCallback as useCallback5, useEffect as useEffect20, useMemo as useMemo6, useRef as useRef16, useState as useState26 } from "react";
22895
+ import { useCallback as useCallback5, useEffect as useEffect24, useMemo as useMemo6, useRef as useRef17, useState as useState26 } from "react";
22648
22896
  import figures8 from "figures";
22649
22897
 
22650
22898
  // packages/experience-design-system-cli/src/tui/import/steps/09-review/review-json-panel.ts
@@ -22905,7 +23153,7 @@ function enumerateCycleBreaks(cycle, components) {
22905
23153
  import { Box as Box32, Text as Text34 } from "ink";
22906
23154
 
22907
23155
  // packages/experience-design-system-cli/src/tui/import/steps/09-review/components/FieldEditor.tsx
22908
- import React13, { useEffect as useEffect14, useLayoutEffect as useLayoutEffect2, useState as useState19 } from "react";
23156
+ import React13, { useEffect as useEffect17, useLayoutEffect as useLayoutEffect2, useState as useState19 } from "react";
22909
23157
  import figures6 from "figures";
22910
23158
  import { Box as Box26, measureElement, Text as Text27 } from "ink";
22911
23159
 
@@ -24463,7 +24711,7 @@ function FieldEditor({
24463
24711
  }
24464
24712
  return Math.max(start + 1, end2);
24465
24713
  };
24466
- useEffect14(() => {
24714
+ useEffect17(() => {
24467
24715
  if (focusLevel === "field" || selectedRowIdx < 0) return;
24468
24716
  setListScrollStart((previous) => {
24469
24717
  if (initialFocusTarget && !initialFocusScrollApplied.current) {
@@ -25535,7 +25783,7 @@ function finalizeReviewSession(extractSessionId, components) {
25535
25783
  }
25536
25784
 
25537
25785
  // packages/experience-design-system-cli/src/tui/import/steps/09-review/use-review-session.ts
25538
- import { useCallback as useCallback2, useEffect as useEffect16, useRef as useRef13, useState as useState21 } from "react";
25786
+ import { useCallback as useCallback2, useEffect as useEffect19, useRef as useRef13, useState as useState21 } from "react";
25539
25787
 
25540
25788
  // packages/experience-design-system-cli/src/tui/import/steps/09-review/history.ts
25541
25789
  var DEFAULT_MAX_DEPTH = 50;
@@ -25591,7 +25839,7 @@ function createHistoryStack(seed, maxDepth = DEFAULT_MAX_DEPTH) {
25591
25839
  }
25592
25840
 
25593
25841
  // packages/experience-design-system-cli/src/tui/import/steps/09-review/use-finalize-preview.ts
25594
- import { useEffect as useEffect15, useRef as useRef12, useState as useState20 } from "react";
25842
+ import { useEffect as useEffect18, useRef as useRef12, useState as useState20 } from "react";
25595
25843
 
25596
25844
  // packages/experience-design-system-cli/src/tui/import/steps/09-review/run-live-preview.ts
25597
25845
  var TimeoutError = class extends Error {
@@ -25751,7 +25999,7 @@ function useFinalizePreview(opts) {
25751
25999
  const [scrollOffset, setScrollOffset] = useState20(0);
25752
26000
  const generationRef = useRef12(0);
25753
26001
  const acceptedKey = [...acceptedKeys].sort().join("\0");
25754
- useEffect15(() => {
26002
+ useEffect18(() => {
25755
26003
  if (!open) {
25756
26004
  setStatus("idle");
25757
26005
  setRemoved([]);
@@ -25814,7 +26062,7 @@ function useReviewSession({
25814
26062
  }));
25815
26063
  return { result, catalog };
25816
26064
  }, [loadSession, tokensPath]);
25817
- useEffect16(() => {
26065
+ useEffect19(() => {
25818
26066
  let disposed = false;
25819
26067
  void (async () => {
25820
26068
  try {
@@ -25867,7 +26115,7 @@ function useReviewSession({
25867
26115
  function useReviewMetadata({ components, selectedIdx, extractSessionId }) {
25868
26116
  const [reviewMetadata, setReviewMetadata] = useState21(null);
25869
26117
  const [componentRationale, setComponentRationale] = useState21(null);
25870
- useEffect16(() => {
26118
+ useEffect19(() => {
25871
26119
  const current = components[selectedIdx];
25872
26120
  if (!current) {
25873
26121
  setReviewMetadata(null);
@@ -25896,10 +26144,16 @@ function useReviewMetadata({ components, selectedIdx, extractSessionId }) {
25896
26144
  }, [components, extractSessionId, selectedIdx]);
25897
26145
  return { reviewMetadata, componentRationale };
25898
26146
  }
25899
- function useReviewHistory({ loading, components, createSnapshot, applySnapshot }) {
26147
+ function useReviewHistory({
26148
+ loading,
26149
+ components,
26150
+ createSnapshot,
26151
+ applySnapshot,
26152
+ onAction
26153
+ }) {
25900
26154
  const historyRef = useRef13(null);
25901
26155
  const historySeededRef = useRef13(false);
25902
- useEffect16(() => {
26156
+ useEffect19(() => {
25903
26157
  if (loading || historySeededRef.current) return;
25904
26158
  historySeededRef.current = true;
25905
26159
  historyRef.current = createHistoryStack(createSnapshot(components));
@@ -25907,14 +26161,19 @@ function useReviewHistory({ loading, components, createSnapshot, applySnapshot }
25907
26161
  const pushHistorySnapshot = (entries, label) => {
25908
26162
  if (!historyRef.current) return;
25909
26163
  historyRef.current.push(createSnapshot(entries), label);
26164
+ onAction?.(label);
25910
26165
  };
25911
26166
  const handleUndo = () => {
25912
26167
  const snapshot = historyRef.current?.undo();
25913
- if (snapshot) applySnapshot(snapshot);
26168
+ if (!snapshot) return;
26169
+ applySnapshot(snapshot);
26170
+ onAction?.("undo");
25914
26171
  };
25915
26172
  const handleRedo = () => {
25916
26173
  const snapshot = historyRef.current?.redo();
25917
- if (snapshot) applySnapshot(snapshot);
26174
+ if (!snapshot) return;
26175
+ applySnapshot(snapshot);
26176
+ onAction?.("redo");
25918
26177
  };
25919
26178
  const resetHistory = (snapshot) => {
25920
26179
  historyRef.current?.reset(snapshot);
@@ -25950,7 +26209,7 @@ function useReviewFinalize({
25950
26209
  }
25951
26210
 
25952
26211
  // packages/experience-design-system-cli/src/tui/import/steps/09-review/use-review-editor.ts
25953
- import { useEffect as useEffect17, useRef as useRef14, useState as useState22 } from "react";
26212
+ import { useEffect as useEffect20, useRef as useRef14, useState as useState22 } from "react";
25954
26213
 
25955
26214
  // packages/experience-design-system-cli/src/tui/import/steps/09-review/token-suggestions.ts
25956
26215
  function collectTokenSuggestions(entry, availableTokens = []) {
@@ -26003,7 +26262,7 @@ function useReviewEditor({
26003
26262
  const [tokenReviewEditSelection, setTokenReviewEditSelection] = useState22(/* @__PURE__ */ new Set());
26004
26263
  const tokenReviewSuggestedRef = useRef14(/* @__PURE__ */ new Map());
26005
26264
  const pendingGRef = useRef14(false);
26006
- useEffect17(() => {
26265
+ useEffect20(() => {
26007
26266
  setTokenReviewRow(0);
26008
26267
  setTokenReviewEditing(false);
26009
26268
  setTokenReviewEditCursor(0);
@@ -26415,7 +26674,7 @@ function handleJsonPanelInput(input, key, state2) {
26415
26674
  }
26416
26675
 
26417
26676
  // packages/experience-design-system-cli/src/tui/import/steps/09-review/use-review-preview.ts
26418
- import { useCallback as useCallback4, useEffect as useEffect19, useState as useState25 } from "react";
26677
+ import { useCallback as useCallback4, useEffect as useEffect22, useState as useState25 } from "react";
26419
26678
 
26420
26679
  // packages/experience-design-system-cli/src/tui/import/steps/09-review/preview-annotations.ts
26421
26680
  function applyPreviewAnnotations(preview, localNames) {
@@ -26450,7 +26709,7 @@ function applyPreviewAnnotations(preview, localNames) {
26450
26709
  }
26451
26710
 
26452
26711
  // packages/experience-design-system-cli/src/tui/import/steps/09-review/use-live-preview.ts
26453
- import { useCallback as useCallback3, useEffect as useEffect18, useRef as useRef15, useState as useState24 } from "react";
26712
+ import { useCallback as useCallback3, useEffect as useEffect21, useRef as useRef15, useState as useState24 } from "react";
26454
26713
  var DEFAULT_DEBOUNCE_MS = 500;
26455
26714
  function useLivePreview(opts) {
26456
26715
  const debounceMs = opts.debounceMs ?? DEFAULT_DEBOUNCE_MS;
@@ -26461,14 +26720,14 @@ function useLivePreview(opts) {
26461
26720
  const latestRef = useRef15(0);
26462
26721
  const inflightRef = useRef15(0);
26463
26722
  const optsRef = useRef15(opts);
26464
- useEffect18(() => {
26723
+ useEffect21(() => {
26465
26724
  optsRef.current = opts;
26466
26725
  });
26467
26726
  const disabledRef = useRef15(disabled);
26468
- useEffect18(() => {
26727
+ useEffect21(() => {
26469
26728
  disabledRef.current = disabled;
26470
26729
  }, [disabled]);
26471
- useEffect18(() => {
26730
+ useEffect21(() => {
26472
26731
  return () => {
26473
26732
  if (timerRef.current) {
26474
26733
  clearTimeout(timerRef.current);
@@ -26582,13 +26841,13 @@ function useReviewPreview({
26582
26841
  deleteAllComponents
26583
26842
  });
26584
26843
  const [spinnerTick, setSpinnerTick] = useState25(0);
26585
- useEffect19(() => {
26844
+ useEffect22(() => {
26586
26845
  if (livePreviewHook.status !== "running") return;
26587
26846
  const id = setInterval(() => setSpinnerTick((tick) => tick + 1), 80);
26588
26847
  return () => clearInterval(id);
26589
26848
  }, [livePreviewHook.status]);
26590
26849
  const livePreviewSpinner = SPINNER_FRAMES[spinnerTick % SPINNER_FRAMES.length];
26591
- useEffect19(() => {
26850
+ useEffect22(() => {
26592
26851
  if (loading) return;
26593
26852
  if (!livePreview) return;
26594
26853
  if (components.length === 0) return;
@@ -26597,6 +26856,117 @@ function useReviewPreview({
26597
26856
  return { previewAnnotations, removedComponents, livePreviewHook, livePreviewSpinner };
26598
26857
  }
26599
26858
 
26859
+ // packages/experience-design-system-cli/src/tui/import/steps/09-review/use-review-log.ts
26860
+ init_debug_store();
26861
+ import { useEffect as useEffect23, useRef as useRef16 } from "react";
26862
+
26863
+ // packages/experience-design-system-cli/src/tui/import/steps/09-review/review-log.ts
26864
+ var REVIEW_RUN = { flow: "import/review", step: "09-review", menuOption: "Review" };
26865
+ var MAX_ACTIONS = 30;
26866
+ var MAX_NAMES2 = 20;
26867
+ var countStatuses = (components) => {
26868
+ const counts = {};
26869
+ for (const { status } of components) counts[status] = (counts[status] ?? 0) + 1;
26870
+ return counts;
26871
+ };
26872
+ var capped2 = (keys) => ({
26873
+ count: keys.length,
26874
+ keys: keys.slice(0, MAX_NAMES2)
26875
+ });
26876
+ function reviewInputs(components) {
26877
+ return { components: components.length, by_status: countStatuses(components) };
26878
+ }
26879
+ function openReviewTrail(components, now) {
26880
+ return {
26881
+ startedAt: now,
26882
+ start: new Map(components.map((component) => [component.key, component.status])),
26883
+ actions: [],
26884
+ kinds: {}
26885
+ };
26886
+ }
26887
+ function recordReviewAction(trail, label) {
26888
+ const kind = label.split(":")[0] ?? label;
26889
+ trail.kinds[kind] = (trail.kinds[kind] ?? 0) + 1;
26890
+ if (trail.actions.length < MAX_ACTIONS) trail.actions.push(label);
26891
+ }
26892
+ function render(trail, components, now, outcome) {
26893
+ const acceptedByUser = [];
26894
+ const rejectedByUser = [];
26895
+ for (const { key, status } of components) {
26896
+ const was = trail.start.get(key);
26897
+ if (was === status) continue;
26898
+ if (status === "accepted") acceptedByUser.push(key);
26899
+ if (status === "rejected") rejectedByUser.push(key);
26900
+ }
26901
+ const total = Object.values(trail.kinds).reduce((sum, count) => sum + count, 0);
26902
+ return {
26903
+ outcome,
26904
+ seconds: Math.round((now - trail.startedAt) / 100) / 10,
26905
+ edits: { total, by_kind: trail.kinds, in_order: trail.actions },
26906
+ now: countStatuses(components),
26907
+ accepted_by_user: capped2(acceptedByUser),
26908
+ rejected_by_user: capped2(rejectedByUser)
26909
+ };
26910
+ }
26911
+ function reviewProgress(trail, components, now) {
26912
+ return render(trail, components, now, "interrupted");
26913
+ }
26914
+ function reviewFinish(trail, components, now, final) {
26915
+ const outcome = final ? `finalized: ${final.accepted} accepted, ${final.rejected} rejected, ${final.unresolved} unresolved` : "left the review without finishing";
26916
+ return {
26917
+ outputs: render(trail, components, now, outcome),
26918
+ status: "success",
26919
+ exitMethod: final ? "saved" : "discarded"
26920
+ };
26921
+ }
26922
+
26923
+ // packages/experience-design-system-cli/src/tui/import/steps/09-review/use-review-log.ts
26924
+ function useReviewLog({
26925
+ loading,
26926
+ loadError,
26927
+ components
26928
+ }) {
26929
+ const trail = useRef16(void 0);
26930
+ const started = useRef16(false);
26931
+ const latest = useRef16(components);
26932
+ latest.current = components;
26933
+ useEffect23(() => {
26934
+ if (loading || started.current) return;
26935
+ started.current = true;
26936
+ startDebugRun({ ...REVIEW_RUN, inputs: reviewInputs(components) });
26937
+ if (loadError) {
26938
+ void finishDebugRun({
26939
+ outputs: { outcome: "could not load the components", error: loadError },
26940
+ status: "error",
26941
+ exitMethod: "discarded"
26942
+ });
26943
+ return;
26944
+ }
26945
+ trail.current = openReviewTrail(components, Date.now());
26946
+ setDebugRunProgress(reviewProgress(trail.current, components, Date.now()));
26947
+ }, [loading, loadError, components]);
26948
+ useEffect23(
26949
+ () => () => {
26950
+ const open = trail.current;
26951
+ trail.current = void 0;
26952
+ if (open) void finishDebugRun(reviewFinish(open, latest.current, Date.now(), void 0));
26953
+ },
26954
+ []
26955
+ );
26956
+ return {
26957
+ record: (label) => {
26958
+ if (!trail.current) return;
26959
+ recordReviewAction(trail.current, label);
26960
+ setDebugRunProgress(reviewProgress(trail.current, latest.current, Date.now()));
26961
+ },
26962
+ finish: (counts) => {
26963
+ const open = trail.current;
26964
+ trail.current = void 0;
26965
+ if (open) void finishDebugRun(reviewFinish(open, latest.current, Date.now(), counts));
26966
+ }
26967
+ };
26968
+ }
26969
+
26600
26970
  // packages/experience-design-system-cli/src/tui/import/steps/09-review/components/LivePreviewSummary.tsx
26601
26971
  import { Box as Box37, Text as Text39 } from "ink";
26602
26972
  import { jsx as jsx47, jsxs as jsxs37 } from "react/jsx-runtime";
@@ -26884,6 +27254,7 @@ function GenerateReviewStepView({
26884
27254
  tokensPath,
26885
27255
  onExtraLoaded: setLoadedSlotCycles
26886
27256
  });
27257
+ const reviewLog = useReviewLog({ loading, loadError, components });
26887
27258
  const [nav, setNav] = useState26({
26888
27259
  cursorRowIdx: 0,
26889
27260
  sidebarScrollOffset: 0
@@ -26901,7 +27272,7 @@ function GenerateReviewStepView({
26901
27272
  setFinalizeError
26902
27273
  } = reviewSurface;
26903
27274
  const [removedBannerCollapsed, setRemovedBannerCollapsed] = useState26(false);
26904
- const removedBannerDefaultedRef = useRef16(false);
27275
+ const removedBannerDefaultedRef = useRef17(false);
26905
27276
  const [cyclePanelScroll, setCyclePanelScroll] = useState26(0);
26906
27277
  const [cyclesCursor, setCyclesCursor] = useState26(0);
26907
27278
  const cyclePanel = useOverlayPanel({
@@ -26921,7 +27292,7 @@ function GenerateReviewStepView({
26921
27292
  const [breakCursor, setBreakCursor] = useState26(0);
26922
27293
  const [breakConfirm, setBreakConfirm] = useState26(false);
26923
27294
  const [expandedGroups, setExpandedGroups] = useState26(/* @__PURE__ */ new Set());
26924
- const seededGroupsRef = useRef16(false);
27295
+ const seededGroupsRef = useRef17(false);
26925
27296
  const {
26926
27297
  searchOpen,
26927
27298
  setSearchOpen,
@@ -26945,7 +27316,7 @@ function GenerateReviewStepView({
26945
27316
  const [pendingEditorFocus, setPendingEditorFocus] = useState26(null);
26946
27317
  const [autoRejected, setAutoRejected] = useState26([]);
26947
27318
  const [undoSnapshot, setUndoSnapshot] = useState26(null);
26948
- const autoRejectFiredRef = useRef16(false);
27319
+ const autoRejectFiredRef = useRef17(false);
26949
27320
  const [showReloadDialog, setShowReloadDialog] = useState26(false);
26950
27321
  const acceptedCountForPreview = components.filter((c2) => c2.status === "accepted").length;
26951
27322
  const { previewAnnotations, removedComponents, livePreviewHook, livePreviewSpinner } = useReviewPreview({
@@ -26977,7 +27348,10 @@ function GenerateReviewStepView({
26977
27348
  cmaToken,
26978
27349
  host,
26979
27350
  components,
26980
- onFinalize
27351
+ onFinalize: (accepted, rejected, unresolved) => {
27352
+ reviewLog.finish({ accepted, rejected, unresolved });
27353
+ onFinalize(accepted, rejected, unresolved);
27354
+ }
26981
27355
  });
26982
27356
  const recomputeCycles = (currentComponents) => {
26983
27357
  try {
@@ -27008,7 +27382,7 @@ function GenerateReviewStepView({
27008
27382
  [components]
27009
27383
  );
27010
27384
  const closures = useMemo6(() => computeAllClosures(componentGraph), [componentGraph]);
27011
- useEffect20(() => {
27385
+ useEffect24(() => {
27012
27386
  if (seededGroupsRef.current) return;
27013
27387
  if (closures.size === 0 && slotCycles.length === 0) return;
27014
27388
  seededGroupsRef.current = true;
@@ -27035,7 +27409,7 @@ function GenerateReviewStepView({
27035
27409
  suggestedBreak: cycle.edges.length > 0 ? suggestCycleBreakEdge2(cycle, cycleView.pushBlocking) : null
27036
27410
  }));
27037
27411
  }, [slotCycles, cycleView]);
27038
- useEffect20(() => {
27412
+ useEffect24(() => {
27039
27413
  const decision = computeAutoRejectDecision({
27040
27414
  loading,
27041
27415
  autoRejectFired: autoRejectFiredRef.current,
@@ -27076,10 +27450,11 @@ function GenerateReviewStepView({
27076
27450
  autoRejected,
27077
27451
  undoSnapshot
27078
27452
  }),
27079
- applySnapshot: applyHistorySnapshot
27453
+ applySnapshot: applyHistorySnapshot,
27454
+ onAction: reviewLog.record
27080
27455
  });
27081
- const autoRejectPushedRef = useRef16(false);
27082
- useEffect20(() => {
27456
+ const autoRejectPushedRef = useRef17(false);
27457
+ useEffect24(() => {
27083
27458
  if (loading) return;
27084
27459
  if (!historySeededRef.current) return;
27085
27460
  if (!autoRejectFiredRef.current) return;
@@ -27163,7 +27538,7 @@ function GenerateReviewStepView({
27163
27538
  const panelHeight = leftPanelHeight + 2;
27164
27539
  const panelContentHeight = Math.max(1, panelHeight - 3);
27165
27540
  const cycleViewportHeight = Math.max(1, panelHeight - 4);
27166
- useEffect20(() => {
27541
+ useEffect24(() => {
27167
27542
  if (selectableRowPositions.length === 0) return;
27168
27543
  const cursorInRange = selectableRowPositions.includes(cursorRowIdx);
27169
27544
  const maxScroll = Math.max(0, visibleRowsMemo.length - visibleCount);
@@ -28108,10 +28483,10 @@ function normalizePath(input) {
28108
28483
  }
28109
28484
 
28110
28485
  // packages/experience-design-system-cli/src/tui/import/steps/10-flow/support/use-blinking-cursor.ts
28111
- import { useEffect as useEffect21, useState as useState27 } from "react";
28486
+ import { useEffect as useEffect25, useState as useState27 } from "react";
28112
28487
  function useBlinkingCursor() {
28113
28488
  const [visible, setVisible] = useState27(true);
28114
- useEffect21(() => {
28489
+ useEffect25(() => {
28115
28490
  const interval = setInterval(() => setVisible((current) => !current), 500);
28116
28491
  return () => clearInterval(interval);
28117
28492
  }, []);
@@ -28227,12 +28602,12 @@ function countedThings({ components, tokens }, counts = {}) {
28227
28602
  }
28228
28603
 
28229
28604
  // packages/experience-design-system-cli/src/tui/import/steps/10-flow/support/use-timed-spinner.tsx
28230
- import { useEffect as useEffect22, useState as useState29 } from "react";
28605
+ import { useEffect as useEffect26, useState as useState29 } from "react";
28231
28606
  import { Spinner as Spinner2 } from "@inkjs/ui";
28232
28607
  import { jsx as jsx53 } from "react/jsx-runtime";
28233
28608
  function useTimedSpinner() {
28234
28609
  const [elapsedSeconds, setElapsedSeconds] = useState29(0);
28235
- useEffect22(() => {
28610
+ useEffect26(() => {
28236
28611
  const timer = setInterval(() => setElapsedSeconds((current) => current + 1), 1e3);
28237
28612
  return () => {
28238
28613
  clearInterval(timer);
@@ -28290,7 +28665,7 @@ function PushingStep({ progress, produced, counts }) {
28290
28665
  }
28291
28666
 
28292
28667
  // packages/experience-design-system-cli/src/tui/import/steps/10-flow/screens/WizardPreviewStep.tsx
28293
- import { useEffect as useEffect23, useState as useState30, useMemo as useMemo7 } from "react";
28668
+ import { useEffect as useEffect27, useState as useState30, useMemo as useMemo7 } from "react";
28294
28669
  import { Box as Box44, Text as Text46 } from "ink";
28295
28670
 
28296
28671
  // packages/experience-design-system-cli/src/tui/import/steps/10-flow/support/preview-diff.ts
@@ -28685,7 +29060,7 @@ function WizardPreviewStep({
28685
29060
  const activeLines = diffExpanded ? diffLines : summaryLines;
28686
29061
  const maxScroll = Math.max(0, activeLines.length - viewportHeight);
28687
29062
  const boundedScrollOffset = Math.min(scrollOffset, maxScroll);
28688
- useEffect23(() => {
29063
+ useEffect27(() => {
28689
29064
  setScrollOffset((previous) => Math.min(previous, maxScroll));
28690
29065
  }, [maxScroll]);
28691
29066
  useImmediateInput((input, key) => {
@@ -28775,6 +29150,194 @@ function buildRunTeaserLine(runId) {
28775
29150
  return `Run saved as ${runId}.`;
28776
29151
  }
28777
29152
 
29153
+ // packages/experience-design-system-cli/src/tui/import/steps/10-flow/flow/use-flow-log.ts
29154
+ init_debug_store();
29155
+ import { useEffect as useEffect28, useRef as useRef18 } from "react";
29156
+
29157
+ // packages/experience-design-system-cli/src/tui/import/steps/10-flow/flow/flow-log.ts
29158
+ var FLOW_RUN = { flow: "import/publish", step: "10-publish", menuOption: "Publish" };
29159
+ var LABELS = {
29160
+ "final-review": "Final review",
29161
+ "path-prompt": "Save path",
29162
+ printing: "Save files",
29163
+ previewing: "Preview",
29164
+ "preview-gate": "Preview confirmation",
29165
+ pushing: "Push",
29166
+ "print-gate": "Files saved",
29167
+ done: "Done",
29168
+ error: "Error",
29169
+ "preview-validation-error": "Preview validation"
29170
+ };
29171
+ var WORK = ["printing", "previewing", "pushing"];
29172
+ var FINISHED = ["done", "error", "preview-validation-error", "final-review"];
29173
+ var MAX_LOGGED = 10;
29174
+ var MAX_OUTCOME = 200;
29175
+ var scrub = (text, state2) => scrubError(text, [state2.cmaToken]);
29176
+ var seconds = (ms) => Math.round(ms / 100) / 10;
29177
+ var pushHasFailures = (result) => result.componentTypes.failed + result.designTokens.failed > 0 || (result.failures?.length ?? 0) > 0 || (result.summary?.failed ?? 0) > 0;
29178
+ function previewSummary(preview) {
29179
+ const counts = (group) => ({
29180
+ new: group.new.length,
29181
+ changed: group.changed.length,
29182
+ removed: group.removed.length
29183
+ });
29184
+ return {
29185
+ components: counts(preview.components),
29186
+ tokens: counts(preview.tokens),
29187
+ breaking_components: preview.components.changed.filter(
29188
+ (entry) => entry.changeClassification?.classification === "breaking"
29189
+ ).length
29190
+ };
29191
+ }
29192
+ function pushSummary(result, state2) {
29193
+ const failures = result.failures ?? [];
29194
+ return {
29195
+ component_types: result.componentTypes,
29196
+ design_tokens: result.designTokens,
29197
+ ...result.summary ? { summary: result.summary } : {},
29198
+ ...failures.length > 0 ? {
29199
+ failure_count: failures.length,
29200
+ failures: failures.slice(0, MAX_LOGGED).map((failure) => ({
29201
+ entity_type: failure.entityType,
29202
+ entity_id: failure.entityId,
29203
+ message: scrub(failure.message, state2)
29204
+ }))
29205
+ } : {}
29206
+ };
29207
+ }
29208
+ function flowContext(state2) {
29209
+ return {
29210
+ agent: state2.agent,
29211
+ space_id: state2.spaceId,
29212
+ environment_id: state2.environmentId,
29213
+ host: state2.host,
29214
+ credentials_skipped: state2.credentialsSkipped,
29215
+ components_generated: state2.generatedCount,
29216
+ components_accepted: state2.generatedAcceptedCount,
29217
+ tokens: state2.tokenCount,
29218
+ cma_token: state2.cmaToken
29219
+ };
29220
+ }
29221
+ function arrive(trail, state2) {
29222
+ const next = { ...trail, at: state2.step };
29223
+ if (state2.step === "error") {
29224
+ next.failure = { step: state2.errorStep, message: scrub(state2.errorMessage, state2) };
29225
+ }
29226
+ if (state2.step === "preview-validation-error") {
29227
+ next.validation = {
29228
+ count: state2.previewValidationErrors.length,
29229
+ errors: state2.previewValidationErrors.slice(0, MAX_LOGGED).map((error) => ({
29230
+ component: error.componentName,
29231
+ path: error.path,
29232
+ message: scrub(error.message, state2)
29233
+ })),
29234
+ missing_names: state2.previewValidationMissingNames.slice(0, MAX_LOGGED * 2)
29235
+ };
29236
+ }
29237
+ return next;
29238
+ }
29239
+ function openTrail(state2, now) {
29240
+ return arrive({ startedAt: now, stageStartedAt: now, at: state2.step, stages: [] }, state2);
29241
+ }
29242
+ function advance(trail, from, to, now) {
29243
+ const next = { ...trail, stages: [...trail.stages], stageStartedAt: now };
29244
+ const failed = to.step === "error" || to.step === "preview-validation-error" || from.step === "pushing" && pushHasFailures(to.pushResult);
29245
+ if (WORK.includes(from.step)) {
29246
+ next.stages.push(`${LABELS[from.step]}: ${failed ? "failed" : "ok"} (${seconds(now - trail.stageStartedAt)}s)`);
29247
+ }
29248
+ if (from.step === "previewing" && to.serverPreview) next.preview = previewSummary(to.serverPreview);
29249
+ if (from.step === "pushing") {
29250
+ next.push = pushSummary(to.pushResult, to);
29251
+ next.pushFailed = pushHasFailures(to.pushResult);
29252
+ }
29253
+ if (from.step === "printing" && !failed) next.saved = { path: to.componentsPath, run_id: to.lastRunId };
29254
+ return arrive(next, to);
29255
+ }
29256
+ var isFlowFinished = (step) => FINISHED.includes(step);
29257
+ function render2(trail, now, outcome) {
29258
+ return {
29259
+ outcome,
29260
+ total_seconds: seconds(now - trail.startedAt),
29261
+ stages: trail.stages,
29262
+ ...trail.preview ? { preview: trail.preview } : {},
29263
+ ...trail.push ? { push: trail.push } : {},
29264
+ ...trail.saved ? { saved: trail.saved } : {},
29265
+ ...trail.failure ? { error: trail.failure } : {},
29266
+ ...trail.validation ? { preview_validation: trail.validation } : {}
29267
+ };
29268
+ }
29269
+ function flowProgress(trail, now) {
29270
+ return render2(trail, now, `interrupted at ${LABELS[trail.at]}`);
29271
+ }
29272
+ function flowFinish(trail, final, now) {
29273
+ if (!final) {
29274
+ const midWork = WORK.includes(trail.at);
29275
+ const outcome2 = `left the import ${midWork ? "while" : "at"} ${LABELS[trail.at]}${midWork ? " was running" : ""}`;
29276
+ return { outputs: render2(trail, now, outcome2), status: midWork ? "error" : "success", exitMethod: "discarded" };
29277
+ }
29278
+ if (final.step === "final-review") {
29279
+ return {
29280
+ outputs: render2(trail, now, "went back to edit the definitions"),
29281
+ status: "success",
29282
+ exitMethod: "discarded"
29283
+ };
29284
+ }
29285
+ let outcome;
29286
+ let failed = true;
29287
+ if (trail.validation) {
29288
+ outcome = `blocked by ${String(trail.validation["count"])} preview validation error(s)`;
29289
+ } else if (trail.failure) {
29290
+ outcome = `failed at ${trail.failure.step}: ${trail.failure.message.slice(0, MAX_OUTCOME)}`;
29291
+ } else if (trail.pushFailed) {
29292
+ outcome = "pushed, but some entities failed";
29293
+ } else {
29294
+ failed = false;
29295
+ outcome = final.credentialsSkipped ? "saved without pushing (credentials skipped)" : "published";
29296
+ }
29297
+ return {
29298
+ outputs: render2(trail, now, outcome),
29299
+ status: failed ? "error" : "success",
29300
+ exitMethod: failed ? "discarded" : "saved"
29301
+ };
29302
+ }
29303
+
29304
+ // packages/experience-design-system-cli/src/tui/import/steps/10-flow/flow/use-flow-log.ts
29305
+ function useFlowLog(state2) {
29306
+ const trail = useRef18(void 0);
29307
+ const previous = useRef18(void 0);
29308
+ useEffect28(() => {
29309
+ const before = previous.current;
29310
+ previous.current = state2;
29311
+ const moved = before !== void 0 && before.step !== state2.step;
29312
+ const now = Date.now();
29313
+ let open = trail.current;
29314
+ if (!open) {
29315
+ if (state2.step === "final-review" || before && !moved) return;
29316
+ open = openTrail(state2, now);
29317
+ startDebugRun({ ...FLOW_RUN, inputs: flowContext(state2) });
29318
+ } else if (before && moved) {
29319
+ open = advance(open, before, state2, now);
29320
+ } else {
29321
+ return;
29322
+ }
29323
+ if (isFlowFinished(state2.step)) {
29324
+ trail.current = void 0;
29325
+ void finishDebugRun(flowFinish(open, state2, now));
29326
+ return;
29327
+ }
29328
+ trail.current = open;
29329
+ setDebugRunProgress(flowProgress(open, now));
29330
+ }, [state2]);
29331
+ useEffect28(
29332
+ () => () => {
29333
+ const open = trail.current;
29334
+ trail.current = void 0;
29335
+ if (open) void finishDebugRun(flowFinish(open, void 0, Date.now()));
29336
+ },
29337
+ []
29338
+ );
29339
+ }
29340
+
28778
29341
  // packages/experience-design-system-cli/src/tui/import/steps/10-flow/flow/screen.tsx
28779
29342
  import { jsx as jsx56, jsxs as jsxs45 } from "react/jsx-runtime";
28780
29343
  function canEditFromPreview(cdf) {
@@ -28788,6 +29351,7 @@ function FlowScreen({
28788
29351
  generatePromptPath,
28789
29352
  onExit
28790
29353
  }) {
29354
+ useFlowLog(state2);
28791
29355
  const produced = producedOf(state2);
28792
29356
  const counts = { components: state2.generatedAcceptedCount, tokens: state2.tokenCount };
28793
29357
  const things = countedThings(produced, counts);
@@ -28903,7 +29467,7 @@ function FlowScreen({
28903
29467
  }
28904
29468
 
28905
29469
  // packages/experience-design-system-cli/src/tui/import/steps/10-flow/flow/use-flow.ts
28906
- import { useEffect as useEffect24, useRef as useRef17, useSyncExternalStore } from "react";
29470
+ import { useEffect as useEffect29, useRef as useRef19, useSyncExternalStore } from "react";
28907
29471
 
28908
29472
  // packages/experience-design-system-cli/src/tui/import/steps/10-flow/flow/controller.ts
28909
29473
  import { appendFileSync, writeFileSync } from "node:fs";
@@ -29268,13 +29832,12 @@ function nextStateAfterPrint(opts) {
29268
29832
 
29269
29833
  // packages/experience-design-system-cli/src/tui/import/steps/10-flow/flow/save.ts
29270
29834
  var SAVE_CONFIRMATION_DELAY_MS = 1e3;
29271
- var describeCdfError = (error) => `${error.path.replace(/^\//, "").replace("/$properties/", ".").replaceAll("/", ".")}: ${error.message}`;
29272
29835
  function buildSavedCDF(components, tokens, opts = {}) {
29273
29836
  const cdf = buildCDF2(components, toCdfTokens(tokens), opts);
29274
29837
  if (!cdf) throw new Error("nothing to save \u2014 no components or tokens resolved");
29275
29838
  const validation = validateCDF2(cdf);
29276
29839
  if (!validation.valid) {
29277
- throw new Error(`generated CDF failed validation: ${validation.errors.map(describeCdfError).join("; ")}`);
29840
+ throw new Error(`generated CDF failed validation: ${validation.errors.map((error) => error.message).join(", ")}`);
29278
29841
  }
29279
29842
  return cdf;
29280
29843
  }
@@ -29301,11 +29864,7 @@ async function runPrintFiles(input, deps, onPatch) {
29301
29864
  db.close();
29302
29865
  }
29303
29866
  if (!input.tokenSessionId && input.tokensPath) tokens = await deps.readTokens(input.tokensPath);
29304
- const cdf = buildSavedCDF(components, tokens, {
29305
- deleteAll: input.allowEmpty,
29306
- onRepair: (message) => deps.warn(`${message}
29307
- `)
29308
- });
29867
+ const cdf = buildSavedCDF(components, tokens, { deleteAll: input.allowEmpty });
29309
29868
  await deps.writeFile(componentsPath, `${JSON.stringify(cdf, null, 2)}
29310
29869
  `);
29311
29870
  deps.warn(
@@ -29650,7 +30209,7 @@ function createFlowController(start, deps) {
29650
30209
 
29651
30210
  // packages/experience-design-system-cli/src/tui/import/steps/10-flow/flow/use-flow.ts
29652
30211
  function useFlow(start, options = {}) {
29653
- const controller = useRef17();
30212
+ const controller = useRef19();
29654
30213
  if (start && !controller.current) {
29655
30214
  try {
29656
30215
  startWizardLog();
@@ -29667,14 +30226,14 @@ function useFlow(start, options = {}) {
29667
30226
  (listener) => current?.subscribe(listener) ?? (() => void 0),
29668
30227
  () => current?.getState()
29669
30228
  );
29670
- useEffect24(() => {
30229
+ useEffect29(() => {
29671
30230
  if (!start) controller.current = void 0;
29672
30231
  }, [start]);
29673
30232
  return current && state2 ? { controller: current, state: state2 } : void 0;
29674
30233
  }
29675
30234
 
29676
30235
  // packages/experience-design-system-cli/src/tui/help/PageContainer.tsx
29677
- import { useEffect as useEffect25, useState as useState31 } from "react";
30236
+ import { useEffect as useEffect30, useState as useState31 } from "react";
29678
30237
  import { Box as Box46, Text as Text47, useInput as useInput13 } from "ink";
29679
30238
  init_debug_store();
29680
30239
 
@@ -29748,7 +30307,7 @@ function Section({ title, rows }) {
29748
30307
  }
29749
30308
  function HelpScreen({ onDone }) {
29750
30309
  const [info, setInfo] = useState31();
29751
- useEffect25(() => {
30310
+ useEffect30(() => {
29752
30311
  startDebugRun({ flow: "help", step: "01-help", menuOption: "Help", inputs: {} });
29753
30312
  void readHelpInfo().then(setInfo);
29754
30313
  }, []);
@@ -29845,43 +30404,10 @@ import { useState as useState36 } from "react";
29845
30404
  import { Box as Box51, Text as Text53, useInput as useInput17 } from "ink";
29846
30405
 
29847
30406
  // packages/experience-design-system-cli/src/tui/settings/configuration/agents/AgentsScreen.tsx
29848
- import { useEffect as useEffect27, useRef as useRef18, useState as useState34 } from "react";
30407
+ import { useEffect as useEffect32, useRef as useRef20, useState as useState34 } from "react";
29849
30408
  import { Box as Box49, Text as Text51, useInput as useInput15 } from "ink";
29850
30409
  init_debug_store();
29851
30410
 
29852
- // packages/experience-design-system-cli/src/tui/settings/shared/debug-trail.ts
29853
- init_config();
29854
- import { existsSync as existsSync10 } from "node:fs";
29855
- function diffSnapshots(before, after) {
29856
- const names = [.../* @__PURE__ */ new Set([...Object.keys(before), ...Object.keys(after)])];
29857
- const changed_fields = names.filter((name) => before[name] !== after[name]);
29858
- return { changed: changed_fields.length > 0, changed_fields };
29859
- }
29860
- var DEFAULT_TRAIL_LIMIT = 30;
29861
- function createTrail(limit = DEFAULT_TRAIL_LIMIT) {
29862
- const actions = [];
29863
- return {
29864
- record(action) {
29865
- actions.push(action);
29866
- if (actions.length > limit) actions.shift();
29867
- },
29868
- entries: () => [...actions]
29869
- };
29870
- }
29871
- var MIN_SECRET_LENGTH = 6;
29872
- function scrubError(error, secrets) {
29873
- let message = error instanceof Error ? error.message : String(error);
29874
- for (const secret of secrets) {
29875
- if (secret.length < MIN_SECRET_LENGTH) continue;
29876
- for (const form of /* @__PURE__ */ new Set([secret, encodeURIComponent(secret)])) message = message.split(form).join("[redacted]");
29877
- }
29878
- return message;
29879
- }
29880
- function describeSettingsFile() {
29881
- const path5 = configFilePath();
29882
- return { path: path5, eds_home_set: Boolean(process.env["EDS_HOME"]), exists: existsSync10(path5) };
29883
- }
29884
-
29885
30411
  // packages/experience-design-system-cli/src/tui/settings/configuration/agents/agent-status.ts
29886
30412
  import { execFile as execFile2 } from "node:child_process";
29887
30413
  import { access as access5, constants } from "node:fs/promises";
@@ -29966,7 +30492,7 @@ async function testAgent(name, binary, model) {
29966
30492
  timeoutMs: PROMPT_TIMEOUT_MS
29967
30493
  })
29968
30494
  );
29969
- const seconds = ((Date.now() - started) / 1e3).toFixed(1);
30495
+ const seconds2 = ((Date.now() - started) / 1e3).toFixed(1);
29970
30496
  if (result.timedOut) {
29971
30497
  return [...checks, { ...fail3("prompt", `no answer within ${PROMPT_TIMEOUT_MS / 1e3}s`), timedOut: true }];
29972
30498
  }
@@ -29974,7 +30500,7 @@ async function testAgent(name, binary, model) {
29974
30500
  const reason = result.stderr.trim().split("\n").pop()?.slice(0, 160) || `exited with code ${result.exitCode}`;
29975
30501
  return [...checks, fail3("prompt", reason)];
29976
30502
  }
29977
- return [...checks, pass("prompt", `answered in ${seconds}s`)];
30503
+ return [...checks, pass("prompt", `answered in ${seconds2}s`)];
29978
30504
  }
29979
30505
  function statusFromChecks(name, checks, savedBinary) {
29980
30506
  if (checks.length === 0) return "checking";
@@ -30174,7 +30700,7 @@ async function writeAgentConfig(config) {
30174
30700
  }
30175
30701
 
30176
30702
  // packages/experience-design-system-cli/src/tui/settings/configuration/agents/AgentDetail.tsx
30177
- import { useEffect as useEffect26, useState as useState33 } from "react";
30703
+ import { useEffect as useEffect31, useState as useState33 } from "react";
30178
30704
  import { Box as Box48, Text as Text50 } from "ink";
30179
30705
 
30180
30706
  // packages/experience-design-system-cli/src/tui/settings/configuration/agents/AgentStatusBadge.tsx
@@ -30237,7 +30763,7 @@ function AgentDetail({
30237
30763
  const [testing, setTesting] = useState33(false);
30238
30764
  const [notice, setNotice] = useState33(null);
30239
30765
  const [checks, setChecks] = useState33(void 0);
30240
- useEffect26(() => {
30766
+ useEffect31(() => {
30241
30767
  let active = true;
30242
30768
  setChecks(void 0);
30243
30769
  const timer = setTimeout(() => {
@@ -30322,7 +30848,7 @@ function AgentsScreen({ onDone }) {
30322
30848
  const [saving, setSaving] = useState34(false);
30323
30849
  const [loadError, setLoadError] = useState34(null);
30324
30850
  const [checks, setChecks] = useState34({});
30325
- const visit = useRef18({
30851
+ const visit = useRef20({
30326
30852
  trail: createTrail(),
30327
30853
  before: void 0,
30328
30854
  environment: void 0,
@@ -30335,7 +30861,7 @@ function AgentsScreen({ onDone }) {
30335
30861
  );
30336
30862
  }
30337
30863
  };
30338
- useEffect27(() => {
30864
+ useEffect32(() => {
30339
30865
  readAgentConfig().then((loaded) => {
30340
30866
  setConfig(loaded);
30341
30867
  inspectAll(loaded);
@@ -30512,7 +31038,7 @@ function AgentsScreen({ onDone }) {
30512
31038
  }
30513
31039
 
30514
31040
  // packages/experience-design-system-cli/src/tui/settings/configuration/project/ProjectScreen.tsx
30515
- import { useEffect as useEffect28, useRef as useRef19, useState as useState35 } from "react";
31041
+ import { useEffect as useEffect33, useRef as useRef21, useState as useState35 } from "react";
30516
31042
  import { Box as Box50, Text as Text52, useInput as useInput16 } from "ink";
30517
31043
  init_debug_store();
30518
31044
 
@@ -30570,14 +31096,14 @@ function ProjectScreen({ onDone }) {
30570
31096
  const [saving, setSaving] = useState35(false);
30571
31097
  const [notice, setNotice] = useState35(null);
30572
31098
  const [loadError, setLoadError] = useState35(null);
30573
- const visit = useRef19({
31099
+ const visit = useRef21({
30574
31100
  trail: createTrail(),
30575
31101
  before: void 0,
30576
31102
  persisted: void 0,
30577
31103
  error: ""
30578
31104
  }).current;
30579
- const scrub = (err) => scrubError(err, [config?.cmaToken ?? ""]);
30580
- useEffect28(() => {
31105
+ const scrub2 = (err) => scrubError(err, [config?.cmaToken ?? ""]);
31106
+ useEffect33(() => {
30581
31107
  readCredentials().then((cfg) => {
30582
31108
  setConfig(cfg);
30583
31109
  visit.before = snapshotOf(cfg);
@@ -30644,7 +31170,7 @@ function ProjectScreen({ onDone }) {
30644
31170
  if (config.contentfulBaseDir) void startDebugSessionIn(config.contentfulBaseDir, { replace: true });
30645
31171
  setNotice({ kind: "success", text: "Project settings saved" });
30646
31172
  }).catch((err) => {
30647
- visit.error = scrub(err);
31173
+ visit.error = scrub2(err);
30648
31174
  visit.trail.record("save failed");
30649
31175
  setNotice({ kind: "error", text: err instanceof Error ? err.message : "Failed to save" });
30650
31176
  }).finally(() => setSaving(false));
@@ -30729,7 +31255,7 @@ function ConfigurationScreen({ onDone }) {
30729
31255
  }
30730
31256
 
30731
31257
  // packages/experience-design-system-cli/src/tui/settings/opt-in-analytics/screen.tsx
30732
- import { useEffect as useEffect29, useState as useState37 } from "react";
31258
+ import { useEffect as useEffect34, useState as useState37 } from "react";
30733
31259
  import { Box as Box52, Text as Text54, useInput as useInput18 } from "ink";
30734
31260
 
30735
31261
  // packages/experience-design-system-cli/src/tui/settings/opt-in-analytics/analytics-store.ts
@@ -30753,7 +31279,7 @@ import { Fragment as Fragment20, jsx as jsx64, jsxs as jsxs52 } from "react/jsx-
30753
31279
  function OptInAnalyticsScreen({ onDone }) {
30754
31280
  const [loading, setLoading] = useState37(true);
30755
31281
  const [enabled, setEnabled] = useState37(true);
30756
- useEffect29(() => {
31282
+ useEffect34(() => {
30757
31283
  readAnalyticsSetting().then((setting) => {
30758
31284
  setEnabled(setting.enabled);
30759
31285
  setLoading(false);
@@ -30807,7 +31333,7 @@ function OptInAnalyticsScreen({ onDone }) {
30807
31333
  }
30808
31334
 
30809
31335
  // packages/experience-design-system-cli/src/tui/settings/debug-mode/screen.tsx
30810
- import { useEffect as useEffect30, useRef as useRef20, useState as useState38 } from "react";
31336
+ import { useEffect as useEffect35, useRef as useRef22, useState as useState38 } from "react";
30811
31337
  import { Box as Box53, Text as Text55, useInput as useInput19 } from "ink";
30812
31338
  init_debug_mode_store();
30813
31339
  init_debug_store();
@@ -30824,8 +31350,8 @@ function DebugModeScreen({ onDone }) {
30824
31350
  RETENTION_CHOICES[RETENTION_CHOICES.length - 1]
30825
31351
  );
30826
31352
  const [notice, setNotice] = useState38(null);
30827
- const visit = useRef20({ trail: createTrail(), before: void 0, error: "" }).current;
30828
- useEffect30(() => {
31353
+ const visit = useRef22({ trail: createTrail(), before: void 0, error: "" }).current;
31354
+ useEffect35(() => {
30829
31355
  readDebugModeSetting().then((loaded) => {
30830
31356
  setSetting(loaded);
30831
31357
  setPending(loaded.retentionDays);
@@ -30980,7 +31506,7 @@ function App({ importOptions, inkClear }) {
30980
31506
  const [flowStart, setFlowStart] = useState39();
30981
31507
  const flow = useFlow(flowStart, { beforeStepChange: inkClear });
30982
31508
  const [importDefaults, setImportDefaults] = useState39();
30983
- useEffect31(() => {
31509
+ useEffect36(() => {
30984
31510
  if (screen !== "import") {
30985
31511
  setImportDefaults(void 0);
30986
31512
  return;
@@ -31053,7 +31579,7 @@ function App({ importOptions, inkClear }) {
31053
31579
  }
31054
31580
  });
31055
31581
  };
31056
- useEffect31(() => {
31582
+ useEffect36(() => {
31057
31583
  if (!tokensOnlyRun || tokensOnly?.status !== "done" || !tokensOnly.result.ok) return;
31058
31584
  const { credentialsSkipped, input, tokens } = tokensOnlyRun;
31059
31585
  const { tokensPath, tokenSessionId, tokenCount } = tokensOnly.result;
@@ -31075,12 +31601,12 @@ function App({ importOptions, inkClear }) {
31075
31601
  }
31076
31602
  });
31077
31603
  }, [tokensOnly, tokensOnlyRun]);
31078
- useEffect31(() => {
31604
+ useEffect36(() => {
31079
31605
  if (!extractionRun || extraction?.status !== "done" || !extraction.result.ok) return;
31080
31606
  setExtractionRun(void 0);
31081
31607
  setScopeRun({ ...extractionRun, extraction: extraction.result.extraction });
31082
31608
  }, [extraction, extractionRun]);
31083
- useEffect31(() => {
31609
+ useEffect36(() => {
31084
31610
  if (!scopeRun || scopeFlow?.status !== "confirmed" || generationInput) return;
31085
31611
  const { extraction: produced, input, generatePromptPath } = scopeRun;
31086
31612
  setGenerationInput({
@@ -31098,7 +31624,7 @@ function App({ importOptions, inkClear }) {
31098
31624
  ...generatePromptPath ? { generatePromptPath } : {}
31099
31625
  });
31100
31626
  }, [scopeFlow, scopeRun, generationInput]);
31101
- useEffect31(() => {
31627
+ useEffect36(() => {
31102
31628
  if (!scopeRun || generation?.status !== "done" || !generation.result.ok) return;
31103
31629
  const { credentialsSkipped, extraction: produced, input, generatePromptPath } = scopeRun;
31104
31630
  inkClear();
@@ -31267,6 +31793,7 @@ function App({ importOptions, inkClear }) {
31267
31793
  return /* @__PURE__ */ jsx66(
31268
31794
  CredentialsScreen,
31269
31795
  {
31796
+ mode: target,
31270
31797
  initial: importDefaults.credentials,
31271
31798
  tokensOnly: target === "tokens",
31272
31799
  onBack: () => goBackFrom("credentials"),