@contentful/experience-design-system-cli 2.32.1-dev-build-71db090.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.
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-71db090.0",
3
+ "version": "2.32.1-dev-build-d28a6f8.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/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
+
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 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 };
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/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";
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/input-hash.ts
8971
+ import { createHash as createHash3 } from "node:crypto";
8972
+ function computeTokenInputHash(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_input_hash2 = __esm({
8976
+ "packages/experience-design-system-cli/src/session/core/tokens/input-hash.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 resolveSession(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
+ markPendingStepsInterrupted(db, sessionId2, command, now);
9553
+ const stepId = insertPendingStep(db, sessionId2, command, inputs, now);
9554
+ touchSession(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 = findStepSessionId(db, stepId);
9567
+ updateStepResult(db, stepId, status, outputs, error ?? null, now);
9568
+ if (stepSessionId) {
9569
+ touchSession(db, stepSessionId, now);
9385
9570
  }
9386
9571
  db.exec("COMMIT");
9387
9572
  } catch (e) {
@@ -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', ?)`
@@ -10182,15 +10351,8 @@ function loadDTCGTokens(db, sessionId2) {
10182
10351
  });
10183
10352
  return { groups, tokens };
10184
10353
  }
10185
- 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;
10354
+ function findLatestSessionForCommand2(db, command) {
10355
+ return findLatestSessionForCommand(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 = mapServerTypeToCdfType(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 = mapServerTypeToCdfType(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_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();
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);
@@ -30458,7 +30577,7 @@ function resolveRationaleSession(sessionFlag, dbPath) {
30458
30577
  }
30459
30578
  return sessionFlag;
30460
30579
  }
30461
- const latest = findLatestSessionForCommand(db, "analyze select");
30580
+ const latest = findLatestSessionForCommand2(db, "analyze select");
30462
30581
  if (!latest) {
30463
30582
  throw new Error(
30464
30583
  `No completed 'analyze select' session found. Run 'analyze select-agent' first, or pass --session <id>.`
@@ -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;
@@ -34080,10 +34199,10 @@ async function assertOutIsNotDirectory(outPath) {
34080
34199
  if (s.isDirectory()) await die3(`Error: --out must be a file path, not a directory: ${outPath}`);
34081
34200
  }
34082
34201
  }
34083
- async function resolveSession(sessionFlag, command) {
34202
+ async function resolveSession2(sessionFlag, command) {
34084
34203
  const db = openPipelineDb();
34085
34204
  try {
34086
- const sessionId2 = sessionFlag ?? findLatestSessionForCommand(db, command);
34205
+ const sessionId2 = sessionFlag ?? findLatestSessionForCommand2(db, command);
34087
34206
  if (!sessionId2) {
34088
34207
  const hint = command === "generate components" ? "generate components" : "generate tokens";
34089
34208
  return await die3(`Error: no completed ${hint} session found. Run ${hint} first, or pass --session <id>.`);
@@ -34133,7 +34252,7 @@ function registerPrintCommand(program) {
34133
34252
  ).action(async (opts) => {
34134
34253
  const outPath = resolve19(opts.out);
34135
34254
  await assertOutIsNotDirectory(outPath);
34136
- const sessionId2 = await resolveSession(opts.session, "generate components");
34255
+ const sessionId2 = await resolveSession2(opts.session, "generate components");
34137
34256
  await bindAnalyticsSessionId(sessionId2);
34138
34257
  const db = openPipelineDb();
34139
34258
  let components;
@@ -34190,7 +34309,7 @@ function registerPrintCommand(program) {
34190
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) => {
34191
34310
  const outPath = resolve19(opts.out);
34192
34311
  await assertOutIsNotDirectory(outPath);
34193
- const sessionId2 = await resolveSession(opts.session, "generate tokens");
34312
+ const sessionId2 = await resolveSession2(opts.session, "generate tokens");
34194
34313
  await bindAnalyticsSessionId(sessionId2);
34195
34314
  const db = openPipelineDb();
34196
34315
  let result;
@@ -34507,7 +34626,7 @@ async function runMapTokens(opts) {
34507
34626
  const resultAgent = configuredAgent ?? "skipped";
34508
34627
  const db = openPipelineDb();
34509
34628
  try {
34510
- const sessionId2 = opts.session ?? findLatestSessionForCommand(db, "generate components");
34629
+ const sessionId2 = opts.session ?? findLatestSessionForCommand2(db, "generate components");
34511
34630
  if (!sessionId2) {
34512
34631
  die2(
34513
34632
  "Error: no completed generate components session found. Run generate components first, or pass --session <id>."
@@ -34892,7 +35011,7 @@ async function runPipeline(opts, progressWriter, cliPathOverride) {
34892
35011
  status: "skipped",
34893
35012
  reason: "--skip-analyze"
34894
35013
  });
34895
- const prior = findLatestSessionForCommand(db, "analyze extract");
35014
+ const prior = findLatestSessionForCommand2(db, "analyze extract");
34896
35015
  extractSessionId = prior ?? null;
34897
35016
  } else {
34898
35017
  const stepId = createStep(db, sessionId2, "analyze extract", {
@@ -34926,7 +35045,7 @@ async function runPipeline(opts, progressWriter, cliPathOverride) {
34926
35045
  db.close();
34927
35046
  return { session: sessionId2, project: projectRoot, steps };
34928
35047
  }
34929
- extractSessionId = findLatestSessionForCommand(db, "analyze extract") ?? null;
35048
+ extractSessionId = findLatestSessionForCommand2(db, "analyze extract") ?? null;
34930
35049
  const componentMatch = /Extracted (\d+) component/.exec(r.stderr);
34931
35050
  const componentCount = componentMatch ? Number(componentMatch[1]) : 0;
34932
35051
  updateStep(db, stepId, "complete", {
@@ -0,0 +1,3 @@
1
+ export type CdfCategory = 'content' | 'design' | 'state';
2
+ export declare function mapServerTypeToCdfType(serverType: string): string;
3
+ export declare function resolveCdfCategory(serverCategory: 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 computeComponentInputHash(component: RawComponentForHash): string;
@@ -0,0 +1 @@
1
+ export declare function groupBy<T>(items: T[], key: (item: T) => string): Map<string, T[]>;
@@ -0,0 +1 @@
1
+ export declare function computeTokenInputHash(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/component-id.js';
10
+ export { computeComponentInputHash } from './core/components/input-hash.js';
11
+ export { computeTokenInputHash } from './core/tokens/input-hash.js';
12
+ export { mapServerTypeToCdfType, resolveCdfCategory } from './core/cdf/server-type-map.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 findSession(db: DatabaseSync, sessionId: string): {
9
+ id: string;
10
+ } | null;
11
+ export declare function findLatestSessionForCommand(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 touchSession(db: DatabaseSync, sessionId: string, timestamp: string): void;
@@ -0,0 +1,2 @@
1
+ import type { DatabaseSync } from 'node:sqlite';
2
+ export declare function findStepSessionId(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 markPendingStepsInterrupted(db: DatabaseSync, sessionId: string, command: CommandName, timestamp: string): void;
4
+ export declare function insertPendingStep(db: DatabaseSync, sessionId: string, command: CommandName, inputs: Record<string, string>, timestamp: string): number;
5
+ export declare function updateStepResult(db: DatabaseSync, stepId: number, status: 'complete' | 'failed', outputs: Record<string, string>, error: string | null, timestamp: string): void;
@@ -0,0 +1,21 @@
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 interface SessionResolution {
9
+ sessionId: string;
10
+ isNew: boolean;
11
+ isResumed: boolean;
12
+ }
13
+ /**
14
+ * Resolve which session the caller should operate on:
15
+ * - `sessionFlag === 'new'` or undefined → create a new session
16
+ * - explicit id → verify it exists and reuse it (throws if missing)
17
+ *
18
+ * `MatchHints` is accepted for signature stability (callers pass it today) but
19
+ * is not currently used — hint-based session resumption was removed upstream.
20
+ */
21
+ export declare function resolveSession(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-71db090.0",
3
+ "version": "2.32.1-dev-build-d28a6f8.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-types": "2.32.1-dev-build-71db090.0",
44
- "@contentful/experience-design-system-cli-v2": "2.32.1-dev-build-71db090.0"
43
+ "@contentful/experience-design-system-cli-v2": "2.32.1-dev-build-d28a6f8.0",
44
+ "@contentful/experience-design-system-types": "2.32.1-dev-build-d28a6f8.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-client": "2.32.1-dev-build-71db090.0",
57
- "@contentful/experience-design-system-extraction": "2.32.1-dev-build-71db090.0",
58
- "@contentful/experience-design-system-generation": "2.32.1-dev-build-71db090.0"
56
+ "@contentful/experience-design-system-client": "2.32.1-dev-build-d28a6f8.0",
57
+ "@contentful/experience-design-system-generation": "2.32.1-dev-build-d28a6f8.0",
58
+ "@contentful/experience-design-system-extraction": "2.32.1-dev-build-d28a6f8.0"
59
59
  },
60
60
  "repository": {
61
61
  "type": "git",
File without changes