@contentful/experience-design-system-cli 2.34.5-dev-build-131193c7.0 → 2.34.5-dev-build-a95aeeba.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contentful/experience-design-system-cli",
3
- "version": "2.34.5-dev-build-131193c7.0",
3
+ "version": "2.34.5-dev-build-a95aeeba.0",
4
4
  "description": "Contentful Experiences design system import CLI",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -11,6 +11,8 @@ export declare function buildGenerateComponentsArgs(opts: {
11
11
  generatePromptPath?: string;
12
12
  promptOverrides?: string[];
13
13
  existingEntitiesPath?: string;
14
+ restoreCache?: boolean;
15
+ cachedComponents?: string[];
14
16
  }): string[];
15
17
  export declare function buildGenerateTokensArgs(opts: {
16
18
  rawTokensPath: string;
package/dist/src/index.js CHANGED
@@ -110,11 +110,15 @@ var init_credentials_store = __esm({
110
110
  var render_with_goodbye_exports = {};
111
111
  __export(render_with_goodbye_exports, {
112
112
  GoodbyeBoundary: () => GoodbyeBoundary,
113
- renderWithGoodbye: () => renderWithGoodbye
113
+ renderWithGoodbye: () => renderWithGoodbye,
114
+ useScreenTransitionClear: () => useScreenTransitionClear
114
115
  });
115
- import { useCallback, useEffect, useRef, useState } from "react";
116
+ import { createContext, useCallback, useContext, useEffect, useRef, useState } from "react";
116
117
  import { render, Text, useInput } from "ink";
117
118
  import { Fragment, jsx } from "react/jsx-runtime";
119
+ function useScreenTransitionClear() {
120
+ return useContext(ScreenTransitionClearContext);
121
+ }
118
122
  function GoodbyeBoundary({ children }) {
119
123
  const [isExiting, setIsExiting] = useState(false);
120
124
  const isExitingRef = useRef(false);
@@ -138,16 +142,26 @@ function GoodbyeBoundary({ children }) {
138
142
  return isExiting ? /* @__PURE__ */ jsx(Text, { children: "Goodbye!" }) : /* @__PURE__ */ jsx(Fragment, { children });
139
143
  }
140
144
  function renderWithGoodbye(element, options) {
141
- return render(/* @__PURE__ */ jsx(GoodbyeBoundary, { children: element }), {
142
- ...options,
143
- exitOnCtrlC: false
144
- });
145
+ const instanceRef = {};
146
+ const clearScreen = () => {
147
+ instanceRef.current?.clear();
148
+ };
149
+ const instance = render(
150
+ /* @__PURE__ */ jsx(ScreenTransitionClearContext.Provider, { value: clearScreen, children: /* @__PURE__ */ jsx(GoodbyeBoundary, { children: element }) }),
151
+ {
152
+ ...options,
153
+ exitOnCtrlC: false
154
+ }
155
+ );
156
+ instanceRef.current = instance;
157
+ return instance;
145
158
  }
146
- var GOODBYE_RENDER_DELAY_MS;
159
+ var GOODBYE_RENDER_DELAY_MS, ScreenTransitionClearContext;
147
160
  var init_render_with_goodbye = __esm({
148
161
  "packages/experience-design-system-cli/src/tui/render-with-goodbye.tsx"() {
149
162
  "use strict";
150
163
  GOODBYE_RENDER_DELAY_MS = 50;
164
+ ScreenTransitionClearContext = createContext(() => void 0);
151
165
  }
152
166
  });
153
167
 
@@ -1955,8 +1969,7 @@ function hashComponentShape(component) {
1955
1969
  })),
1956
1970
  slots: component.slots.map((s) => ({
1957
1971
  name: s.name,
1958
- isDefault: s.isDefault,
1959
- allowedComponents: [...s.allowedComponents ?? []].sort()
1972
+ isDefault: s.isDefault
1960
1973
  }))
1961
1974
  };
1962
1975
  return createHash2("sha256").update(JSON.stringify(payload)).digest("hex");
@@ -3546,15 +3559,38 @@ function lookupCacheByEntity(db, entityType, entityId) {
3546
3559
  };
3547
3560
  }
3548
3561
  function storeCache(db, inputHash, entityType, entityId, sourceSessionId, humanEdited, promptHash = "") {
3562
+ storeCaches(db, [{ inputHash, entityType, entityId, sourceSessionId, humanEdited, promptHash }]);
3563
+ }
3564
+ function storeCaches(db, entries) {
3565
+ if (entries.length === 0) return;
3549
3566
  const now = (/* @__PURE__ */ new Date()).toISOString();
3550
- db.prepare(
3567
+ const insert = db.prepare(
3551
3568
  `INSERT INTO generation_cache (input_hash, entity_type, entity_id, source_session_id, human_edited, created_at, updated_at, prompt_hash)
3552
3569
  VALUES (?, ?, ?, ?, ?, ?, ?, ?)
3553
3570
  ON CONFLICT(input_hash, prompt_hash, entity_type, entity_id) DO UPDATE SET
3554
3571
  source_session_id = excluded.source_session_id,
3555
3572
  human_edited = CASE WHEN generation_cache.human_edited = 1 THEN 1 ELSE excluded.human_edited END,
3556
3573
  updated_at = excluded.updated_at`
3557
- ).run(inputHash, entityType, entityId, sourceSessionId, humanEdited ? 1 : 0, now, now, promptHash);
3574
+ );
3575
+ db.exec("BEGIN");
3576
+ try {
3577
+ for (const entry of entries) {
3578
+ insert.run(
3579
+ entry.inputHash,
3580
+ entry.entityType,
3581
+ entry.entityId,
3582
+ entry.sourceSessionId,
3583
+ entry.humanEdited ? 1 : 0,
3584
+ now,
3585
+ now,
3586
+ entry.promptHash ?? ""
3587
+ );
3588
+ }
3589
+ db.exec("COMMIT");
3590
+ } catch (e) {
3591
+ db.exec("ROLLBACK");
3592
+ throw e;
3593
+ }
3558
3594
  }
3559
3595
  function storeScannedFiles(db, sessionId2, filePaths) {
3560
3596
  db.exec("BEGIN");
@@ -3604,9 +3640,9 @@ function loadSlotCycles(db, sessionId2) {
3604
3640
  suggestedBreak: r.suggested_break_json ? JSON.parse(r.suggested_break_json) : null
3605
3641
  }));
3606
3642
  }
3607
- function copyComponentFromCache(db, sourceSessionId, targetSessionId, componentId) {
3643
+ function copyComponentFromCache(db, sourceSessionId, targetSessionId, componentId, manageTransaction = true) {
3608
3644
  const now = (/* @__PURE__ */ new Date()).toISOString();
3609
- db.exec("BEGIN");
3645
+ if (manageTransaction) db.exec("BEGIN");
3610
3646
  try {
3611
3647
  const srcComp = db.prepare(
3612
3648
  `SELECT description, status, component_description_rationale, props_rationale, slots_rationale
@@ -3682,6 +3718,19 @@ function copyComponentFromCache(db, sourceSessionId, targetSessionId, componentI
3682
3718
  insertSAC.run(targetSessionId, componentId, sac.slot_name, sac.allowed_component, sac.position);
3683
3719
  }
3684
3720
  db.prepare("UPDATE sessions SET updated_at = ? WHERE id = ?").run(now, targetSessionId);
3721
+ if (manageTransaction) db.exec("COMMIT");
3722
+ } catch (e) {
3723
+ if (manageTransaction) db.exec("ROLLBACK");
3724
+ throw e;
3725
+ }
3726
+ }
3727
+ function copyComponentsFromCache(db, entries) {
3728
+ if (entries.length === 0) return;
3729
+ db.exec("BEGIN");
3730
+ try {
3731
+ for (const entry of entries) {
3732
+ copyComponentFromCache(db, entry.sourceSessionId, entry.targetSessionId, entry.componentId, false);
3733
+ }
3685
3734
  db.exec("COMMIT");
3686
3735
  } catch (e) {
3687
3736
  db.exec("ROLLBACK");
@@ -4824,43 +4873,41 @@ function printFallbackInstructions(options) {
4824
4873
  lines.push(` Re-run the generate command with the agent available, or use --dry-run to inspect the prompt.`);
4825
4874
  process.stderr.write(lines.join("\n") + "\n");
4826
4875
  }
4827
- async function runOneComponent(agent, model, db, sessionId2, component, tokensInline, tokenMapInline, index, total, verbose, noCache, skillPathOverride, skillContentOverride, promptHash, existingContentfulEntities, existingTokensInline) {
4876
+ function cachedComponentResult(componentName, warnings = []) {
4877
+ return {
4878
+ componentName,
4879
+ classified: 0,
4880
+ excluded: 0,
4881
+ slots: 0,
4882
+ warnings,
4883
+ failed: false,
4884
+ cached: true,
4885
+ renamedSlotsCount: 0
4886
+ };
4887
+ }
4888
+ function normalizeComponentForCache(component) {
4889
+ const slots = component.slots.map((slot, index, allSlots) => ({
4890
+ ...slot,
4891
+ name: slot.name.trim() || (allSlots.length === 1 ? "children" : `slot_${index}`)
4892
+ }));
4893
+ return { ...component, slots };
4894
+ }
4895
+ function lookupComponentCache(db, component, promptHash) {
4896
+ const normalized = normalizeComponentForCache(component);
4897
+ const inputHash = hashComponentShape(normalized);
4898
+ const cached = lookupCache(db, inputHash, "component", component.component_id, promptHash);
4899
+ if (cached) return cached;
4900
+ const legacyInputHash = hashComponentShape(component);
4901
+ return legacyInputHash === inputHash ? null : lookupCache(db, legacyInputHash, "component", component.component_id, promptHash);
4902
+ }
4903
+ function resolveComponentCache(db, component, promptHash) {
4904
+ const cached = lookupComponentCache(db, component, promptHash);
4905
+ if (cached) return { entry: cached, humanEdited: cached.humanEdited };
4906
+ const pinned = lookupCacheByEntity(db, "component", component.component_id);
4907
+ return pinned?.humanEdited ? { entry: pinned, humanEdited: true } : null;
4908
+ }
4909
+ async function runOneComponent(agent, model, db, sessionId2, component, tokensInline, tokenMapInline, index, total, verbose, noCache, skillPathOverride, skillContentOverride, promptHash, existingContentfulEntities, existingTokensInline, precomputedCachedNames) {
4828
4910
  const pos = c.dim(`[${index + 1}/${total}]`);
4829
- if (!noCache) {
4830
- const inputHash = hashComponentShape(component);
4831
- const cached = lookupCache(db, inputHash, "component", component.component_id, promptHash);
4832
- if (cached) {
4833
- copyComponentFromCache(db, cached.sourceSessionId, sessionId2, component.component_id);
4834
- process.stderr.write(` ${pos} ${c.bold(component.name)} ${c.green("cached")}
4835
- `);
4836
- return {
4837
- componentName: component.name,
4838
- classified: 0,
4839
- excluded: 0,
4840
- slots: 0,
4841
- warnings: [],
4842
- failed: false,
4843
- cached: true,
4844
- renamedSlotsCount: 0
4845
- };
4846
- }
4847
- const pinned = lookupCacheByEntity(db, "component", component.component_id);
4848
- if (pinned?.humanEdited) {
4849
- copyComponentFromCache(db, pinned.sourceSessionId, sessionId2, component.component_id);
4850
- process.stderr.write(` ${pos} ${c.bold(component.name)} ${c.cyan("pinned (human-edited)")}
4851
- `);
4852
- return {
4853
- componentName: component.name,
4854
- classified: 0,
4855
- excluded: 0,
4856
- slots: 0,
4857
- warnings: [`${component.name}: source changed but human edits preserved`],
4858
- failed: false,
4859
- cached: true,
4860
- renamedSlotsCount: 0
4861
- };
4862
- }
4863
- }
4864
4911
  const { renames, warnings: renameWarnings } = renameEmptySlots(
4865
4912
  db,
4866
4913
  sessionId2,
@@ -4875,6 +4922,37 @@ async function runOneComponent(agent, model, db, sessionId2, component, tokensIn
4875
4922
  for (const w of renameWarnings) process.stderr.write(` ${c.yellow("\u26A0")} ${w}
4876
4923
  `);
4877
4924
  }
4925
+ const cacheComponent = normalizeComponentForCache(component);
4926
+ if (!noCache && precomputedCachedNames.has(component.name)) {
4927
+ process.stderr.write(` ${pos} ${c.bold(component.name)} ${c.green("cached")}
4928
+ `);
4929
+ return cachedComponentResult(component.name);
4930
+ }
4931
+ if (!noCache) {
4932
+ const inputHash = hashComponentShape(cacheComponent);
4933
+ const resolution = resolveComponentCache(db, component, promptHash);
4934
+ if (resolution && !resolution.humanEdited) {
4935
+ copyComponentFromCache(db, resolution.entry.sourceSessionId, sessionId2, component.component_id);
4936
+ storeCache(
4937
+ db,
4938
+ inputHash,
4939
+ "component",
4940
+ component.component_id,
4941
+ resolution.entry.sourceSessionId,
4942
+ resolution.entry.humanEdited,
4943
+ promptHash
4944
+ );
4945
+ process.stderr.write(` ${pos} ${c.bold(component.name)} ${c.green("cached")}
4946
+ `);
4947
+ return cachedComponentResult(component.name);
4948
+ }
4949
+ if (resolution?.humanEdited) {
4950
+ copyComponentFromCache(db, resolution.entry.sourceSessionId, sessionId2, component.component_id);
4951
+ process.stderr.write(` ${pos} ${c.bold(component.name)} ${c.cyan("pinned (human-edited)")}
4952
+ `);
4953
+ return cachedComponentResult(component.name, [`${component.name}: source changed but human edits preserved`]);
4954
+ }
4955
+ }
4878
4956
  const rawComponentsInline = JSON.stringify(
4879
4957
  [
4880
4958
  {
@@ -4944,7 +5022,7 @@ ${outputBuf}`);
4944
5022
  }
4945
5023
  const applied = applyToolCalls(db, sessionId2, component.component_id, component.name, calls, warnings);
4946
5024
  if (!noCache) {
4947
- const inputHash = hashComponentShape(component);
5025
+ const inputHash = hashComponentShape(cacheComponent);
4948
5026
  storeCache(db, inputHash, "component", component.component_id, sessionId2, false, promptHash);
4949
5027
  }
4950
5028
  return {
@@ -4968,7 +5046,7 @@ ${outputBuf}`);
4968
5046
  renamedSlotsCount: renames.length
4969
5047
  };
4970
5048
  }
4971
- async function runAllComponents(agent, model, db, sessionId2, components, tokensInline, tokenMapInline, verbose, noCache, skillPathOverride, skillContentOverride, promptHash, existingContentfulEntities, existingTokensInline) {
5049
+ async function runAllComponents(agent, model, db, sessionId2, components, tokensInline, tokenMapInline, verbose, noCache, skillPathOverride, skillContentOverride, promptHash, existingContentfulEntities, existingTokensInline, precomputedCachedNames) {
4972
5050
  const concurrency = Number(process.env.EDS_GENERATE_CONCURRENCY ?? DEFAULT_COMPONENT_CONCURRENCY);
4973
5051
  process.stderr.write(
4974
5052
  `Categorizing ${c.bold(String(components.length))} component${components.length === 1 ? "" : "s"}` + c.dim(` (concurrency: ${concurrency})`) + "\n"
@@ -4995,7 +5073,8 @@ async function runAllComponents(agent, model, db, sessionId2, components, tokens
4995
5073
  skillContentOverride,
4996
5074
  promptHash,
4997
5075
  existingContentfulEntities,
4998
- existingTokensInline
5076
+ existingTokensInline,
5077
+ precomputedCachedNames
4999
5078
  );
5000
5079
  completed += 1;
5001
5080
  process.stderr.write(`${formatGenerateProgressLine(completed, components.length, results[i].componentName)}
@@ -5024,6 +5103,15 @@ async function loadAcceptedNames(sessionId2) {
5024
5103
  return null;
5025
5104
  }
5026
5105
  }
5106
+ function parsePrecomputedCachedNames(value) {
5107
+ if (!value) return /* @__PURE__ */ new Set();
5108
+ try {
5109
+ const parsed = JSON.parse(value);
5110
+ return new Set(Array.isArray(parsed) ? parsed.filter((name) => typeof name === "string") : []);
5111
+ } catch {
5112
+ return /* @__PURE__ */ new Set();
5113
+ }
5114
+ }
5027
5115
  async function runGenerateSkill(skill, opts, verbose = false) {
5028
5116
  const savedCreds = await readExperiencesCredentials();
5029
5117
  const agentName = opts.agent ?? savedCreds.agent;
@@ -5178,6 +5266,7 @@ async function runGenerateSkill(skill, opts, verbose = false) {
5178
5266
  if (skill === "components" && allComponents && sessionId2) {
5179
5267
  const db = openPipelineDb();
5180
5268
  let componentResults;
5269
+ const precomputedCachedNames = parsePrecomputedCachedNames(opts.cachedComponents);
5181
5270
  try {
5182
5271
  const existingContentfulEntitiesHashInputs = [];
5183
5272
  if (existingTokensInline) existingContentfulEntitiesHashInputs.push(hashContent(existingTokensInline));
@@ -5189,6 +5278,52 @@ async function runGenerateSkill(skill, opts, verbose = false) {
5189
5278
  existingContentfulEntitiesHashInputs,
5190
5279
  generatePrompt
5191
5280
  );
5281
+ if (opts.cacheStatus) {
5282
+ const cacheEnabled = opts.cache !== false && process.env.EDS_NO_CACHE !== "1";
5283
+ const cachedComponents = cacheEnabled ? allComponents.flatMap((component) => {
5284
+ const resolution = resolveComponentCache(db, component, promptHash);
5285
+ return resolution ? [{ component, resolution }] : [];
5286
+ }) : [];
5287
+ if (cacheEnabled && opts.restoreCache) {
5288
+ const restorations = [];
5289
+ const rekeyed = [];
5290
+ const componentStatus = db.prepare(
5291
+ "SELECT status FROM raw_components WHERE session_id = ? AND component_id = ?"
5292
+ );
5293
+ for (const { component, resolution } of cachedComponents) {
5294
+ const current = componentStatus.get(sessionId2, component.component_id);
5295
+ if (current?.status === "generated") continue;
5296
+ renameEmptySlots(db, sessionId2, component.component_id, component.name, component.slots.length);
5297
+ restorations.push({
5298
+ sourceSessionId: resolution.entry.sourceSessionId,
5299
+ targetSessionId: sessionId2,
5300
+ componentId: component.component_id
5301
+ });
5302
+ rekeyed.push({ component, cached: resolution.entry });
5303
+ }
5304
+ copyComponentsFromCache(db, restorations);
5305
+ storeCaches(
5306
+ db,
5307
+ rekeyed.map(({ component, cached }) => ({
5308
+ inputHash: hashComponentShape(normalizeComponentForCache(component)),
5309
+ entityType: "component",
5310
+ entityId: component.component_id,
5311
+ sourceSessionId: cached.sourceSessionId,
5312
+ humanEdited: cached.humanEdited,
5313
+ promptHash
5314
+ }))
5315
+ );
5316
+ }
5317
+ const fullyCached = cacheEnabled && cachedComponents.length === allComponents.length;
5318
+ process.stdout.write(`cache-status=${fullyCached ? "hit" : "miss"}
5319
+ `);
5320
+ process.stdout.write(
5321
+ `cache-components=${JSON.stringify(cachedComponents.map(({ component }) => component.name))}
5322
+ `
5323
+ );
5324
+ await exitWithAnalytics(0);
5325
+ return;
5326
+ }
5192
5327
  componentResults = await runAllComponents(
5193
5328
  agent,
5194
5329
  model,
@@ -5203,7 +5338,8 @@ async function runGenerateSkill(skill, opts, verbose = false) {
5203
5338
  generatePrompt,
5204
5339
  promptHash,
5205
5340
  existingContentfulEntities,
5206
- existingTokensInline
5341
+ existingTokensInline,
5342
+ precomputedCachedNames
5207
5343
  );
5208
5344
  } finally {
5209
5345
  db.close();
@@ -5389,6 +5525,12 @@ function registerInternalGenerateCommand(program) {
5389
5525
  "--existing-entities-path <path>",
5390
5526
  "Path to the .existing-entities.json file written after CMA credentials are supplied. When present, per-component prompts include a summary of the target space so classifications can align to existing prop names/tokens. Missing/malformed files are treated as no-op."
5391
5527
  );
5528
+ componentsCmd.option("--cache-status", "Check whether all selected component definitions are cached");
5529
+ componentsCmd.option("--restore-cache", "Restore cached component definitions into the current session");
5530
+ componentsCmd.option(
5531
+ "--cached-components <json>",
5532
+ "Component names already restored by a prior cache-status lookup; skip per-component cache lookup"
5533
+ );
5392
5534
  addAgentFlags(componentsCmd).action(async (opts) => {
5393
5535
  await runGenerateSkill("components", opts, opts.verbose ?? false);
5394
5536
  });
@@ -26590,10 +26732,31 @@ var init_GenerateReviewStep = __esm({
26590
26732
 
26591
26733
  // packages/experience-design-system-cli/src/import/tui/runScopeGate.ts
26592
26734
  async function runScopeGate(opts) {
26735
+ const startedAt = Date.now();
26736
+ getDebugLogger().event("wizard", "scope-decision-persistence.start", {
26737
+ sessionId: opts.sessionId,
26738
+ acceptedCount: opts.decisions.accepted.length,
26739
+ rejectedCount: opts.decisions.rejected.length
26740
+ });
26593
26741
  const db = openPipelineDb();
26594
26742
  try {
26595
26743
  applyScopeDecisions(db, opts.sessionId, opts.decisions);
26596
26744
  await writeScopeDecisionsSnapshot(db, opts.sessionId, opts.decisions);
26745
+ getDebugLogger().event("wizard", "scope-decision-persistence.complete", {
26746
+ sessionId: opts.sessionId,
26747
+ acceptedCount: opts.decisions.accepted.length,
26748
+ rejectedCount: opts.decisions.rejected.length,
26749
+ durationMs: Date.now() - startedAt
26750
+ });
26751
+ } catch (error) {
26752
+ getDebugLogger().event("wizard", "scope-decision-persistence.error", {
26753
+ sessionId: opts.sessionId,
26754
+ acceptedCount: opts.decisions.accepted.length,
26755
+ rejectedCount: opts.decisions.rejected.length,
26756
+ durationMs: Date.now() - startedAt,
26757
+ error: error instanceof Error ? error.message : String(error)
26758
+ });
26759
+ throw error;
26597
26760
  } finally {
26598
26761
  db.close();
26599
26762
  }
@@ -26607,6 +26770,7 @@ var init_runScopeGate = __esm({
26607
26770
  "packages/experience-design-system-cli/src/import/tui/runScopeGate.ts"() {
26608
26771
  "use strict";
26609
26772
  init_persistence();
26773
+ init_debug_logger();
26610
26774
  init_db();
26611
26775
  }
26612
26776
  });
@@ -26860,6 +27024,10 @@ function buildGenerateComponentsArgs(opts) {
26860
27024
  if (opts.generatePromptPath) args.push("--generate-prompt-path", opts.generatePromptPath);
26861
27025
  for (const prompt of opts.promptOverrides ?? []) args.push("--prompt", prompt);
26862
27026
  if (opts.existingEntitiesPath) args.push("--existing-entities-path", opts.existingEntitiesPath);
27027
+ if (opts.restoreCache) args.push("--restore-cache");
27028
+ if (opts.cachedComponents && opts.cachedComponents.length > 0) {
27029
+ args.push("--cached-components", JSON.stringify(opts.cachedComponents));
27030
+ }
26863
27031
  return args;
26864
27032
  }
26865
27033
  function buildGenerateTokensArgs(opts) {
@@ -26943,6 +27111,17 @@ function logStep(entry) {
26943
27111
  appendFileSync2(WIZARD_LOG, line);
26944
27112
  getDebugLogger().event("wizard", "step", entry);
26945
27113
  }
27114
+ function startWizardTimer(name, payload = {}) {
27115
+ const startedAt = Date.now();
27116
+ getDebugLogger().event("wizard", `${name}.start`, payload);
27117
+ return startedAt;
27118
+ }
27119
+ function finishWizardTimer(name, startedAt, payload = {}) {
27120
+ getDebugLogger().event("wizard", `${name}.complete`, {
27121
+ ...payload,
27122
+ durationMs: Date.now() - startedAt
27123
+ });
27124
+ }
26946
27125
  function WizardApp({
26947
27126
  initialSpaceId = "",
26948
27127
  initialEnvironmentId = "master",
@@ -26965,6 +27144,7 @@ function WizardApp({
26965
27144
  const resolveWizardHost = (hostValue) => hostValue || defaultConfiguredHost;
26966
27145
  const credentialKey = (spaceId, environmentId, cmaToken, hostValue) => [spaceId.trim(), environmentId.trim(), cmaToken.trim(), resolveWizardHost(hostValue)].join("\0");
26967
27146
  const { columns: terminalWidth } = useTerminalSize();
27147
+ const clearScreenOnTransition = useScreenTransitionClear();
26968
27148
  const logInit = useRef10(false);
26969
27149
  const initialAgentAuthRef = useRef10(initialAgentAuth ?? null);
26970
27150
  if (!logInit.current) {
@@ -26978,6 +27158,8 @@ function WizardApp({
26978
27158
  });
26979
27159
  const allowEmptyDeleteAllRef = useRef10(false);
26980
27160
  const generateChildRef = useRef10(null);
27161
+ const generationCachePreflightRef = useRef10(null);
27162
+ const selectionToReviewStartedAtRef = useRef10(null);
26981
27163
  const credentialsValidationIdRef = useRef10(0);
26982
27164
  const pendingCredentialValidationRef = useRef10(null);
26983
27165
  const validatedCredentialsKeyRef = useRef10(null);
@@ -26985,6 +27167,7 @@ function WizardApp({
26985
27167
  const extractPromiseRef = useRef10(null);
26986
27168
  const extractStartedRef = useRef10(false);
26987
27169
  const credentialsReadyRef = useRef10(false);
27170
+ const agentAuthVerifiedRef = useRef10(false);
26988
27171
  const scopeGateCompletedRef = useRef10(false);
26989
27172
  const existingEntitiesPromiseRef = useRef10(null);
26990
27173
  const generatePromiseRef = useRef10(null);
@@ -27055,7 +27238,10 @@ function WizardApp({
27055
27238
  tokensPath: state.tokensPath
27056
27239
  };
27057
27240
  }, [state.extractSessionId, state.tokensPath]);
27058
- const update = (partial) => {
27241
+ const update = (partial, options = {}) => {
27242
+ if (partial.step !== void 0 && partial.step !== state.step && options.clearScreen !== false) {
27243
+ clearScreenOnTransition();
27244
+ }
27059
27245
  const sanitized = { ...partial };
27060
27246
  if (sanitized.serverPreview) {
27061
27247
  const p = sanitized.serverPreview;
@@ -27102,12 +27288,41 @@ function WizardApp({
27102
27288
  logStep({ update: sanitized });
27103
27289
  setState((prev) => ({ ...prev, ...partial }));
27104
27290
  };
27105
- const runAgentAuthCheck = async (nextStep) => {
27291
+ const finishSelectionToReviewTimer = (mode) => {
27292
+ const startedAt = selectionToReviewStartedAtRef.current;
27293
+ if (startedAt === null) return;
27294
+ selectionToReviewStartedAtRef.current = null;
27295
+ finishWizardTimer("selection-to-review", startedAt, { mode });
27296
+ };
27297
+ const runAgentAuthCheck = async (nextStep, deferStep = false) => {
27298
+ const timer = startWizardTimer("agent-auth-validation", {
27299
+ agent: state.agent,
27300
+ deferred: deferStep,
27301
+ nextStep
27302
+ });
27303
+ if (agentAuthVerifiedRef.current) {
27304
+ finishWizardTimer("agent-auth-validation", timer, { status: "already-verified" });
27305
+ if (!deferStep) update({ step: nextStep });
27306
+ return true;
27307
+ }
27106
27308
  const authCheckStepNumber = state.tokensPath ? 4 : 3;
27107
27309
  const prefetchedAuth = initialAgentAuthRef.current;
27108
27310
  initialAgentAuthRef.current = null;
27109
- if (!prefetchedAuth) update({ step: "checking-claude-auth", authCheckStepNumber });
27110
- const status = await (prefetchedAuth ?? checkAgentAuth(state.agent));
27311
+ if (!prefetchedAuth && !deferStep) update({ step: "checking-claude-auth", authCheckStepNumber });
27312
+ let status;
27313
+ try {
27314
+ status = await (prefetchedAuth ?? checkAgentAuth(state.agent));
27315
+ } catch (error) {
27316
+ finishWizardTimer("agent-auth-validation", timer, {
27317
+ status: "error",
27318
+ error: error instanceof Error ? error.message : String(error)
27319
+ });
27320
+ throw error;
27321
+ }
27322
+ finishWizardTimer("agent-auth-validation", timer, {
27323
+ status,
27324
+ prefetched: Boolean(prefetchedAuth)
27325
+ });
27111
27326
  if (status === "not-found") {
27112
27327
  update({
27113
27328
  step: "error",
@@ -27131,7 +27346,8 @@ If you are using AWS Bedrock, run:
27131
27346
  });
27132
27347
  return false;
27133
27348
  }
27134
- update({ step: nextStep });
27349
+ agentAuthVerifiedRef.current = true;
27350
+ if (!deferStep) update({ step: nextStep });
27135
27351
  return true;
27136
27352
  };
27137
27353
  const runGenerateTokens = async (rawTokensPath, outDir, forceRegenerate = false) => {
@@ -27186,7 +27402,13 @@ If you are using AWS Bedrock, run:
27186
27402
  update({ tokensPath, tokenSessionId, tokenCount, tokenGenerationStatus: "complete" });
27187
27403
  return true;
27188
27404
  };
27189
- const runMapTokens2 = async (sessionId2) => {
27405
+ const runMapTokens2 = async (sessionId2, silent = false) => {
27406
+ const timer = startWizardTimer("token-mapping", {
27407
+ sessionId: sessionId2,
27408
+ silent,
27409
+ noCache: effectiveNoCache,
27410
+ skipAgent: skipMapTokens
27411
+ });
27190
27412
  let mappablePropCount = 0;
27191
27413
  let rawTokenCount = 0;
27192
27414
  try {
@@ -27213,13 +27435,22 @@ If you are using AWS Bedrock, run:
27213
27435
  errorStep: "map tokens",
27214
27436
  errorMessage: error instanceof Error ? error.message : String(error)
27215
27437
  });
27438
+ finishWizardTimer("token-mapping", timer, {
27439
+ status: "error",
27440
+ error: error instanceof Error ? error.message : String(error)
27441
+ });
27216
27442
  return false;
27217
27443
  }
27218
27444
  if (!shouldRunMapTokens({ mappablePropCount, rawTokenCount })) {
27219
- update({ mapTokensEligible: false, mapTokensStatus: "complete" });
27445
+ if (!silent) update({ mapTokensEligible: false, mapTokensStatus: "complete" });
27446
+ finishWizardTimer("token-mapping", timer, {
27447
+ status: "skipped",
27448
+ mappablePropCount,
27449
+ rawTokenCount
27450
+ });
27220
27451
  return true;
27221
27452
  }
27222
- update({ mapTokensEligible: true, mapTokensStatus: "running" });
27453
+ if (!silent) update({ mapTokensEligible: true, mapTokensStatus: "running", step: "generating" });
27223
27454
  const args = buildMapTokensArgs({
27224
27455
  sessionId: sessionId2,
27225
27456
  agent: state.agent,
@@ -27237,9 +27468,21 @@ If you are using AWS Bedrock, run:
27237
27468
  errorStep: "map tokens",
27238
27469
  errorMessage: result.stderr.trim() || "Unknown error"
27239
27470
  });
27471
+ finishWizardTimer("token-mapping", timer, {
27472
+ status: "error",
27473
+ exitCode: result.exitCode,
27474
+ mappablePropCount,
27475
+ rawTokenCount
27476
+ });
27240
27477
  return false;
27241
27478
  }
27242
- update({ mapTokensStatus: "complete" });
27479
+ if (!silent) update({ mapTokensStatus: "complete" });
27480
+ finishWizardTimer("token-mapping", timer, {
27481
+ status: "complete",
27482
+ exitCode: result.exitCode,
27483
+ mappablePropCount,
27484
+ rawTokenCount
27485
+ });
27243
27486
  return true;
27244
27487
  };
27245
27488
  const startExistingEntitiesFetch = (projectPath, outDir) => {
@@ -27489,7 +27732,7 @@ Make sure this path contains TypeScript/React/Vue component files (.tsx, .ts, .v
27489
27732
  generateProgress: null
27490
27733
  }));
27491
27734
  };
27492
- const buildGenerateArgs = (extractSessionId, tokensPath, generatePromptPath2) => buildGenerateProcessArgs({
27735
+ const buildGenerateOptions = (extractSessionId, tokensPath, generatePromptPath2, cachedComponents) => ({
27493
27736
  sessionId: extractSessionId,
27494
27737
  tokensPath,
27495
27738
  agent: state.agent,
@@ -27498,8 +27741,127 @@ Make sure this path contains TypeScript/React/Vue component files (.tsx, .ts, .v
27498
27741
  noCache: effectiveNoCache,
27499
27742
  ...state.existingEntitiesPath ? { existingEntitiesPath: state.existingEntitiesPath } : {},
27500
27743
  ...generatePromptPath2 ? { generatePromptPath: generatePromptPath2 } : {},
27501
- promptOverrides
27744
+ promptOverrides,
27745
+ ...cachedComponents && cachedComponents.length > 0 ? { cachedComponents } : {}
27502
27746
  });
27747
+ const buildGenerateArgs = (extractSessionId, tokensPath, generatePromptPath2, cachedComponents) => buildGenerateProcessArgs(buildGenerateOptions(extractSessionId, tokensPath, generatePromptPath2, cachedComponents));
27748
+ const buildGenerateCliArgs = (extractSessionId, tokensPath, generatePromptPath2, cachedComponents) => buildGenerateComponentsArgs(
27749
+ buildGenerateOptions(extractSessionId, tokensPath, generatePromptPath2, cachedComponents)
27750
+ );
27751
+ const checkGenerateCache = async (extractSessionId, tokensPath) => {
27752
+ const timer = startWizardTimer("generation-cache-status", {
27753
+ sessionId: extractSessionId,
27754
+ noCache: effectiveNoCache
27755
+ });
27756
+ if (effectiveNoCache) {
27757
+ finishWizardTimer("generation-cache-status", timer, { status: "skipped" });
27758
+ return false;
27759
+ }
27760
+ const result = await runCli([...buildGenerateCliArgs(extractSessionId, tokensPath), "--cache-status"]);
27761
+ const hit = result.exitCode === 0 && /^cache-status=hit$/m.test(result.stdout);
27762
+ finishWizardTimer("generation-cache-status", timer, {
27763
+ status: hit ? "hit" : "miss",
27764
+ exitCode: result.exitCode,
27765
+ ...result.exitCode !== 0 ? { stderrTail: result.stderr.trim().slice(-500) } : {}
27766
+ });
27767
+ return hit;
27768
+ };
27769
+ const checkGenerateCacheComponents = async (extractSessionId, tokensPath, restoreCache = false) => {
27770
+ const timer = startWizardTimer("generation-cache-components", {
27771
+ sessionId: extractSessionId,
27772
+ restoreCache,
27773
+ noCache: effectiveNoCache
27774
+ });
27775
+ if (effectiveNoCache) {
27776
+ finishWizardTimer("generation-cache-components", timer, { status: "skipped" });
27777
+ return /* @__PURE__ */ new Set();
27778
+ }
27779
+ const args = [...buildGenerateCliArgs(extractSessionId, tokensPath), "--cache-status"];
27780
+ if (restoreCache) args.push("--restore-cache");
27781
+ const result = await runCli(args);
27782
+ if (result.exitCode !== 0) {
27783
+ finishWizardTimer("generation-cache-components", timer, {
27784
+ status: "error",
27785
+ exitCode: result.exitCode,
27786
+ stderrTail: result.stderr.trim().slice(-500)
27787
+ });
27788
+ return /* @__PURE__ */ new Set();
27789
+ }
27790
+ const line = /^cache-components=(.+)$/m.exec(result.stdout)?.[1];
27791
+ if (!line) {
27792
+ finishWizardTimer("generation-cache-components", timer, {
27793
+ status: "missing-output",
27794
+ exitCode: result.exitCode,
27795
+ cachedCount: 0
27796
+ });
27797
+ return /* @__PURE__ */ new Set();
27798
+ }
27799
+ try {
27800
+ const names = JSON.parse(line);
27801
+ const cachedNames = new Set(
27802
+ Array.isArray(names) ? names.filter((name) => typeof name === "string") : []
27803
+ );
27804
+ finishWizardTimer("generation-cache-components", timer, {
27805
+ status: "complete",
27806
+ exitCode: result.exitCode,
27807
+ cachedCount: cachedNames.size
27808
+ });
27809
+ return cachedNames;
27810
+ } catch {
27811
+ finishWizardTimer("generation-cache-components", timer, {
27812
+ status: "invalid-output",
27813
+ exitCode: result.exitCode,
27814
+ cachedCount: 0
27815
+ });
27816
+ return /* @__PURE__ */ new Set();
27817
+ }
27818
+ };
27819
+ useEffect15(() => {
27820
+ if (state.step !== "extracting" && state.step !== "scope-gate" || !state.extractSessionId || state.existingEntitiesStatus === "running" || state.existingEntitiesStatus === "idle" || state.selectionAgentStatus !== "complete" || state.compositionPhase !== "done" && state.compositionPhase !== "cache-hit" || state.rawTokensPath && state.tokenGenerationStatus !== "complete" || effectiveNoCache) {
27821
+ return;
27822
+ }
27823
+ const sessionId2 = state.extractSessionId;
27824
+ if (generationCachePreflightRef.current?.sessionId === sessionId2) return;
27825
+ const timer = startWizardTimer("generation-cache-preflight", { sessionId: sessionId2 });
27826
+ const db = openPipelineDb();
27827
+ let generatedNames = null;
27828
+ try {
27829
+ const rows = db.prepare("SELECT name, status FROM raw_components WHERE session_id = ?").all(sessionId2);
27830
+ if (rows.length > 0 && rows.every((row) => row.status === "generated")) {
27831
+ generatedNames = new Set(rows.map((row) => row.name));
27832
+ }
27833
+ } finally {
27834
+ db.close();
27835
+ }
27836
+ if (generatedNames) {
27837
+ generationCachePreflightRef.current = { sessionId: sessionId2, promise: Promise.resolve(generatedNames) };
27838
+ finishWizardTimer("generation-cache-preflight", timer, {
27839
+ status: "complete",
27840
+ source: "session-db",
27841
+ cachedCount: generatedNames.size
27842
+ });
27843
+ return;
27844
+ }
27845
+ const promise = checkGenerateCacheComponents(sessionId2, state.tokensPath, true);
27846
+ generationCachePreflightRef.current = { sessionId: sessionId2, promise };
27847
+ void promise.then((cachedNames) => {
27848
+ finishWizardTimer("generation-cache-preflight", timer, {
27849
+ status: "complete",
27850
+ source: "cache-status",
27851
+ cachedCount: cachedNames.size
27852
+ });
27853
+ });
27854
+ }, [
27855
+ state.step,
27856
+ state.extractSessionId,
27857
+ state.tokensPath,
27858
+ state.rawTokensPath,
27859
+ state.tokenGenerationStatus,
27860
+ state.selectionAgentStatus,
27861
+ state.compositionPhase,
27862
+ state.existingEntitiesStatus,
27863
+ state.existingEntitiesPath
27864
+ ]);
27503
27865
  const startGeneratePrefetch = (extractSessionId, tokensPath) => {
27504
27866
  const args = buildGenerateArgs(extractSessionId, tokensPath);
27505
27867
  let progressCursor = null;
@@ -27554,8 +27916,14 @@ Make sure this path contains TypeScript/React/Vue component files (.tsx, .ts, .v
27554
27916
  });
27555
27917
  return donePromise;
27556
27918
  };
27557
- const runGenerate = async (extractSessionId, tokensPath, acceptedCount) => {
27558
- const args = buildGenerateArgs(extractSessionId, tokensPath, generatePromptPath);
27919
+ const runGenerate = async (extractSessionId, tokensPath, acceptedCount, suppressScreen = false, cachedComponents = []) => {
27920
+ const timer = startWizardTimer("component-generation", {
27921
+ sessionId: extractSessionId,
27922
+ acceptedCount,
27923
+ suppressScreen,
27924
+ noCache: effectiveNoCache
27925
+ });
27926
+ const args = buildGenerateArgs(extractSessionId, tokensPath, generatePromptPath, cachedComponents);
27559
27927
  let progressCursor = state.generateProgress;
27560
27928
  const { donePromise } = spawnGenerateChild({
27561
27929
  command: "node",
@@ -27564,12 +27932,17 @@ Make sure this path contains TypeScript/React/Vue component files (.tsx, .ts, .v
27564
27932
  const nextProgress = parseGenerateStderrChunk(chunk, progressCursor);
27565
27933
  if (nextProgress !== progressCursor) {
27566
27934
  progressCursor = nextProgress;
27567
- update({ generateProgress: nextProgress });
27935
+ if (!suppressScreen) update({ generateProgress: nextProgress });
27568
27936
  }
27569
27937
  }
27570
27938
  });
27571
27939
  const result = await donePromise;
27572
27940
  if (result.exitCode !== 0) {
27941
+ finishWizardTimer("component-generation", timer, {
27942
+ status: "error",
27943
+ exitCode: result.exitCode
27944
+ });
27945
+ finishSelectionToReviewTimer("error");
27573
27946
  update({
27574
27947
  step: "error",
27575
27948
  errorStep: "generate components",
@@ -27577,14 +27950,67 @@ Make sure this path contains TypeScript/React/Vue component files (.tsx, .ts, .v
27577
27950
  });
27578
27951
  return;
27579
27952
  }
27580
- const { generateSessionId: generateSessionId2, generatedCount } = parseGenerateResult(result, acceptedCount);
27953
+ const { generateSessionId: generateSessionId2, generatedCount, renamedSlotsCount } = parseGenerateResult(result, acceptedCount);
27581
27954
  const mappedSessionId = generateSessionId2 ?? extractSessionId;
27582
- update({
27583
- generateSessionId: mappedSessionId,
27955
+ finishWizardTimer("component-generation", timer, {
27956
+ status: "complete",
27957
+ exitCode: result.exitCode,
27584
27958
  generatedCount,
27585
- generateProgress: null
27959
+ renamedSlotsCount
27586
27960
  });
27587
- if (await runMapTokens2(mappedSessionId)) update({ step: "final-review" });
27961
+ if (!suppressScreen) {
27962
+ update({
27963
+ acceptedCount,
27964
+ autoRejectedCount: 0,
27965
+ generateSessionId: mappedSessionId,
27966
+ generatedCount,
27967
+ generateProgress: null
27968
+ });
27969
+ if (await runMapTokens2(mappedSessionId)) {
27970
+ finishSelectionToReviewTimer("generated");
27971
+ update({ step: "final-review" });
27972
+ } else {
27973
+ finishSelectionToReviewTimer("error");
27974
+ }
27975
+ return;
27976
+ }
27977
+ const mapped = await runMapTokens2(mappedSessionId, true);
27978
+ if (mapped) {
27979
+ finishSelectionToReviewTimer("generated");
27980
+ update(
27981
+ {
27982
+ acceptedCount,
27983
+ autoRejectedCount: 0,
27984
+ generateSessionId: mappedSessionId,
27985
+ generatedCount,
27986
+ generateProgress: null,
27987
+ mapTokensStatus: "complete",
27988
+ step: "final-review"
27989
+ },
27990
+ { clearScreen: false }
27991
+ );
27992
+ } else {
27993
+ finishSelectionToReviewTimer("error");
27994
+ }
27995
+ };
27996
+ const finishCachedGeneration = async (sessionId2, acceptedCount) => {
27997
+ if (await runMapTokens2(sessionId2, true)) {
27998
+ finishSelectionToReviewTimer("cached");
27999
+ update(
28000
+ {
28001
+ acceptedCount,
28002
+ autoRejectedCount: 0,
28003
+ generateSessionId: sessionId2,
28004
+ generatedCount: acceptedCount,
28005
+ generateProgress: null,
28006
+ mapTokensStatus: "complete",
28007
+ step: "final-review"
28008
+ },
28009
+ { clearScreen: false }
28010
+ );
28011
+ } else {
28012
+ finishSelectionToReviewTimer("error");
28013
+ }
27588
28014
  };
27589
28015
  const advanceToPushFlow = (generatedAcceptedCount) => {
27590
28016
  update({ generatedAcceptedCount });
@@ -27769,8 +28195,15 @@ Make sure this path contains TypeScript/React/Vue component files (.tsx, .ts, .v
27769
28195
  return;
27770
28196
  }
27771
28197
  }
27772
- if (await runAgentAuthCheck("generating")) {
27773
- void runGenerate(sid, state.tokensPath, state.acceptedCount);
28198
+ if (await runAgentAuthCheck("generating", true)) {
28199
+ const cacheHit = await checkGenerateCache(sid, state.tokensPath);
28200
+ if (cacheHit) {
28201
+ update({ step: "generating" });
28202
+ void finishCachedGeneration(sid, state.acceptedCount);
28203
+ } else {
28204
+ update({ step: "generating" });
28205
+ void runGenerate(sid, state.tokensPath, state.acceptedCount);
28206
+ }
27774
28207
  }
27775
28208
  return;
27776
28209
  }
@@ -28138,13 +28571,13 @@ If using a custom host configuration, make sure the space exists on that host.`
28138
28571
  update(nextStateAfterPrint({ skipGate: opts.skipGate, componentsPath }));
28139
28572
  return { ok: true };
28140
28573
  };
28141
- const runSaveAndPush = async () => {
28142
- await startSaveFlow({ skipGate: true, andPush: true });
28574
+ const runSaveAndPush = async (statePatch = {}) => {
28575
+ await startSaveFlow({ skipGate: true, andPush: true }, statePatch);
28143
28576
  };
28144
28577
  const pendingSaveOptionsRef = useRef10({});
28145
- const startSaveFlow = async (opts = {}) => {
28578
+ const startSaveFlow = async (opts = {}, statePatch = {}) => {
28146
28579
  pendingSaveOptionsRef.current = opts;
28147
- setState((prev) => ({ ...prev, step: "path-prompt" }));
28580
+ update({ ...statePatch, step: "path-prompt" });
28148
28581
  };
28149
28582
  const proceedToWrite = async (path) => {
28150
28583
  setState((prev) => ({ ...prev, outDir: path }));
@@ -28387,31 +28820,86 @@ If using a custom host configuration, make sure the space exists on that host.`
28387
28820
  {
28388
28821
  components,
28389
28822
  onConfirm: (decisions) => {
28390
- void runScopeGate({
28391
- sessionId: sessionId2,
28392
- decisions,
28393
- onAdvanceToGenerate: async ({ sessionId: sid, acceptedCount }) => {
28394
- scopeGateCompletedRef.current = true;
28395
- if (shouldGenerateAfterScopeGate({ acceptedCount })) {
28396
- update({
28397
- acceptedCount,
28398
- autoRejectedCount: 0,
28399
- step: "checking-claude-auth",
28400
- authCheckStepNumber: state.tokensPath ? 4 : 3
28401
- });
28402
- if (await runAgentAuthCheck("generating")) {
28403
- void runGenerate(sid, state.tokensPath, acceptedCount);
28823
+ void (async () => {
28824
+ selectionToReviewStartedAtRef.current = decisions.accepted.length > 0 ? startWizardTimer("selection-to-review", {
28825
+ sessionId: sessionId2,
28826
+ acceptedCount: decisions.accepted.length,
28827
+ rejectedCount: decisions.rejected.length
28828
+ }) : null;
28829
+ const preflight = generationCachePreflightRef.current;
28830
+ const cachePromise = preflight?.sessionId === sessionId2 ? preflight.promise : checkGenerateCacheComponents(sessionId2, state.tokensPath, true);
28831
+ if (!preflight || preflight.sessionId !== sessionId2) {
28832
+ generationCachePreflightRef.current = { sessionId: sessionId2, promise: cachePromise };
28833
+ }
28834
+ const cacheWaitStartedAt = startWizardTimer("selection-cache-restoration-wait", {
28835
+ sessionId: sessionId2,
28836
+ preflight: Boolean(preflight?.sessionId === sessionId2)
28837
+ });
28838
+ try {
28839
+ const cachedNames = await cachePromise;
28840
+ finishWizardTimer("selection-cache-restoration-wait", cacheWaitStartedAt, {
28841
+ status: "complete",
28842
+ cachedCount: cachedNames.size
28843
+ });
28844
+ } catch (error) {
28845
+ finishWizardTimer("selection-cache-restoration-wait", cacheWaitStartedAt, {
28846
+ status: "error",
28847
+ error: error instanceof Error ? error.message : String(error)
28848
+ });
28849
+ finishSelectionToReviewTimer("error");
28850
+ throw error;
28851
+ }
28852
+ await runScopeGate({
28853
+ sessionId: sessionId2,
28854
+ decisions,
28855
+ onAdvanceToGenerate: async ({ sessionId: sid, acceptedCount }) => {
28856
+ scopeGateCompletedRef.current = true;
28857
+ if (shouldGenerateAfterScopeGate({ acceptedCount })) {
28858
+ const authPromise = runAgentAuthCheck("generating", true);
28859
+ if (await authPromise) {
28860
+ const comparisonStartedAt = startWizardTimer("generation-cache-set-comparison", {
28861
+ sessionId: sid,
28862
+ acceptedCount: decisions?.accepted.length ?? 0
28863
+ });
28864
+ let cachedNames = await cachePromise;
28865
+ const acceptedNames = decisions?.accepted ?? [];
28866
+ let cacheHit = !effectiveNoCache && acceptedNames.length > 0 && acceptedNames.every((name) => cachedNames.has(name));
28867
+ if (!cacheHit && !effectiveNoCache && acceptedNames.length > 0) {
28868
+ cachedNames = await checkGenerateCacheComponents(sid, state.tokensPath, true);
28869
+ cacheHit = acceptedNames.every((name) => cachedNames.has(name));
28870
+ }
28871
+ finishWizardTimer("generation-cache-set-comparison", comparisonStartedAt, {
28872
+ status: "complete",
28873
+ cacheHit,
28874
+ cachedCount: cachedNames.size,
28875
+ acceptedCount: acceptedNames.length
28876
+ });
28877
+ if (cacheHit) {
28878
+ void finishCachedGeneration(sid, acceptedCount);
28879
+ } else {
28880
+ const acceptedNameSet = new Set(acceptedNames);
28881
+ const restoredCachedNames = [...cachedNames].filter((name) => acceptedNameSet.has(name));
28882
+ update({
28883
+ step: "generating",
28884
+ generateProgress: null,
28885
+ acceptedCount
28886
+ });
28887
+ void runGenerate(sid, state.tokensPath, acceptedCount, false, restoredCachedNames);
28888
+ }
28889
+ } else {
28890
+ finishSelectionToReviewTimer("error");
28891
+ }
28892
+ return;
28404
28893
  }
28405
- return;
28894
+ void runSaveAndPush();
28895
+ },
28896
+ onAdvanceToPushFlow: (count) => {
28897
+ scopeGateCompletedRef.current = true;
28898
+ update({ acceptedCount: count, autoRejectedCount: 0 });
28899
+ advanceToPushFlow(count);
28406
28900
  }
28407
- void runSaveAndPush();
28408
- },
28409
- onAdvanceToPushFlow: (count) => {
28410
- scopeGateCompletedRef.current = true;
28411
- update({ acceptedCount: count, autoRejectedCount: 0 });
28412
- advanceToPushFlow(count);
28413
- }
28414
- });
28901
+ });
28902
+ })();
28415
28903
  },
28416
28904
  onQuit: () => process.exit(0)
28417
28905
  }
@@ -28498,8 +28986,10 @@ If using a custom host configuration, make sure the space exists on that host.`
28498
28986
  }
28499
28987
  const allowEmptyDeleteAll = acceptedCount === 0;
28500
28988
  allowEmptyDeleteAllRef.current = allowEmptyDeleteAll;
28501
- update({ finalReviewPassed: true, generatedAcceptedCount: acceptedCount });
28502
- void runSaveAndPush();
28989
+ void runSaveAndPush({
28990
+ finalReviewPassed: true,
28991
+ generatedAcceptedCount: acceptedCount
28992
+ });
28503
28993
  },
28504
28994
  onQuit: () => process.exit(0)
28505
28995
  }
@@ -28738,6 +29228,7 @@ var init_WizardApp = __esm({
28738
29228
  init_prompt_overrides();
28739
29229
  init_run_selection_agent();
28740
29230
  init_use_terminal_size();
29231
+ init_render_with_goodbye();
28741
29232
  SAVE_CONFIRMATION_DELAY_MS = 1e3;
28742
29233
  WIZARD_LOG = join20(tmpdir(), "experiences-import-wizard.log");
28743
29234
  }
@@ -122,6 +122,14 @@ export declare function computeMapTokensInputHash(db: DatabaseSync, sessionId: s
122
122
  export declare function lookupCache(db: DatabaseSync, inputHash: string, entityType: CacheEntityType, entityId: string, promptHash?: string): CacheEntry | null;
123
123
  export declare function lookupCacheByEntity(db: DatabaseSync, entityType: CacheEntityType, entityId: string): CacheEntry | null;
124
124
  export declare function storeCache(db: DatabaseSync, inputHash: string, entityType: CacheEntityType, entityId: string, sourceSessionId: string, humanEdited: boolean, promptHash?: string): void;
125
+ export declare function storeCaches(db: DatabaseSync, entries: Array<{
126
+ inputHash: string;
127
+ entityType: CacheEntityType;
128
+ entityId: string;
129
+ sourceSessionId: string;
130
+ humanEdited: boolean;
131
+ promptHash?: string;
132
+ }>): void;
125
133
  export declare function storeScannedFiles(db: DatabaseSync, sessionId: string, filePaths: string[]): void;
126
134
  export declare function loadScannedFiles(db: DatabaseSync, sessionId: string): string[];
127
135
  export declare function storeSlotCycles(db: DatabaseSync, sessionId: string, cycles: Array<SlotCycle & {
@@ -133,7 +141,12 @@ export interface StoredSlotCycle extends SlotCycle {
133
141
  export declare function loadSlotCycles(db: DatabaseSync, sessionId: string): StoredSlotCycle[];
134
142
  export declare function clearSlotCycles(db: DatabaseSync, sessionId: string): void;
135
143
  export declare function markCacheHumanEdited(db: DatabaseSync, entityType: 'component' | 'token_set', entityId: string): void;
136
- export declare function copyComponentFromCache(db: DatabaseSync, sourceSessionId: string, targetSessionId: string, componentId: string): void;
144
+ export declare function copyComponentFromCache(db: DatabaseSync, sourceSessionId: string, targetSessionId: string, componentId: string, manageTransaction?: boolean): void;
145
+ export declare function copyComponentsFromCache(db: DatabaseSync, entries: Array<{
146
+ sourceSessionId: string;
147
+ targetSessionId: string;
148
+ componentId: string;
149
+ }>): void;
137
150
  export declare function copyTokensFromCache(db: DatabaseSync, sourceSessionId: string, targetSessionId: string): void;
138
151
  export declare function copyMapTokensFromCache(db: DatabaseSync, sourceSessionId: string, targetSessionId: string): number;
139
152
  export declare function getCliCacheVersion(): Promise<string>;
@@ -1,5 +1,6 @@
1
1
  import React from 'react';
2
2
  import { type Instance, type RenderOptions } from 'ink';
3
+ export declare function useScreenTransitionClear(): () => void;
3
4
  export declare function GoodbyeBoundary({ children }: {
4
5
  children: React.ReactNode;
5
6
  }): React.ReactElement;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contentful/experience-design-system-cli",
3
- "version": "2.34.5-dev-build-131193c7.0",
3
+ "version": "2.34.5-dev-build-a95aeeba.0",
4
4
  "description": "Contentful Experiences design system import CLI",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -41,8 +41,8 @@
41
41
  "svelte": "^5.56.4",
42
42
  "ts-morph": "^27.0.2",
43
43
  "typescript": "^5.9.3",
44
- "@contentful/experience-design-system-cli-v2": "2.34.5-dev-build-131193c7.0",
45
- "@contentful/experience-design-system-types": "2.34.5-dev-build-131193c7.0"
44
+ "@contentful/experience-design-system-types": "2.34.5-dev-build-a95aeeba.0",
45
+ "@contentful/experience-design-system-cli-v2": "2.34.5-dev-build-a95aeeba.0"
46
46
  },
47
47
  "devDependencies": {
48
48
  "@tsconfig/node24": "^24.0.4",
@@ -54,9 +54,9 @@
54
54
  "ink-testing-library": "^4.0.0",
55
55
  "typescript-eslint": "^8.67.0",
56
56
  "vitest": "^4.0.16",
57
- "@contentful/experience-design-system-extraction": "2.34.5-dev-build-131193c7.0",
58
- "@contentful/experience-design-system-generation": "2.34.5-dev-build-131193c7.0",
59
- "@contentful/experience-design-system-client": "2.34.5-dev-build-131193c7.0"
57
+ "@contentful/experience-design-system-extraction": "2.34.5-dev-build-a95aeeba.0",
58
+ "@contentful/experience-design-system-client": "2.34.5-dev-build-a95aeeba.0",
59
+ "@contentful/experience-design-system-generation": "2.34.5-dev-build-a95aeeba.0"
60
60
  },
61
61
  "repository": {
62
62
  "type": "git",