@contentful/experience-design-system-cli 2.32.1-dev-build-b78fe18.0 → 2.32.1-dev-build-d28a6f8.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.
Files changed (29) hide show
  1. package/dist/package.json +1 -1
  2. package/dist/src/helpers/build-contentful-management-client.d.ts +7 -0
  3. package/dist/src/helpers/fetch-and-persist-existing-contentful-entities.d.ts +29 -0
  4. package/dist/src/helpers/fetch-existing-contentful-entities.d.ts +11 -0
  5. package/dist/src/helpers/find-nearly-matching-component.d.ts +7 -0
  6. package/dist/src/helpers/read-existing-contentful-entities-from-session.d.ts +7 -0
  7. package/dist/src/helpers/summarize-existing-contentful-entities.d.ts +50 -0
  8. package/dist/src/import/orchestrator.d.ts +0 -1
  9. package/dist/src/import/tui/WizardApp.d.ts +3 -0
  10. package/dist/src/index.js +826 -445
  11. package/dist/src/session/cache-keys.d.ts +1 -1
  12. package/dist/src/session/core/cdf/server-type-map.d.ts +3 -0
  13. package/dist/src/session/core/components/component-id.d.ts +1 -0
  14. package/dist/src/session/core/components/input-hash.d.ts +5 -0
  15. package/dist/src/session/core/shared/group-by.d.ts +1 -0
  16. package/dist/src/session/core/tokens/input-hash.d.ts +1 -0
  17. package/dist/src/session/db.d.ts +9 -13
  18. package/dist/src/session/repositories/sessions/read.d.ts +11 -0
  19. package/dist/src/session/repositories/sessions/write.d.ts +3 -0
  20. package/dist/src/session/repositories/steps/read.d.ts +2 -0
  21. package/dist/src/session/repositories/steps/write.d.ts +5 -0
  22. package/dist/src/session/services/session-resolver.d.ts +21 -0
  23. package/package.json +6 -6
  24. package/skills/generate-components.md +27 -0
  25. package/skills/map-tokens.md +12 -0
  26. package/skills/select-components.md +11 -0
  27. package/dist/src/helpers/cma-client.d.ts +0 -17
  28. package/dist/src/helpers/fetch-existing-entities.d.ts +0 -16
  29. /package/dist/src/session/{command.d.ts → cli.d.ts} +0 -0
package/dist/src/index.js CHANGED
@@ -335,7 +335,7 @@ async function runAgent(options) {
335
335
  promptLen: prompt2.length,
336
336
  promptHead: prompt2.slice(0, 500)
337
337
  });
338
- return new Promise((resolve27) => {
338
+ return new Promise((resolve28) => {
339
339
  const bedrockEnv = bedrock ? BEDROCK_ENV_BY_AGENT[agent] : void 0;
340
340
  const child = spawn(binary, args, {
341
341
  stdio: ["pipe", "pipe", "pipe"],
@@ -384,25 +384,25 @@ async function runAgent(options) {
384
384
  stderrLen: stderr.length,
385
385
  stderrTail: stderr.slice(-1e3)
386
386
  });
387
- resolve27(result);
387
+ resolve28(result);
388
388
  });
389
389
  });
390
390
  }
391
391
  async function checkAgentAuth(agent) {
392
392
  const binary = resolveBinary(agent);
393
- const binaryExists2 = await new Promise((resolve27) => {
393
+ const binaryExists2 = await new Promise((resolve28) => {
394
394
  if (binary.startsWith("/")) {
395
- import("node:fs/promises").then((fs2) => fs2.access(binary).then(() => resolve27(true), () => resolve27(false)));
395
+ import("node:fs/promises").then((fs2) => fs2.access(binary).then(() => resolve28(true), () => resolve28(false)));
396
396
  return;
397
397
  }
398
398
  const child = spawn("which", [binary], { stdio: "ignore" });
399
- child.on("close", (code) => resolve27(code === 0));
399
+ child.on("close", (code) => resolve28(code === 0));
400
400
  });
401
401
  if (!binaryExists2)
402
402
  return "not-found";
403
403
  if (agent !== "claude")
404
404
  return "ok";
405
- return new Promise((resolve27) => {
405
+ return new Promise((resolve28) => {
406
406
  const child = spawn(binary, ["auth", "status", "--json"], {
407
407
  stdio: ["ignore", "pipe", "pipe"]
408
408
  });
@@ -412,7 +412,7 @@ async function checkAgentAuth(agent) {
412
412
  if (!done) {
413
413
  done = true;
414
414
  child.kill("SIGTERM");
415
- resolve27("unauthenticated");
415
+ resolve28("unauthenticated");
416
416
  }
417
417
  }, 5e3);
418
418
  child.stdout?.on("data", (chunk) => {
@@ -424,14 +424,14 @@ async function checkAgentAuth(agent) {
424
424
  done = true;
425
425
  clearTimeout(timer);
426
426
  if (code !== 0) {
427
- resolve27("unauthenticated");
427
+ resolve28("unauthenticated");
428
428
  return;
429
429
  }
430
430
  try {
431
431
  const status = JSON.parse(stdout);
432
- resolve27(status.loggedIn ? "ok" : "unauthenticated");
432
+ resolve28(status.loggedIn ? "ok" : "unauthenticated");
433
433
  } catch {
434
- resolve27("unauthenticated");
434
+ resolve28("unauthenticated");
435
435
  }
436
436
  });
437
437
  });
@@ -624,8 +624,20 @@ function renderTokenCandidateSection(kind, entries) {
624
624
  ${formatTokenCandidateLines(entries)}`;
625
625
  }
626
626
  function buildPreamble(options) {
627
- const { skill, rawComponentsInline, rawTokensInline, rawTokensFilename, tokensInline, tokenMapInline, generatedCdf, tokenTree, componentSourceRefs } = options;
627
+ const { skill, rawComponentsInline, rawTokensInline, rawTokensFilename, tokensInline, tokenMapInline, generatedCdf, tokenTree, componentSourceRefs, existingComponentsInline, existingTokensInline } = options;
628
628
  const sections = [];
629
+ if (existingComponentsInline) {
630
+ sections.push(`Existing components in the target Contentful space (JSON) \u2014 use for alignment, not as a hard filter:
631
+ \`\`\`json
632
+ ${existingComponentsInline}
633
+ \`\`\``);
634
+ }
635
+ if (existingTokensInline) {
636
+ sections.push(`Existing design tokens in the target Contentful space (JSON) \u2014 prefer binding to these paths over inventing new ones:
637
+ \`\`\`json
638
+ ${existingTokensInline}
639
+ \`\`\``);
640
+ }
629
641
  if (rawComponentsInline) {
630
642
  sections.push(`Raw component data (JSON):
631
643
  \`\`\`json
@@ -8460,6 +8472,230 @@ var init_terminal_capabilities = __esm({
8460
8472
  }
8461
8473
  });
8462
8474
 
8475
+ // packages/experience-design-system-cli/src/session/source-excerpt.ts
8476
+ function escapeForRegExp(value) {
8477
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
8478
+ }
8479
+ function identifierPattern(name) {
8480
+ return new RegExp(`(?<![A-Za-z0-9_$])${escapeForRegExp(name)}(?![A-Za-z0-9_$])`);
8481
+ }
8482
+ function excerptAroundNames(text, names, maxChars, contextLines = 6) {
8483
+ if (text.length <= maxChars) return { content: text, usesNotShown: [] };
8484
+ const patterns = names.filter((name) => name.length > 0).map((name) => ({ name, pattern: identifierPattern(name) }));
8485
+ const lines = text.split("\n");
8486
+ const windows = [];
8487
+ lines.forEach((line, index) => {
8488
+ const mentioned = patterns.filter(({ pattern }) => pattern.test(line)).map(({ name }) => name);
8489
+ if (mentioned.length === 0) return;
8490
+ const start = Math.max(0, index - contextLines);
8491
+ const end = Math.min(lines.length - 1, index + contextLines);
8492
+ const last = windows[windows.length - 1];
8493
+ if (last && start <= last.end + 1) {
8494
+ last.end = Math.max(last.end, end);
8495
+ for (const name of mentioned) last.names.add(name);
8496
+ } else {
8497
+ windows.push({ start, end, names: new Set(mentioned) });
8498
+ }
8499
+ });
8500
+ if (windows.length === 0) {
8501
+ return { content: `${text.slice(0, maxChars)}
8502
+ ${TRUNCATED_MARKER}`, usesNotShown: [] };
8503
+ }
8504
+ const lastWindowFor = /* @__PURE__ */ new Map();
8505
+ for (const window of windows) for (const name of window.names) lastWindowFor.set(name, window);
8506
+ const kept = [];
8507
+ const cut = /* @__PURE__ */ new Set();
8508
+ let used = 0;
8509
+ for (const window of [...windows].reverse()) {
8510
+ const chunk = lines.slice(window.start, window.end + 1).join("\n");
8511
+ const separator = kept.length > 0 ? `
8512
+ ${ELLIPSIS_MARKER}
8513
+ ` : "";
8514
+ if (used + separator.length + chunk.length > maxChars) {
8515
+ if (kept.length === 0) {
8516
+ const head = chunk.slice(0, maxChars);
8517
+ kept.push({ window, text: head });
8518
+ used += head.length;
8519
+ for (const name of window.names) {
8520
+ if (lastWindowFor.get(name) === window && !identifierPattern(name).test(head)) cut.add(name);
8521
+ }
8522
+ continue;
8523
+ }
8524
+ for (const name of window.names) {
8525
+ if (lastWindowFor.get(name) === window) cut.add(name);
8526
+ }
8527
+ continue;
8528
+ }
8529
+ kept.push({ window, text: chunk });
8530
+ used += separator.length + chunk.length;
8531
+ }
8532
+ kept.sort((a, b) => a.window.start - b.window.start);
8533
+ const parts = kept.map((entry, index) => (index > 0 ? `
8534
+ ${ELLIPSIS_MARKER}
8535
+ ` : "") + entry.text);
8536
+ const usesNotShown = names.filter((name, index) => cut.has(name) && names.indexOf(name) === index);
8537
+ return { content: `${parts.join("")}
8538
+ ${TRUNCATED_MARKER}`, usesNotShown };
8539
+ }
8540
+ var ELLIPSIS_MARKER, TRUNCATED_MARKER;
8541
+ var init_source_excerpt = __esm({
8542
+ "packages/experience-design-system-cli/src/session/source-excerpt.ts"() {
8543
+ "use strict";
8544
+ ELLIPSIS_MARKER = "/* \u2026 */";
8545
+ TRUNCATED_MARKER = "/* truncated */";
8546
+ }
8547
+ });
8548
+
8549
+ // packages/experience-design-system-cli/src/session/core/components/component-id.ts
8550
+ import { createHash } from "node:crypto";
8551
+ function deriveComponentId(name, source) {
8552
+ return createHash("sha256").update(`${name}:${source}`).digest("hex").slice(0, 12);
8553
+ }
8554
+ var init_component_id = __esm({
8555
+ "packages/experience-design-system-cli/src/session/core/components/component-id.ts"() {
8556
+ "use strict";
8557
+ }
8558
+ });
8559
+
8560
+ // packages/experience-design-system-cli/src/session/core/cdf/server-type-map.ts
8561
+ function mapServerTypeToCdfType(serverType) {
8562
+ switch (serverType.toLowerCase()) {
8563
+ case "string":
8564
+ case "text":
8565
+ return "string";
8566
+ case "richtext":
8567
+ return "richtext";
8568
+ case "media":
8569
+ return "media";
8570
+ case "link":
8571
+ return "link";
8572
+ case "enum":
8573
+ case "symbol":
8574
+ return "enum";
8575
+ case "token":
8576
+ return "token";
8577
+ case "boolean":
8578
+ return "boolean";
8579
+ default:
8580
+ return "string";
8581
+ }
8582
+ }
8583
+ function resolveCdfCategory(serverCategory, propName, contentProps, designProps) {
8584
+ if (serverCategory && VALID_CATEGORIES2.includes(serverCategory)) {
8585
+ return serverCategory;
8586
+ }
8587
+ if (contentProps.has(propName)) return "content";
8588
+ if (designProps.has(propName)) return "design";
8589
+ return "state";
8590
+ }
8591
+ var VALID_CATEGORIES2;
8592
+ var init_server_type_map = __esm({
8593
+ "packages/experience-design-system-cli/src/session/core/cdf/server-type-map.ts"() {
8594
+ "use strict";
8595
+ VALID_CATEGORIES2 = ["content", "design", "state"];
8596
+ }
8597
+ });
8598
+
8599
+ // packages/experience-design-system-cli/src/session/core/shared/group-by.ts
8600
+ function groupBy(items, key) {
8601
+ const map = /* @__PURE__ */ new Map();
8602
+ for (const item of items) {
8603
+ const k = key(item);
8604
+ let arr = map.get(k);
8605
+ if (!arr) {
8606
+ arr = [];
8607
+ map.set(k, arr);
8608
+ }
8609
+ arr.push(item);
8610
+ }
8611
+ return map;
8612
+ }
8613
+ var init_group_by = __esm({
8614
+ "packages/experience-design-system-cli/src/session/core/shared/group-by.ts"() {
8615
+ "use strict";
8616
+ }
8617
+ });
8618
+
8619
+ // packages/experience-design-system-cli/src/session/repositories/sessions/read.ts
8620
+ function findSession(db, sessionId2) {
8621
+ const row = db.prepare("SELECT id FROM sessions WHERE id = ?").get(sessionId2);
8622
+ return row ?? null;
8623
+ }
8624
+ function findLatestSessionForCommand(db, command) {
8625
+ const row = db.prepare(
8626
+ `SELECT s.id FROM sessions s
8627
+ JOIN steps st ON st.session_id = s.id
8628
+ WHERE st.command = ? AND st.status = 'complete'
8629
+ ORDER BY st.started_at DESC, st.id DESC
8630
+ LIMIT 1`
8631
+ ).get(command);
8632
+ return row?.id ?? null;
8633
+ }
8634
+ var init_read = __esm({
8635
+ "packages/experience-design-system-cli/src/session/repositories/sessions/read.ts"() {
8636
+ "use strict";
8637
+ }
8638
+ });
8639
+
8640
+ // packages/experience-design-system-cli/src/session/repositories/sessions/write.ts
8641
+ function createSession(db, id, name, timestamp) {
8642
+ db.prepare("INSERT INTO sessions (id, name, created_at, updated_at) VALUES (?, ?, ?, ?)").run(
8643
+ id,
8644
+ name,
8645
+ timestamp,
8646
+ timestamp
8647
+ );
8648
+ }
8649
+ function touchSession(db, sessionId2, timestamp) {
8650
+ db.prepare("UPDATE sessions SET updated_at = ? WHERE id = ?").run(timestamp, sessionId2);
8651
+ }
8652
+ var init_write = __esm({
8653
+ "packages/experience-design-system-cli/src/session/repositories/sessions/write.ts"() {
8654
+ "use strict";
8655
+ }
8656
+ });
8657
+
8658
+ // packages/experience-design-system-cli/src/session/repositories/steps/read.ts
8659
+ function findStepSessionId(db, stepId) {
8660
+ const row = db.prepare("SELECT session_id FROM steps WHERE id = ?").get(stepId);
8661
+ return row?.session_id ?? null;
8662
+ }
8663
+ var init_read2 = __esm({
8664
+ "packages/experience-design-system-cli/src/session/repositories/steps/read.ts"() {
8665
+ "use strict";
8666
+ }
8667
+ });
8668
+
8669
+ // packages/experience-design-system-cli/src/session/repositories/steps/write.ts
8670
+ function markPendingStepsInterrupted(db, sessionId2, command, timestamp) {
8671
+ db.prepare(
8672
+ `UPDATE steps SET status = 'interrupted', completed_at = ?, updated_at = ?
8673
+ WHERE session_id = ? AND command = ? AND status = 'pending'`
8674
+ ).run(timestamp, timestamp, sessionId2, command);
8675
+ }
8676
+ function insertPendingStep(db, sessionId2, command, inputs, timestamp) {
8677
+ const result = db.prepare(
8678
+ `INSERT INTO steps (session_id, command, status, started_at, inputs, outputs, updated_at)
8679
+ VALUES (?, ?, 'pending', ?, ?, '{}', ?)`
8680
+ ).run(sessionId2, command, timestamp, JSON.stringify(inputs), timestamp);
8681
+ return Number(result.lastInsertRowid);
8682
+ }
8683
+ function updateStepResult(db, stepId, status, outputs, error, timestamp) {
8684
+ db.prepare(`UPDATE steps SET status = ?, completed_at = ?, outputs = ?, error = ?, updated_at = ? WHERE id = ?`).run(
8685
+ status,
8686
+ timestamp,
8687
+ JSON.stringify(outputs),
8688
+ error,
8689
+ timestamp,
8690
+ stepId
8691
+ );
8692
+ }
8693
+ var init_write2 = __esm({
8694
+ "packages/experience-design-system-cli/src/session/repositories/steps/write.ts"() {
8695
+ "use strict";
8696
+ }
8697
+ });
8698
+
8463
8699
  // packages/experience-design-system-cli/src/session/session-id.ts
8464
8700
  var session_id_exports = {};
8465
8701
  __export(session_id_exports, {
@@ -8684,77 +8920,61 @@ var init_session_id = __esm({
8684
8920
  }
8685
8921
  });
8686
8922
 
8687
- // packages/experience-design-system-cli/src/session/source-excerpt.ts
8688
- function escapeForRegExp(value) {
8689
- return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
8690
- }
8691
- function identifierPattern(name) {
8692
- return new RegExp(`(?<![A-Za-z0-9_$])${escapeForRegExp(name)}(?![A-Za-z0-9_$])`);
8923
+ // packages/experience-design-system-cli/src/session/services/session-resolver.ts
8924
+ function resolveSession(db, sessionFlag, sessionName, _hints) {
8925
+ const now = (/* @__PURE__ */ new Date()).toISOString();
8926
+ if (sessionFlag === "new" || sessionFlag === void 0) {
8927
+ const id = generateSessionId();
8928
+ createSession(db, id, sessionName ?? null, now);
8929
+ return { sessionId: id, isNew: true, isResumed: false };
8930
+ }
8931
+ if (!findSession(db, sessionFlag)) {
8932
+ throw new Error(`session '${sessionFlag}' not found. Run 'session list' to see active sessions.`);
8933
+ }
8934
+ return { sessionId: sessionFlag, isNew: false, isResumed: false };
8693
8935
  }
8694
- function excerptAroundNames(text, names, maxChars, contextLines = 6) {
8695
- if (text.length <= maxChars) return { content: text, usesNotShown: [] };
8696
- const patterns = names.filter((name) => name.length > 0).map((name) => ({ name, pattern: identifierPattern(name) }));
8697
- const lines = text.split("\n");
8698
- const windows = [];
8699
- lines.forEach((line, index) => {
8700
- const mentioned = patterns.filter(({ pattern }) => pattern.test(line)).map(({ name }) => name);
8701
- if (mentioned.length === 0) return;
8702
- const start = Math.max(0, index - contextLines);
8703
- const end = Math.min(lines.length - 1, index + contextLines);
8704
- const last = windows[windows.length - 1];
8705
- if (last && start <= last.end + 1) {
8706
- last.end = Math.max(last.end, end);
8707
- for (const name of mentioned) last.names.add(name);
8708
- } else {
8709
- windows.push({ start, end, names: new Set(mentioned) });
8710
- }
8711
- });
8712
- if (windows.length === 0) {
8713
- return { content: `${text.slice(0, maxChars)}
8714
- ${TRUNCATED_MARKER}`, usesNotShown: [] };
8936
+ var init_session_resolver = __esm({
8937
+ "packages/experience-design-system-cli/src/session/services/session-resolver.ts"() {
8938
+ "use strict";
8939
+ init_session_id();
8940
+ init_read();
8941
+ init_write();
8715
8942
  }
8716
- const lastWindowFor = /* @__PURE__ */ new Map();
8717
- for (const window of windows) for (const name of window.names) lastWindowFor.set(name, window);
8718
- const kept = [];
8719
- const cut = /* @__PURE__ */ new Set();
8720
- let used = 0;
8721
- for (const window of [...windows].reverse()) {
8722
- const chunk = lines.slice(window.start, window.end + 1).join("\n");
8723
- const separator = kept.length > 0 ? `
8724
- ${ELLIPSIS_MARKER}
8725
- ` : "";
8726
- if (used + separator.length + chunk.length > maxChars) {
8727
- if (kept.length === 0) {
8728
- const head = chunk.slice(0, maxChars);
8729
- kept.push({ window, text: head });
8730
- used += head.length;
8731
- for (const name of window.names) {
8732
- if (lastWindowFor.get(name) === window && !identifierPattern(name).test(head)) cut.add(name);
8733
- }
8734
- continue;
8735
- }
8736
- for (const name of window.names) {
8737
- if (lastWindowFor.get(name) === window) cut.add(name);
8738
- }
8739
- continue;
8740
- }
8741
- kept.push({ window, text: chunk });
8742
- used += separator.length + chunk.length;
8943
+ });
8944
+
8945
+ // packages/experience-design-system-cli/src/session/core/components/input-hash.ts
8946
+ import { createHash as createHash2 } from "node:crypto";
8947
+ function computeComponentInputHash(component) {
8948
+ const payload = {
8949
+ framework: component.framework,
8950
+ name: component.name,
8951
+ source: component.source,
8952
+ props: component.props.map((p) => ({
8953
+ name: p.name,
8954
+ type: p.type
8955
+ })),
8956
+ slots: component.slots.map((s) => ({
8957
+ name: s.name,
8958
+ isDefault: s.isDefault,
8959
+ allowedComponents: [...s.allowedComponents ?? []].sort()
8960
+ }))
8961
+ };
8962
+ return createHash2("sha256").update(JSON.stringify(payload)).digest("hex");
8963
+ }
8964
+ var init_input_hash = __esm({
8965
+ "packages/experience-design-system-cli/src/session/core/components/input-hash.ts"() {
8966
+ "use strict";
8743
8967
  }
8744
- kept.sort((a, b) => a.window.start - b.window.start);
8745
- const parts = kept.map((entry, index) => (index > 0 ? `
8746
- ${ELLIPSIS_MARKER}
8747
- ` : "") + entry.text);
8748
- const usesNotShown = names.filter((name, index) => cut.has(name) && names.indexOf(name) === index);
8749
- return { content: `${parts.join("")}
8750
- ${TRUNCATED_MARKER}`, usesNotShown };
8968
+ });
8969
+
8970
+ // packages/experience-design-system-cli/src/session/core/tokens/input-hash.ts
8971
+ import { createHash as createHash3 } from "node:crypto";
8972
+ function computeTokenInputHash(rawTokenContent) {
8973
+ return createHash3("sha256").update(rawTokenContent.trim()).digest("hex");
8751
8974
  }
8752
- var ELLIPSIS_MARKER, TRUNCATED_MARKER;
8753
- var init_source_excerpt = __esm({
8754
- "packages/experience-design-system-cli/src/session/source-excerpt.ts"() {
8975
+ var init_input_hash2 = __esm({
8976
+ "packages/experience-design-system-cli/src/session/core/tokens/input-hash.ts"() {
8755
8977
  "use strict";
8756
- ELLIPSIS_MARKER = "/* \u2026 */";
8757
- TRUNCATED_MARKER = "/* truncated */";
8758
8978
  }
8759
8979
  });
8760
8980
 
@@ -8765,19 +8985,20 @@ __export(cache_keys_exports, {
8765
8985
  hashFile: () => hashFile,
8766
8986
  hashPromptForSkill: () => hashPromptForSkill
8767
8987
  });
8768
- import { createHash } from "node:crypto";
8988
+ import { createHash as createHash4 } from "node:crypto";
8769
8989
  import { readFile as readFile6 } from "node:fs/promises";
8770
8990
  import { resolve as resolve6 } from "node:path";
8771
8991
  function hashContent(content) {
8772
- return createHash("sha256").update(content).digest("hex");
8992
+ return createHash4("sha256").update(content).digest("hex");
8773
8993
  }
8774
8994
  async function hashFile(filePath) {
8775
8995
  const content = await readFile6(filePath, "utf8");
8776
8996
  return hashContent(content);
8777
8997
  }
8778
- async function hashPromptForSkill(skill, agent, model, skillPathOverride) {
8998
+ async function hashPromptForSkill(skill, agent, model, skillPathOverride, extraInputs = []) {
8779
8999
  const promptHash = skillPathOverride ? await hashFile(resolve6(skillPathOverride)) : await hashFile(resolveSkillPath(skill));
8780
- return hashContent(`${promptHash}|${agent}|${model ?? ""}`);
9000
+ const extraSegment = extraInputs.length > 0 ? `|${extraInputs.join("|")}` : "";
9001
+ return hashContent(`${promptHash}|${agent}|${model ?? ""}${extraSegment}`);
8781
9002
  }
8782
9003
  var init_cache_keys = __esm({
8783
9004
  "packages/experience-design-system-cli/src/session/cache-keys.ts"() {
@@ -8790,7 +9011,7 @@ var init_cache_keys = __esm({
8790
9011
  import { DatabaseSync } from "node:sqlite";
8791
9012
  import { mkdirSync, readFileSync as readFileSync5 } from "node:fs";
8792
9013
  import { readFile as readFile7 } from "node:fs/promises";
8793
- import { createHash as createHash2 } from "node:crypto";
9014
+ import { createHash as createHash5 } from "node:crypto";
8794
9015
  import { homedir } from "node:os";
8795
9016
  import { dirname as dirname7, resolve as resolve7 } from "node:path";
8796
9017
  function getPipelineDbPath() {
@@ -9321,39 +9542,18 @@ function applyToolCalls(db, sessionId2, componentId, componentName, calls, incom
9321
9542
  }
9322
9543
  return { classified, excluded, slots, warnings };
9323
9544
  }
9324
- function getOrCreateSession(db, sessionFlag, sessionName, _hints) {
9325
- const now = (/* @__PURE__ */ new Date()).toISOString();
9326
- if (sessionFlag === "new" || sessionFlag === void 0) {
9327
- const id = generateSessionId();
9328
- db.prepare("INSERT INTO sessions (id, name, created_at, updated_at) VALUES (?, ?, ?, ?)").run(
9329
- id,
9330
- sessionName ?? null,
9331
- now,
9332
- now
9333
- );
9334
- return { sessionId: id, isNew: true, isResumed: false };
9335
- }
9336
- const existing = db.prepare("SELECT id FROM sessions WHERE id = ?").get(sessionFlag);
9337
- if (!existing) {
9338
- throw new Error(`session '${sessionFlag}' not found. Run 'session list' to see active sessions.`);
9339
- }
9340
- return { sessionId: sessionFlag, isNew: false, isResumed: false };
9545
+ function getOrCreateSession(db, sessionFlag, sessionName, hints) {
9546
+ return resolveSession(db, sessionFlag, sessionName, hints);
9341
9547
  }
9342
9548
  function createStep(db, sessionId2, command, inputs) {
9343
9549
  const now = (/* @__PURE__ */ new Date()).toISOString();
9344
9550
  db.exec("BEGIN");
9345
9551
  try {
9346
- db.prepare(
9347
- `UPDATE steps SET status = 'interrupted', completed_at = ?, updated_at = ?
9348
- WHERE session_id = ? AND command = ? AND status = 'pending'`
9349
- ).run(now, now, sessionId2, command);
9350
- const result = db.prepare(
9351
- `INSERT INTO steps (session_id, command, status, started_at, inputs, outputs, updated_at)
9352
- VALUES (?, ?, 'pending', ?, ?, '{}', ?)`
9353
- ).run(sessionId2, command, now, JSON.stringify(inputs), now);
9354
- db.prepare("UPDATE sessions SET updated_at = ? WHERE id = ?").run(now, sessionId2);
9552
+ markPendingStepsInterrupted(db, sessionId2, command, now);
9553
+ const stepId = insertPendingStep(db, sessionId2, command, inputs, now);
9554
+ touchSession(db, sessionId2, now);
9355
9555
  db.exec("COMMIT");
9356
- return Number(result.lastInsertRowid);
9556
+ return stepId;
9357
9557
  } catch (e) {
9358
9558
  db.exec("ROLLBACK");
9359
9559
  throw e;
@@ -9363,12 +9563,10 @@ function updateStep(db, stepId, status, outputs, error) {
9363
9563
  const now = (/* @__PURE__ */ new Date()).toISOString();
9364
9564
  db.exec("BEGIN");
9365
9565
  try {
9366
- const step = db.prepare("SELECT session_id FROM steps WHERE id = ?").get(stepId);
9367
- db.prepare(
9368
- `UPDATE steps SET status = ?, completed_at = ?, outputs = ?, error = ?, updated_at = ? WHERE id = ?`
9369
- ).run(status, now, JSON.stringify(outputs), error ?? null, now, stepId);
9370
- if (step) {
9371
- db.prepare("UPDATE sessions SET updated_at = ? WHERE id = ?").run(now, step.session_id);
9566
+ const stepSessionId = findStepSessionId(db, stepId);
9567
+ updateStepResult(db, stepId, status, outputs, error ?? null, now);
9568
+ if (stepSessionId) {
9569
+ touchSession(db, stepSessionId, now);
9372
9570
  }
9373
9571
  db.exec("COMMIT");
9374
9572
  } catch (e) {
@@ -9795,22 +9993,6 @@ function parseReviewReasons(raw) {
9795
9993
  return [];
9796
9994
  }
9797
9995
  }
9798
- function groupBy(items, key) {
9799
- const map = /* @__PURE__ */ new Map();
9800
- for (const item of items) {
9801
- const k = key(item);
9802
- let arr = map.get(k);
9803
- if (!arr) {
9804
- arr = [];
9805
- map.set(k, arr);
9806
- }
9807
- arr.push(item);
9808
- }
9809
- return map;
9810
- }
9811
- function deriveComponentId(name, source) {
9812
- return createHash2("sha256").update(`${name}:${source}`).digest("hex").slice(0, 12);
9813
- }
9814
9996
  function storeCDFComponents(db, sessionId2, components) {
9815
9997
  const now = (/* @__PURE__ */ new Date()).toISOString();
9816
9998
  const updateComp = db.prepare(
@@ -9903,7 +10085,7 @@ function storeCDFComponents(db, sessionId2, components) {
9903
10085
  }
9904
10086
  }
9905
10087
  } else {
9906
- const componentId = createHash2("sha256").update(`${key}:generated`).digest("hex").slice(0, 12);
10088
+ const componentId = deriveComponentId(key, "generated");
9907
10089
  db.prepare(
9908
10090
  `INSERT INTO raw_components (session_id, component_id, name, source, framework, extracted_at, status, description)
9909
10091
  VALUES (?, ?, ?, '', 'react', ?, 'generated', ?)`
@@ -10169,15 +10351,8 @@ function loadDTCGTokens(db, sessionId2) {
10169
10351
  });
10170
10352
  return { groups, tokens };
10171
10353
  }
10172
- function findLatestSessionForCommand(db, command) {
10173
- const row = db.prepare(
10174
- `SELECT s.id FROM sessions s
10175
- JOIN steps st ON st.session_id = s.id
10176
- WHERE st.command = ? AND st.status = 'complete'
10177
- ORDER BY st.started_at DESC, st.id DESC
10178
- LIMIT 1`
10179
- ).get(command);
10180
- return row?.id ?? null;
10354
+ function findLatestSessionForCommand2(db, command) {
10355
+ return findLatestSessionForCommand(db, command);
10181
10356
  }
10182
10357
  function seedCDFFromPreviewResponse(db, sessionId2, removedItems) {
10183
10358
  if (removedItems.length === 0) return 0;
@@ -10194,14 +10369,8 @@ function seedCDFFromPreviewResponse(db, sessionId2, removedItems) {
10194
10369
  const contentProps = new Set(item.contentProperties);
10195
10370
  const designProps = new Set(item.designProperties);
10196
10371
  for (const [propName, propSummary] of Object.entries(item.fullProperties)) {
10197
- const cdfType = mapServerTypeToCDFType(propSummary.type);
10198
- if (!cdfType) continue;
10199
- let cdfCategory = propSummary.category || null;
10200
- if (!cdfCategory || !["content", "design", "state"].includes(cdfCategory)) {
10201
- if (contentProps.has(propName)) cdfCategory = "content";
10202
- else if (designProps.has(propName)) cdfCategory = "design";
10203
- else cdfCategory = "state";
10204
- }
10372
+ const cdfType = mapServerTypeToCdfType(propSummary.type);
10373
+ const cdfCategory = resolveCdfCategory(propSummary.category, propName, contentProps, designProps);
10205
10374
  const result = updateStmt.run(cdfType, cdfCategory, sessionId2, localComponent.component_id, propName);
10206
10375
  totalSeeded += Number(result.changes);
10207
10376
  }
@@ -10231,14 +10400,8 @@ function seedDefaultsFromChangedItems(db, sessionId2, changedItems) {
10231
10400
  const result2 = updateDefaultStmt.run(defaultStr, sessionId2, localComponent.component_id, propName);
10232
10401
  totalSeeded += Number(result2.changes);
10233
10402
  }
10234
- const cdfType = mapServerTypeToCDFType(propSummary.type);
10235
- if (!cdfType) continue;
10236
- let cdfCategory = propSummary.category || null;
10237
- if (!cdfCategory || !["content", "design", "state"].includes(cdfCategory)) {
10238
- if (contentProps.has(propName)) cdfCategory = "content";
10239
- else if (designProps.has(propName)) cdfCategory = "design";
10240
- else cdfCategory = "state";
10241
- }
10403
+ const cdfType = mapServerTypeToCdfType(propSummary.type);
10404
+ const cdfCategory = resolveCdfCategory(propSummary.category, propName, contentProps, designProps);
10242
10405
  const result = updateCDFStmt.run(cdfType, cdfCategory, sessionId2, localComponent.component_id, propName);
10243
10406
  totalSeeded += Number(result.changes);
10244
10407
  }
@@ -10262,48 +10425,6 @@ function backfillUnclassifiedProps(db, sessionId2) {
10262
10425
  ).run(sessionId2, sessionId2);
10263
10426
  return Number(withCategory.changes) + Number(withoutCategory.changes);
10264
10427
  }
10265
- function mapServerTypeToCDFType(serverType) {
10266
- switch (serverType.toLowerCase()) {
10267
- case "string":
10268
- case "text":
10269
- return "string";
10270
- case "richtext":
10271
- return "richtext";
10272
- case "media":
10273
- return "media";
10274
- case "link":
10275
- return "link";
10276
- case "enum":
10277
- case "symbol":
10278
- return "enum";
10279
- case "token":
10280
- return "token";
10281
- case "boolean":
10282
- return "boolean";
10283
- default:
10284
- return "string";
10285
- }
10286
- }
10287
- function computeComponentInputHash(component) {
10288
- const payload = {
10289
- framework: component.framework,
10290
- name: component.name,
10291
- source: component.source,
10292
- props: component.props.map((p) => ({
10293
- name: p.name,
10294
- type: p.type
10295
- })),
10296
- slots: component.slots.map((s) => ({
10297
- name: s.name,
10298
- isDefault: s.isDefault,
10299
- allowedComponents: [...s.allowedComponents ?? []].sort()
10300
- }))
10301
- };
10302
- return createHash2("sha256").update(JSON.stringify(payload)).digest("hex");
10303
- }
10304
- function computeTokenInputHash(rawTokenContent) {
10305
- return createHash2("sha256").update(rawTokenContent.trim()).digest("hex");
10306
- }
10307
10428
  function computeMapTokensInputHash(db, sessionId2, componentSourceRefs = []) {
10308
10429
  const props = db.prepare(
10309
10430
  `SELECT rc.name AS component_name, rp.name AS prop_name, rp.cdf_token_kind, rp.default_value
@@ -10333,7 +10454,7 @@ function computeMapTokensInputHash(db, sessionId2, componentSourceRefs = []) {
10333
10454
  usesNotShown: [...ref.usesNotShown ?? []].sort()
10334
10455
  }))
10335
10456
  };
10336
- return createHash2("sha256").update(JSON.stringify(payload)).digest("hex");
10457
+ return createHash5("sha256").update(JSON.stringify(payload)).digest("hex");
10337
10458
  }
10338
10459
  function lookupCache(db, inputHash, entityType, entityId, promptHash = "") {
10339
10460
  const row = db.prepare(
@@ -10641,8 +10762,19 @@ var SCHEMA, MAX_COMPONENT_SOURCE_CHARS, MAX_SIBLING_FILES, MAX_SIBLING_SNIPPET_C
10641
10762
  var init_db = __esm({
10642
10763
  "packages/experience-design-system-cli/src/session/db.ts"() {
10643
10764
  "use strict";
10644
- init_session_id();
10645
10765
  init_source_excerpt();
10766
+ init_component_id();
10767
+ init_server_type_map();
10768
+ init_group_by();
10769
+ init_read();
10770
+ init_write();
10771
+ init_read2();
10772
+ init_write2();
10773
+ init_session_resolver();
10774
+ init_component_id();
10775
+ init_input_hash();
10776
+ init_input_hash2();
10777
+ init_server_type_map();
10646
10778
  SCHEMA = `
10647
10779
  PRAGMA journal_mode = WAL;
10648
10780
  PRAGMA foreign_keys = ON;
@@ -10919,11 +11051,11 @@ var init_persistence = __esm({
10919
11051
  });
10920
11052
 
10921
11053
  // packages/experience-design-system-cli/src/analyze/select/parser.ts
10922
- import { createHash as createHash3 } from "node:crypto";
11054
+ import { createHash as createHash6 } from "node:crypto";
10923
11055
  import { access as access2 } from "node:fs/promises";
10924
11056
  import { isAbsolute, relative, resolve as resolve9 } from "node:path";
10925
11057
  function createComponentId(name, resolvedSourcePath) {
10926
- const sourceHash = createHash3("sha256").update(`${name}:${resolvedSourcePath}`).digest("hex").slice(0, 12);
11058
+ const sourceHash = createHash6("sha256").update(`${name}:${resolvedSourcePath}`).digest("hex").slice(0, 12);
10927
11059
  return `${name}-${sourceHash}`;
10928
11060
  }
10929
11061
  async function resolveComponentSourcePath(source, reviewRoot) {
@@ -12885,7 +13017,7 @@ var init_user_agent = __esm({
12885
13017
 
12886
13018
  // packages/experience-design-system-cli/src/apply/api-client.ts
12887
13019
  function defaultSleep(delayMs) {
12888
- return new Promise((resolve27) => setTimeout(resolve27, delayMs));
13020
+ return new Promise((resolve28) => setTimeout(resolve28, delayMs));
12889
13021
  }
12890
13022
  function isTransientStatus(status) {
12891
13023
  return status >= 500 && status <= 599;
@@ -13273,7 +13405,7 @@ ${trimmed}`;
13273
13405
  const progress = maxAttempts > 1 ? attempt / (maxAttempts - 1) : 0;
13274
13406
  const baseDelay = intervalMs + (maxIntervalMs - intervalMs) * progress;
13275
13407
  const jitter = Math.random() * baseDelay * 0.15;
13276
- await new Promise((resolve27) => setTimeout(resolve27, baseDelay + jitter));
13408
+ await new Promise((resolve28) => setTimeout(resolve28, baseDelay + jitter));
13277
13409
  }
13278
13410
  }
13279
13411
  throw new Error(`Operation ${operationId} timed out after ${maxAttempts} attempts`);
@@ -16565,7 +16697,7 @@ var init_command2 = __esm({
16565
16697
  });
16566
16698
 
16567
16699
  // packages/experience-design-system-cli/src/import/path-utils.ts
16568
- import { resolve as resolve20 } from "node:path";
16700
+ import { resolve as resolve21 } from "node:path";
16569
16701
  import { homedir as homedir6 } from "node:os";
16570
16702
  function expandTilde(input) {
16571
16703
  if (input === "~" || input.startsWith("~/") || input.startsWith("~\\")) {
@@ -16579,7 +16711,7 @@ function normalizePath(input) {
16579
16711
  p = p.slice(1, -1);
16580
16712
  }
16581
16713
  p = expandTilde(p);
16582
- return resolve20(p);
16714
+ return resolve21(p);
16583
16715
  }
16584
16716
  var init_path_utils = __esm({
16585
16717
  "packages/experience-design-system-cli/src/import/path-utils.ts"() {
@@ -16587,9 +16719,74 @@ var init_path_utils = __esm({
16587
16719
  }
16588
16720
  });
16589
16721
 
16722
+ // packages/experience-design-system-cli/src/helpers/build-contentful-management-client.ts
16723
+ import { createClient as createClient2 } from "contentful-management";
16724
+ function buildContentfulManagementClient(opts) {
16725
+ return createClient2(
16726
+ {
16727
+ accessToken: opts.cmaToken,
16728
+ ...opts.host ? { host: toConfiguredHost(opts.host) } : {}
16729
+ },
16730
+ { type: "plain" }
16731
+ );
16732
+ }
16733
+ var init_build_contentful_management_client = __esm({
16734
+ "packages/experience-design-system-cli/src/helpers/build-contentful-management-client.ts"() {
16735
+ "use strict";
16736
+ init_host_utils();
16737
+ }
16738
+ });
16739
+
16740
+ // packages/experience-design-system-cli/src/helpers/fetch-existing-contentful-entities.ts
16741
+ import { fetchAll } from "contentful-management";
16742
+ async function fetchExistingContentfulEntitiesFromContentful(client2, params) {
16743
+ const scope = { spaceId: params.spaceId, environmentId: params.environmentId, query: {} };
16744
+ const components = await fetchAll(client2.component.getMany, scope);
16745
+ const tokens = await fetchAll(client2.designToken.getMany, scope);
16746
+ return { components, tokens };
16747
+ }
16748
+ var init_fetch_existing_contentful_entities = __esm({
16749
+ "packages/experience-design-system-cli/src/helpers/fetch-existing-contentful-entities.ts"() {
16750
+ "use strict";
16751
+ }
16752
+ });
16753
+
16754
+ // packages/experience-design-system-cli/src/helpers/fetch-and-persist-existing-contentful-entities.ts
16755
+ import { writeFile as writeFile5 } from "node:fs/promises";
16756
+ import { join as join18 } from "node:path";
16757
+ async function fetchAndPersistExistingContentfulEntities(params) {
16758
+ const t0 = Date.now();
16759
+ try {
16760
+ const client2 = buildContentfulManagementClient({
16761
+ cmaToken: params.cmaToken,
16762
+ ...params.host ? { host: params.host } : {}
16763
+ });
16764
+ const entities = await fetchExistingContentfulEntitiesFromContentful(client2, {
16765
+ spaceId: params.spaceId,
16766
+ environmentId: params.environmentId
16767
+ });
16768
+ const path = join18(params.outDir, ".existing-entities.json");
16769
+ await writeFile5(path, JSON.stringify(entities, null, 2), "utf8");
16770
+ return { ok: true, path, durationMs: Date.now() - t0, entities };
16771
+ } catch (error) {
16772
+ return {
16773
+ ok: false,
16774
+ durationMs: Date.now() - t0,
16775
+ error: error instanceof Error ? error.message : String(error)
16776
+ };
16777
+ }
16778
+ }
16779
+ var init_fetch_and_persist_existing_contentful_entities = __esm({
16780
+ "packages/experience-design-system-cli/src/helpers/fetch-and-persist-existing-contentful-entities.ts"() {
16781
+ "use strict";
16782
+ init_build_contentful_management_client();
16783
+ init_fetch_existing_contentful_entities();
16784
+ }
16785
+ });
16786
+
16590
16787
  // packages/experience-design-system-cli/src/runs/save-path-resolver.ts
16591
16788
  import { access as access8 } from "node:fs/promises";
16592
- import { join as join19 } from "node:path";
16789
+ import { join as join20 } from "node:path";
16593
16790
  function isConflictMode(value) {
16594
16791
  return CONFLICT_MODES.includes(value);
16595
16792
  }
@@ -16597,7 +16794,7 @@ async function listConflictingFiles(path) {
16597
16794
  const conflicts = [];
16598
16795
  for (const name of SAVE_FILES) {
16599
16796
  try {
16600
- await access8(join19(path, name));
16797
+ await access8(join20(path, name));
16601
16798
  conflicts.push(name);
16602
16799
  } catch {
16603
16800
  }
@@ -16617,7 +16814,7 @@ function buildTimestampedSubdir(base, now = /* @__PURE__ */ new Date()) {
16617
16814
  const hh = pad2(now.getHours());
16618
16815
  const mm = pad2(now.getMinutes());
16619
16816
  const ss = pad2(now.getSeconds());
16620
- return join19(base, `dsi-${y}${m}${d}-${hh}${mm}${ss}`);
16817
+ return join20(base, `dsi-${y}${m}${d}-${hh}${mm}${ss}`);
16621
16818
  }
16622
16819
  async function resolveSavePath(path, options = {}) {
16623
16820
  const conflicts = await listConflictingFiles(path);
@@ -16647,8 +16844,8 @@ var init_save_path_resolver = __esm({
16647
16844
  });
16648
16845
 
16649
16846
  // packages/experience-design-system-cli/src/runs/store.ts
16650
- import { readFile as readFile22, writeFile as writeFile6, mkdir as mkdir6, rename } from "node:fs/promises";
16651
- import { join as join20 } from "node:path";
16847
+ import { readFile as readFile23, writeFile as writeFile6, mkdir as mkdir6, rename } from "node:fs/promises";
16848
+ import { join as join21 } from "node:path";
16652
16849
  import { homedir as homedir7 } from "node:os";
16653
16850
  import { randomBytes as randomBytes2 } from "node:crypto";
16654
16851
  function runsFilePath() {
@@ -16691,7 +16888,7 @@ function migrateRecord(rec) {
16691
16888
  }
16692
16889
  async function readFileMaybe() {
16693
16890
  try {
16694
- const raw = await readFile22(RUNS_PATH, "utf8");
16891
+ const raw = await readFile23(RUNS_PATH, "utf8");
16695
16892
  const parsed = JSON.parse(raw);
16696
16893
  if (!READABLE_VERSIONS.has(parsed.version)) {
16697
16894
  throw new Error(
@@ -16769,8 +16966,8 @@ var init_store = __esm({
16769
16966
  RUNS_FILE_VERSION = 3;
16770
16967
  RUNS_FILE_CAP = 200;
16771
16968
  READABLE_VERSIONS = /* @__PURE__ */ new Set([1, 2, 3]);
16772
- RUNS_DIR = join20(homedir7(), ".config", "experiences");
16773
- RUNS_PATH = join20(RUNS_DIR, "runs.json");
16969
+ RUNS_DIR = join21(homedir7(), ".config", "experiences");
16970
+ RUNS_PATH = join21(RUNS_DIR, "runs.json");
16774
16971
  CROCKFORD = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
16775
16972
  }
16776
16973
  });
@@ -16834,7 +17031,7 @@ var init_run_teaser = __esm({
16834
17031
  import { useState as useState9, useEffect as useEffect3 } from "react";
16835
17032
  import { Box as Box20, Text as Text20 } from "ink";
16836
17033
  import { readdirSync as readdirSync3 } from "node:fs";
16837
- import { dirname as dirname13, basename as basename6, join as join21 } from "node:path";
17034
+ import { dirname as dirname13, basename as basename6, join as join22 } from "node:path";
16838
17035
  import { jsx as jsx20, jsxs as jsxs20 } from "react/jsx-runtime";
16839
17036
  function autocomplete(partial) {
16840
17037
  if (!partial) return null;
@@ -16849,13 +17046,13 @@ function autocomplete(partial) {
16849
17046
  }
16850
17047
  const matches = entries.filter((e) => e.startsWith(base));
16851
17048
  if (matches.length === 0) return null;
16852
- if (matches.length === 1) return join21(dir, matches[0]);
17049
+ if (matches.length === 1) return join22(dir, matches[0]);
16853
17050
  let prefix = matches[0];
16854
17051
  for (const m of matches) {
16855
17052
  while (!m.startsWith(prefix)) prefix = prefix.slice(0, -1);
16856
17053
  if (!prefix) break;
16857
17054
  }
16858
- return prefix.length > base.length ? join21(dir, prefix) : null;
17055
+ return prefix.length > base.length ? join22(dir, prefix) : null;
16859
17056
  }
16860
17057
  function PathPrompt({
16861
17058
  defaultPath,
@@ -17286,15 +17483,15 @@ var init_save_conflict = __esm({
17286
17483
  });
17287
17484
 
17288
17485
  // packages/experience-design-system-cli/src/runs/fingerprint.ts
17289
- import { createHash as createHash4 } from "node:crypto";
17290
- import { readFile as readFile23, stat as stat5 } from "node:fs/promises";
17291
- import { resolve as resolve22 } from "node:path";
17486
+ import { createHash as createHash7 } from "node:crypto";
17487
+ import { readFile as readFile24, stat as stat5 } from "node:fs/promises";
17488
+ import { resolve as resolve23 } from "node:path";
17292
17489
  function rowField(row, key) {
17293
17490
  const v = row[key];
17294
17491
  return typeof v === "string" ? v : null;
17295
17492
  }
17296
17493
  function sha256Hex(buf) {
17297
- return createHash4("sha256").update(buf).digest("hex");
17494
+ return createHash7("sha256").update(buf).digest("hex");
17298
17495
  }
17299
17496
  async function buildSourceFingerprint(opts) {
17300
17497
  const rows = opts.db.prepare("SELECT name, source_path FROM raw_components WHERE session_id = ?").all(opts.extractSessionId);
@@ -17304,7 +17501,7 @@ async function buildSourceFingerprint(opts) {
17304
17501
  const sourcePath = rowField(row, "source_path");
17305
17502
  const name = rowField(row, "name");
17306
17503
  if (!sourcePath) continue;
17307
- const abs = resolve22(sourcePath);
17504
+ const abs = resolve23(sourcePath);
17308
17505
  if (seen.has(abs)) continue;
17309
17506
  seen.add(abs);
17310
17507
  try {
@@ -17319,10 +17516,10 @@ async function buildSourceFingerprint(opts) {
17319
17516
  let rawTokensMtime = null;
17320
17517
  let rawTokensContentHash = null;
17321
17518
  if (opts.rawTokensPath) {
17322
- const abs = resolve22(opts.rawTokensPath);
17519
+ const abs = resolve23(opts.rawTokensPath);
17323
17520
  rawTokensPath = abs;
17324
17521
  try {
17325
- const [st, buf] = await Promise.all([stat5(abs), readFile23(abs)]);
17522
+ const [st, buf] = await Promise.all([stat5(abs), readFile24(abs)]);
17326
17523
  rawTokensMtime = st.mtime.toISOString();
17327
17524
  rawTokensContentHash = sha256Hex(buf);
17328
17525
  } catch {
@@ -17453,7 +17650,7 @@ var init_WelcomeStep = __esm({
17453
17650
  import { useState as useState13, useEffect as useEffect5 } from "react";
17454
17651
  import { Box as Box25, Text as Text25 } from "ink";
17455
17652
  import { promises as fs } from "node:fs";
17456
- import { join as join22 } from "node:path";
17653
+ import { join as join23 } from "node:path";
17457
17654
  import { jsx as jsx25, jsxs as jsxs25 } from "react/jsx-runtime";
17458
17655
  async function countFiles(dir) {
17459
17656
  const counts = {
@@ -17477,7 +17674,7 @@ async function countFiles(dir) {
17477
17674
  await Promise.all(
17478
17675
  entries.map(async (entry) => {
17479
17676
  if (IGNORE_DIRS.has(entry)) return;
17480
- const full = join22(current, entry);
17677
+ const full = join23(current, entry);
17481
17678
  let stat8;
17482
17679
  try {
17483
17680
  stat8 = await fs.stat(full);
@@ -17821,7 +18018,7 @@ __export(CredentialsStep_exports, {
17821
18018
  });
17822
18019
  import { useState as useState15, useEffect as useEffect7, useRef as useRef3 } from "react";
17823
18020
  import { Box as Box28, Text as Text28 } from "ink";
17824
- import { jsx as jsx28, jsxs as jsxs28 } from "react/jsx-runtime";
18021
+ import { Fragment as Fragment9, jsx as jsx28, jsxs as jsxs28 } from "react/jsx-runtime";
17825
18022
  function CredentialsStep({
17826
18023
  summary,
17827
18024
  error: externalError,
@@ -17935,8 +18132,13 @@ function CredentialsStep({
17935
18132
  "\u2713 ",
17936
18133
  summary
17937
18134
  ] }),
17938
- /* @__PURE__ */ jsx28(Box28, { marginTop: 1, children: /* @__PURE__ */ jsx28(Text28, { children: initialSpaceId && initialCmaToken ? "Credentials pre-filled from experiences setup. Press Enter to continue or edit any field to update." : "Enter your Contentful credentials to continue." }) }),
17939
- !(initialSpaceId && initialCmaToken) && /* @__PURE__ */ jsx28(Text28, { dimColor: true, children: "Tip: run experiences setup to save these to ~/.config/experiences/credentials.json so they pre-fill here automatically." }),
18135
+ /* @__PURE__ */ jsxs28(Box28, { flexDirection: "column", marginTop: 1, gap: 0, children: [
18136
+ /* @__PURE__ */ jsx28(Text28, { children: initialSpaceId && initialCmaToken ? "Credentials pre-filled from experiences setup. Press Enter to continue or edit any field to update." : "Enter the Contentful space you want to import into." }),
18137
+ !(initialSpaceId && initialCmaToken) && /* @__PURE__ */ jsxs28(Fragment9, { children: [
18138
+ /* @__PURE__ */ jsx28(Text28, { dimColor: true, children: "These credentials are used both to align agent suggestions with what already exists in the space and to push your import at the end. Press S to skip and run without space context (push will be disabled)." }),
18139
+ /* @__PURE__ */ jsx28(Text28, { dimColor: true, children: "Tip: run experiences setup to save these to ~/.config/experiences/credentials.json so they pre-fill here automatically." })
18140
+ ] })
18141
+ ] }),
17940
18142
  /* @__PURE__ */ jsxs28(Box28, { flexDirection: "column", gap: 0, marginTop: 1, children: [
17941
18143
  renderField("Space ID", spaceId, "spaceId"),
17942
18144
  renderField("Environment", environmentId, "environmentId"),
@@ -18134,7 +18336,7 @@ var init_preview_diff = __esm({
18134
18336
  // packages/experience-design-system-cli/src/import/tui/steps/WizardPreviewStep.tsx
18135
18337
  import { useState as useState16, useMemo as useMemo3 } from "react";
18136
18338
  import { Box as Box29, Text as Text29, useStdout as useStdout3 } from "ink";
18137
- import { Fragment as Fragment9, jsx as jsx29, jsxs as jsxs29 } from "react/jsx-runtime";
18339
+ import { Fragment as Fragment10, jsx as jsx29, jsxs as jsxs29 } from "react/jsx-runtime";
18138
18340
  function buildPreviewDiffLines(preview) {
18139
18341
  const lines = [];
18140
18342
  const { components, tokens } = preview;
@@ -18311,7 +18513,7 @@ function WizardPreviewStep({
18311
18513
  ] }),
18312
18514
  /* @__PURE__ */ jsx29(Text29, { dimColor: true, children: "\u2500".repeat(40) })
18313
18515
  ] }),
18314
- hasAnything ? /* @__PURE__ */ jsxs29(Fragment9, { children: [
18516
+ hasAnything ? /* @__PURE__ */ jsxs29(Fragment10, { children: [
18315
18517
  /* @__PURE__ */ jsx29(Text29, { children: "Here's what will happen in your space:" }),
18316
18518
  hasComponents && /* @__PURE__ */ jsxs29(Box29, { flexDirection: "column", gap: 0, children: [
18317
18519
  /* @__PURE__ */ jsx29(Box29, { gap: 1, marginTop: 1, children: /* @__PURE__ */ jsx29(Text29, { bold: true, dimColor: true, children: "ComponentTypes" }) }),
@@ -18477,7 +18679,7 @@ var init_WizardPreviewStep = __esm({
18477
18679
 
18478
18680
  // packages/experience-design-system-cli/src/import/tui/steps/DoneStep.tsx
18479
18681
  import { Box as Box30, Text as Text30 } from "ink";
18480
- import { Fragment as Fragment10, jsx as jsx30, jsxs as jsxs30 } from "react/jsx-runtime";
18682
+ import { Fragment as Fragment11, jsx as jsx30, jsxs as jsxs30 } from "react/jsx-runtime";
18481
18683
  function DoneStep({
18482
18684
  componentTypes,
18483
18685
  designTokens,
@@ -18498,7 +18700,7 @@ function DoneStep({
18498
18700
  const totalPushed = componentTypes.created + componentTypes.updated + componentTypes.removed + designTokens.created + designTokens.updated + designTokens.removed;
18499
18701
  const success = totalFailed === 0;
18500
18702
  function EntityRows({ entity, label }) {
18501
- return /* @__PURE__ */ jsxs30(Fragment10, { children: [
18703
+ return /* @__PURE__ */ jsxs30(Fragment11, { children: [
18502
18704
  entity.created > 0 && /* @__PURE__ */ jsxs30(Box30, { gap: 1, children: [
18503
18705
  /* @__PURE__ */ jsx30(Text30, { color: PALETTE.success, children: "\u2713" }),
18504
18706
  /* @__PURE__ */ jsxs30(Text30, { children: [
@@ -19103,9 +19305,9 @@ function spawnGenerateChild(opts) {
19103
19305
  stderr += chunk;
19104
19306
  opts.onStderr?.(chunk);
19105
19307
  });
19106
- const donePromise = new Promise((resolve27) => {
19308
+ const donePromise = new Promise((resolve28) => {
19107
19309
  child.on("close", (code, signal) => {
19108
- resolve27({
19310
+ resolve28({
19109
19311
  exitCode: code ?? 0,
19110
19312
  signal: signal ?? null,
19111
19313
  stdout,
@@ -19113,7 +19315,7 @@ function spawnGenerateChild(opts) {
19113
19315
  });
19114
19316
  });
19115
19317
  child.on("error", (err) => {
19116
- resolve27({
19318
+ resolve28({
19117
19319
  exitCode: 1,
19118
19320
  signal: null,
19119
19321
  stdout,
@@ -20670,7 +20872,7 @@ var init_scope_gate_columns = __esm({
20670
20872
  // packages/experience-design-system-cli/src/import/tui/steps/ScopeGateStep.tsx
20671
20873
  import { Box as Box39, Text as Text41, useStdout as useStdout4 } from "ink";
20672
20874
  import React21, { useEffect as useEffect10, useMemo as useMemo5, useRef as useRef4, useState as useState21 } from "react";
20673
- import { Fragment as Fragment11, jsx as jsx42, jsxs as jsxs41 } from "react/jsx-runtime";
20875
+ import { Fragment as Fragment12, jsx as jsx42, jsxs as jsxs41 } from "react/jsx-runtime";
20674
20876
  function capReasonForFocusedRow(reason, width) {
20675
20877
  const safeWidth = Math.max(20, width);
20676
20878
  const budget = safeWidth * FOCUSED_REASON_MAX_LINES;
@@ -21419,7 +21621,7 @@ function ScopeGateStep({
21419
21621
  graph
21420
21622
  }
21421
21623
  ),
21422
- columnPlan.layout === "three-column" && /* @__PURE__ */ jsxs41(Fragment11, { children: [
21624
+ columnPlan.layout === "three-column" && /* @__PURE__ */ jsxs41(Fragment12, { children: [
21423
21625
  /* @__PURE__ */ jsx42(Box39, { width: 2, flexShrink: 0 }),
21424
21626
  /* @__PURE__ */ jsx42(
21425
21627
  AddedComponentsColumn,
@@ -21594,7 +21796,7 @@ function AddedComponentsColumn(props) {
21594
21796
  borderColor: focused ? PALETTE.inverse : void 0,
21595
21797
  children: [
21596
21798
  /* @__PURE__ */ jsx42(ColumnHeader, { title: "Added components", width, focused }),
21597
- entries.length === 0 ? /* @__PURE__ */ jsx42(Text41, { dimColor: true, children: "(none)" }) : /* @__PURE__ */ jsxs41(Fragment11, { children: [
21799
+ entries.length === 0 ? /* @__PURE__ */ jsx42(Text41, { dimColor: true, children: "(none)" }) : /* @__PURE__ */ jsxs41(Fragment12, { children: [
21598
21800
  window.above > 0 && /* @__PURE__ */ jsx42(Text41, { dimColor: true, children: `\u2191 ${window.above} more` }),
21599
21801
  entries.slice(window.start, window.end).map((entry, vi) => {
21600
21802
  const i = window.start + vi;
@@ -21657,7 +21859,7 @@ function AddedGroupsColumn(props) {
21657
21859
  borderColor: focused ? PALETTE.inverse : void 0,
21658
21860
  children: [
21659
21861
  /* @__PURE__ */ jsx42(ColumnHeader, { title: "Added groups", width, focused }),
21660
- entries.length === 0 ? /* @__PURE__ */ jsx42(Text41, { dimColor: true, children: "(none)" }) : /* @__PURE__ */ jsxs41(Fragment11, { children: [
21862
+ entries.length === 0 ? /* @__PURE__ */ jsx42(Text41, { dimColor: true, children: "(none)" }) : /* @__PURE__ */ jsxs41(Fragment12, { children: [
21661
21863
  window.above > 0 && /* @__PURE__ */ jsx42(Text41, { dimColor: true, children: `\u2191 ${window.above} more` }),
21662
21864
  entries.slice(window.start, window.end).map((g, vi) => {
21663
21865
  const i = window.start + vi;
@@ -22363,7 +22565,7 @@ import {
22363
22565
  CDF_PROPERTY_CATEGORIES,
22364
22566
  DESIGN_TOKEN_TYPES as DESIGN_TOKEN_TYPES2
22365
22567
  } from "@contentful/experience-design-system-types";
22366
- import { Fragment as Fragment12, jsx as jsx45, jsxs as jsxs44 } from "react/jsx-runtime";
22568
+ import { Fragment as Fragment13, jsx as jsx45, jsxs as jsxs44 } from "react/jsx-runtime";
22367
22569
  function parseToState(json) {
22368
22570
  let parsed;
22369
22571
  try {
@@ -22565,7 +22767,7 @@ function PropRow({
22565
22767
  activeField === "category" && /* @__PURE__ */ jsx45(Picker, { value: prop.category, active: true }),
22566
22768
  /* @__PURE__ */ jsx45(Text44, { dimColor: !selected, children: "req:" }),
22567
22769
  activeField === "required" ? /* @__PURE__ */ jsx45(Toggle, { value: prop.required, active: true }) : /* @__PURE__ */ jsx45(Toggle, { value: prop.required, active: false }),
22568
- prop.type === "enum" && /* @__PURE__ */ jsxs44(Fragment12, { children: [
22770
+ prop.type === "enum" && /* @__PURE__ */ jsxs44(Fragment13, { children: [
22569
22771
  /* @__PURE__ */ jsx45(Text44, { dimColor: !selected, children: "values:" }),
22570
22772
  /* @__PURE__ */ jsxs44(Text44, { color: selected ? PALETTE.warning : PALETTE.inverse, children: [
22571
22773
  "[",
@@ -22573,7 +22775,7 @@ function PropRow({
22573
22775
  "]"
22574
22776
  ] })
22575
22777
  ] }),
22576
- prop.type === "token" && /* @__PURE__ */ jsxs44(Fragment12, { children: [
22778
+ prop.type === "token" && /* @__PURE__ */ jsxs44(Fragment13, { children: [
22577
22779
  /* @__PURE__ */ jsx45(Text44, { dimColor: !selected, children: "kind:" }),
22578
22780
  activeField === "tokenKind" ? /* @__PURE__ */ jsx45(Picker, { value: prop.tokenKind || DESIGN_TOKEN_TYPES2[0], active: true }) : /* @__PURE__ */ jsx45(Text44, { color: selected ? PALETTE.success : PALETTE.inverse, children: prop.tokenKind || "\u2014" })
22579
22781
  ] })
@@ -23778,7 +23980,7 @@ var init_cycle_panel_scroll = __esm({
23778
23980
 
23779
23981
  // packages/experience-design-system-cli/src/analyze/select/tui/components/RationalePanel.tsx
23780
23982
  import { Box as Box43, Text as Text45 } from "ink";
23781
- import { Fragment as Fragment13, jsx as jsx46, jsxs as jsxs45 } from "react/jsx-runtime";
23983
+ import { Fragment as Fragment14, jsx as jsx46, jsxs as jsxs45 } from "react/jsx-runtime";
23782
23984
  function wrapText(text, innerWidth) {
23783
23985
  if (!text) return [""];
23784
23986
  const width = Math.max(1, innerWidth);
@@ -23858,7 +24060,7 @@ function RationalePanel({
23858
24060
  children: [
23859
24061
  /* @__PURE__ */ jsxs45(Box43, { children: [
23860
24062
  /* @__PURE__ */ jsx46(Text45, { bold: true, dimColor: !active, children: `RATIONALE \u2014 ${componentName}` }),
23861
- overflowed && /* @__PURE__ */ jsxs45(Fragment13, { children: [
24063
+ overflowed && /* @__PURE__ */ jsxs45(Fragment14, { children: [
23862
24064
  /* @__PURE__ */ jsx46(Box43, { flexGrow: 1 }),
23863
24065
  /* @__PURE__ */ jsx46(Text45, { dimColor: !active, children: `\u2195 ${visibleStart}-${visibleEnd}/${totalLines}` })
23864
24066
  ] })
@@ -24582,7 +24784,7 @@ var init_history = __esm({
24582
24784
  // packages/experience-design-system-cli/src/import/tui/steps/GenerateReviewStep.tsx
24583
24785
  import { useEffect as useEffect13, useMemo as useMemo7, useRef as useRef7, useState as useState26 } from "react";
24584
24786
  import { Box as Box46, Text as Text48, useStdout as useStdout6 } from "ink";
24585
- import { Fragment as Fragment14, jsx as jsx49, jsxs as jsxs48 } from "react/jsx-runtime";
24787
+ import { Fragment as Fragment15, jsx as jsx49, jsxs as jsxs48 } from "react/jsx-runtime";
24586
24788
  function sortComponentsForSidebar2(components, cycleParticipants) {
24587
24789
  const isEmpty2 = (entry) => Object.keys(entry.$properties ?? {}).length === 0 && Object.keys(entry.$slots ?? {}).length === 0;
24588
24790
  const tier = (c2) => {
@@ -25976,7 +26178,7 @@ function GenerateReviewStep({
25976
26178
  const isCursor = idx === breakCursor;
25977
26179
  return /* @__PURE__ */ jsx49(Text48, { inverse: isCursor, children: `${isCursor ? "\u25B6" : " "} remove '${edge.toComponent}' from ${edge.fromComponent}.$slots.${edge.slotName}.$allowedComponents` }, `break-${idx}`);
25978
26180
  }),
25979
- breakConfirm ? /* @__PURE__ */ jsxs48(Fragment14, { children: [
26181
+ breakConfirm ? /* @__PURE__ */ jsxs48(Fragment15, { children: [
25980
26182
  /* @__PURE__ */ jsx49(Text48, { children: " " }),
25981
26183
  /* @__PURE__ */ jsx49(Text48, { bold: true, color: PALETTE.warning, children: "Delete this slot edge? [y] confirm [n] cancel" })
25982
26184
  ] }) : /* @__PURE__ */ jsx49(Text48, { dimColor: true, children: "[\u2191\u2193/j/k] move [Enter] delete [x/Esc] close" })
@@ -26058,7 +26260,7 @@ function GenerateReviewStep({
26058
26260
  ] }),
26059
26261
  removedComponents.length > 0 && !dialogOpen && /* @__PURE__ */ jsxs48(Box46, { flexDirection: "column", borderStyle: "round", borderColor: PALETTE.error, paddingX: 1, children: [
26060
26262
  /* @__PURE__ */ jsx49(Text48, { bold: true, color: PALETTE.error, children: removedComponentsHeader(removedComponents.length, true) }),
26061
- !removedBannerCollapsed && /* @__PURE__ */ jsxs48(Fragment14, { children: [
26263
+ !removedBannerCollapsed && /* @__PURE__ */ jsxs48(Fragment15, { children: [
26062
26264
  /* @__PURE__ */ jsx49(Text48, { children: " " }),
26063
26265
  removedComponents.map((rc) => /* @__PURE__ */ jsx49(Text48, { children: removedComponentLine(rc) }, rc.id))
26064
26266
  ] })
@@ -26235,7 +26437,7 @@ function GenerateReviewStep({
26235
26437
  graph: sidebarGraph
26236
26438
  }
26237
26439
  ),
26238
- /* @__PURE__ */ jsx49(Box46, { flexGrow: 1, paddingLeft: 1, flexDirection: "column", children: selected ? /* @__PURE__ */ jsxs48(Fragment14, { children: [
26440
+ /* @__PURE__ */ jsx49(Box46, { flexGrow: 1, paddingLeft: 1, flexDirection: "column", children: selected ? /* @__PURE__ */ jsxs48(Fragment15, { children: [
26239
26441
  /* @__PURE__ */ jsxs48(Box46, { children: [
26240
26442
  /* @__PURE__ */ jsx49(Text48, { bold: true, children: selected.key }),
26241
26443
  /* @__PURE__ */ jsx49(Box46, { flexGrow: 1 }),
@@ -26404,11 +26606,11 @@ function GenerateReviewStep({
26404
26606
  autocompleteCandidates.length > 1 && /* @__PURE__ */ jsx49(Text48, { dimColor: true, children: ` possibilities: ${autocompleteCandidates.join(" \xB7 ").slice(0, 120)}` })
26405
26607
  ] }),
26406
26608
  !dialogOpen && !searchOpen && searchQuery && /* @__PURE__ */ jsx49(Box46, { children: /* @__PURE__ */ jsx49(Text48, { dimColor: true, children: `/${searchQuery} (${searchMatchCount}/${components.length} matches) \xB7 [Esc] clear` }) }),
26407
- !dialogOpen && sidebarFocused && /* @__PURE__ */ jsx49(Box46, { columnGap: 2, flexWrap: "wrap", children: panelOpen === "token-review" ? /* @__PURE__ */ jsxs48(Fragment14, { children: [
26609
+ !dialogOpen && sidebarFocused && /* @__PURE__ */ jsx49(Box46, { columnGap: 2, flexWrap: "wrap", children: panelOpen === "token-review" ? /* @__PURE__ */ jsxs48(Fragment15, { children: [
26408
26610
  legendEntry("[\u2191/\u2193]", "move"),
26409
26611
  legendEntry("[Enter]", "edit allowed"),
26410
26612
  legendEntry("[Esc]", "close")
26411
- ] }) : /* @__PURE__ */ jsxs48(Fragment14, { children: [
26613
+ ] }) : /* @__PURE__ */ jsxs48(Fragment15, { children: [
26412
26614
  legendEntry("[j/k]", "move"),
26413
26615
  legendEntry("[a]", "accept"),
26414
26616
  legendEntry("[r]", "reject"),
@@ -26576,7 +26778,7 @@ var init_GenerateReviewStep = __esm({
26576
26778
  // packages/experience-design-system-cli/src/import/tui/steps/AtomicGenerateReviewStep.tsx
26577
26779
  import { useEffect as useEffect14, useRef as useRef8, useState as useState27 } from "react";
26578
26780
  import { Box as Box47, Text as Text49, useStdout as useStdout7 } from "ink";
26579
- import { Fragment as Fragment15, jsx as jsx50, jsxs as jsxs49 } from "react/jsx-runtime";
26781
+ import { Fragment as Fragment16, jsx as jsx50, jsxs as jsxs49 } from "react/jsx-runtime";
26580
26782
  function sortComponentsForSidebar3(components) {
26581
26783
  return [...components].sort((a, b) => {
26582
26784
  const aEmpty = Object.keys(a.entry.$properties ?? {}).length === 0;
@@ -27301,7 +27503,7 @@ function AtomicGenerateReviewStep({
27301
27503
  width: sidebarWidth
27302
27504
  }
27303
27505
  ),
27304
- /* @__PURE__ */ jsx50(Box47, { flexGrow: 1, paddingLeft: 1, flexDirection: "column", children: selected ? /* @__PURE__ */ jsxs49(Fragment15, { children: [
27506
+ /* @__PURE__ */ jsx50(Box47, { flexGrow: 1, paddingLeft: 1, flexDirection: "column", children: selected ? /* @__PURE__ */ jsxs49(Fragment16, { children: [
27305
27507
  /* @__PURE__ */ jsxs49(Box47, { children: [
27306
27508
  /* @__PURE__ */ jsx50(Text49, { bold: true, children: selected.key }),
27307
27509
  /* @__PURE__ */ jsx50(Box47, { flexGrow: 1 }),
@@ -27656,9 +27858,9 @@ __export(WizardApp_exports, {
27656
27858
  });
27657
27859
  import { useEffect as useEffect15, useRef as useRef9, useState as useState28 } from "react";
27658
27860
  import { Box as Box49, Text as Text51, useStdout as useStdout8 } from "ink";
27659
- import { join as join23, resolve as resolve23 } from "node:path";
27861
+ import { join as join24, resolve as resolve24 } from "node:path";
27660
27862
  import { appendFileSync as appendFileSync2, writeFileSync } from "node:fs";
27661
- import { access as access9, readFile as readFile24, stat as stat6 } from "node:fs/promises";
27863
+ import { access as access9, readFile as readFile25, stat as stat6 } from "node:fs/promises";
27662
27864
  import { tmpdir } from "node:os";
27663
27865
  import { execFile as execFile4, spawn as spawn4 } from "node:child_process";
27664
27866
  import { mkdir as mkdir7 } from "node:fs/promises";
@@ -27670,6 +27872,7 @@ function buildSelectAgentArgs(opts) {
27670
27872
  if (opts.bedrock) args.push("--bedrock");
27671
27873
  if (opts.selectPromptPath) args.push("--select-prompt-path", opts.selectPromptPath);
27672
27874
  if (opts.noCache) args.push("--no-cache");
27875
+ if (opts.existingEntitiesPath) args.push("--existing-entities-path", opts.existingEntitiesPath);
27673
27876
  return args;
27674
27877
  }
27675
27878
  function parseAutoFilterProgressLine(line) {
@@ -27706,6 +27909,7 @@ function buildGenerateComponentsArgs(opts) {
27706
27909
  if (opts.bedrock) args.push("--bedrock");
27707
27910
  if (opts.noCache) args.push("--no-cache");
27708
27911
  if (opts.generatePromptPath) args.push("--generate-prompt-path", opts.generatePromptPath);
27912
+ if (opts.existingEntitiesPath) args.push("--existing-entities-path", opts.existingEntitiesPath);
27709
27913
  return args;
27710
27914
  }
27711
27915
  function buildMapTokensArgs(opts) {
@@ -27713,6 +27917,7 @@ function buildMapTokensArgs(opts) {
27713
27917
  if (opts.model) args.push("--model", opts.model);
27714
27918
  if (opts.noCache) args.push("--no-cache");
27715
27919
  if (opts.skipAgent) args.push("--skip-agent");
27920
+ if (opts.existingEntitiesPath) args.push("--existing-entities-path", opts.existingEntitiesPath);
27716
27921
  return args;
27717
27922
  }
27718
27923
  function shouldRunMapTokens(opts) {
@@ -27802,8 +28007,8 @@ function WizardApp({
27802
28007
  const rawTokensEntryReady = !modifyEntryReady && !pushFromPickerReady && !!initialRawTokensPath;
27803
28008
  const effectiveNoCache = resolveNoCacheForGenerate({ cliNoCache: noCache });
27804
28009
  const initialStepResolved = modifyEntryReady ? "final-review" : pushFromPickerReady ? "push-from-picker" : rawTokensEntryReady ? "generating-tokens" : initialProjectPath ? "token-input" : "welcome";
27805
- const initialOutDir = initialProjectPath ? join23(resolve23(initialProjectPath), ".contentful") : "";
27806
- const initialTokensPath = (modifyEntryReady || pushFromPickerReady) && initialOutDir && seedTokenSessionId ? join23(initialOutDir, "tokens.json") : "";
28010
+ const initialOutDir = initialProjectPath ? join24(resolve24(initialProjectPath), ".contentful") : "";
28011
+ const initialTokensPath = (modifyEntryReady || pushFromPickerReady) && initialOutDir && seedTokenSessionId ? join24(initialOutDir, "tokens.json") : "";
27807
28012
  const [state, setState] = useState28({
27808
28013
  step: modifyEntryReady || rawTokensEntryReady || pushFromPickerReady ? initialStepResolved : initialRuns && initialRuns.length > 0 ? "run-picker" : initialStepResolved,
27809
28014
  agent: initialAgent ?? "claude",
@@ -27856,6 +28061,7 @@ function WizardApp({
27856
28061
  generatePrefetchError: null,
27857
28062
  mapTokensEligible: null,
27858
28063
  credentialsSkipped: false,
28064
+ existingEntitiesPath: null,
27859
28065
  lastRunId: null,
27860
28066
  finalizeErrorBanner: null,
27861
28067
  finalReviewPassed: modifyEntryReady || pushFromPickerReady,
@@ -27970,7 +28176,7 @@ If you are using AWS Bedrock, run:
27970
28176
  }
27971
28177
  const sessionMatch = /^session=(.+)$/m.exec(result.stdout);
27972
28178
  const tokenSessionId = sessionMatch ? sessionMatch[1].trim() : null;
27973
- const tokensPath = join23(outDir, "tokens.json");
28179
+ const tokensPath = join24(outDir, "tokens.json");
27974
28180
  const printArgs = ["print", "tokens", "--out", tokensPath];
27975
28181
  if (tokenSessionId) printArgs.push("--session", tokenSessionId);
27976
28182
  const r = await runCli2(printArgs);
@@ -27990,7 +28196,7 @@ If you are using AWS Bedrock, run:
27990
28196
  tokenCount,
27991
28197
  skipComponents: true,
27992
28198
  acceptedCount: 0,
27993
- outDir: state.outDir || join23(process.cwd(), ".contentful")
28199
+ outDir: state.outDir || join24(process.cwd(), ".contentful")
27994
28200
  });
27995
28201
  if (noPush) {
27996
28202
  void startSaveFlow();
@@ -28042,7 +28248,8 @@ If you are using AWS Bedrock, run:
28042
28248
  agent: state.agent,
28043
28249
  ...state.agentModel ? { model: state.agentModel } : {},
28044
28250
  noCache: effectiveNoCache,
28045
- skipAgent: skipMapTokens
28251
+ skipAgent: skipMapTokens,
28252
+ ...state.existingEntitiesPath ? { existingEntitiesPath: state.existingEntitiesPath } : {}
28046
28253
  });
28047
28254
  const result = await runCli2(args);
28048
28255
  if (result.exitCode !== 0) {
@@ -28056,7 +28263,7 @@ If you are using AWS Bedrock, run:
28056
28263
  return true;
28057
28264
  };
28058
28265
  const runExtract = async (projectPath) => {
28059
- const outDir = join23(resolve23(projectPath), ".contentful");
28266
+ const outDir = join24(resolve24(projectPath), ".contentful");
28060
28267
  update({ step: "extracting", outDir, extractProgress: null, compositionPhase: null });
28061
28268
  const r = await new Promise((res) => {
28062
28269
  const extractArgs = [findCliPath(), "analyze", "extract", "--project", projectPath];
@@ -28163,7 +28370,8 @@ Make sure this path contains TypeScript/React/Vue component files (.tsx, .ts, .v
28163
28370
  ...state.agentModel ? { model: state.agentModel } : {},
28164
28371
  ...state.bedrock ? { bedrock: true } : {},
28165
28372
  selectPromptPath,
28166
- noCache
28373
+ noCache,
28374
+ ...state.existingEntitiesPath ? { existingEntitiesPath: state.existingEntitiesPath } : {}
28167
28375
  });
28168
28376
  const child = spawn4("node", [findCliPath(), ...args]);
28169
28377
  autoFilterChildRef.current = child;
@@ -28261,7 +28469,8 @@ Make sure this path contains TypeScript/React/Vue component files (.tsx, .ts, .v
28261
28469
  agent: state.agent,
28262
28470
  ...state.agentModel ? { model: state.agentModel } : {},
28263
28471
  ...state.bedrock ? { bedrock: true } : {},
28264
- noCache: effectiveNoCache
28472
+ noCache: effectiveNoCache,
28473
+ ...state.existingEntitiesPath ? { existingEntitiesPath: state.existingEntitiesPath } : {}
28265
28474
  })
28266
28475
  ];
28267
28476
  let progressCursor = null;
@@ -28332,7 +28541,8 @@ Make sure this path contains TypeScript/React/Vue component files (.tsx, .ts, .v
28332
28541
  ...state.agentModel ? { model: state.agentModel } : {},
28333
28542
  ...state.bedrock ? { bedrock: true } : {},
28334
28543
  noCache: effectiveNoCache,
28335
- generatePromptPath
28544
+ generatePromptPath,
28545
+ ...state.existingEntitiesPath ? { existingEntitiesPath: state.existingEntitiesPath } : {}
28336
28546
  })
28337
28547
  ];
28338
28548
  let progressCursor = state.generateProgress;
@@ -28372,7 +28582,7 @@ Make sure this path contains TypeScript/React/Vue component files (.tsx, .ts, .v
28372
28582
  if (await runMapTokens2(mappedSessionId)) update({ step: "final-review" });
28373
28583
  };
28374
28584
  const advanceToPushFlow = (generatedAcceptedCount) => {
28375
- update({ generatedAcceptedCount, step: "credentials" });
28585
+ update({ generatedAcceptedCount, step: "push-decision-gate" });
28376
28586
  };
28377
28587
  const runEditFromPreview = async () => {
28378
28588
  update({ step: "final-review" });
@@ -28443,6 +28653,24 @@ Make sure this path contains TypeScript/React/Vue component files (.tsx, .ts, .v
28443
28653
  }
28444
28654
  };
28445
28655
  const advanceAfterCredentialsValidated = async () => {
28656
+ if (!state.credentialsSkipped && state.spaceId && state.environmentId && state.cmaToken && state.projectPath) {
28657
+ const outDir = join24(resolve24(state.projectPath), ".contentful");
28658
+ await mkdir7(outDir, { recursive: true });
28659
+ const result = await fetchAndPersistExistingContentfulEntities({
28660
+ spaceId: state.spaceId,
28661
+ environmentId: state.environmentId,
28662
+ cmaToken: state.cmaToken,
28663
+ ...state.host ? { host: state.host } : {},
28664
+ outDir
28665
+ });
28666
+ if (result.ok) {
28667
+ update({ existingEntitiesPath: result.path });
28668
+ }
28669
+ }
28670
+ if (!sessionRef.current.extractSessionId && state.projectPath) {
28671
+ void runExtract(state.projectPath);
28672
+ return;
28673
+ }
28446
28674
  if (shouldSkipFinalReviewAfterCredentials(state)) {
28447
28675
  update({ step: "push-decision-gate" });
28448
28676
  return;
@@ -28798,7 +29026,7 @@ If using a custom --host, make sure the space exists on that host.`
28798
29026
  };
28799
29027
  const runPrintFiles = async (extractSessionId, outDir, opts = {}) => {
28800
29028
  update({ step: "printing" });
28801
- const componentsPath = join23(outDir, "components.json");
29029
+ const componentsPath = join24(outDir, "components.json");
28802
29030
  const printArgs = ["print", "components", "--out", componentsPath];
28803
29031
  if (extractSessionId) printArgs.push("--session", extractSessionId);
28804
29032
  if (opts.allowEmpty) printArgs.push("--allow-empty");
@@ -28814,7 +29042,7 @@ If using a custom --host, make sure the space exists on that host.`
28814
29042
  let emittedTokensPath;
28815
29043
  let emittedTokenCount;
28816
29044
  if (opts.tokenSessionId) {
28817
- const tokensOut = join23(outDir, "tokens.json");
29045
+ const tokensOut = join24(outDir, "tokens.json");
28818
29046
  const tokenArgs = ["print", "tokens", "--out", tokensOut, "--session", opts.tokenSessionId];
28819
29047
  const tr = await runCli2(tokenArgs);
28820
29048
  if (tr.exitCode !== 0) {
@@ -28901,8 +29129,8 @@ If using a custom --host, make sure the space exists on that host.`
28901
29129
  );
28902
29130
  }
28903
29131
  try {
28904
- const componentsBuf = await readFile24(join23(path, "components.json")).catch(() => null);
28905
- const tokensBuf = recordedTokensPath ? await readFile24(recordedTokensPath).catch(() => null) : null;
29132
+ const componentsBuf = await readFile25(join24(path, "components.json")).catch(() => null);
29133
+ const tokensBuf = recordedTokensPath ? await readFile25(recordedTokensPath).catch(() => null) : null;
28906
29134
  savedFingerprint = buildSavedFingerprint({
28907
29135
  componentsJson: componentsBuf,
28908
29136
  tokensJson: tokensBuf
@@ -28943,7 +29171,7 @@ If using a custom --host, make sure the space exists on that host.`
28943
29171
  if (state.step === "generating-tokens") {
28944
29172
  if (tokenReuseChecked.current) return;
28945
29173
  tokenReuseChecked.current = true;
28946
- const existingTokensPath = join23(state.outDir, "tokens.json");
29174
+ const existingTokensPath = join24(state.outDir, "tokens.json");
28947
29175
  (async () => {
28948
29176
  try {
28949
29177
  await access9(existingTokensPath);
@@ -29019,7 +29247,7 @@ If using a custom --host, make sure the space exists on that host.`
29019
29247
  {
29020
29248
  onContinue: (path) => {
29021
29249
  const projectPath = normalizePath(path);
29022
- const outDir = join23(projectPath, ".contentful");
29250
+ const outDir = join24(projectPath, ".contentful");
29023
29251
  update({ step: "token-input", projectPath, outDir });
29024
29252
  },
29025
29253
  onQuit: () => process.exit(0)
@@ -29084,7 +29312,7 @@ If using a custom --host, make sure the space exists on that host.`
29084
29312
  {
29085
29313
  projectPath: state.projectPath,
29086
29314
  onConfirm: (path) => {
29087
- void runExtract(path);
29315
+ update({ projectPath: path, step: "credentials" });
29088
29316
  },
29089
29317
  onSkipComponents: () => {
29090
29318
  if (noPush) {
@@ -29168,12 +29396,7 @@ If using a custom --host, make sure the space exists on that host.`
29168
29396
  }
29169
29397
  return;
29170
29398
  }
29171
- if (acceptedCount > 0 && !noPush) {
29172
- if (await runAgentAuthCheck("credentials")) {
29173
- startGeneratePrefetch(sid, state.tokensPath);
29174
- }
29175
- }
29176
- update({ step: "credentials" });
29399
+ update({ step: "push-decision-gate" });
29177
29400
  },
29178
29401
  onAdvanceToPushFlow: (count) => {
29179
29402
  update({ acceptedCount: count, autoRejectedCount: 0 });
@@ -29644,10 +29867,11 @@ var init_WizardApp = __esm({
29644
29867
  init_path_utils();
29645
29868
  init_host_utils();
29646
29869
  init_credentials_store();
29870
+ init_fetch_and_persist_existing_contentful_entities();
29647
29871
  init_wizard_state_transitions();
29648
29872
  init_cycle_auto_reject();
29649
29873
  init_cli_path();
29650
- WIZARD_LOG = join23(tmpdir(), "experiences-import-wizard.log");
29874
+ WIZARD_LOG = join24(tmpdir(), "experiences-import-wizard.log");
29651
29875
  }
29652
29876
  });
29653
29877
 
@@ -29658,8 +29882,8 @@ __export(staleness_exports, {
29658
29882
  formatStalenessDetail: () => formatStalenessDetail,
29659
29883
  shortStalenessSummary: () => shortStalenessSummary
29660
29884
  });
29661
- import { readFile as readFile25, stat as stat7 } from "node:fs/promises";
29662
- import { join as join24 } from "node:path";
29885
+ import { readFile as readFile26, stat as stat7 } from "node:fs/promises";
29886
+ import { join as join25 } from "node:path";
29663
29887
  async function checkRunStaleness(run) {
29664
29888
  if (!run.sourceFingerprint) return { ...UNKNOWN };
29665
29889
  const result = {
@@ -29685,7 +29909,7 @@ async function checkRunStaleness(run) {
29685
29909
  if (run.sourceFingerprint.rawTokensPath) {
29686
29910
  const absPath = run.sourceFingerprint.rawTokensPath;
29687
29911
  try {
29688
- const [st, buf] = await Promise.all([stat7(absPath), readFile25(absPath)]);
29912
+ const [st, buf] = await Promise.all([stat7(absPath), readFile26(absPath)]);
29689
29913
  const mtime = st.mtime.toISOString();
29690
29914
  const hash = sha256Hex(buf);
29691
29915
  const mtimeChanged = run.sourceFingerprint.rawTokensMtime !== null && mtime !== run.sourceFingerprint.rawTokensMtime;
@@ -29701,9 +29925,9 @@ async function checkRunStaleness(run) {
29701
29925
  }
29702
29926
  if (run.savedFingerprint) {
29703
29927
  if (run.savedFingerprint.componentsJsonHash !== null) {
29704
- const compPath = join24(run.savePath, "components.json");
29928
+ const compPath = join25(run.savePath, "components.json");
29705
29929
  try {
29706
- const buf = await readFile25(compPath);
29930
+ const buf = await readFile26(compPath);
29707
29931
  if (sha256Hex(buf) !== run.savedFingerprint.componentsJsonHash) {
29708
29932
  result.savedComponentsEdited = true;
29709
29933
  result.stale = true;
@@ -29714,9 +29938,9 @@ async function checkRunStaleness(run) {
29714
29938
  }
29715
29939
  }
29716
29940
  if (run.savedFingerprint.tokensJsonHash !== null) {
29717
- const tokensPath = run.tokensPath ?? join24(run.savePath, "tokens.json");
29941
+ const tokensPath = run.tokensPath ?? join25(run.savePath, "tokens.json");
29718
29942
  try {
29719
- const buf = await readFile25(tokensPath);
29943
+ const buf = await readFile26(tokensPath);
29720
29944
  if (sha256Hex(buf) !== run.savedFingerprint.tokensJsonHash) {
29721
29945
  result.savedTokensEdited = true;
29722
29946
  result.stale = true;
@@ -29783,7 +30007,7 @@ async function promptForPushCredentials(opts = {}) {
29783
30007
  const { render: render7, Box: Box50, Text: Text52 } = await import("ink");
29784
30008
  const { useState: useState29 } = await import("react");
29785
30009
  const { CredentialsStep: CredentialsStep2 } = await Promise.resolve().then(() => (init_CredentialsStep(), CredentialsStep_exports));
29786
- return new Promise((resolve27, reject) => {
30010
+ return new Promise((resolve28, reject) => {
29787
30011
  let app = null;
29788
30012
  function App2() {
29789
30013
  const [done, setDone] = useState29(false);
@@ -29792,7 +30016,7 @@ async function promptForPushCredentials(opts = {}) {
29792
30016
  setDone(true);
29793
30017
  queueMicrotask(() => {
29794
30018
  app?.unmount();
29795
- resolve27({ spaceId, environmentId, cmaToken, host });
30019
+ resolve28({ spaceId, environmentId, cmaToken, host });
29796
30020
  });
29797
30021
  };
29798
30022
  if (done) {
@@ -29824,14 +30048,14 @@ var init_push_creds_prompt = __esm({
29824
30048
  // packages/experience-design-system-cli/src/program.ts
29825
30049
  import { spawn as spawn6 } from "node:child_process";
29826
30050
  import { fileURLToPath as fileURLToPath5 } from "node:url";
29827
- import { dirname as dirname14, join as join27, resolve as resolve26 } from "node:path";
30051
+ import { dirname as dirname14, join as join28, resolve as resolve27 } from "node:path";
29828
30052
  import { readFileSync as readFileSync10 } from "node:fs";
29829
30053
  import { Command } from "commander";
29830
30054
 
29831
30055
  // packages/experience-design-system-cli/src/analyze/command.ts
29832
30056
  import { createElement as createElement3 } from "react";
29833
30057
  import { render as render3 } from "ink";
29834
- import { mkdir as mkdir3, readdir as readdir2, readFile as readFile16, stat as stat2, writeFile as writeFile3 } from "node:fs/promises";
30058
+ import { mkdir as mkdir3, readdir as readdir2, readFile as readFile17, stat as stat2, writeFile as writeFile3 } from "node:fs/promises";
29835
30059
  import { isAbsolute as isAbsolute4, join as join15, relative as relative3, resolve as resolve15 } from "node:path";
29836
30060
 
29837
30061
  // packages/experience-design-system-cli/src/lib/agent-model-options.ts
@@ -29958,6 +30182,104 @@ init_command2();
29958
30182
  // packages/experience-design-system-cli/src/analyze/select-agent/command.ts
29959
30183
  init_db();
29960
30184
  init_cache_keys();
30185
+
30186
+ // packages/experience-design-system-cli/src/helpers/read-existing-contentful-entities-from-session.ts
30187
+ import { readFile as readFile13 } from "node:fs/promises";
30188
+ async function readExistingContentfulEntitiesFromSession(path) {
30189
+ if (!path) return void 0;
30190
+ try {
30191
+ const raw = await readFile13(path, "utf8");
30192
+ const parsed = JSON.parse(raw);
30193
+ if (!Array.isArray(parsed.components) || !Array.isArray(parsed.tokens)) return void 0;
30194
+ return parsed;
30195
+ } catch {
30196
+ return void 0;
30197
+ }
30198
+ }
30199
+
30200
+ // packages/experience-design-system-cli/src/helpers/find-nearly-matching-component.ts
30201
+ var MAX_CHARACTER_EDITS_FOR_LIKELY_MATCH = 2;
30202
+ function findNearlyMatchingComponent(components, codebaseName) {
30203
+ const target = simplifyNameForComparison(codebaseName);
30204
+ if (!target) return void 0;
30205
+ let best;
30206
+ for (const c2 of components) {
30207
+ const edits = countCharacterEdits(target, simplifyNameForComparison(c2.name));
30208
+ if (edits > MAX_CHARACTER_EDITS_FOR_LIKELY_MATCH) continue;
30209
+ if (!best || edits < best.edits) best = { component: c2, edits };
30210
+ if (edits === 0) break;
30211
+ }
30212
+ return best?.component;
30213
+ }
30214
+ function simplifyNameForComparison(name) {
30215
+ const stripped = name.toLowerCase().replace(/[^a-z0-9]/g, "");
30216
+ return stripped.endsWith("s") && stripped.length > 1 ? stripped.slice(0, -1) : stripped;
30217
+ }
30218
+ function countCharacterEdits(a, b) {
30219
+ if (a === b) return 0;
30220
+ if (a.length === 0) return b.length;
30221
+ if (b.length === 0) return a.length;
30222
+ if (a.length > b.length) [a, b] = [b, a];
30223
+ let prev = new Array(a.length + 1);
30224
+ let curr = new Array(a.length + 1);
30225
+ for (let i = 0; i <= a.length; i++) prev[i] = i;
30226
+ for (let j = 1; j <= b.length; j++) {
30227
+ curr[0] = j;
30228
+ for (let i = 1; i <= a.length; i++) {
30229
+ const cost = a[i - 1] === b[j - 1] ? 0 : 1;
30230
+ curr[i] = Math.min(curr[i - 1] + 1, prev[i] + 1, prev[i - 1] + cost);
30231
+ }
30232
+ [prev, curr] = [curr, prev];
30233
+ }
30234
+ return prev[a.length];
30235
+ }
30236
+
30237
+ // packages/experience-design-system-cli/src/helpers/summarize-existing-contentful-entities.ts
30238
+ function summarizeForSelectAgent(entities) {
30239
+ return {
30240
+ components: entities.components.map((c2) => ({
30241
+ id: c2.sys.id,
30242
+ name: c2.name,
30243
+ description: c2.description
30244
+ })),
30245
+ tokens: summarizeTokens(entities.tokens)
30246
+ };
30247
+ }
30248
+ function summarizeForGenerateAgent(entities, codebaseComponentName) {
30249
+ const match2 = findNearlyMatchingComponent(entities.components, codebaseComponentName);
30250
+ const otherComponents = entities.components.filter((c2) => c2.sys.id !== match2?.sys.id).map((c2) => ({ id: c2.sys.id, name: c2.name }));
30251
+ return {
30252
+ likelyMatch: match2 ? {
30253
+ id: match2.sys.id,
30254
+ name: match2.name,
30255
+ designProperties: match2.designProperties.map((p) => ({
30256
+ id: p.id,
30257
+ name: p.name,
30258
+ type: p.type
30259
+ })),
30260
+ contentProperties: match2.contentProperties.map((p) => ({
30261
+ id: p.id,
30262
+ name: p.name,
30263
+ type: p.type
30264
+ })),
30265
+ slots: (match2.slots ?? []).map((s) => ({ id: s.id, name: s.name }))
30266
+ } : void 0,
30267
+ otherComponents,
30268
+ tokens: summarizeTokens(entities.tokens)
30269
+ };
30270
+ }
30271
+ function summarizeForMapTokens(entities) {
30272
+ return {
30273
+ tokens: entities.tokens.map((t) => ({ id: t.sys.id, name: t.name, type: t.type }))
30274
+ };
30275
+ }
30276
+ function summarizeTokens(tokens) {
30277
+ const kinds = /* @__PURE__ */ new Set();
30278
+ for (const t of tokens) kinds.add(t.type);
30279
+ return { count: tokens.length, kinds: [...kinds].sort() };
30280
+ }
30281
+
30282
+ // packages/experience-design-system-cli/src/analyze/select-agent/command.ts
29961
30283
  init_persistence();
29962
30284
  init_parser();
29963
30285
  init_src();
@@ -30059,7 +30381,7 @@ var OutputFormatter = class {
30059
30381
  };
30060
30382
 
30061
30383
  // packages/experience-design-system-cli/src/analyze/select-agent/context-builder.ts
30062
- import { readFile as readFile13 } from "node:fs/promises";
30384
+ import { readFile as readFile14 } from "node:fs/promises";
30063
30385
  import { dirname as dirname10, isAbsolute as isAbsolute2, join as join13, relative as relative2, resolve as resolve11, sep } from "node:path";
30064
30386
  var SCANNED_FILE_EXTENSIONS = /* @__PURE__ */ new Set([".astro", ".js", ".jsx", ".svelte", ".ts", ".tsx", ".vue"]);
30065
30387
  var IMPORT_PATTERN2 = /import\s+(?:type\s+)?(.+?)\s+from\s+['"]([^'"]+)['"]/g;
@@ -30188,7 +30510,7 @@ async function buildRepoContextIndex(root, filePaths) {
30188
30510
  absolutePath,
30189
30511
  relativePath: toPosixPath(relative2(resolvedRoot, absolutePath)),
30190
30512
  directory: dirname10(absolutePath),
30191
- text: await readFile13(absolutePath, "utf8").catch(() => "")
30513
+ text: await readFile14(absolutePath, "utf8").catch(() => "")
30192
30514
  })
30193
30515
  )
30194
30516
  );
@@ -30255,7 +30577,7 @@ function resolveRationaleSession(sessionFlag, dbPath) {
30255
30577
  }
30256
30578
  return sessionFlag;
30257
30579
  }
30258
- const latest = findLatestSessionForCommand(db, "analyze select");
30580
+ const latest = findLatestSessionForCommand2(db, "analyze select");
30259
30581
  if (!latest) {
30260
30582
  throw new Error(
30261
30583
  `No completed 'analyze select' session found. Run 'analyze select-agent' first, or pass --session <id>.`
@@ -30401,7 +30723,7 @@ function resolveProjectRoot(sessionId2, projectRootFlag) {
30401
30723
  db.close();
30402
30724
  }
30403
30725
  }
30404
- async function selectBatch(agent, model, batch, total, verbose, skillPathOverride) {
30726
+ async function selectBatch(agent, model, batch, total, verbose, skillPathOverride, existingComponentsInline) {
30405
30727
  const prompt2 = await buildPrompt({
30406
30728
  skill: "select",
30407
30729
  mode: "autonomous",
@@ -30411,7 +30733,8 @@ async function selectBatch(agent, model, batch, total, verbose, skillPathOverrid
30411
30733
  2
30412
30734
  ),
30413
30735
  outDir: process.cwd(),
30414
- skillPathOverride
30736
+ skillPathOverride,
30737
+ existingComponentsInline
30415
30738
  });
30416
30739
  let outputBuf = "";
30417
30740
  const formatter = new OutputFormatter(verbose, (s) => {
@@ -30506,7 +30829,7 @@ ${outputBuf}`);
30506
30829
  }
30507
30830
  return results;
30508
30831
  }
30509
- async function selectAllComponents(agent, model, components, verbose, skillPathOverride, cacheConfig = { noCache: true }) {
30832
+ async function selectAllComponents(agent, model, components, verbose, skillPathOverride, existingComponentsInline, cacheConfig = { noCache: true }) {
30510
30833
  const concurrency = Number(process.env.EDS_GENERATE_CONCURRENCY ?? DEFAULT_CONCURRENCY);
30511
30834
  const batchSize = resolveBatchSize();
30512
30835
  const total = components.length;
@@ -30515,7 +30838,13 @@ async function selectAllComponents(agent, model, components, verbose, skillPathO
30515
30838
  let cliVersion2 = "";
30516
30839
  if (!cacheConfig.noCache) {
30517
30840
  try {
30518
- promptHash = await hashPromptForSkill("select", agent, model, skillPathOverride);
30841
+ promptHash = await hashPromptForSkill(
30842
+ "select",
30843
+ agent,
30844
+ model,
30845
+ skillPathOverride,
30846
+ existingComponentsInline ? [hashContent(existingComponentsInline)] : []
30847
+ );
30519
30848
  cliVersion2 = await getCliCacheVersion();
30520
30849
  const db = openPipelineDb(cacheConfig.dbPath);
30521
30850
  try {
@@ -30571,7 +30900,15 @@ async function selectAllComponents(agent, model, components, verbose, skillPathO
30571
30900
  while (nextBatch < batches.length) {
30572
30901
  const b = nextBatch++;
30573
30902
  const batch = batches[b];
30574
- const batchResults = await selectBatch(agent, model, batch, total, verbose, skillPathOverride);
30903
+ const batchResults = await selectBatch(
30904
+ agent,
30905
+ model,
30906
+ batch,
30907
+ total,
30908
+ verbose,
30909
+ skillPathOverride,
30910
+ existingComponentsInline
30911
+ );
30575
30912
  for (let k = 0; k < batch.length; k++) {
30576
30913
  results[batch[k].index] = batchResults[k];
30577
30914
  }
@@ -30607,6 +30944,9 @@ function registerAnalyzeSelectAgentCommand(program) {
30607
30944
  "--select-prompt-path <path>",
30608
30945
  "Path to a custom .md skill prompt for select-agent (bypasses bundled prompt invariants)"
30609
30946
  ).option("--no-select-cache", "Skip the per-component select cache and re-LLM every component").option("--no-cache", "Skip ALL fine-grained caches (extract, select, generate)").option(
30947
+ "--existing-entities-path <path>",
30948
+ "Path to the .existing-entities.json file written by the orchestrator when CMA credentials are supplied. When present, the agent gets an existing-components summary to align rejection/acceptance reasoning with the target space. Missing/malformed files are treated as no-op."
30949
+ ).option(
30610
30950
  "--show-rationale",
30611
30951
  "Read-only: print the AI rejection rationale persisted by a prior select-agent run and exit. No LLM call. Combine with --json for machine-readable output."
30612
30952
  ).option("--json", "When used with --show-rationale, emit a JSON array instead of a human-readable table").action(
@@ -30715,6 +31055,20 @@ function registerAnalyzeSelectAgentCommand(program) {
30715
31055
  }));
30716
31056
  }
30717
31057
  }
31058
+ let existingComponentsInline;
31059
+ if (opts.existingEntitiesPath) {
31060
+ const existingContentfulEntities = await readExistingContentfulEntitiesFromSession(
31061
+ resolve12(opts.existingEntitiesPath)
31062
+ );
31063
+ if (existingContentfulEntities) {
31064
+ existingComponentsInline = JSON.stringify(summarizeForSelectAgent(existingContentfulEntities));
31065
+ } else {
31066
+ process.stderr.write(
31067
+ `warn: --existing-entities-path ${opts.existingEntitiesPath} could not be read as JSON \u2014 proceeding without space-context enrichment
31068
+ `
31069
+ );
31070
+ }
31071
+ }
30718
31072
  if (opts.dryRun) {
30719
31073
  if (selectionCandidates.length === 0) {
30720
31074
  process.stderr.write(
@@ -30729,7 +31083,8 @@ function registerAnalyzeSelectAgentCommand(program) {
30729
31083
  mode: "autonomous",
30730
31084
  rawComponentsInline: JSON.stringify([buildComponentData(first)], null, 2),
30731
31085
  outDir: process.cwd(),
30732
- skillPathOverride: selectPromptPath ? resolve12(selectPromptPath) : void 0
31086
+ skillPathOverride: selectPromptPath ? resolve12(selectPromptPath) : void 0,
31087
+ existingComponentsInline
30733
31088
  });
30734
31089
  process.stdout.write(prompt2 + "\n");
30735
31090
  await exitWithAnalytics(0);
@@ -30742,6 +31097,7 @@ function registerAnalyzeSelectAgentCommand(program) {
30742
31097
  selectionCandidates,
30743
31098
  opts.verbose ?? false,
30744
31099
  selectPromptPath ? resolve12(selectPromptPath) : void 0,
31100
+ existingComponentsInline,
30745
31101
  { noCache }
30746
31102
  );
30747
31103
  const decisions = /* @__PURE__ */ new Map();
@@ -31129,11 +31485,11 @@ ${f.content}`).join("\n\n");
31129
31485
  }
31130
31486
 
31131
31487
  // packages/experience-design-system-cli/src/analyze/composition/resolve-mapping-cli.ts
31132
- import { readFile as readFile14 } from "node:fs/promises";
31488
+ import { readFile as readFile15 } from "node:fs/promises";
31133
31489
  async function loadUserMap(path) {
31134
31490
  let text;
31135
31491
  try {
31136
- text = await readFile14(path, "utf8");
31492
+ text = await readFile15(path, "utf8");
31137
31493
  } catch {
31138
31494
  return { ok: false, error: `--composition-map: file not found: ${path}` };
31139
31495
  }
@@ -31369,16 +31725,16 @@ var HEAP_CAP_MB = 128;
31369
31725
  var MAX_INPUT_BYTES = 8 * 1024 * 1024;
31370
31726
  function runParserInSandbox(source, ctx, opts = {}) {
31371
31727
  const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS2;
31372
- return new Promise((resolve27) => {
31728
+ return new Promise((resolve28) => {
31373
31729
  let input;
31374
31730
  try {
31375
31731
  input = JSON.stringify({ source, ctx, timeoutMs });
31376
31732
  } catch {
31377
- resolve27({ edges: [], error: "ctx is not serializable" });
31733
+ resolve28({ edges: [], error: "ctx is not serializable" });
31378
31734
  return;
31379
31735
  }
31380
31736
  if (input.length > MAX_INPUT_BYTES) {
31381
- resolve27({ edges: [], error: "parser input exceeds size limit" });
31737
+ resolve28({ edges: [], error: "parser input exceeds size limit" });
31382
31738
  return;
31383
31739
  }
31384
31740
  let settled = false;
@@ -31410,7 +31766,7 @@ function runParserInSandbox(source, ctx, opts = {}) {
31410
31766
  child.kill("SIGKILL");
31411
31767
  } catch {
31412
31768
  }
31413
- resolve27(r);
31769
+ resolve28(r);
31414
31770
  };
31415
31771
  const timer = setTimeout(
31416
31772
  () => done({ edges: [], error: `parser timed out after ${timeoutMs}ms` }),
@@ -31622,7 +31978,7 @@ ${loadPrompt("composition-parser-repair-error.md").trim().replace("{{error}}", f
31622
31978
  }
31623
31979
 
31624
31980
  // packages/experience-design-system-cli/src/lib/prompt-overrides.ts
31625
- import { readFile as readFile15 } from "node:fs/promises";
31981
+ import { readFile as readFile16 } from "node:fs/promises";
31626
31982
  import { resolve as resolve14 } from "node:path";
31627
31983
  var PROMPT_FILE_EXTENSIONS = [".md", ".txt", ".prompt"];
31628
31984
  function looksLikePath(value) {
@@ -31658,7 +32014,7 @@ async function resolvePromptOverride(override) {
31658
32014
  if (override.kind === "text") return override.value;
31659
32015
  const abs = resolve14(override.value);
31660
32016
  try {
31661
- return await readFile15(abs, "utf8");
32017
+ return await readFile16(abs, "utf8");
31662
32018
  } catch {
31663
32019
  throw new Error(`--prompt: could not read prompt file: ${abs}`);
31664
32020
  }
@@ -31841,7 +32197,7 @@ async function readCandidateFiles(components, extraFiles = []) {
31841
32197
  await Promise.all(
31842
32198
  [...paths].map(async (p) => {
31843
32199
  try {
31844
- const content = await readFile16(p, "utf8");
32200
+ const content = await readFile17(p, "utf8");
31845
32201
  out.push({ path: p, content });
31846
32202
  } catch {
31847
32203
  }
@@ -32245,7 +32601,7 @@ function registerAnalyzeCommand(program) {
32245
32601
  init_src();
32246
32602
  import { createElement as createElement4 } from "react";
32247
32603
  import { render as render4 } from "ink";
32248
- import { access as access6, readFile as readFile18, readdir as readdir3, stat as stat3 } from "node:fs/promises";
32604
+ import { access as access6, readFile as readFile19, readdir as readdir3, stat as stat3 } from "node:fs/promises";
32249
32605
  import { join as join16, resolve as resolve17 } from "node:path";
32250
32606
  init_debug_logger();
32251
32607
 
@@ -32286,7 +32642,7 @@ function GenerateView({ result, onExit }) {
32286
32642
  }
32287
32643
 
32288
32644
  // packages/experience-design-system-cli/src/generate/edit/command.ts
32289
- import { readFile as readFile17 } from "node:fs/promises";
32645
+ import { readFile as readFile18 } from "node:fs/promises";
32290
32646
  import { resolve as resolve16 } from "node:path";
32291
32647
  var SAFE_PATH_RE2 = /^[a-zA-Z0-9_.$[\]=]+$/;
32292
32648
  var PROTO_KEYS2 = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
@@ -32369,7 +32725,7 @@ async function runNonInteractive2(opts, skill) {
32369
32725
  if (opts.patch) {
32370
32726
  let patchOps;
32371
32727
  try {
32372
- const raw = await readFile17(resolve16(opts.patch), "utf8");
32728
+ const raw = await readFile18(resolve16(opts.patch), "utf8");
32373
32729
  patchOps = JSON.parse(raw);
32374
32730
  } catch {
32375
32731
  process.stderr.write(`Error: cannot read or parse --patch file: ${opts.patch}
@@ -32463,7 +32819,7 @@ async function readFileInline(path) {
32463
32819
  } catch {
32464
32820
  return void 0;
32465
32821
  }
32466
- if (!s.isDirectory()) return readFile18(resolved, "utf8");
32822
+ if (!s.isDirectory()) return readFile19(resolved, "utf8");
32467
32823
  const files = [];
32468
32824
  async function walk(dir) {
32469
32825
  let entries;
@@ -32489,7 +32845,7 @@ async function readFileInline(path) {
32489
32845
  }
32490
32846
  await walk(resolved);
32491
32847
  if (files.length === 0) return void 0;
32492
- const parts = await Promise.all(files.map((f) => readFile18(f, "utf8").catch(() => "")));
32848
+ const parts = await Promise.all(files.map((f) => readFile19(f, "utf8").catch(() => "")));
32493
32849
  return parts.filter(Boolean).join("\n\n");
32494
32850
  }
32495
32851
  function printFallbackInstructions(options) {
@@ -32511,7 +32867,7 @@ function printFallbackInstructions(options) {
32511
32867
  lines.push(` Re-run the generate command with the agent available, or use --dry-run to inspect the prompt.`);
32512
32868
  process.stderr.write(lines.join("\n") + "\n");
32513
32869
  }
32514
- async function runOneComponent(agent, model, db, sessionId2, component, tokensInline, tokenMapInline, index, total, verbose, noCache, skillPathOverride, promptHash) {
32870
+ async function runOneComponent(agent, model, db, sessionId2, component, tokensInline, tokenMapInline, index, total, verbose, noCache, skillPathOverride, promptHash, existingContentfulEntities, existingTokensInline) {
32515
32871
  const pos = c.dim(`[${index + 1}/${total}]`);
32516
32872
  if (!noCache) {
32517
32873
  const inputHash = computeComponentInputHash(component);
@@ -32581,6 +32937,7 @@ async function runOneComponent(agent, model, db, sessionId2, component, tokensIn
32581
32937
  component.props.map((p) => p.name),
32582
32938
  component.props.map((p) => p.type)
32583
32939
  );
32940
+ const existingComponentsInline = existingContentfulEntities ? JSON.stringify(summarizeForGenerateAgent(existingContentfulEntities, component.name)) : void 0;
32584
32941
  const prompt2 = await buildPrompt({
32585
32942
  skill: "components",
32586
32943
  mode: "autonomous",
@@ -32590,7 +32947,9 @@ async function runOneComponent(agent, model, db, sessionId2, component, tokensIn
32590
32947
  outDir: process.cwd(),
32591
32948
  componentName: component.name,
32592
32949
  componentSourceRefs: [sourceRef],
32593
- skillPathOverride
32950
+ skillPathOverride,
32951
+ existingComponentsInline,
32952
+ existingTokensInline
32594
32953
  });
32595
32954
  const maxAttempts = 2;
32596
32955
  let lastError = "";
@@ -32658,7 +33017,7 @@ ${outputBuf}`);
32658
33017
  renamedSlotsCount: renames.length
32659
33018
  };
32660
33019
  }
32661
- async function runAllComponents(agent, model, db, sessionId2, components, tokensInline, tokenMapInline, verbose, noCache, skillPathOverride, promptHash) {
33020
+ async function runAllComponents(agent, model, db, sessionId2, components, tokensInline, tokenMapInline, verbose, noCache, skillPathOverride, promptHash, existingContentfulEntities, existingTokensInline) {
32662
33021
  const concurrency = Number(process.env.EDS_GENERATE_CONCURRENCY ?? DEFAULT_COMPONENT_CONCURRENCY);
32663
33022
  process.stderr.write(
32664
33023
  `Categorizing ${c.bold(String(components.length))} component${components.length === 1 ? "" : "s"}` + c.dim(` (concurrency: ${concurrency})`) + "\n"
@@ -32682,7 +33041,9 @@ async function runAllComponents(agent, model, db, sessionId2, components, tokens
32682
33041
  verbose,
32683
33042
  noCache,
32684
33043
  skillPathOverride,
32685
- promptHash
33044
+ promptHash,
33045
+ existingContentfulEntities,
33046
+ existingTokensInline
32686
33047
  );
32687
33048
  completed += 1;
32688
33049
  process.stderr.write(`${formatGenerateProgressLine(completed, components.length, results[i].componentName)}
@@ -32720,7 +33081,7 @@ async function loadAcceptedNames(sessionId2) {
32720
33081
  try {
32721
33082
  const artifactsRoot = getRefineArtifactsRoot();
32722
33083
  const paths = await getRefineSessionPaths(sessionId2, artifactsRoot);
32723
- const raw = await readFile18(paths.statePath, "utf8");
33084
+ const raw = await readFile19(paths.statePath, "utf8");
32724
33085
  const snapshot = JSON.parse(raw);
32725
33086
  const accepted = snapshot.components.filter((c2) => c2.status === "accepted").map((c2) => c2.name);
32726
33087
  if (accepted.length === 0) return null;
@@ -32766,6 +33127,19 @@ async function runGenerateSkill(skill, opts, verbose = false) {
32766
33127
  readFileInline(opts.tokens),
32767
33128
  readFileInline(opts.tokenMap)
32768
33129
  ]);
33130
+ let existingContentfulEntities;
33131
+ let existingTokensInline;
33132
+ if (opts.existingEntitiesPath) {
33133
+ existingContentfulEntities = await readExistingContentfulEntitiesFromSession(resolve17(opts.existingEntitiesPath));
33134
+ if (existingContentfulEntities) {
33135
+ existingTokensInline = JSON.stringify(summarizeForMapTokens(existingContentfulEntities));
33136
+ } else {
33137
+ process.stderr.write(
33138
+ `warn: --existing-entities-path ${opts.existingEntitiesPath} could not be read as JSON \u2014 proceeding without space-context enrichment
33139
+ `
33140
+ );
33141
+ }
33142
+ }
32769
33143
  let sessionId2;
32770
33144
  let allComponents;
32771
33145
  if (skill === "components") {
@@ -32826,6 +33200,7 @@ async function runGenerateSkill(skill, opts, verbose = false) {
32826
33200
  sampleComponent.props.map((p) => p.name),
32827
33201
  sampleComponent.props.map((p) => p.type)
32828
33202
  ) : void 0;
33203
+ const dryRunExistingComponentsInline = skill === "components" && existingContentfulEntities && sampleComponent ? JSON.stringify(summarizeForGenerateAgent(existingContentfulEntities, sampleComponent.name)) : void 0;
32829
33204
  const prompt2 = await buildPrompt({
32830
33205
  skill,
32831
33206
  mode: "autonomous",
@@ -32836,7 +33211,9 @@ async function runGenerateSkill(skill, opts, verbose = false) {
32836
33211
  tokenMapInline,
32837
33212
  outDir: process.cwd(),
32838
33213
  componentSourceRefs: sampleSourceRef ? [sampleSourceRef] : void 0,
32839
- skillPathOverride: generatePromptPath
33214
+ skillPathOverride: generatePromptPath,
33215
+ existingComponentsInline: dryRunExistingComponentsInline,
33216
+ existingTokensInline: skill === "components" ? existingTokensInline : void 0
32840
33217
  });
32841
33218
  process.stdout.write(prompt2 + "\n");
32842
33219
  await exitWithAnalytics(0);
@@ -32854,7 +33231,15 @@ async function runGenerateSkill(skill, opts, verbose = false) {
32854
33231
  const db = openPipelineDb();
32855
33232
  let componentResults;
32856
33233
  try {
32857
- const promptHash = await hashPromptForSkill("components", agent, model, generatePromptPath);
33234
+ const existingContentfulEntitiesHashInputs = [];
33235
+ if (existingTokensInline) existingContentfulEntitiesHashInputs.push(hashContent(existingTokensInline));
33236
+ const promptHash = await hashPromptForSkill(
33237
+ "components",
33238
+ agent,
33239
+ model,
33240
+ generatePromptPath,
33241
+ existingContentfulEntitiesHashInputs
33242
+ );
32858
33243
  componentResults = await runAllComponents(
32859
33244
  agent,
32860
33245
  model,
@@ -32866,7 +33251,9 @@ async function runGenerateSkill(skill, opts, verbose = false) {
32866
33251
  verbose,
32867
33252
  opts.cache === false || process.env.EDS_NO_CACHE === "1",
32868
33253
  generatePromptPath,
32869
- promptHash
33254
+ promptHash,
33255
+ existingContentfulEntities,
33256
+ existingTokensInline
32870
33257
  );
32871
33258
  } finally {
32872
33259
  db.close();
@@ -33043,6 +33430,9 @@ function registerGenerateCommand(program) {
33043
33430
  const componentsCmd = generate.command("components").description("Invoke a coding agent to produce components.json from raw analysis output").option("--session <id>", "Session ID from analyze extract (defaults to most recent)").option("--tokens <path>", "Path to tokens.json for token-linked prop resolution").option("--token-map <path>", "Path to token-name-map.json sidecar").option(
33044
33431
  "--generate-prompt-path <path>",
33045
33432
  "Path to a custom .md skill prompt for components generation (bypasses bundled prompt invariants)"
33433
+ ).option(
33434
+ "--existing-entities-path <path>",
33435
+ "Path to the .existing-entities.json file written by the orchestrator when 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."
33046
33436
  );
33047
33437
  addAgentFlags(componentsCmd).action(async (opts) => {
33048
33438
  await runGenerateSkill("components", opts, opts.verbose ?? false);
@@ -33058,7 +33448,7 @@ function registerGenerateCommand(program) {
33058
33448
  // packages/experience-design-system-cli/src/program.ts
33059
33449
  init_command();
33060
33450
 
33061
- // packages/experience-design-system-cli/src/session/command.ts
33451
+ // packages/experience-design-system-cli/src/session/cli.ts
33062
33452
  init_db();
33063
33453
 
33064
33454
  // packages/experience-design-system-cli/src/session/stats.ts
@@ -33262,7 +33652,7 @@ function migrateImportDb(db, _now) {
33262
33652
  }
33263
33653
  }
33264
33654
 
33265
- // packages/experience-design-system-cli/src/session/command.ts
33655
+ // packages/experience-design-system-cli/src/session/cli.ts
33266
33656
  function parseDuration(str) {
33267
33657
  const m = /^(\d+)([dwmy])$/.exec(str);
33268
33658
  if (!m) return null;
@@ -33489,9 +33879,9 @@ ${"\u2500".repeat(60)}
33489
33879
  `);
33490
33880
  }
33491
33881
  process.stdout.write("\nDelete these sessions? (y/N) ");
33492
- const answer = await new Promise((resolve27) => {
33882
+ const answer = await new Promise((resolve28) => {
33493
33883
  process.stdin.setEncoding("utf8");
33494
- process.stdin.once("data", (chunk) => resolve27(String(chunk).trim().toLowerCase()));
33884
+ process.stdin.once("data", (chunk) => resolve28(String(chunk).trim().toLowerCase()));
33495
33885
  });
33496
33886
  if (answer !== "y") {
33497
33887
  db.close();
@@ -33526,7 +33916,7 @@ import { access as access7, mkdir as mkdir4, stat as stat4, writeFile as writeFi
33526
33916
  import { basename as basename5, resolve as resolve19 } from "node:path";
33527
33917
 
33528
33918
  // packages/experience-design-system-cli/src/print/validate/validators/cdf-validator.ts
33529
- import { readFile as readFile19 } from "node:fs/promises";
33919
+ import { readFile as readFile20 } from "node:fs/promises";
33530
33920
  import { validateCDF as validateCDF2 } from "@contentful/experience-design-system-types";
33531
33921
  function extractValue(input, path) {
33532
33922
  if (path === "/") return void 0;
@@ -33585,7 +33975,7 @@ function rewriteDiagnostic(error, input) {
33585
33975
  async function validateCDFFile(filePath) {
33586
33976
  let content;
33587
33977
  try {
33588
- content = await readFile19(filePath, "utf-8");
33978
+ content = await readFile20(filePath, "utf-8");
33589
33979
  } catch (err) {
33590
33980
  return {
33591
33981
  valid: false,
@@ -33620,7 +34010,7 @@ async function validateCDFFile(filePath) {
33620
34010
  }
33621
34011
 
33622
34012
  // packages/experience-design-system-cli/src/print/validate/validators/dtcg-validator.ts
33623
- import { readFile as readFile20 } from "node:fs/promises";
34013
+ import { readFile as readFile21 } from "node:fs/promises";
33624
34014
  import { DESIGN_TOKEN_TYPES } from "@contentful/experience-design-system-types";
33625
34015
  function walkDTCG(obj, path, diagnostics, counts) {
33626
34016
  for (const [key, value] of Object.entries(obj)) {
@@ -33665,7 +34055,7 @@ function walkDTCG(obj, path, diagnostics, counts) {
33665
34055
  async function validateDTCGTokenFile(filePath) {
33666
34056
  let content;
33667
34057
  try {
33668
- content = await readFile20(filePath, "utf-8");
34058
+ content = await readFile21(filePath, "utf-8");
33669
34059
  } catch (err) {
33670
34060
  return {
33671
34061
  valid: false,
@@ -33809,10 +34199,10 @@ async function assertOutIsNotDirectory(outPath) {
33809
34199
  if (s.isDirectory()) await die3(`Error: --out must be a file path, not a directory: ${outPath}`);
33810
34200
  }
33811
34201
  }
33812
- async function resolveSession(sessionFlag, command) {
34202
+ async function resolveSession2(sessionFlag, command) {
33813
34203
  const db = openPipelineDb();
33814
34204
  try {
33815
- const sessionId2 = sessionFlag ?? findLatestSessionForCommand(db, command);
34205
+ const sessionId2 = sessionFlag ?? findLatestSessionForCommand2(db, command);
33816
34206
  if (!sessionId2) {
33817
34207
  const hint = command === "generate components" ? "generate components" : "generate tokens";
33818
34208
  return await die3(`Error: no completed ${hint} session found. Run ${hint} first, or pass --session <id>.`);
@@ -33862,7 +34252,7 @@ function registerPrintCommand(program) {
33862
34252
  ).action(async (opts) => {
33863
34253
  const outPath = resolve19(opts.out);
33864
34254
  await assertOutIsNotDirectory(outPath);
33865
- const sessionId2 = await resolveSession(opts.session, "generate components");
34255
+ const sessionId2 = await resolveSession2(opts.session, "generate components");
33866
34256
  await bindAnalyticsSessionId(sessionId2);
33867
34257
  const db = openPipelineDb();
33868
34258
  let components;
@@ -33919,7 +34309,7 @@ function registerPrintCommand(program) {
33919
34309
  print.command("tokens").description("Write generated tokens to a DTCG JSON file").option("--session <id>", "Session ID to print from (default: most recent generate tokens session)").option("--out <path>", "Output file path", "tokens.json").action(async (opts) => {
33920
34310
  const outPath = resolve19(opts.out);
33921
34311
  await assertOutIsNotDirectory(outPath);
33922
- const sessionId2 = await resolveSession(opts.session, "generate tokens");
34312
+ const sessionId2 = await resolveSession2(opts.session, "generate tokens");
33923
34313
  await bindAnalyticsSessionId(sessionId2);
33924
34314
  const db = openPipelineDb();
33925
34315
  let result;
@@ -33998,7 +34388,8 @@ init_db();
33998
34388
  init_cache_keys();
33999
34389
  import { createElement as createElement6 } from "react";
34000
34390
  import { render as render6 } from "ink";
34001
- import { readFile as readFile21 } from "node:fs/promises";
34391
+ import { readFile as readFile22 } from "node:fs/promises";
34392
+ import { resolve as resolve20 } from "node:path";
34002
34393
 
34003
34394
  // packages/experience-design-system-cli/src/map-tokens/apply.ts
34004
34395
  init_db();
@@ -34235,7 +34626,7 @@ async function runMapTokens(opts) {
34235
34626
  const resultAgent = configuredAgent ?? "skipped";
34236
34627
  const db = openPipelineDb();
34237
34628
  try {
34238
- const sessionId2 = opts.session ?? findLatestSessionForCommand(db, "generate components");
34629
+ const sessionId2 = opts.session ?? findLatestSessionForCommand2(db, "generate components");
34239
34630
  if (!sessionId2) {
34240
34631
  die2(
34241
34632
  "Error: no completed generate components session found. Run generate components first, or pass --session <id>."
@@ -34246,7 +34637,7 @@ async function runMapTokens(opts) {
34246
34637
  const knownTokenPaths = new Set(tokenLeaves.map((t) => t.path));
34247
34638
  const tokenMapDiagnostics = [];
34248
34639
  if (opts.tokenMap) {
34249
- const fileMappings = JSON.parse(await readFile21(opts.tokenMap, "utf8"));
34640
+ const fileMappings = JSON.parse(await readFile22(opts.tokenMap, "utf8"));
34250
34641
  const validMappings = {};
34251
34642
  for (const [rawName, path] of Object.entries(fileMappings)) {
34252
34643
  if (knownTokenPaths.has(path)) {
@@ -34321,6 +34712,20 @@ ${defaultDiagnostics.map((diagnostic) => ` ${diagnostic}`).join("\n")}
34321
34712
  const generatedCdf = Object.fromEntries(cdfEntries.map((c2) => [c2.key, c2.entry]));
34322
34713
  const tokenTree = rebuildDTCGTree(groups, tokens);
34323
34714
  const componentSourceRefs = await loadComponentSourceRefs(db, sessionId2);
34715
+ let existingTokensInline;
34716
+ if (opts.existingEntitiesPath) {
34717
+ const existingContentfulEntities = await readExistingContentfulEntitiesFromSession(
34718
+ resolve20(opts.existingEntitiesPath)
34719
+ );
34720
+ if (existingContentfulEntities) {
34721
+ existingTokensInline = JSON.stringify(summarizeForMapTokens(existingContentfulEntities));
34722
+ } else {
34723
+ process.stderr.write(
34724
+ `warn: --existing-entities-path ${opts.existingEntitiesPath} could not be read as JSON \u2014 proceeding without space-context enrichment
34725
+ `
34726
+ );
34727
+ }
34728
+ }
34324
34729
  if (opts.printPrompt) {
34325
34730
  const prompt3 = await buildPrompt({
34326
34731
  skill: "map-tokens",
@@ -34328,7 +34733,8 @@ ${defaultDiagnostics.map((diagnostic) => ` ${diagnostic}`).join("\n")}
34328
34733
  generatedCdf,
34329
34734
  tokenTree,
34330
34735
  componentSourceRefs,
34331
- outDir: process.cwd()
34736
+ outDir: process.cwd(),
34737
+ existingTokensInline
34332
34738
  });
34333
34739
  process.stdout.write(prompt3 + "\n");
34334
34740
  await exitWithAnalytics(0);
@@ -34346,7 +34752,13 @@ ${defaultDiagnostics.map((diagnostic) => ` ${diagnostic}`).join("\n")}
34346
34752
  }
34347
34753
  const agent = configuredAgent;
34348
34754
  const noCache = opts.cache === false || process.env.EDS_NO_CACHE === "1";
34349
- const promptHash = await hashPromptForSkill("map-tokens", agent, model);
34755
+ const promptHash = await hashPromptForSkill(
34756
+ "map-tokens",
34757
+ agent,
34758
+ model,
34759
+ void 0,
34760
+ existingTokensInline ? [hashContent(existingTokensInline)] : []
34761
+ );
34350
34762
  const inputHash = computeMapTokensInputHash(db, sessionId2, componentSourceRefs);
34351
34763
  if (!noCache) {
34352
34764
  const cached = lookupCache(db, inputHash, "token_mapping", "__map_tokens__", promptHash);
@@ -34373,7 +34785,8 @@ Install it, choose another agent with --agent, or use --print-prompt to run the
34373
34785
  generatedCdf,
34374
34786
  tokenTree,
34375
34787
  componentSourceRefs,
34376
- outDir: process.cwd()
34788
+ outDir: process.cwd(),
34789
+ existingTokensInline
34377
34790
  });
34378
34791
  const invoker3 = createLocalCliAgentInvoker();
34379
34792
  const result = await invoker3.invoke({ agent, model, prompt: prompt2, timeoutMs: DEFAULT_TIMEOUT_MS4 });
@@ -34400,7 +34813,10 @@ ${warnings.map((w) => ` ${w}`).join("\n")}
34400
34813
  }
34401
34814
  function registerMapTokensCommand(program) {
34402
34815
  const map = program.command("map").description("Suggest token restrictions for generated design-token props");
34403
- const tokensCmd = map.command("tokens").description("Invoke a coding agent to suggest $token.allowed for design-category token props").option("--session <id>", "Session ID from generate components (defaults to most recent)").option("--print-prompt", "Print the prompt without invoking the agent").option("--skip-agent", "Resolve token defaults without agentic $token.allowed inference").option("--no-cache", "Bypass the map-tokens cache and force a re-run").option("--token-map <path>", "Path to token-name-map.json sidecar");
34816
+ const tokensCmd = map.command("tokens").description("Invoke a coding agent to suggest $token.allowed for design-category token props").option("--session <id>", "Session ID from generate components (defaults to most recent)").option("--print-prompt", "Print the prompt without invoking the agent").option("--skip-agent", "Resolve token defaults without agentic $token.allowed inference").option("--no-cache", "Bypass the map-tokens cache and force a re-run").option("--token-map <path>", "Path to token-name-map.json sidecar").option(
34817
+ "--existing-entities-path <path>",
34818
+ "Path to the .existing-entities.json file written by the orchestrator when CMA credentials are supplied. When present, the agent gets a list of the space's existing design tokens so it can prefer binding to them. Missing/malformed files are treated as no-op."
34819
+ );
34404
34820
  addAgentModelOptions(tokensCmd).action(async (opts) => {
34405
34821
  await runMapTokens(opts);
34406
34822
  });
@@ -34409,45 +34825,22 @@ function registerMapTokensCommand(program) {
34409
34825
  // packages/experience-design-system-cli/src/import/command.ts
34410
34826
  init_src();
34411
34827
  init_path_utils();
34412
- import { resolve as resolve25, join as join25 } from "node:path";
34828
+ import { resolve as resolve26, join as join26 } from "node:path";
34413
34829
 
34414
34830
  // packages/experience-design-system-cli/src/import/orchestrator.ts
34415
34831
  init_db();
34416
34832
  init_command();
34417
34833
  init_manifest();
34418
34834
  init_api_client();
34419
- import { mkdir as mkdir5, writeFile as writeFile5 } from "node:fs/promises";
34420
- import { join as join18, resolve as resolve21 } from "node:path";
34421
- import { execFile as execFile2 } from "node:child_process";
34422
-
34423
- // packages/experience-design-system-cli/src/helpers/fetch-existing-entities.ts
34424
- import { fetchAll } from "contentful-management";
34425
- async function fetchExistingEntities(client2, params) {
34426
- const scope = { spaceId: params.spaceId, environmentId: params.environmentId, query: {} };
34427
- const components = await fetchAll(client2.component.getMany, scope);
34428
- const tokens = await fetchAll(client2.designToken.getMany, scope);
34429
- return { components, tokens };
34430
- }
34431
-
34432
- // packages/experience-design-system-cli/src/helpers/cma-client.ts
34433
- init_host_utils();
34434
- import { createClient as createClient2 } from "contentful-management";
34435
- function createCmaClient(opts) {
34436
- return createClient2(
34437
- {
34438
- accessToken: opts.cmaToken,
34439
- ...opts.host ? { host: toConfiguredHost(opts.host) } : {}
34440
- },
34441
- { type: "plain" }
34442
- );
34443
- }
34444
-
34445
- // packages/experience-design-system-cli/src/import/orchestrator.ts
34835
+ init_fetch_and_persist_existing_contentful_entities();
34446
34836
  init_contentful_urls();
34447
34837
  init_debug_logger();
34448
34838
  init_analytics();
34449
34839
  init_env();
34450
34840
  init_cli_path();
34841
+ import { mkdir as mkdir5 } from "node:fs/promises";
34842
+ import { join as join19, resolve as resolve22 } from "node:path";
34843
+ import { execFile as execFile2 } from "node:child_process";
34451
34844
  async function runStep(args, cliPath, analyticsSessionId, env = {}, streamStderr = false) {
34452
34845
  const debug = getDebugLogger();
34453
34846
  const startedAt = Date.now();
@@ -34532,9 +34925,9 @@ function buildPushStepResult(args) {
34532
34925
  };
34533
34926
  }
34534
34927
  async function runPipeline(opts, progressWriter, cliPathOverride) {
34535
- const projectRoot = resolve21(opts.project);
34536
- const outDir = resolve21(opts.out);
34537
- const componentsPath = join18(outDir, "components.json");
34928
+ const projectRoot = resolve22(opts.project);
34929
+ const outDir = resolve22(opts.out);
34930
+ const componentsPath = join19(outDir, "components.json");
34538
34931
  const cliPath = cliPathOverride ?? findCliPath();
34539
34932
  const db = openPipelineDb();
34540
34933
  const { sessionId: sessionId2 } = getOrCreateSession(db, void 0, void 0, {
@@ -34555,67 +34948,56 @@ async function runPipeline(opts, progressWriter, cliPathOverride) {
34555
34948
  await mkdir5(outDir, { recursive: true });
34556
34949
  const steps = [];
34557
34950
  let stepNum = 0;
34558
- const wantsSpaceContext = opts.withSpaceContext === true;
34559
- const canFetchSpaceContext = wantsSpaceContext && !!opts.spaceId && !!opts.environmentId && !!opts.cmaToken;
34560
- const totalSteps = 5 + (opts.print ? 1 : 0) + (canFetchSpaceContext ? 1 : 0);
34951
+ const canFetchExistingContentfulEntities = !!opts.spaceId && !!opts.environmentId && !!opts.cmaToken;
34952
+ const totalSteps = 5 + (opts.print ? 1 : 0) + (canFetchExistingContentfulEntities ? 1 : 0);
34561
34953
  function stepLabel(name) {
34562
34954
  stepNum++;
34563
34955
  return ` Step ${stepNum}/${totalSteps} ${name} `;
34564
34956
  }
34565
- if (wantsSpaceContext && !canFetchSpaceContext) {
34566
- progressWriter(
34567
- " Note: --with-space-context requires --space-id, --environment-id, and --cma-token; skipping context fetch."
34568
- );
34569
- }
34570
- if (canFetchSpaceContext) {
34957
+ let existingEntitiesPath;
34958
+ if (canFetchExistingContentfulEntities) {
34571
34959
  const fetchLabel = stepLabel("Fetching existing components + design tokens");
34572
34960
  const fetchStepId = createStep(db, sessionId2, "fetch existing entities", {
34573
34961
  spaceId: opts.spaceId,
34574
34962
  environmentId: opts.environmentId
34575
34963
  });
34576
- const t0 = Date.now();
34577
- try {
34578
- const cmaClient = createCmaClient({
34579
- cmaToken: opts.cmaToken,
34580
- ...opts.host ? { host: opts.host } : {}
34581
- });
34582
- const existingComponentsAndTokens = await fetchExistingEntities(cmaClient, {
34583
- spaceId: opts.spaceId,
34584
- environmentId: opts.environmentId
34585
- });
34586
- const fetchDurationMs = Date.now() - t0;
34587
- const existingEntitiesPath = join18(outDir, ".existing-entities.json");
34588
- await writeFile5(existingEntitiesPath, JSON.stringify(existingComponentsAndTokens, null, 2), "utf8");
34964
+ const result = await fetchAndPersistExistingContentfulEntities({
34965
+ spaceId: opts.spaceId,
34966
+ environmentId: opts.environmentId,
34967
+ cmaToken: opts.cmaToken,
34968
+ ...opts.host ? { host: opts.host } : {},
34969
+ outDir
34970
+ });
34971
+ if (result.ok) {
34972
+ existingEntitiesPath = result.path;
34589
34973
  updateStep(db, fetchStepId, "complete", {
34590
- components: String(existingComponentsAndTokens.components.length),
34591
- tokens: String(existingComponentsAndTokens.tokens.length),
34592
- path: existingEntitiesPath
34974
+ components: String(result.entities.components.length),
34975
+ tokens: String(result.entities.tokens.length),
34976
+ path: result.path
34593
34977
  });
34594
34978
  progressWriter(
34595
- `${fetchLabel}\u2713 ${existingComponentsAndTokens.components.length} component${existingComponentsAndTokens.components.length === 1 ? "" : "s"}, ${existingComponentsAndTokens.tokens.length} token${existingComponentsAndTokens.tokens.length === 1 ? "" : "s"} (${(fetchDurationMs / 1e3).toFixed(1)}s)`
34979
+ `${fetchLabel}\u2713 ${result.entities.components.length} component${result.entities.components.length === 1 ? "" : "s"}, ${result.entities.tokens.length} token${result.entities.tokens.length === 1 ? "" : "s"} (${(result.durationMs / 1e3).toFixed(1)}s)`
34596
34980
  );
34597
34981
  steps.push({
34598
34982
  step: "fetch existing entities",
34599
34983
  status: "complete",
34600
- durationMs: fetchDurationMs,
34984
+ durationMs: result.durationMs,
34601
34985
  detail: {
34602
- components: existingComponentsAndTokens.components.length,
34603
- tokens: existingComponentsAndTokens.tokens.length
34986
+ components: result.entities.components.length,
34987
+ tokens: result.entities.tokens.length
34604
34988
  }
34605
34989
  });
34606
- } catch (error) {
34607
- const fetchDurationMs = Date.now() - t0;
34608
- const message = error instanceof Error ? error.message : String(error);
34609
- updateStep(db, fetchStepId, "complete", {}, message);
34990
+ } else {
34991
+ updateStep(db, fetchStepId, "complete", {}, result.error);
34610
34992
  progressWriter(
34611
- `${fetchLabel}\u26A0 fetch failed, continuing without space context (${(fetchDurationMs / 1e3).toFixed(1)}s)`
34993
+ `${fetchLabel}\u26A0 fetch failed, continuing without space context (${(result.durationMs / 1e3).toFixed(1)}s)`
34612
34994
  );
34613
- progressWriter(` ${message.split("\n")[0]}`);
34995
+ progressWriter(` ${result.error.split("\n")[0]}`);
34614
34996
  steps.push({
34615
34997
  step: "fetch existing entities",
34616
34998
  status: "skipped",
34617
- durationMs: fetchDurationMs,
34618
- reason: `fetch failed: ${message.split("\n")[0]}`
34999
+ durationMs: result.durationMs,
35000
+ reason: `fetch failed: ${result.error.split("\n")[0]}`
34619
35001
  });
34620
35002
  }
34621
35003
  }
@@ -34629,7 +35011,7 @@ async function runPipeline(opts, progressWriter, cliPathOverride) {
34629
35011
  status: "skipped",
34630
35012
  reason: "--skip-analyze"
34631
35013
  });
34632
- const prior = findLatestSessionForCommand(db, "analyze extract");
35014
+ const prior = findLatestSessionForCommand2(db, "analyze extract");
34633
35015
  extractSessionId = prior ?? null;
34634
35016
  } else {
34635
35017
  const stepId = createStep(db, sessionId2, "analyze extract", {
@@ -34663,7 +35045,7 @@ async function runPipeline(opts, progressWriter, cliPathOverride) {
34663
35045
  db.close();
34664
35046
  return { session: sessionId2, project: projectRoot, steps };
34665
35047
  }
34666
- extractSessionId = findLatestSessionForCommand(db, "analyze extract") ?? null;
35048
+ extractSessionId = findLatestSessionForCommand2(db, "analyze extract") ?? null;
34667
35049
  const componentMatch = /Extracted (\d+) component/.exec(r.stderr);
34668
35050
  const componentCount = componentMatch ? Number(componentMatch[1]) : 0;
34669
35051
  updateStep(db, stepId, "complete", {
@@ -34701,6 +35083,7 @@ async function runPipeline(opts, progressWriter, cliPathOverride) {
34701
35083
  if (opts.excludeInvalid) editArgs.push("--exclude-invalid");
34702
35084
  if (opts.noCache) editArgs.push("--no-cache");
34703
35085
  if (opts.selectPromptPath) editArgs.push("--select-prompt-path", opts.selectPromptPath);
35086
+ if (existingEntitiesPath) editArgs.push("--existing-entities-path", existingEntitiesPath);
34704
35087
  } else {
34705
35088
  editArgs = ["analyze", "select", "--session", extractSessionId];
34706
35089
  if (opts.select && opts.select.length > 0) {
@@ -34763,6 +35146,7 @@ async function runPipeline(opts, progressWriter, cliPathOverride) {
34763
35146
  if (extractSessionId) generateArgs.push("--session", extractSessionId);
34764
35147
  if (opts.dryRun) generateArgs.push("--dry-run");
34765
35148
  if (opts.verbose) generateArgs.push("--verbose");
35149
+ if (existingEntitiesPath) generateArgs.push("--existing-entities-path", existingEntitiesPath);
34766
35150
  const stepId = createStep(db, sessionId2, "generate components", {
34767
35151
  extractSession: extractSessionId ?? ""
34768
35152
  });
@@ -34817,6 +35201,7 @@ async function runPipeline(opts, progressWriter, cliPathOverride) {
34817
35201
  if (opts.model) mapTokensArgs.push("--model", opts.model);
34818
35202
  if (opts.noCache) mapTokensArgs.push("--no-cache");
34819
35203
  if (opts.skipMapTokens) mapTokensArgs.push("--skip-agent");
35204
+ if (existingEntitiesPath) mapTokensArgs.push("--existing-entities-path", existingEntitiesPath);
34820
35205
  const mapTokensStepId = createStep(db, sessionId2, "map tokens", {
34821
35206
  extractSession: extractSessionId,
34822
35207
  skipAgent: String(opts.skipMapTokens === true)
@@ -35178,7 +35563,7 @@ init_host_utils();
35178
35563
  // packages/experience-design-system-cli/src/runs/replay-helpers.ts
35179
35564
  init_resolve_run_target();
35180
35565
  init_store();
35181
- import { resolve as resolve24 } from "node:path";
35566
+ import { resolve as resolve25 } from "node:path";
35182
35567
 
35183
35568
  // packages/experience-design-system-cli/src/runs/push-helpers.ts
35184
35569
  init_cli_path();
@@ -35368,7 +35753,7 @@ async function modifyRun(opts) {
35368
35753
  entryStep: "final-review",
35369
35754
  saveMode,
35370
35755
  ...run.compositionMode ? { compositionMode: run.compositionMode } : {},
35371
- ...opts.outDir ? { outDirOverride: resolve24(opts.outDir) } : {},
35756
+ ...opts.outDir ? { outDirOverride: resolve25(opts.outDir) } : {},
35372
35757
  ...mergedSpaceId ? { initialSpaceId: mergedSpaceId } : {},
35373
35758
  ...mergedEnvironmentId ? { initialEnvironmentId: mergedEnvironmentId } : {},
35374
35759
  ...mergedHost ? { initialHost: mergedHost } : {},
@@ -35445,7 +35830,7 @@ function resolvePromptFlags(flags) {
35445
35830
 
35446
35831
  // packages/experience-design-system-cli/src/runs/run-picker-mount.ts
35447
35832
  init_store();
35448
- import { readFile as readFile26 } from "node:fs/promises";
35833
+ import { readFile as readFile27 } from "node:fs/promises";
35449
35834
  function migrateRecord2(rec) {
35450
35835
  return {
35451
35836
  ...rec,
@@ -35468,7 +35853,7 @@ async function shouldShowRunPicker(input) {
35468
35853
  const path = input.runsJsonPath ?? runsFilePath();
35469
35854
  let raw;
35470
35855
  try {
35471
- raw = await readFile26(path, "utf8");
35856
+ raw = await readFile27(path, "utf8");
35472
35857
  } catch {
35473
35858
  return { shouldShow: false, runs: [] };
35474
35859
  }
@@ -35573,10 +35958,7 @@ function registerImportCommand(program) {
35573
35958
  "Override a stage prompt (repeatable). value is a file path or literal text, e.g. --prompt composition=./p.md",
35574
35959
  (v, acc) => [...acc, v],
35575
35960
  []
35576
- ).option("--auto-reject-cycles", "Automatically reject components involved in slot cycles and retry").option(
35577
- "--with-space-context",
35578
- "Fetch existing Components + DesignTokens from the target space+env and persist them under <out>/.existing-entities.json for future agent-context enrichment. Requires --space-id, --environment-id, and --cma-token."
35579
- ).option("--auto-filter", "Force the AI auto-filter ON (overrides the credentials.json autoFilter preference)").option(
35961
+ ).option("--auto-reject-cycles", "Automatically reject components involved in slot cycles and retry").option("--auto-filter", "Force the AI auto-filter ON (overrides the credentials.json autoFilter preference)").option(
35580
35962
  "--no-auto-filter",
35581
35963
  "Skip the automatic AI pre-filter; jump straight to manual scope-gate (overrides the credentials.json autoFilter preference; no-op when paired with --auto-accept-scope)"
35582
35964
  ).option(
@@ -35844,7 +36226,7 @@ function registerImportCommand(program) {
35844
36226
  livePreview: opts.livePreview !== false,
35845
36227
  noPush: noPushRequested,
35846
36228
  noSave: opts.save === false,
35847
- ...opts.outDir ? { outDirOverride: resolve25(opts.outDir) } : {},
36229
+ ...opts.outDir ? { outDirOverride: resolve26(opts.outDir) } : {},
35848
36230
  ...opts.onConflict ? { onConflictMode: opts.onConflict } : {},
35849
36231
  selectPromptPath: opts.selectPromptPath ?? creds.selectPromptPath,
35850
36232
  generatePromptPath: opts.generatePromptPath ?? creds.generatePromptPath,
@@ -35885,7 +36267,7 @@ function registerImportCommand(program) {
35885
36267
  return;
35886
36268
  }
35887
36269
  const projectRoot = normalizePath(opts.project);
35888
- const outDir = opts.out ? resolve25(opts.out) : join25(projectRoot, ".contentful");
36270
+ const outDir = opts.out ? resolve26(opts.out) : join26(projectRoot, ".contentful");
35889
36271
  const headlessCreds = await readExperiencesCredentials();
35890
36272
  const headlessAgent = resolveAgent(opts.agent, headlessCreds.agent);
35891
36273
  const headlessModel = resolveModel(opts.model, headlessCreds.agentModel);
@@ -35923,7 +36305,6 @@ function registerImportCommand(program) {
35923
36305
  dryRun: dryRunForward,
35924
36306
  selectPromptPath: opts.selectPromptPath,
35925
36307
  autoRejectCycles: opts.autoRejectCycles ?? false,
35926
- withSpaceContext: opts.withSpaceContext ?? false,
35927
36308
  allowDeletions: opts.allowDeletions ?? false,
35928
36309
  compositionMode: headlessCompositionMode,
35929
36310
  ...opts.compositionMap ? { compositionMap: opts.compositionMap } : {},
@@ -35948,8 +36329,8 @@ function registerImportCommand(program) {
35948
36329
  // packages/experience-design-system-cli/src/setup/command.ts
35949
36330
  init_credentials_store();
35950
36331
  import { execFile as execFile5, spawn as spawn5 } from "node:child_process";
35951
- import { appendFile as appendFile2, readFile as readFile27, access as access10 } from "node:fs/promises";
35952
- import { join as join26 } from "node:path";
36332
+ import { appendFile as appendFile2, readFile as readFile28, access as access10 } from "node:fs/promises";
36333
+ import { join as join27 } from "node:path";
35953
36334
  import { homedir as homedir9 } from "node:os";
35954
36335
  import { fileURLToPath as fileURLToPath4 } from "node:url";
35955
36336
  import { createInterface } from "node:readline";
@@ -36027,10 +36408,10 @@ function prompt(question) {
36027
36408
  return Promise.resolve("");
36028
36409
  }
36029
36410
  const rl = createInterface({ input: process.stdin, output: process.stdout });
36030
- return new Promise((resolve27) => {
36411
+ return new Promise((resolve28) => {
36031
36412
  rl.question(question, (answer) => {
36032
36413
  rl.close();
36033
- resolve27(answer.trim());
36414
+ resolve28(answer.trim());
36034
36415
  });
36035
36416
  });
36036
36417
  }
@@ -36038,7 +36419,7 @@ function promptSecret(question) {
36038
36419
  if (!isInteractivePromptSession()) {
36039
36420
  return Promise.resolve("");
36040
36421
  }
36041
- return new Promise((resolve27) => {
36422
+ return new Promise((resolve28) => {
36042
36423
  const rl = createInterface({
36043
36424
  input: process.stdin,
36044
36425
  output: process.stdout,
@@ -36065,7 +36446,7 @@ function promptSecret(question) {
36065
36446
  }
36066
36447
  if (!process.stdin.isTTY) process.stdout.write("\n");
36067
36448
  process.stdin.resume();
36068
- resolve27(value);
36449
+ resolve28(value);
36069
36450
  });
36070
36451
  });
36071
36452
  }
@@ -36087,7 +36468,7 @@ async function binaryExists(name) {
36087
36468
  }
36088
36469
  }
36089
36470
  function runSpawn(cmd, args, opts = {}) {
36090
- return new Promise((resolve27) => {
36471
+ return new Promise((resolve28) => {
36091
36472
  const child = spawn5(cmd, args, {
36092
36473
  cwd: opts.cwd,
36093
36474
  env: opts.env ?? process.env,
@@ -36099,7 +36480,7 @@ function runSpawn(cmd, args, opts = {}) {
36099
36480
  child.on("error", (err) => {
36100
36481
  if (!settled) {
36101
36482
  settled = true;
36102
- resolve27({ exitCode: 1, stdout: "", stderr: err.message });
36483
+ resolve28({ exitCode: 1, stdout: "", stderr: err.message });
36103
36484
  }
36104
36485
  });
36105
36486
  child.stdout.on("data", (d) => {
@@ -36111,7 +36492,7 @@ function runSpawn(cmd, args, opts = {}) {
36111
36492
  child.on("exit", (code) => {
36112
36493
  if (!settled) {
36113
36494
  settled = true;
36114
- resolve27({ exitCode: code ?? 1, stdout, stderr });
36495
+ resolve28({ exitCode: code ?? 1, stdout, stderr });
36115
36496
  }
36116
36497
  });
36117
36498
  });
@@ -36120,21 +36501,21 @@ async function detectShellProfile() {
36120
36501
  const shell = process.env["SHELL"] ?? "";
36121
36502
  const home = homedir9();
36122
36503
  if (shell.includes("zsh")) {
36123
- return join26(home, ".zshrc");
36504
+ return join27(home, ".zshrc");
36124
36505
  }
36125
36506
  if (shell.includes("bash")) {
36126
- const bashProfile = join26(home, ".bash_profile");
36507
+ const bashProfile = join27(home, ".bash_profile");
36127
36508
  const exists = await access10(bashProfile).then(() => true).catch(() => false);
36128
- return exists ? bashProfile : join26(home, ".bashrc");
36509
+ return exists ? bashProfile : join27(home, ".bashrc");
36129
36510
  }
36130
36511
  if (shell.includes("fish")) {
36131
- return join26(home, ".config", "fish", "config.fish");
36512
+ return join27(home, ".config", "fish", "config.fish");
36132
36513
  }
36133
- return join26(home, ".profile");
36514
+ return join27(home, ".profile");
36134
36515
  }
36135
36516
  async function profileContains(profilePath, str) {
36136
36517
  try {
36137
- const content = await readFile27(profilePath, "utf8");
36518
+ const content = await readFile28(profilePath, "utf8");
36138
36519
  return content.includes(str);
36139
36520
  } catch {
36140
36521
  return false;
@@ -36155,7 +36536,7 @@ async function setupNode() {
36155
36536
  }
36156
36537
  fail(`Node.js v${current} \u2014 need v${REQUIRED_NODE_MAJOR}+`);
36157
36538
  info("");
36158
- const hasNvm = await binaryExists("nvm") || await access10(join26(homedir9(), ".nvm", "nvm.sh")).then(() => true).catch(() => false);
36539
+ const hasNvm = await binaryExists("nvm") || await access10(join27(homedir9(), ".nvm", "nvm.sh")).then(() => true).catch(() => false);
36159
36540
  const hasFnm = await binaryExists("fnm");
36160
36541
  if (hasNvm) {
36161
36542
  info(`nvm detected. Will run: nvm install ${REQUIRED_NODE_MAJOR} && nvm use ${REQUIRED_NODE_MAJOR}`);
@@ -36164,7 +36545,7 @@ async function setupNode() {
36164
36545
  warn(`Skipped. Re-run experiences setup after switching to Node ${REQUIRED_NODE_MAJOR}.`);
36165
36546
  return false;
36166
36547
  }
36167
- const nvmScript = join26(homedir9(), ".nvm", "nvm.sh");
36548
+ const nvmScript = join27(homedir9(), ".nvm", "nvm.sh");
36168
36549
  const result = await runSpawn("bash", [
36169
36550
  "-c",
36170
36551
  `source "${nvmScript}" && nvm install ${REQUIRED_NODE_MAJOR} && nvm alias default ${REQUIRED_NODE_MAJOR}`
@@ -36631,13 +37012,13 @@ async function checkPnpm(pkgRoot) {
36631
37012
  }
36632
37013
  async function checkDependencies(pkgRoot) {
36633
37014
  section("Checking dependencies (pnpm install)");
36634
- const nodeModulesExists = await access10(join26(pkgRoot, "node_modules")).then(() => true).catch(() => false);
37015
+ const nodeModulesExists = await access10(join27(pkgRoot, "node_modules")).then(() => true).catch(() => false);
36635
37016
  if (!nodeModulesExists) {
36636
37017
  info("node_modules not found \u2014 running pnpm install...");
36637
37018
  } else {
36638
37019
  info("Running pnpm install to ensure dependencies are up to date...");
36639
37020
  }
36640
- const repoRoot = join26(pkgRoot, "..", "..");
37021
+ const repoRoot = join27(pkgRoot, "..", "..");
36641
37022
  const result = await runSpawn("pnpm", ["install", "--frozen-lockfile"], { cwd: repoRoot });
36642
37023
  if (result.exitCode !== 0) {
36643
37024
  fail("pnpm install failed");
@@ -36656,7 +37037,7 @@ async function checkDependencies(pkgRoot) {
36656
37037
  async function checkBuild(pkgRoot) {
36657
37038
  section("Building CLI");
36658
37039
  info("Running pnpm build...");
36659
- const repoRoot = join26(pkgRoot, "..", "..");
37040
+ const repoRoot = join27(pkgRoot, "..", "..");
36660
37041
  const result = await runSpawn("pnpm", ["--filter", "@contentful/experience-design-system-cli", "run", "build"], {
36661
37042
  cwd: repoRoot
36662
37043
  });
@@ -36772,7 +37153,7 @@ function registerSetupCommand(program) {
36772
37153
  process.stdout.write("\n\x1B[1mexperiences setup\x1B[0m \u2014 interactive setup wizard\n");
36773
37154
  process.stdout.write("Sets up everything you need to run \x1B[1mexperiences import\x1B[0m.\n");
36774
37155
  const pkgRoot = findPkgRoot();
36775
- const repoRoot = join26(pkgRoot, "..", "..");
37156
+ const repoRoot = join27(pkgRoot, "..", "..");
36776
37157
  const profilePath = await detectShellProfile();
36777
37158
  const results = [];
36778
37159
  const nodeOk = await setupNode();
@@ -37012,7 +37393,7 @@ async function beginCommand(command, opts) {
37012
37393
  init_analytics();
37013
37394
  init_credentials_store();
37014
37395
  init_cli_path();
37015
- var pkg3 = JSON.parse(readFileSync10(join27(findPkgRoot(), "package.json"), "utf8"));
37396
+ var pkg3 = JSON.parse(readFileSync10(join28(findPkgRoot(), "package.json"), "utf8"));
37016
37397
  async function runBuild(opts) {
37017
37398
  return new Promise((resolvePromise) => {
37018
37399
  const child = opts.spawnFn();
@@ -37049,7 +37430,7 @@ function registerImportV2Command(program) {
37049
37430
  }
37050
37431
  function registerBuildCommand(program) {
37051
37432
  program.command("build").description("Rebuild from source and re-link exo/experiences binaries to this build").action(async () => {
37052
- const pkgRoot = resolve26(dirname14(fileURLToPath5(import.meta.url)), "..", "..");
37433
+ const pkgRoot = resolve27(dirname14(fileURLToPath5(import.meta.url)), "..", "..");
37053
37434
  process.stderr.write("\u2699 Building from source...\n");
37054
37435
  const { exitCode } = await runBuild({
37055
37436
  spawnFn: () => spawn6("pnpm", ["build"], { cwd: pkgRoot, stdio: "inherit" }),