@contentful/experience-design-system-cli 2.32.1-dev-build-413e3a3.0 → 2.32.1-dev-build-23e5797.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-413e3a3.0",
3
+ "version": "2.32.1-dev-build-23e5797.0",
4
4
  "description": "Contentful Experiences design system import CLI",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -29,7 +29,7 @@
29
29
  "skills/"
30
30
  ],
31
31
  "scripts": {
32
- "build": "nx build experience-design-system-cli && BINDIR=$(dirname $(which node)) && for cmd in exo experiences experience-design-system-cli; do ln -sf \"$(pwd)/bin/cli.js\" \"$BINDIR/$cmd\"; done",
32
+ "build": "nx build experience-design-system-cli",
33
33
  "typecheck": "nx typecheck experience-design-system-cli",
34
34
  "clean": "nx clean experience-design-system-cli",
35
35
  "test": "nx test experience-design-system-cli",
package/dist/src/index.js CHANGED
@@ -8472,230 +8472,6 @@ 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/contentful-type-map.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_contentful_type_map = __esm({
8593
- "packages/experience-design-system-cli/src/session/core/cdf/contentful-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
-
8699
8475
  // packages/experience-design-system-cli/src/session/session-id.ts
8700
8476
  var session_id_exports = {};
8701
8477
  __export(session_id_exports, {
@@ -8920,61 +8696,77 @@ var init_session_id = __esm({
8920
8696
  }
8921
8697
  });
8922
8698
 
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 };
8699
+ // packages/experience-design-system-cli/src/session/source-excerpt.ts
8700
+ function escapeForRegExp(value) {
8701
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
8935
8702
  }
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();
8942
- }
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");
8703
+ function identifierPattern(name) {
8704
+ return new RegExp(`(?<![A-Za-z0-9_$])${escapeForRegExp(name)}(?![A-Za-z0-9_$])`);
8963
8705
  }
8964
- var init_input_hash = __esm({
8965
- "packages/experience-design-system-cli/src/session/core/components/input-hash.ts"() {
8966
- "use strict";
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: [] };
8967
8727
  }
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");
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;
8755
+ }
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 };
8974
8763
  }
8975
- var init_input_hash2 = __esm({
8976
- "packages/experience-design-system-cli/src/session/core/tokens/input-hash.ts"() {
8764
+ var ELLIPSIS_MARKER, TRUNCATED_MARKER;
8765
+ var init_source_excerpt = __esm({
8766
+ "packages/experience-design-system-cli/src/session/source-excerpt.ts"() {
8977
8767
  "use strict";
8768
+ ELLIPSIS_MARKER = "/* \u2026 */";
8769
+ TRUNCATED_MARKER = "/* truncated */";
8978
8770
  }
8979
8771
  });
8980
8772
 
@@ -8985,11 +8777,11 @@ __export(cache_keys_exports, {
8985
8777
  hashFile: () => hashFile,
8986
8778
  hashPromptForSkill: () => hashPromptForSkill
8987
8779
  });
8988
- import { createHash as createHash4 } from "node:crypto";
8780
+ import { createHash } from "node:crypto";
8989
8781
  import { readFile as readFile6 } from "node:fs/promises";
8990
8782
  import { resolve as resolve6 } from "node:path";
8991
8783
  function hashContent(content) {
8992
- return createHash4("sha256").update(content).digest("hex");
8784
+ return createHash("sha256").update(content).digest("hex");
8993
8785
  }
8994
8786
  async function hashFile(filePath) {
8995
8787
  const content = await readFile6(filePath, "utf8");
@@ -9011,7 +8803,7 @@ var init_cache_keys = __esm({
9011
8803
  import { DatabaseSync } from "node:sqlite";
9012
8804
  import { mkdirSync, readFileSync as readFileSync5 } from "node:fs";
9013
8805
  import { readFile as readFile7 } from "node:fs/promises";
9014
- import { createHash as createHash5 } from "node:crypto";
8806
+ import { createHash as createHash2 } from "node:crypto";
9015
8807
  import { homedir } from "node:os";
9016
8808
  import { dirname as dirname7, resolve as resolve7 } from "node:path";
9017
8809
  function getPipelineDbPath() {
@@ -9542,18 +9334,39 @@ function applyToolCalls(db, sessionId2, componentId, componentName, calls, incom
9542
9334
  }
9543
9335
  return { classified, excluded, slots, warnings };
9544
9336
  }
9545
- function getOrCreateSession(db, sessionFlag, sessionName, hints) {
9546
- return resolveSession(db, sessionFlag, sessionName, hints);
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 };
9547
9354
  }
9548
9355
  function createStep(db, sessionId2, command, inputs) {
9549
9356
  const now = (/* @__PURE__ */ new Date()).toISOString();
9550
9357
  db.exec("BEGIN");
9551
9358
  try {
9552
- markPendingStepsInterrupted(db, sessionId2, command, now);
9553
- const stepId = insertPendingStep(db, sessionId2, command, inputs, now);
9554
- touchSession(db, sessionId2, now);
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);
9555
9368
  db.exec("COMMIT");
9556
- return stepId;
9369
+ return Number(result.lastInsertRowid);
9557
9370
  } catch (e) {
9558
9371
  db.exec("ROLLBACK");
9559
9372
  throw e;
@@ -9563,10 +9376,12 @@ function updateStep(db, stepId, status, outputs, error) {
9563
9376
  const now = (/* @__PURE__ */ new Date()).toISOString();
9564
9377
  db.exec("BEGIN");
9565
9378
  try {
9566
- const stepSessionId = findStepSessionId(db, stepId);
9567
- updateStepResult(db, stepId, status, outputs, error ?? null, now);
9568
- if (stepSessionId) {
9569
- touchSession(db, stepSessionId, now);
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);
9570
9385
  }
9571
9386
  db.exec("COMMIT");
9572
9387
  } catch (e) {
@@ -9993,6 +9808,22 @@ function parseReviewReasons(raw) {
9993
9808
  return [];
9994
9809
  }
9995
9810
  }
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
+ }
9996
9827
  function storeCDFComponents(db, sessionId2, components) {
9997
9828
  const now = (/* @__PURE__ */ new Date()).toISOString();
9998
9829
  const updateComp = db.prepare(
@@ -10085,7 +9916,7 @@ function storeCDFComponents(db, sessionId2, components) {
10085
9916
  }
10086
9917
  }
10087
9918
  } else {
10088
- const componentId = deriveComponentId(key, "generated");
9919
+ const componentId = createHash2("sha256").update(`${key}:generated`).digest("hex").slice(0, 12);
10089
9920
  db.prepare(
10090
9921
  `INSERT INTO raw_components (session_id, component_id, name, source, framework, extracted_at, status, description)
10091
9922
  VALUES (?, ?, ?, '', 'react', ?, 'generated', ?)`
@@ -10351,8 +10182,15 @@ function loadDTCGTokens(db, sessionId2) {
10351
10182
  });
10352
10183
  return { groups, tokens };
10353
10184
  }
10354
- function findLatestSessionForCommand2(db, command) {
10355
- return findLatestSessionForCommand(db, command);
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;
10356
10194
  }
10357
10195
  function seedCDFFromPreviewResponse(db, sessionId2, removedItems) {
10358
10196
  if (removedItems.length === 0) return 0;
@@ -10369,8 +10207,14 @@ function seedCDFFromPreviewResponse(db, sessionId2, removedItems) {
10369
10207
  const contentProps = new Set(item.contentProperties);
10370
10208
  const designProps = new Set(item.designProperties);
10371
10209
  for (const [propName, propSummary] of Object.entries(item.fullProperties)) {
10372
- const cdfType = mapContentfulTypeToCdfType(propSummary.type);
10373
- const cdfCategory = resolveCdfCategory(propSummary.category, propName, contentProps, designProps);
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
+ }
10374
10218
  const result = updateStmt.run(cdfType, cdfCategory, sessionId2, localComponent.component_id, propName);
10375
10219
  totalSeeded += Number(result.changes);
10376
10220
  }
@@ -10400,8 +10244,14 @@ function seedDefaultsFromChangedItems(db, sessionId2, changedItems) {
10400
10244
  const result2 = updateDefaultStmt.run(defaultStr, sessionId2, localComponent.component_id, propName);
10401
10245
  totalSeeded += Number(result2.changes);
10402
10246
  }
10403
- const cdfType = mapContentfulTypeToCdfType(propSummary.type);
10404
- const cdfCategory = resolveCdfCategory(propSummary.category, propName, contentProps, designProps);
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
+ }
10405
10255
  const result = updateCDFStmt.run(cdfType, cdfCategory, sessionId2, localComponent.component_id, propName);
10406
10256
  totalSeeded += Number(result.changes);
10407
10257
  }
@@ -10425,6 +10275,48 @@ function backfillUnclassifiedProps(db, sessionId2) {
10425
10275
  ).run(sessionId2, sessionId2);
10426
10276
  return Number(withCategory.changes) + Number(withoutCategory.changes);
10427
10277
  }
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
+ }
10428
10320
  function computeMapTokensInputHash(db, sessionId2, componentSourceRefs = []) {
10429
10321
  const props = db.prepare(
10430
10322
  `SELECT rc.name AS component_name, rp.name AS prop_name, rp.cdf_token_kind, rp.default_value
@@ -10454,7 +10346,7 @@ function computeMapTokensInputHash(db, sessionId2, componentSourceRefs = []) {
10454
10346
  usesNotShown: [...ref.usesNotShown ?? []].sort()
10455
10347
  }))
10456
10348
  };
10457
- return createHash5("sha256").update(JSON.stringify(payload)).digest("hex");
10349
+ return createHash2("sha256").update(JSON.stringify(payload)).digest("hex");
10458
10350
  }
10459
10351
  function lookupCache(db, inputHash, entityType, entityId, promptHash = "") {
10460
10352
  const row = db.prepare(
@@ -10762,19 +10654,8 @@ var SCHEMA, MAX_COMPONENT_SOURCE_CHARS, MAX_SIBLING_FILES, MAX_SIBLING_SNIPPET_C
10762
10654
  var init_db = __esm({
10763
10655
  "packages/experience-design-system-cli/src/session/db.ts"() {
10764
10656
  "use strict";
10657
+ init_session_id();
10765
10658
  init_source_excerpt();
10766
- init_component_id();
10767
- init_contentful_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_contentful_type_map();
10778
10659
  SCHEMA = `
10779
10660
  PRAGMA journal_mode = WAL;
10780
10661
  PRAGMA foreign_keys = ON;
@@ -11051,11 +10932,11 @@ var init_persistence = __esm({
11051
10932
  });
11052
10933
 
11053
10934
  // packages/experience-design-system-cli/src/analyze/select/parser.ts
11054
- import { createHash as createHash6 } from "node:crypto";
10935
+ import { createHash as createHash3 } from "node:crypto";
11055
10936
  import { access as access2 } from "node:fs/promises";
11056
10937
  import { isAbsolute, relative, resolve as resolve9 } from "node:path";
11057
10938
  function createComponentId(name, resolvedSourcePath) {
11058
- const sourceHash = createHash6("sha256").update(`${name}:${resolvedSourcePath}`).digest("hex").slice(0, 12);
10939
+ const sourceHash = createHash3("sha256").update(`${name}:${resolvedSourcePath}`).digest("hex").slice(0, 12);
11059
10940
  return `${name}-${sourceHash}`;
11060
10941
  }
11061
10942
  async function resolveComponentSourcePath(source, reviewRoot) {
@@ -17483,7 +17364,7 @@ var init_save_conflict = __esm({
17483
17364
  });
17484
17365
 
17485
17366
  // packages/experience-design-system-cli/src/runs/fingerprint.ts
17486
- import { createHash as createHash7 } from "node:crypto";
17367
+ import { createHash as createHash4 } from "node:crypto";
17487
17368
  import { readFile as readFile24, stat as stat5 } from "node:fs/promises";
17488
17369
  import { resolve as resolve23 } from "node:path";
17489
17370
  function rowField(row, key) {
@@ -17491,7 +17372,7 @@ function rowField(row, key) {
17491
17372
  return typeof v === "string" ? v : null;
17492
17373
  }
17493
17374
  function sha256Hex(buf) {
17494
- return createHash7("sha256").update(buf).digest("hex");
17375
+ return createHash4("sha256").update(buf).digest("hex");
17495
17376
  }
17496
17377
  async function buildSourceFingerprint(opts) {
17497
17378
  const rows = opts.db.prepare("SELECT name, source_path FROM raw_components WHERE session_id = ?").all(opts.extractSessionId);
@@ -30577,7 +30458,7 @@ function resolveRationaleSession(sessionFlag, dbPath) {
30577
30458
  }
30578
30459
  return sessionFlag;
30579
30460
  }
30580
- const latest = findLatestSessionForCommand2(db, "analyze select");
30461
+ const latest = findLatestSessionForCommand(db, "analyze select");
30581
30462
  if (!latest) {
30582
30463
  throw new Error(
30583
30464
  `No completed 'analyze select' session found. Run 'analyze select-agent' first, or pass --session <id>.`
@@ -33448,7 +33329,7 @@ function registerGenerateCommand(program) {
33448
33329
  // packages/experience-design-system-cli/src/program.ts
33449
33330
  init_command();
33450
33331
 
33451
- // packages/experience-design-system-cli/src/session/cli.ts
33332
+ // packages/experience-design-system-cli/src/session/command.ts
33452
33333
  init_db();
33453
33334
 
33454
33335
  // packages/experience-design-system-cli/src/session/stats.ts
@@ -33652,7 +33533,7 @@ function migrateImportDb(db, _now) {
33652
33533
  }
33653
33534
  }
33654
33535
 
33655
- // packages/experience-design-system-cli/src/session/cli.ts
33536
+ // packages/experience-design-system-cli/src/session/command.ts
33656
33537
  function parseDuration(str) {
33657
33538
  const m = /^(\d+)([dwmy])$/.exec(str);
33658
33539
  if (!m) return null;
@@ -34199,10 +34080,10 @@ async function assertOutIsNotDirectory(outPath) {
34199
34080
  if (s.isDirectory()) await die3(`Error: --out must be a file path, not a directory: ${outPath}`);
34200
34081
  }
34201
34082
  }
34202
- async function resolveSession2(sessionFlag, command) {
34083
+ async function resolveSession(sessionFlag, command) {
34203
34084
  const db = openPipelineDb();
34204
34085
  try {
34205
- const sessionId2 = sessionFlag ?? findLatestSessionForCommand2(db, command);
34086
+ const sessionId2 = sessionFlag ?? findLatestSessionForCommand(db, command);
34206
34087
  if (!sessionId2) {
34207
34088
  const hint = command === "generate components" ? "generate components" : "generate tokens";
34208
34089
  return await die3(`Error: no completed ${hint} session found. Run ${hint} first, or pass --session <id>.`);
@@ -34252,7 +34133,7 @@ function registerPrintCommand(program) {
34252
34133
  ).action(async (opts) => {
34253
34134
  const outPath = resolve19(opts.out);
34254
34135
  await assertOutIsNotDirectory(outPath);
34255
- const sessionId2 = await resolveSession2(opts.session, "generate components");
34136
+ const sessionId2 = await resolveSession(opts.session, "generate components");
34256
34137
  await bindAnalyticsSessionId(sessionId2);
34257
34138
  const db = openPipelineDb();
34258
34139
  let components;
@@ -34309,7 +34190,7 @@ function registerPrintCommand(program) {
34309
34190
  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) => {
34310
34191
  const outPath = resolve19(opts.out);
34311
34192
  await assertOutIsNotDirectory(outPath);
34312
- const sessionId2 = await resolveSession2(opts.session, "generate tokens");
34193
+ const sessionId2 = await resolveSession(opts.session, "generate tokens");
34313
34194
  await bindAnalyticsSessionId(sessionId2);
34314
34195
  const db = openPipelineDb();
34315
34196
  let result;
@@ -34626,7 +34507,7 @@ async function runMapTokens(opts) {
34626
34507
  const resultAgent = configuredAgent ?? "skipped";
34627
34508
  const db = openPipelineDb();
34628
34509
  try {
34629
- const sessionId2 = opts.session ?? findLatestSessionForCommand2(db, "generate components");
34510
+ const sessionId2 = opts.session ?? findLatestSessionForCommand(db, "generate components");
34630
34511
  if (!sessionId2) {
34631
34512
  die2(
34632
34513
  "Error: no completed generate components session found. Run generate components first, or pass --session <id>."
@@ -35011,7 +34892,7 @@ async function runPipeline(opts, progressWriter, cliPathOverride) {
35011
34892
  status: "skipped",
35012
34893
  reason: "--skip-analyze"
35013
34894
  });
35014
- const prior = findLatestSessionForCommand2(db, "analyze extract");
34895
+ const prior = findLatestSessionForCommand(db, "analyze extract");
35015
34896
  extractSessionId = prior ?? null;
35016
34897
  } else {
35017
34898
  const stepId = createStep(db, sessionId2, "analyze extract", {
@@ -35045,7 +34926,7 @@ async function runPipeline(opts, progressWriter, cliPathOverride) {
35045
34926
  db.close();
35046
34927
  return { session: sessionId2, project: projectRoot, steps };
35047
34928
  }
35048
- extractSessionId = findLatestSessionForCommand2(db, "analyze extract") ?? null;
34929
+ extractSessionId = findLatestSessionForCommand(db, "analyze extract") ?? null;
35049
34930
  const componentMatch = /Extracted (\d+) component/.exec(r.stderr);
35050
34931
  const componentCount = componentMatch ? Number(componentMatch[1]) : 0;
35051
34932
  updateStep(db, stepId, "complete", {
@@ -4,12 +4,6 @@ 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 { mapContentfulTypeToCdfType, resolveCdfCategory } from './core/cdf/contentful-type-map.js';
13
7
  export type StepStatus = 'pending' | 'complete' | 'failed' | 'interrupted';
14
8
  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';
15
9
  export interface SessionRow {
@@ -92,9 +86,17 @@ export interface ComponentRationale {
92
86
  }
93
87
  export declare function loadComponentRationale(db: DatabaseSync, sessionId: string, componentName: string): ComponentRationale | null;
94
88
  export declare function applyToolCalls(db: DatabaseSync, sessionId: string, componentId: string, componentName: string, calls: ToolCall[], incomingWarnings: string[]): ApplyToolCallsResult;
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;
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;
98
100
  export declare function createStep(db: DatabaseSync, sessionId: string, command: CommandName, inputs: Record<string, string>): number;
99
101
  export declare function updateStep(db: DatabaseSync, stepId: number, status: 'complete' | 'failed', outputs: Record<string, string>, error?: string): void;
100
102
  export declare function storeRawComponents(db: DatabaseSync, sessionId: string, components: RawComponentDefinition[], options?: {
@@ -168,6 +170,8 @@ export interface CacheEntry {
168
170
  createdAt: string;
169
171
  updatedAt: string;
170
172
  }
173
+ export declare function computeComponentInputHash(component: RawComponentWithId): string;
174
+ export declare function computeTokenInputHash(rawTokenContent: string): string;
171
175
  export declare function computeMapTokensInputHash(db: DatabaseSync, sessionId: string, componentSourceRefs?: readonly ComponentSourceRef[]): string;
172
176
  export declare function lookupCache(db: DatabaseSync, inputHash: string, entityType: CacheEntityType, entityId: string, promptHash?: string): CacheEntry | null;
173
177
  export declare function lookupCacheByEntity(db: DatabaseSync, entityType: CacheEntityType, entityId: string): CacheEntry | null;
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-413e3a3.0",
3
+ "version": "2.32.1-dev-build-23e5797.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-413e3a3.0",
44
- "@contentful/experience-design-system-types": "2.32.1-dev-build-413e3a3.0"
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"
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-413e3a3.0",
57
- "@contentful/experience-design-system-extraction": "2.32.1-dev-build-413e3a3.0",
58
- "@contentful/experience-design-system-generation": "2.32.1-dev-build-413e3a3.0"
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"
59
59
  },
60
60
  "repository": {
61
61
  "type": "git",
@@ -70,7 +70,7 @@
70
70
  "node": ">=24"
71
71
  },
72
72
  "scripts": {
73
- "build": "nx build experience-design-system-cli && BINDIR=$(dirname $(which node)) && for cmd in exo experiences experience-design-system-cli; do ln -sf \"$(pwd)/bin/cli.js\" \"$BINDIR/$cmd\"; done",
73
+ "build": "nx build experience-design-system-cli",
74
74
  "typecheck": "nx typecheck experience-design-system-cli",
75
75
  "clean": "nx clean experience-design-system-cli",
76
76
  "test": "nx test experience-design-system-cli",
@@ -1,15 +0,0 @@
1
- export type CdfCategory = 'content' | 'design' | 'state';
2
- /**
3
- * Translate a Contentful CMA type name into the CLI's internal CDF type name.
4
- * The vocabularies overlap but differ (e.g. Contentful "symbol" → CDF "enum",
5
- * Contentful "text" → CDF "string"). Unknown inputs default to "string".
6
- */
7
- export declare function mapContentfulTypeToCdfType(contentfulType: string): string;
8
- /**
9
- * Decide which CDF category (`content` | `design` | `state`) a prop belongs to.
10
- *
11
- * Trusts a valid Contentful-provided category when present. Otherwise, falls
12
- * back to per-component prop-name classification (contentProperties /
13
- * designProperties from the same Contentful response), defaulting to `state`.
14
- */
15
- export declare function resolveCdfCategory(contentfulCategory: string | null | undefined, propName: string, contentProps: Set<string>, designProps: Set<string>): CdfCategory;
@@ -1 +0,0 @@
1
- export declare function deriveComponentId(name: string, source: string): string;
@@ -1,5 +0,0 @@
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;
@@ -1 +0,0 @@
1
- export declare function groupBy<T>(items: T[], key: (item: T) => string): Map<string, T[]>;
@@ -1 +0,0 @@
1
- export declare function computeTokenInputHash(rawTokenContent: string): string;
@@ -1,11 +0,0 @@
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;
@@ -1,3 +0,0 @@
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;
@@ -1,2 +0,0 @@
1
- import type { DatabaseSync } from 'node:sqlite';
2
- export declare function findStepSessionId(db: DatabaseSync, stepId: number): string | null;
@@ -1,5 +0,0 @@
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;
@@ -1,21 +0,0 @@
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;
File without changes