@contentful/experience-design-system-cli 2.32.1-dev-build-23e5797.0 → 2.32.1-dev-build-661f431.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contentful/experience-design-system-cli",
3
- "version": "2.32.1-dev-build-23e5797.0",
3
+ "version": "2.32.1-dev-build-661f431.0",
4
4
  "description": "Contentful Experiences design system import CLI",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/dist/src/index.js CHANGED
@@ -8472,6 +8472,230 @@ var init_terminal_capabilities = __esm({
8472
8472
  }
8473
8473
  });
8474
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/derive-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_derive_component_id = __esm({
8555
+ "packages/experience-design-system-cli/src/session/core/components/derive-component-id.ts"() {
8556
+ "use strict";
8557
+ }
8558
+ });
8559
+
8560
+ // packages/experience-design-system-cli/src/session/core/cdf/cdf-mappers.ts
8561
+ function mapContentfulTypeToCdfType(contentfulType) {
8562
+ switch (contentfulType.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(contentfulCategory, propName, contentProps, designProps) {
8584
+ if (contentfulCategory && VALID_CATEGORIES2.includes(contentfulCategory)) {
8585
+ return contentfulCategory;
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_cdf_mappers = __esm({
8593
+ "packages/experience-design-system-cli/src/session/core/cdf/cdf-mappers.ts"() {
8594
+ "use strict";
8595
+ VALID_CATEGORIES2 = ["content", "design", "state"];
8596
+ }
8597
+ });
8598
+
8599
+ // packages/experience-design-system-cli/src/session/core/shared/index-rows-by-key.ts
8600
+ function indexRowsByKey(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_index_rows_by_key = __esm({
8614
+ "packages/experience-design-system-cli/src/session/core/shared/index-rows-by-key.ts"() {
8615
+ "use strict";
8616
+ }
8617
+ });
8618
+
8619
+ // packages/experience-design-system-cli/src/session/repositories/sessions/read.ts
8620
+ function getSessionById(db, sessionId2) {
8621
+ const row = db.prepare("SELECT id FROM sessions WHERE id = ?").get(sessionId2);
8622
+ return row ?? null;
8623
+ }
8624
+ function getLatestCompletedSessionForCommand(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 updateSessionTimestamp(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 getSessionIdForStep(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 updatePendingStepsToInterrupted(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 createPendingStep(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 updateStepStatus(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
+
8475
8699
  // packages/experience-design-system-cli/src/session/session-id.ts
8476
8700
  var session_id_exports = {};
8477
8701
  __export(session_id_exports, {
@@ -8696,77 +8920,61 @@ var init_session_id = __esm({
8696
8920
  }
8697
8921
  });
8698
8922
 
8699
- // packages/experience-design-system-cli/src/session/source-excerpt.ts
8700
- function escapeForRegExp(value) {
8701
- return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
8702
- }
8703
- function identifierPattern(name) {
8704
- 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 getOrCreateSessionForCommand(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 (!getSessionById(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 };
8705
8935
  }
8706
- function excerptAroundNames(text, names, maxChars, contextLines = 6) {
8707
- if (text.length <= maxChars) return { content: text, usesNotShown: [] };
8708
- const patterns = names.filter((name) => name.length > 0).map((name) => ({ name, pattern: identifierPattern(name) }));
8709
- const lines = text.split("\n");
8710
- const windows = [];
8711
- lines.forEach((line, index) => {
8712
- const mentioned = patterns.filter(({ pattern }) => pattern.test(line)).map(({ name }) => name);
8713
- if (mentioned.length === 0) return;
8714
- const start = Math.max(0, index - contextLines);
8715
- const end = Math.min(lines.length - 1, index + contextLines);
8716
- const last = windows[windows.length - 1];
8717
- if (last && start <= last.end + 1) {
8718
- last.end = Math.max(last.end, end);
8719
- for (const name of mentioned) last.names.add(name);
8720
- } else {
8721
- windows.push({ start, end, names: new Set(mentioned) });
8722
- }
8723
- });
8724
- if (windows.length === 0) {
8725
- return { content: `${text.slice(0, maxChars)}
8726
- ${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();
8727
8942
  }
8728
- const lastWindowFor = /* @__PURE__ */ new Map();
8729
- for (const window of windows) for (const name of window.names) lastWindowFor.set(name, window);
8730
- const kept = [];
8731
- const cut = /* @__PURE__ */ new Set();
8732
- let used = 0;
8733
- for (const window of [...windows].reverse()) {
8734
- const chunk = lines.slice(window.start, window.end + 1).join("\n");
8735
- const separator = kept.length > 0 ? `
8736
- ${ELLIPSIS_MARKER}
8737
- ` : "";
8738
- if (used + separator.length + chunk.length > maxChars) {
8739
- if (kept.length === 0) {
8740
- const head = chunk.slice(0, maxChars);
8741
- kept.push({ window, text: head });
8742
- used += head.length;
8743
- for (const name of window.names) {
8744
- if (lastWindowFor.get(name) === window && !identifierPattern(name).test(head)) cut.add(name);
8745
- }
8746
- continue;
8747
- }
8748
- for (const name of window.names) {
8749
- if (lastWindowFor.get(name) === window) cut.add(name);
8750
- }
8751
- continue;
8752
- }
8753
- kept.push({ window, text: chunk });
8754
- used += separator.length + chunk.length;
8943
+ });
8944
+
8945
+ // packages/experience-design-system-cli/src/session/core/components/hash-component-shape.ts
8946
+ import { createHash as createHash2 } from "node:crypto";
8947
+ function hashComponentShape(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_hash_component_shape = __esm({
8965
+ "packages/experience-design-system-cli/src/session/core/components/hash-component-shape.ts"() {
8966
+ "use strict";
8755
8967
  }
8756
- kept.sort((a, b) => a.window.start - b.window.start);
8757
- const parts = kept.map((entry, index) => (index > 0 ? `
8758
- ${ELLIPSIS_MARKER}
8759
- ` : "") + entry.text);
8760
- const usesNotShown = names.filter((name, index) => cut.has(name) && names.indexOf(name) === index);
8761
- return { content: `${parts.join("")}
8762
- ${TRUNCATED_MARKER}`, usesNotShown };
8968
+ });
8969
+
8970
+ // packages/experience-design-system-cli/src/session/core/tokens/hash-token-content.ts
8971
+ import { createHash as createHash3 } from "node:crypto";
8972
+ function hashTokenContent(rawTokenContent) {
8973
+ return createHash3("sha256").update(rawTokenContent.trim()).digest("hex");
8763
8974
  }
8764
- var ELLIPSIS_MARKER, TRUNCATED_MARKER;
8765
- var init_source_excerpt = __esm({
8766
- "packages/experience-design-system-cli/src/session/source-excerpt.ts"() {
8975
+ var init_hash_token_content = __esm({
8976
+ "packages/experience-design-system-cli/src/session/core/tokens/hash-token-content.ts"() {
8767
8977
  "use strict";
8768
- ELLIPSIS_MARKER = "/* \u2026 */";
8769
- TRUNCATED_MARKER = "/* truncated */";
8770
8978
  }
8771
8979
  });
8772
8980
 
@@ -8777,11 +8985,11 @@ __export(cache_keys_exports, {
8777
8985
  hashFile: () => hashFile,
8778
8986
  hashPromptForSkill: () => hashPromptForSkill
8779
8987
  });
8780
- import { createHash } from "node:crypto";
8988
+ import { createHash as createHash4 } from "node:crypto";
8781
8989
  import { readFile as readFile6 } from "node:fs/promises";
8782
8990
  import { resolve as resolve6 } from "node:path";
8783
8991
  function hashContent(content) {
8784
- return createHash("sha256").update(content).digest("hex");
8992
+ return createHash4("sha256").update(content).digest("hex");
8785
8993
  }
8786
8994
  async function hashFile(filePath) {
8787
8995
  const content = await readFile6(filePath, "utf8");
@@ -8803,7 +9011,7 @@ var init_cache_keys = __esm({
8803
9011
  import { DatabaseSync } from "node:sqlite";
8804
9012
  import { mkdirSync, readFileSync as readFileSync5 } from "node:fs";
8805
9013
  import { readFile as readFile7 } from "node:fs/promises";
8806
- import { createHash as createHash2 } from "node:crypto";
9014
+ import { createHash as createHash5 } from "node:crypto";
8807
9015
  import { homedir } from "node:os";
8808
9016
  import { dirname as dirname7, resolve as resolve7 } from "node:path";
8809
9017
  function getPipelineDbPath() {
@@ -9334,39 +9542,18 @@ function applyToolCalls(db, sessionId2, componentId, componentName, calls, incom
9334
9542
  }
9335
9543
  return { classified, excluded, slots, warnings };
9336
9544
  }
9337
- function getOrCreateSession(db, sessionFlag, sessionName, _hints) {
9338
- const now = (/* @__PURE__ */ new Date()).toISOString();
9339
- if (sessionFlag === "new" || sessionFlag === void 0) {
9340
- const id = generateSessionId();
9341
- db.prepare("INSERT INTO sessions (id, name, created_at, updated_at) VALUES (?, ?, ?, ?)").run(
9342
- id,
9343
- sessionName ?? null,
9344
- now,
9345
- now
9346
- );
9347
- return { sessionId: id, isNew: true, isResumed: false };
9348
- }
9349
- const existing = db.prepare("SELECT id FROM sessions WHERE id = ?").get(sessionFlag);
9350
- if (!existing) {
9351
- throw new Error(`session '${sessionFlag}' not found. Run 'session list' to see active sessions.`);
9352
- }
9353
- return { sessionId: sessionFlag, isNew: false, isResumed: false };
9545
+ function getOrCreateSession(db, sessionFlag, sessionName, hints) {
9546
+ return getOrCreateSessionForCommand(db, sessionFlag, sessionName, hints);
9354
9547
  }
9355
9548
  function createStep(db, sessionId2, command, inputs) {
9356
9549
  const now = (/* @__PURE__ */ new Date()).toISOString();
9357
9550
  db.exec("BEGIN");
9358
9551
  try {
9359
- db.prepare(
9360
- `UPDATE steps SET status = 'interrupted', completed_at = ?, updated_at = ?
9361
- WHERE session_id = ? AND command = ? AND status = 'pending'`
9362
- ).run(now, now, sessionId2, command);
9363
- const result = db.prepare(
9364
- `INSERT INTO steps (session_id, command, status, started_at, inputs, outputs, updated_at)
9365
- VALUES (?, ?, 'pending', ?, ?, '{}', ?)`
9366
- ).run(sessionId2, command, now, JSON.stringify(inputs), now);
9367
- db.prepare("UPDATE sessions SET updated_at = ? WHERE id = ?").run(now, sessionId2);
9552
+ updatePendingStepsToInterrupted(db, sessionId2, command, now);
9553
+ const stepId = createPendingStep(db, sessionId2, command, inputs, now);
9554
+ updateSessionTimestamp(db, sessionId2, now);
9368
9555
  db.exec("COMMIT");
9369
- return Number(result.lastInsertRowid);
9556
+ return stepId;
9370
9557
  } catch (e) {
9371
9558
  db.exec("ROLLBACK");
9372
9559
  throw e;
@@ -9376,12 +9563,10 @@ function updateStep(db, stepId, status, outputs, error) {
9376
9563
  const now = (/* @__PURE__ */ new Date()).toISOString();
9377
9564
  db.exec("BEGIN");
9378
9565
  try {
9379
- const step = db.prepare("SELECT session_id FROM steps WHERE id = ?").get(stepId);
9380
- db.prepare(
9381
- `UPDATE steps SET status = ?, completed_at = ?, outputs = ?, error = ?, updated_at = ? WHERE id = ?`
9382
- ).run(status, now, JSON.stringify(outputs), error ?? null, now, stepId);
9383
- if (step) {
9384
- db.prepare("UPDATE sessions SET updated_at = ? WHERE id = ?").run(now, step.session_id);
9566
+ const stepSessionId = getSessionIdForStep(db, stepId);
9567
+ updateStepStatus(db, stepId, status, outputs, error ?? null, now);
9568
+ if (stepSessionId) {
9569
+ updateSessionTimestamp(db, stepSessionId, now);
9385
9570
  }
9386
9571
  db.exec("COMMIT");
9387
9572
  } catch (e) {
@@ -9579,10 +9764,10 @@ function loadRawComponents(db, sessionId2, allowedNames) {
9579
9764
  `SELECT component_id, slot_name, position, allowed_component
9580
9765
  FROM raw_slot_allowed_components WHERE session_id = ? ORDER BY component_id, slot_name, position`
9581
9766
  ).all(sessionId2);
9582
- const propsByComponent = groupBy(props, (p) => p.component_id);
9583
- const allowedValuesByProp = groupBy(allowedValues, (av) => `${av.component_id}::${av.prop_name}`);
9584
- const slotsByComponent = groupBy(slots, (s) => s.component_id);
9585
- const allowedComponentsBySlot = groupBy(allowedComponents, (ac) => `${ac.component_id}::${ac.slot_name}`);
9767
+ const propsByComponent = indexRowsByKey(props, (p) => p.component_id);
9768
+ const allowedValuesByProp = indexRowsByKey(allowedValues, (av) => `${av.component_id}::${av.prop_name}`);
9769
+ const slotsByComponent = indexRowsByKey(slots, (s) => s.component_id);
9770
+ const allowedComponentsBySlot = indexRowsByKey(allowedComponents, (ac) => `${ac.component_id}::${ac.slot_name}`);
9586
9771
  return components.map(
9587
9772
  (c2) => ({
9588
9773
  component_id: c2.component_id,
@@ -9808,22 +9993,6 @@ function parseReviewReasons(raw) {
9808
9993
  return [];
9809
9994
  }
9810
9995
  }
9811
- function groupBy(items, key) {
9812
- const map = /* @__PURE__ */ new Map();
9813
- for (const item of items) {
9814
- const k = key(item);
9815
- let arr = map.get(k);
9816
- if (!arr) {
9817
- arr = [];
9818
- map.set(k, arr);
9819
- }
9820
- arr.push(item);
9821
- }
9822
- return map;
9823
- }
9824
- function deriveComponentId(name, source) {
9825
- return createHash2("sha256").update(`${name}:${source}`).digest("hex").slice(0, 12);
9826
- }
9827
9996
  function storeCDFComponents(db, sessionId2, components) {
9828
9997
  const now = (/* @__PURE__ */ new Date()).toISOString();
9829
9998
  const updateComp = db.prepare(
@@ -9916,7 +10085,7 @@ function storeCDFComponents(db, sessionId2, components) {
9916
10085
  }
9917
10086
  }
9918
10087
  } else {
9919
- const componentId = createHash2("sha256").update(`${key}:generated`).digest("hex").slice(0, 12);
10088
+ const componentId = deriveComponentId(key, "generated");
9920
10089
  db.prepare(
9921
10090
  `INSERT INTO raw_components (session_id, component_id, name, source, framework, extracted_at, status, description)
9922
10091
  VALUES (?, ?, ?, '', 'react', ?, 'generated', ?)`
@@ -9998,11 +10167,11 @@ function loadCDFComponents(db, sessionId2) {
9998
10167
  const tokenTypeByPath = new Map(
9999
10168
  db.prepare("SELECT path, type FROM raw_tokens WHERE session_id = ?").all(sessionId2).map((token) => [token.path, token.type])
10000
10169
  );
10001
- const propsByComponent = groupBy(props, (p) => p.component_id);
10002
- const allowedValuesByProp = groupBy(allowedValues, (av) => `${av.component_id}::${av.prop_name}`);
10003
- const slotsByComponent = groupBy(slots, (s) => s.component_id);
10004
- const allowedComponentsBySlot = groupBy(allowedComponents, (ac) => `${ac.component_id}::${ac.slot_name}`);
10005
- const tokenPathsByProp = groupBy(tokenPaths, (t) => `${t.component_id}::${t.prop_name}`);
10170
+ const propsByComponent = indexRowsByKey(props, (p) => p.component_id);
10171
+ const allowedValuesByProp = indexRowsByKey(allowedValues, (av) => `${av.component_id}::${av.prop_name}`);
10172
+ const slotsByComponent = indexRowsByKey(slots, (s) => s.component_id);
10173
+ const allowedComponentsBySlot = indexRowsByKey(allowedComponents, (ac) => `${ac.component_id}::${ac.slot_name}`);
10174
+ const tokenPathsByProp = indexRowsByKey(tokenPaths, (t) => `${t.component_id}::${t.prop_name}`);
10006
10175
  const toTokenPaths = (rows) => rows === void 0 ? void 0 : rows.map((r) => r.path);
10007
10176
  return components.map(({ component_id, name, description }) => {
10008
10177
  const compProps = propsByComponent.get(component_id) ?? [];
@@ -10067,8 +10236,8 @@ function loadScopeComponents(db, sessionId2) {
10067
10236
  `SELECT component_id, slot_name, position, allowed_component
10068
10237
  FROM raw_slot_allowed_components WHERE session_id = ? ORDER BY component_id, slot_name, position`
10069
10238
  ).all(sessionId2);
10070
- const slotsByComponent = groupBy(slotRows, (s) => s.component_id);
10071
- const allowedBySlot = groupBy(allowedRows, (a) => `${a.component_id}::${a.slot_name}`);
10239
+ const slotsByComponent = indexRowsByKey(slotRows, (s) => s.component_id);
10240
+ const allowedBySlot = indexRowsByKey(allowedRows, (a) => `${a.component_id}::${a.slot_name}`);
10072
10241
  return rows.map((r) => {
10073
10242
  const reviewReasons = parseReviewReasons(r.review_reasons);
10074
10243
  const nonAuthorableReason = reviewReasons.find((reason) => reason.startsWith("non-authorable:"));
@@ -10183,14 +10352,7 @@ function loadDTCGTokens(db, sessionId2) {
10183
10352
  return { groups, tokens };
10184
10353
  }
10185
10354
  function findLatestSessionForCommand(db, command) {
10186
- const row = db.prepare(
10187
- `SELECT s.id FROM sessions s
10188
- JOIN steps st ON st.session_id = s.id
10189
- WHERE st.command = ? AND st.status = 'complete'
10190
- ORDER BY st.started_at DESC, st.id DESC
10191
- LIMIT 1`
10192
- ).get(command);
10193
- return row?.id ?? null;
10355
+ return getLatestCompletedSessionForCommand(db, command);
10194
10356
  }
10195
10357
  function seedCDFFromPreviewResponse(db, sessionId2, removedItems) {
10196
10358
  if (removedItems.length === 0) return 0;
@@ -10207,14 +10369,8 @@ function seedCDFFromPreviewResponse(db, sessionId2, removedItems) {
10207
10369
  const contentProps = new Set(item.contentProperties);
10208
10370
  const designProps = new Set(item.designProperties);
10209
10371
  for (const [propName, propSummary] of Object.entries(item.fullProperties)) {
10210
- const cdfType = mapServerTypeToCDFType(propSummary.type);
10211
- if (!cdfType) continue;
10212
- let cdfCategory = propSummary.category || null;
10213
- if (!cdfCategory || !["content", "design", "state"].includes(cdfCategory)) {
10214
- if (contentProps.has(propName)) cdfCategory = "content";
10215
- else if (designProps.has(propName)) cdfCategory = "design";
10216
- else cdfCategory = "state";
10217
- }
10372
+ const cdfType = mapContentfulTypeToCdfType(propSummary.type);
10373
+ const cdfCategory = resolveCdfCategory(propSummary.category, propName, contentProps, designProps);
10218
10374
  const result = updateStmt.run(cdfType, cdfCategory, sessionId2, localComponent.component_id, propName);
10219
10375
  totalSeeded += Number(result.changes);
10220
10376
  }
@@ -10244,14 +10400,8 @@ function seedDefaultsFromChangedItems(db, sessionId2, changedItems) {
10244
10400
  const result2 = updateDefaultStmt.run(defaultStr, sessionId2, localComponent.component_id, propName);
10245
10401
  totalSeeded += Number(result2.changes);
10246
10402
  }
10247
- const cdfType = mapServerTypeToCDFType(propSummary.type);
10248
- if (!cdfType) continue;
10249
- let cdfCategory = propSummary.category || null;
10250
- if (!cdfCategory || !["content", "design", "state"].includes(cdfCategory)) {
10251
- if (contentProps.has(propName)) cdfCategory = "content";
10252
- else if (designProps.has(propName)) cdfCategory = "design";
10253
- else cdfCategory = "state";
10254
- }
10403
+ const cdfType = mapContentfulTypeToCdfType(propSummary.type);
10404
+ const cdfCategory = resolveCdfCategory(propSummary.category, propName, contentProps, designProps);
10255
10405
  const result = updateCDFStmt.run(cdfType, cdfCategory, sessionId2, localComponent.component_id, propName);
10256
10406
  totalSeeded += Number(result.changes);
10257
10407
  }
@@ -10275,48 +10425,6 @@ function backfillUnclassifiedProps(db, sessionId2) {
10275
10425
  ).run(sessionId2, sessionId2);
10276
10426
  return Number(withCategory.changes) + Number(withoutCategory.changes);
10277
10427
  }
10278
- function mapServerTypeToCDFType(serverType) {
10279
- switch (serverType.toLowerCase()) {
10280
- case "string":
10281
- case "text":
10282
- return "string";
10283
- case "richtext":
10284
- return "richtext";
10285
- case "media":
10286
- return "media";
10287
- case "link":
10288
- return "link";
10289
- case "enum":
10290
- case "symbol":
10291
- return "enum";
10292
- case "token":
10293
- return "token";
10294
- case "boolean":
10295
- return "boolean";
10296
- default:
10297
- return "string";
10298
- }
10299
- }
10300
- function computeComponentInputHash(component) {
10301
- const payload = {
10302
- framework: component.framework,
10303
- name: component.name,
10304
- source: component.source,
10305
- props: component.props.map((p) => ({
10306
- name: p.name,
10307
- type: p.type
10308
- })),
10309
- slots: component.slots.map((s) => ({
10310
- name: s.name,
10311
- isDefault: s.isDefault,
10312
- allowedComponents: [...s.allowedComponents ?? []].sort()
10313
- }))
10314
- };
10315
- return createHash2("sha256").update(JSON.stringify(payload)).digest("hex");
10316
- }
10317
- function computeTokenInputHash(rawTokenContent) {
10318
- return createHash2("sha256").update(rawTokenContent.trim()).digest("hex");
10319
- }
10320
10428
  function computeMapTokensInputHash(db, sessionId2, componentSourceRefs = []) {
10321
10429
  const props = db.prepare(
10322
10430
  `SELECT rc.name AS component_name, rp.name AS prop_name, rp.cdf_token_kind, rp.default_value
@@ -10346,7 +10454,7 @@ function computeMapTokensInputHash(db, sessionId2, componentSourceRefs = []) {
10346
10454
  usesNotShown: [...ref.usesNotShown ?? []].sort()
10347
10455
  }))
10348
10456
  };
10349
- return createHash2("sha256").update(JSON.stringify(payload)).digest("hex");
10457
+ return createHash5("sha256").update(JSON.stringify(payload)).digest("hex");
10350
10458
  }
10351
10459
  function lookupCache(db, inputHash, entityType, entityId, promptHash = "") {
10352
10460
  const row = db.prepare(
@@ -10654,8 +10762,19 @@ var SCHEMA, MAX_COMPONENT_SOURCE_CHARS, MAX_SIBLING_FILES, MAX_SIBLING_SNIPPET_C
10654
10762
  var init_db = __esm({
10655
10763
  "packages/experience-design-system-cli/src/session/db.ts"() {
10656
10764
  "use strict";
10657
- init_session_id();
10658
10765
  init_source_excerpt();
10766
+ init_derive_component_id();
10767
+ init_cdf_mappers();
10768
+ init_index_rows_by_key();
10769
+ init_read();
10770
+ init_write();
10771
+ init_read2();
10772
+ init_write2();
10773
+ init_session_resolver();
10774
+ init_derive_component_id();
10775
+ init_hash_component_shape();
10776
+ init_hash_token_content();
10777
+ init_cdf_mappers();
10659
10778
  SCHEMA = `
10660
10779
  PRAGMA journal_mode = WAL;
10661
10780
  PRAGMA foreign_keys = ON;
@@ -10932,11 +11051,11 @@ var init_persistence = __esm({
10932
11051
  });
10933
11052
 
10934
11053
  // packages/experience-design-system-cli/src/analyze/select/parser.ts
10935
- import { createHash as createHash3 } from "node:crypto";
11054
+ import { createHash as createHash6 } from "node:crypto";
10936
11055
  import { access as access2 } from "node:fs/promises";
10937
11056
  import { isAbsolute, relative, resolve as resolve9 } from "node:path";
10938
11057
  function createComponentId(name, resolvedSourcePath) {
10939
- 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);
10940
11059
  return `${name}-${sourceHash}`;
10941
11060
  }
10942
11061
  async function resolveComponentSourcePath(source, reviewRoot) {
@@ -17364,7 +17483,7 @@ var init_save_conflict = __esm({
17364
17483
  });
17365
17484
 
17366
17485
  // packages/experience-design-system-cli/src/runs/fingerprint.ts
17367
- import { createHash as createHash4 } from "node:crypto";
17486
+ import { createHash as createHash7 } from "node:crypto";
17368
17487
  import { readFile as readFile24, stat as stat5 } from "node:fs/promises";
17369
17488
  import { resolve as resolve23 } from "node:path";
17370
17489
  function rowField(row, key) {
@@ -17372,7 +17491,7 @@ function rowField(row, key) {
17372
17491
  return typeof v === "string" ? v : null;
17373
17492
  }
17374
17493
  function sha256Hex(buf) {
17375
- return createHash4("sha256").update(buf).digest("hex");
17494
+ return createHash7("sha256").update(buf).digest("hex");
17376
17495
  }
17377
17496
  async function buildSourceFingerprint(opts) {
17378
17497
  const rows = opts.db.prepare("SELECT name, source_path FROM raw_components WHERE session_id = ?").all(opts.extractSessionId);
@@ -30731,7 +30850,7 @@ async function selectAllComponents(agent, model, components, verbose, skillPathO
30731
30850
  try {
30732
30851
  for (let i = 0; i < components.length; i++) {
30733
30852
  const candidate = components[i];
30734
- const compHash = computeComponentInputHash(candidate.component);
30853
+ const compHash = hashComponentShape(candidate.component);
30735
30854
  const hit = lookupSelectCache(db, compHash, promptHash, cliVersion2);
30736
30855
  if (hit) {
30737
30856
  const finalColor = hit.decision === "accepted" ? c.green : c.red;
@@ -30805,7 +30924,7 @@ async function selectAllComponents(agent, model, components, verbose, skillPathO
30805
30924
  const r = results[i];
30806
30925
  if (!r || r.failed || !r.decision) continue;
30807
30926
  const candidate = components[i];
30808
- const compHash = computeComponentInputHash(candidate.component);
30927
+ const compHash = hashComponentShape(candidate.component);
30809
30928
  storeSelectCache(db, compHash, promptHash, cliVersion2, r.decision, r.reason ?? null);
30810
30929
  }
30811
30930
  } finally {
@@ -32751,7 +32870,7 @@ function printFallbackInstructions(options) {
32751
32870
  async function runOneComponent(agent, model, db, sessionId2, component, tokensInline, tokenMapInline, index, total, verbose, noCache, skillPathOverride, promptHash, existingContentfulEntities, existingTokensInline) {
32752
32871
  const pos = c.dim(`[${index + 1}/${total}]`);
32753
32872
  if (!noCache) {
32754
- const inputHash = computeComponentInputHash(component);
32873
+ const inputHash = hashComponentShape(component);
32755
32874
  const cached = lookupCache(db, inputHash, "component", component.component_id, promptHash);
32756
32875
  if (cached) {
32757
32876
  copyComponentFromCache(db, cached.sourceSessionId, sessionId2, component.component_id);
@@ -32874,7 +32993,7 @@ ${outputBuf}`);
32874
32993
  }
32875
32994
  const applied = applyToolCalls(db, sessionId2, component.component_id, component.name, calls, warnings);
32876
32995
  if (!noCache) {
32877
- const inputHash = computeComponentInputHash(component);
32996
+ const inputHash = hashComponentShape(component);
32878
32997
  storeCache(db, inputHash, "component", component.component_id, sessionId2, false, promptHash);
32879
32998
  }
32880
32999
  return {
@@ -33171,7 +33290,7 @@ async function runGenerateSkill(skill, opts, verbose = false) {
33171
33290
  } else if (skill === "tokens") {
33172
33291
  const noCache = opts.cache === false || process.env.EDS_NO_CACHE === "1";
33173
33292
  const tokenInputContent = rawTokensInline ?? "";
33174
- const tokenInputHash = computeTokenInputHash(tokenInputContent);
33293
+ const tokenInputHash = hashTokenContent(tokenInputContent);
33175
33294
  const db = openPipelineDb();
33176
33295
  try {
33177
33296
  let resolvedSessionId = opts.session;
@@ -33329,7 +33448,7 @@ function registerGenerateCommand(program) {
33329
33448
  // packages/experience-design-system-cli/src/program.ts
33330
33449
  init_command();
33331
33450
 
33332
- // packages/experience-design-system-cli/src/session/command.ts
33451
+ // packages/experience-design-system-cli/src/session/cli.ts
33333
33452
  init_db();
33334
33453
 
33335
33454
  // packages/experience-design-system-cli/src/session/stats.ts
@@ -33533,7 +33652,7 @@ function migrateImportDb(db, _now) {
33533
33652
  }
33534
33653
  }
33535
33654
 
33536
- // packages/experience-design-system-cli/src/session/command.ts
33655
+ // packages/experience-design-system-cli/src/session/cli.ts
33537
33656
  function parseDuration(str) {
33538
33657
  const m = /^(\d+)([dwmy])$/.exec(str);
33539
33658
  if (!m) return null;
@@ -0,0 +1,3 @@
1
+ export type CdfCategory = 'content' | 'design' | 'state';
2
+ export declare function mapContentfulTypeToCdfType(contentfulType: string): string;
3
+ export declare function resolveCdfCategory(contentfulCategory: string | null | undefined, propName: string, contentProps: Set<string>, designProps: Set<string>): CdfCategory;
@@ -0,0 +1 @@
1
+ export declare function deriveComponentId(name: string, source: string): string;
@@ -0,0 +1,5 @@
1
+ import type { RawComponentDefinition } from '../../../types.js';
2
+ export type RawComponentForHash = RawComponentDefinition & {
3
+ component_id?: string;
4
+ };
5
+ export declare function hashComponentShape(component: RawComponentForHash): string;
@@ -0,0 +1 @@
1
+ export declare function indexRowsByKey<T>(items: T[], key: (item: T) => string): Map<string, T[]>;
@@ -0,0 +1 @@
1
+ export declare function hashTokenContent(rawTokenContent: string): string;
@@ -4,6 +4,12 @@ import type { CDFComponentEntry, DTCGTokenEntry, DTCGTokenGroup } from '@content
4
4
  import type { ToolCall, TokenToolCall, ComponentSourceRef } from '@contentful/experience-design-system-generation';
5
5
  import type { ComponentTypeSummary } from '@contentful/experience-design-system-types';
6
6
  import type { SlotCycle, SlotEdge } from '../analyze/cycle-detection.js';
7
+ import { type MatchHints as SessionMatchHints } from './repositories/sessions/read.js';
8
+ import { type SessionResolution } from './services/session-resolver.js';
9
+ export { deriveComponentId } from './core/components/derive-component-id.js';
10
+ export { hashComponentShape as computeComponentInputHash } from './core/components/hash-component-shape.js';
11
+ export { hashTokenContent as computeTokenInputHash } from './core/tokens/hash-token-content.js';
12
+ export { mapContentfulTypeToCdfType, resolveCdfCategory } from './core/cdf/cdf-mappers.js';
7
13
  export type StepStatus = 'pending' | 'complete' | 'failed' | 'interrupted';
8
14
  export type CommandName = 'analyze extract' | 'analyze select' | 'generate components' | 'generate tokens' | 'generate edit' | 'apply preview' | 'apply select' | 'apply push' | 'print components' | 'print tokens' | 'map tokens' | 'fetch existing entities' | 'import';
9
15
  export interface SessionRow {
@@ -86,17 +92,9 @@ export interface ComponentRationale {
86
92
  }
87
93
  export declare function loadComponentRationale(db: DatabaseSync, sessionId: string, componentName: string): ComponentRationale | null;
88
94
  export declare function applyToolCalls(db: DatabaseSync, sessionId: string, componentId: string, componentName: string, calls: ToolCall[], incomingWarnings: string[]): ApplyToolCallsResult;
89
- export interface MatchHints {
90
- command: CommandName;
91
- inputPath?: string;
92
- outDir?: string;
93
- }
94
- export interface SessionResolution {
95
- sessionId: string;
96
- isNew: boolean;
97
- isResumed: boolean;
98
- }
99
- export declare function getOrCreateSession(db: DatabaseSync, sessionFlag: string | undefined, sessionName: string | undefined, _hints: MatchHints): SessionResolution;
95
+ export type MatchHints = SessionMatchHints;
96
+ export type { SessionResolution };
97
+ export declare function getOrCreateSession(db: DatabaseSync, sessionFlag: string | undefined, sessionName: string | undefined, hints: MatchHints): SessionResolution;
100
98
  export declare function createStep(db: DatabaseSync, sessionId: string, command: CommandName, inputs: Record<string, string>): number;
101
99
  export declare function updateStep(db: DatabaseSync, stepId: number, status: 'complete' | 'failed', outputs: Record<string, string>, error?: string): void;
102
100
  export declare function storeRawComponents(db: DatabaseSync, sessionId: string, components: RawComponentDefinition[], options?: {
@@ -170,8 +168,6 @@ export interface CacheEntry {
170
168
  createdAt: string;
171
169
  updatedAt: string;
172
170
  }
173
- export declare function computeComponentInputHash(component: RawComponentWithId): string;
174
- export declare function computeTokenInputHash(rawTokenContent: string): string;
175
171
  export declare function computeMapTokensInputHash(db: DatabaseSync, sessionId: string, componentSourceRefs?: readonly ComponentSourceRef[]): string;
176
172
  export declare function lookupCache(db: DatabaseSync, inputHash: string, entityType: CacheEntityType, entityId: string, promptHash?: string): CacheEntry | null;
177
173
  export declare function lookupCacheByEntity(db: DatabaseSync, entityType: CacheEntityType, entityId: string): CacheEntry | null;
@@ -0,0 +1,11 @@
1
+ import type { DatabaseSync } from 'node:sqlite';
2
+ import type { CommandName } from '../../db.js';
3
+ export interface MatchHints {
4
+ command: CommandName;
5
+ inputPath?: string;
6
+ outDir?: string;
7
+ }
8
+ export declare function getSessionById(db: DatabaseSync, sessionId: string): {
9
+ id: string;
10
+ } | null;
11
+ export declare function getLatestCompletedSessionForCommand(db: DatabaseSync, command: CommandName): string | null;
@@ -0,0 +1,3 @@
1
+ import type { DatabaseSync } from 'node:sqlite';
2
+ export declare function createSession(db: DatabaseSync, id: string, name: string | null, timestamp: string): void;
3
+ export declare function updateSessionTimestamp(db: DatabaseSync, sessionId: string, timestamp: string): void;
@@ -0,0 +1,2 @@
1
+ import type { DatabaseSync } from 'node:sqlite';
2
+ export declare function getSessionIdForStep(db: DatabaseSync, stepId: number): string | null;
@@ -0,0 +1,5 @@
1
+ import type { DatabaseSync } from 'node:sqlite';
2
+ import type { CommandName } from '../../db.js';
3
+ export declare function updatePendingStepsToInterrupted(db: DatabaseSync, sessionId: string, command: CommandName, timestamp: string): void;
4
+ export declare function createPendingStep(db: DatabaseSync, sessionId: string, command: CommandName, inputs: Record<string, string>, timestamp: string): number;
5
+ export declare function updateStepStatus(db: DatabaseSync, stepId: number, status: 'complete' | 'failed', outputs: Record<string, string>, error: string | null, timestamp: string): void;
@@ -0,0 +1,9 @@
1
+ import type { DatabaseSync } from 'node:sqlite';
2
+ import { type MatchHints } from '../repositories/sessions/read.js';
3
+ export type { MatchHints };
4
+ export interface SessionResolution {
5
+ sessionId: string;
6
+ isNew: boolean;
7
+ isResumed: boolean;
8
+ }
9
+ export declare function getOrCreateSessionForCommand(db: DatabaseSync, sessionFlag: string | undefined, sessionName: string | undefined, _hints: MatchHints): SessionResolution;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contentful/experience-design-system-cli",
3
- "version": "2.32.1-dev-build-23e5797.0",
3
+ "version": "2.32.1-dev-build-661f431.0",
4
4
  "description": "Contentful Experiences design system import CLI",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -40,8 +40,8 @@
40
40
  "svelte": "^5.56.4",
41
41
  "ts-morph": "^27.0.2",
42
42
  "typescript": "^5.9.3",
43
- "@contentful/experience-design-system-cli-v2": "2.32.1-dev-build-23e5797.0",
44
- "@contentful/experience-design-system-types": "2.32.1-dev-build-23e5797.0"
43
+ "@contentful/experience-design-system-types": "2.32.1-dev-build-661f431.0",
44
+ "@contentful/experience-design-system-cli-v2": "2.32.1-dev-build-661f431.0"
45
45
  },
46
46
  "devDependencies": {
47
47
  "@tsconfig/node24": "^24.0.4",
@@ -53,9 +53,9 @@
53
53
  "ink-testing-library": "^4.0.0",
54
54
  "typescript-eslint": "^8.67.0",
55
55
  "vitest": "^4.0.16",
56
- "@contentful/experience-design-system-extraction": "2.32.1-dev-build-23e5797.0",
57
- "@contentful/experience-design-system-client": "2.32.1-dev-build-23e5797.0",
58
- "@contentful/experience-design-system-generation": "2.32.1-dev-build-23e5797.0"
56
+ "@contentful/experience-design-system-generation": "2.32.1-dev-build-661f431.0",
57
+ "@contentful/experience-design-system-client": "2.32.1-dev-build-661f431.0",
58
+ "@contentful/experience-design-system-extraction": "2.32.1-dev-build-661f431.0"
59
59
  },
60
60
  "repository": {
61
61
  "type": "git",
File without changes