@contentful/experience-design-system-cli 2.27.3-dev-build-7b25e3f.0 → 2.27.3-dev-build-90d1ffe.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.27.3-dev-build-7b25e3f.0",
3
+ "version": "2.27.3-dev-build-90d1ffe.0",
4
4
  "description": "Contentful Experiences design system import CLI",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/dist/src/index.js CHANGED
@@ -16207,25 +16207,104 @@ var init_path_prompt = __esm({
16207
16207
  }
16208
16208
  });
16209
16209
 
16210
+ // packages/experience-design-system-cli/src/runs/picker-labels.ts
16211
+ function pathSegments(projectPath) {
16212
+ const normalised = projectPath.replace(/\\/g, "/");
16213
+ return normalised.split("/").filter((s) => s.length > 0);
16214
+ }
16215
+ function disambiguateLabels(runs) {
16216
+ const entries = runs.map((r) => ({
16217
+ id: r.id,
16218
+ segments: pathSegments(r.projectPath),
16219
+ level: 1
16220
+ }));
16221
+ const labelAt = (e) => {
16222
+ if (e.segments.length === 0) return e.id;
16223
+ const take = Math.min(e.level, e.segments.length);
16224
+ return e.segments.slice(-take).join("/");
16225
+ };
16226
+ let stable = false;
16227
+ while (!stable) {
16228
+ stable = true;
16229
+ const groups = /* @__PURE__ */ new Map();
16230
+ for (const e of entries) {
16231
+ const key = labelAt(e);
16232
+ const arr = groups.get(key);
16233
+ if (arr) arr.push(e);
16234
+ else groups.set(key, [e]);
16235
+ }
16236
+ for (const group of groups.values()) {
16237
+ if (group.length < 2) continue;
16238
+ const anyExpandable = group.some((e) => e.level < e.segments.length);
16239
+ if (!anyExpandable) continue;
16240
+ for (const e of group) {
16241
+ if (e.level < e.segments.length) e.level += 1;
16242
+ }
16243
+ stable = false;
16244
+ }
16245
+ }
16246
+ const result = /* @__PURE__ */ new Map();
16247
+ const orderedGroups = [];
16248
+ const byLabel = /* @__PURE__ */ new Map();
16249
+ for (const e of entries) {
16250
+ const key = labelAt(e);
16251
+ const existing = byLabel.get(key);
16252
+ if (existing) {
16253
+ existing.push(e);
16254
+ } else {
16255
+ const fresh = [e];
16256
+ byLabel.set(key, fresh);
16257
+ orderedGroups.push(fresh);
16258
+ }
16259
+ }
16260
+ for (const group of orderedGroups) {
16261
+ if (group.length === 1) {
16262
+ const only = group[0];
16263
+ result.set(only.id, labelAt(only));
16264
+ } else {
16265
+ group.forEach((e, i) => {
16266
+ result.set(e.id, `${labelAt(e)} (#${i + 1})`);
16267
+ });
16268
+ }
16269
+ }
16270
+ return result;
16271
+ }
16272
+ function pad22(n) {
16273
+ return String(n).padStart(2, "0");
16274
+ }
16275
+ function formatRelativeTime(iso, now = /* @__PURE__ */ new Date()) {
16276
+ const then = new Date(iso);
16277
+ if (Number.isNaN(then.getTime())) return iso;
16278
+ const diffMs = now.getTime() - then.getTime();
16279
+ const diffSec = Math.floor(diffMs / 1e3);
16280
+ if (diffSec < 60) return "just now";
16281
+ const diffMin = Math.floor(diffSec / 60);
16282
+ if (diffMin < 60) return `${diffMin}m ago`;
16283
+ const diffHr = Math.floor(diffMin / 60);
16284
+ if (diffHr < 24) return `${diffHr}h ago`;
16285
+ const diffDay = Math.floor(diffHr / 24);
16286
+ if (diffDay < 7) return `${diffDay}d ago`;
16287
+ return `${then.getFullYear()}-${pad22(then.getMonth() + 1)}-${pad22(then.getDate())} ${pad22(then.getHours())}:${pad22(then.getMinutes())}`;
16288
+ }
16289
+ var init_picker_labels = __esm({
16290
+ "packages/experience-design-system-cli/src/runs/picker-labels.ts"() {
16291
+ "use strict";
16292
+ }
16293
+ });
16294
+
16210
16295
  // packages/experience-design-system-cli/src/runs/run-picker.tsx
16211
- import { useState as useState10 } from "react";
16296
+ import { useMemo as useMemo2, useState as useState10 } from "react";
16212
16297
  import { Box as Box20, Text as Text20 } from "ink";
16213
16298
  import { jsx as jsx20, jsxs as jsxs20 } from "react/jsx-runtime";
16214
- function formatCreatedAt(iso) {
16215
- const d = new Date(iso);
16216
- if (Number.isNaN(d.getTime())) return iso;
16217
- const yyyy = d.getFullYear();
16218
- const mm = String(d.getMonth() + 1).padStart(2, "0");
16219
- const dd = String(d.getDate()).padStart(2, "0");
16220
- const hh = String(d.getHours()).padStart(2, "0");
16221
- const mi = String(d.getMinutes()).padStart(2, "0");
16222
- return `${yyyy}-${mm}-${dd} ${hh}:${mi}`;
16223
- }
16224
- function runLine(run) {
16225
- const date = formatCreatedAt(run.createdAt);
16226
- const pushedTag = run.pushedTo ? "pushed" : "not pushed";
16299
+ function pushStatus(run) {
16300
+ if (!run.pushedTo) return "not pushed";
16301
+ return `\u2192 ${run.pushedTo.spaceId}/${run.pushedTo.environmentId}`;
16302
+ }
16303
+ function runLine(run, label) {
16304
+ const when = formatRelativeTime(run.createdAt);
16227
16305
  const count = `${run.componentCount} component${run.componentCount === 1 ? "" : "s"}`;
16228
- return `${run.id} - ${date} - ${run.projectPath} (${count}, ${pushedTag})`;
16306
+ const agent = run.agent ? ` ${run.agent}` : "";
16307
+ return `${label} ${when} ${count} ${pushStatus(run)}${agent}`;
16229
16308
  }
16230
16309
  function ActionScreen({
16231
16310
  runId,
@@ -16293,6 +16372,12 @@ function RunPicker({ runs, staleRunIds, onSelect, onCancel }) {
16293
16372
  const [actionRunId, setActionRunId] = useState10(null);
16294
16373
  const rows = buildRows(runs, expanded);
16295
16374
  const clampedFocus = Math.min(focusIdx, rows.length - 1);
16375
+ const visibleRunLabels = useMemo2(() => {
16376
+ const visibleRuns = rows.filter((r) => r.kind === "run").map((r) => ({ id: r.run.id, projectPath: r.run.projectPath }));
16377
+ return disambiguateLabels(visibleRuns);
16378
+ }, [rows]);
16379
+ const focusedRow = rows[clampedFocus];
16380
+ const focusedRunId = focusedRow?.kind === "run" ? focusedRow.run.id : null;
16296
16381
  const selectRow = (row) => {
16297
16382
  if (row.kind === "show-all") {
16298
16383
  setExpanded(true);
@@ -16355,9 +16440,10 @@ function RunPicker({ runs, staleRunIds, onSelect, onCancel }) {
16355
16440
  const cursor = focused ? ">" : " ";
16356
16441
  if (row.kind === "run") {
16357
16442
  const isStale = staleRunIds?.has(row.run.id) ?? false;
16443
+ const label = visibleRunLabels.get(row.run.id) ?? row.run.projectPath;
16358
16444
  return /* @__PURE__ */ jsxs20(Box20, { gap: 1, children: [
16359
16445
  /* @__PURE__ */ jsx20(Text20, { color, children: cursor }),
16360
- /* @__PURE__ */ jsx20(Text20, { color, children: runLine(row.run) }),
16446
+ /* @__PURE__ */ jsx20(Text20, { color, children: runLine(row.run, label) }),
16361
16447
  isStale ? /* @__PURE__ */ jsx20(Text20, { dimColor: true, children: " (stale)" }) : null
16362
16448
  ] }, `run-${row.run.id}`);
16363
16449
  }
@@ -16376,6 +16462,10 @@ function RunPicker({ runs, staleRunIds, onSelect, onCancel }) {
16376
16462
  /* @__PURE__ */ jsx20(Text20, { color, children: "[n] Start a new run" })
16377
16463
  ] }, "new");
16378
16464
  }) }),
16465
+ focusedRunId ? /* @__PURE__ */ jsx20(Box20, { marginTop: 1, children: /* @__PURE__ */ jsxs20(Text20, { dimColor: true, children: [
16466
+ "ID: ",
16467
+ focusedRunId
16468
+ ] }) }) : null,
16379
16469
  /* @__PURE__ */ jsxs20(Box20, { gap: 3, marginTop: 1, children: [
16380
16470
  /* @__PURE__ */ jsx20(Text20, { dimColor: true, children: "[j/k] Navigate" }),
16381
16471
  /* @__PURE__ */ jsx20(Text20, { dimColor: true, children: "[Enter] Select" }),
@@ -16389,6 +16479,7 @@ var init_run_picker = __esm({
16389
16479
  "packages/experience-design-system-cli/src/runs/run-picker.tsx"() {
16390
16480
  "use strict";
16391
16481
  init_useImmediateInput();
16482
+ init_picker_labels();
16392
16483
  COLLAPSED_LIMIT = 10;
16393
16484
  COLLAPSE_THRESHOLD = 12;
16394
16485
  ACTION_OPTIONS = [
@@ -17327,7 +17418,7 @@ var init_preview_diff = __esm({
17327
17418
  });
17328
17419
 
17329
17420
  // packages/experience-design-system-cli/src/import/tui/steps/WizardPreviewStep.tsx
17330
- import { useState as useState16, useMemo as useMemo2 } from "react";
17421
+ import { useState as useState16, useMemo as useMemo3 } from "react";
17331
17422
  import { Box as Box28, Text as Text28, useStdout as useStdout3 } from "ink";
17332
17423
  import { Fragment as Fragment9, jsx as jsx28, jsxs as jsxs28 } from "react/jsx-runtime";
17333
17424
  function buildPreviewDiffLines(preview) {
@@ -17433,7 +17524,7 @@ function WizardPreviewStep({
17433
17524
  const { stdout } = useStdout3();
17434
17525
  const terminalRows = stdout?.rows ?? 40;
17435
17526
  const viewportHeight = Math.max(terminalRows - 14, 10);
17436
- const allDiffLines = useMemo2(() => {
17527
+ const allDiffLines = useMemo3(() => {
17437
17528
  if (!diffExpanded) return [];
17438
17529
  return buildPreviewDiffLines(preview).map((line) => ({
17439
17530
  key: line.key,
@@ -19179,12 +19270,12 @@ var init_lineage = __esm({
19179
19270
  });
19180
19271
 
19181
19272
  // packages/experience-design-system-cli/src/import/tui/hooks/useLineage.ts
19182
- import { useMemo as useMemo3 } from "react";
19273
+ import { useMemo as useMemo4 } from "react";
19183
19274
  function useLineage(focusedKey, graph) {
19184
- const graphKey = useMemo3(() => JSON.stringify(graph), [graph]);
19185
- const stableGraph = useMemo3(() => graph, [graphKey]);
19186
- const closures = useMemo3(() => computeAllClosures(stableGraph), [stableGraph]);
19187
- const entries = useMemo3(() => {
19275
+ const graphKey = useMemo4(() => JSON.stringify(graph), [graph]);
19276
+ const stableGraph = useMemo4(() => graph, [graphKey]);
19277
+ const closures = useMemo4(() => computeAllClosures(stableGraph), [stableGraph]);
19278
+ const entries = useMemo4(() => {
19188
19279
  if (!focusedKey) return [];
19189
19280
  const name = focusedKey;
19190
19281
  const tree = buildAncestorTree(name, stableGraph);
@@ -19218,7 +19309,7 @@ function useLineage(focusedKey, graph) {
19218
19309
  }
19219
19310
  return out;
19220
19311
  }, [focusedKey, stableGraph, closures]);
19221
- const jumpables = useMemo3(
19312
+ const jumpables = useMemo4(
19222
19313
  () => entries.map((entry, i) => ({ entry, i })).filter(({ entry }) => entry.kind === "ancestor" || entry.kind === "descendant"),
19223
19314
  [entries]
19224
19315
  );
@@ -19864,7 +19955,7 @@ var init_scope_gate_columns = __esm({
19864
19955
 
19865
19956
  // packages/experience-design-system-cli/src/import/tui/steps/ScopeGateStep.tsx
19866
19957
  import { Box as Box38, Text as Text40, useStdout as useStdout4 } from "ink";
19867
- import React20, { useEffect as useEffect10, useMemo as useMemo4, useRef as useRef4, useState as useState21 } from "react";
19958
+ import React20, { useEffect as useEffect10, useMemo as useMemo5, useRef as useRef4, useState as useState21 } from "react";
19868
19959
  import { Fragment as Fragment11, jsx as jsx41, jsxs as jsxs40 } from "react/jsx-runtime";
19869
19960
  function capReasonForFocusedRow(reason, width) {
19870
19961
  const safeWidth = Math.max(20, width);
@@ -19897,7 +19988,7 @@ function ScopeGateStep({
19897
19988
  }) {
19898
19989
  const { stdout } = useStdout4();
19899
19990
  const totalWidth = stdout?.columns ?? 80;
19900
- const columnPlan = useMemo4(() => computeColumnWidths(totalWidth), [totalWidth]);
19991
+ const columnPlan = useMemo5(() => computeColumnWidths(totalWidth), [totalWidth]);
19901
19992
  const sidebarWidth = columnPlan.main;
19902
19993
  const [userDecisions, setUserDecisions] = useState21(/* @__PURE__ */ new Map());
19903
19994
  const [nav, setNav] = useState21({ cursor: 0, scrollOffset: 0 });
@@ -19932,7 +20023,7 @@ function ScopeGateStep({
19932
20023
  return next;
19933
20024
  });
19934
20025
  };
19935
- const groupedItems = useMemo4(
20026
+ const groupedItems = useMemo5(
19936
20027
  () => components.map((c2) => ({
19937
20028
  key: c2.name,
19938
20029
  entry: toSidebarEntry(c2),
@@ -19940,21 +20031,21 @@ function ScopeGateStep({
19940
20031
  })),
19941
20032
  [components]
19942
20033
  );
19943
- const graph = useMemo4(() => buildComponentGraph(groupedItems), [groupedItems]);
19944
- const slotCycles = useMemo4(() => {
20034
+ const graph = useMemo5(() => buildComponentGraph(groupedItems), [groupedItems]);
20035
+ const slotCycles = useMemo5(() => {
19945
20036
  try {
19946
20037
  return findSlotCycles(graph);
19947
20038
  } catch {
19948
20039
  return [];
19949
20040
  }
19950
20041
  }, [graph]);
19951
- const cycleParticipants = useMemo4(() => {
20042
+ const cycleParticipants = useMemo5(() => {
19952
20043
  const set = /* @__PURE__ */ new Set();
19953
20044
  for (const c2 of slotCycles) for (const n of c2.path) set.add(n);
19954
20045
  return set;
19955
20046
  }, [slotCycles]);
19956
- const cycleUnits = useMemo4(() => buildCycleUnits(slotCycles), [slotCycles]);
19957
- const cyclesJumpables = useMemo4(
20047
+ const cycleUnits = useMemo5(() => buildCycleUnits(slotCycles), [slotCycles]);
20048
+ const cyclesJumpables = useMemo5(
19958
20049
  () => slotCycles.map((c2, i) => ({
19959
20050
  cycleIndex: i,
19960
20051
  jumpTarget: c2.path[0]
@@ -19962,7 +20053,7 @@ function ScopeGateStep({
19962
20053
  [slotCycles]
19963
20054
  );
19964
20055
  const hasCycles = slotCycles.length > 0;
19965
- const closures = useMemo4(() => computeAllClosures(graph), [graph]);
20056
+ const closures = useMemo5(() => computeAllClosures(graph), [graph]);
19966
20057
  const [expandedGroups, setExpandedGroups] = useState21(() => {
19967
20058
  const seed = new Set(closures.keys());
19968
20059
  for (const p of cycleParticipants) seed.add(p);
@@ -19977,7 +20068,7 @@ function ScopeGateStep({
19977
20068
  for (const p of cycleParticipants) seed.add(p);
19978
20069
  setExpandedGroups(seed);
19979
20070
  }, [closures, cycleParticipants]);
19980
- const hasGroupRoots = useMemo4(() => {
20071
+ const hasGroupRoots = useMemo5(() => {
19981
20072
  if (cycleParticipants.size > 0) return true;
19982
20073
  for (const c2 of closures.values()) if (c2.nodes.length > 1) return true;
19983
20074
  return false;
@@ -19990,12 +20081,12 @@ function ScopeGateStep({
19990
20081
  return next;
19991
20082
  });
19992
20083
  };
19993
- const brokenKeys = useMemo4(() => {
20084
+ const brokenKeys = useMemo5(() => {
19994
20085
  const set = /* @__PURE__ */ new Set();
19995
20086
  for (const c2 of components) if (isAiFlagged(c2)) set.add(c2.name);
19996
20087
  return set;
19997
20088
  }, [components]);
19998
- const filterVisibleKeys = useMemo4(() => {
20089
+ const filterVisibleKeys = useMemo5(() => {
19999
20090
  if (jumpFilterTarget) {
20000
20091
  return findAllAncestors2(jumpFilterTarget, graph);
20001
20092
  }
@@ -20011,7 +20102,7 @@ function ScopeGateStep({
20011
20102
  })();
20012
20103
  return intersectFilterKeys(categoryKeys, searchKeys);
20013
20104
  }, [jumpFilterTarget, activeFilters, cycleParticipants, brokenKeys, searchQuery, groupedItems, graph]);
20014
- const visibleRows = useMemo4(
20105
+ const visibleRows = useMemo5(
20015
20106
  () => buildVisibleRows({
20016
20107
  items: groupedItems,
20017
20108
  cycleParticipants,
@@ -20028,19 +20119,19 @@ function ScopeGateStep({
20028
20119
  const currentRow = visibleRows[safeCursor];
20029
20120
  const currentRowKey = currentRow && currentRow.itemIdx >= 0 ? groupedItems[currentRow.itemIdx]?.key : void 0;
20030
20121
  const focusedComponent = currentRowKey ? components.find((c2) => c2.name === currentRowKey) : void 0;
20031
- const selectionStateByKey = useMemo4(() => {
20122
+ const selectionStateByKey = useMemo5(() => {
20032
20123
  const map = /* @__PURE__ */ new Map();
20033
20124
  for (const c2 of components) {
20034
20125
  map.set(c2.name, getState(c2.name));
20035
20126
  }
20036
20127
  return map;
20037
20128
  }, [components, userDecisions]);
20038
- const aiFlaggedByKey = useMemo4(() => {
20129
+ const aiFlaggedByKey = useMemo5(() => {
20039
20130
  const map = /* @__PURE__ */ new Map();
20040
20131
  for (const c2 of components) map.set(c2.name, isAiFlagged(c2));
20041
20132
  return map;
20042
20133
  }, [components]);
20043
- const dimPredicate = useMemo4(
20134
+ const dimPredicate = useMemo5(
20044
20135
  () => buildFlatDimPredicate({
20045
20136
  viewMode: columnOneView,
20046
20137
  searchQuery,
@@ -20113,7 +20204,7 @@ function ScopeGateStep({
20113
20204
  return { cursor: nextCursor, scrollOffset: nextScroll };
20114
20205
  });
20115
20206
  }, [visibleRows]);
20116
- const searchMatches = useMemo4(() => {
20207
+ const searchMatches = useMemo5(() => {
20117
20208
  if (!searchQuery) return [];
20118
20209
  return components.filter((c2) => fuzzyMatches(searchQuery, c2.name)).map((c2) => c2.name);
20119
20210
  }, [components, searchQuery]);
@@ -20509,13 +20600,13 @@ function ScopeGateStep({
20509
20600
  return;
20510
20601
  }
20511
20602
  });
20512
- const includedCount = useMemo4(() => components.filter((c2) => isIncluded(c2.name)).length, [components, userDecisions]);
20603
+ const includedCount = useMemo5(() => components.filter((c2) => isIncluded(c2.name)).length, [components, userDecisions]);
20513
20604
  const hasAnyAi = components.some(isAiFlagged);
20514
20605
  const aiExcludedCount = components.filter(isAiFlagged).length;
20515
20606
  const aiExcludedWithReasons = components.filter(
20516
20607
  (c2) => isAiFlagged(c2) && c2.aiReason !== null && c2.aiReason !== void 0 && c2.aiReason !== ""
20517
20608
  );
20518
- const aiRows = useMemo4(
20609
+ const aiRows = useMemo5(
20519
20610
  () => aiExcludedWithReasons.map((c2) => ({
20520
20611
  label: `${c2.name} \u2014 ${c2.aiReason}`,
20521
20612
  jumpTarget: c2.name
@@ -20526,15 +20617,15 @@ function ScopeGateStep({
20526
20617
  const nothingIncluded = components.length > 0 && components.every((c2) => !isIncluded(c2.name));
20527
20618
  const totalComponents = components.length;
20528
20619
  const totalMatches = searchQuery ? searchMatches.length : 0;
20529
- const addedComponents = useMemo4(
20620
+ const addedComponents = useMemo5(
20530
20621
  () => buildAddedComponentsList(components, selectionStateByKey, cycleParticipants),
20531
20622
  [components, selectionStateByKey, cycleParticipants]
20532
20623
  );
20533
- const addedGroups = useMemo4(
20624
+ const addedGroups = useMemo5(
20534
20625
  () => buildAddedGroupsList(closures, selectionStateByKey, cycleParticipants, cycleUnits),
20535
20626
  [closures, selectionStateByKey, cycleParticipants, cycleUnits]
20536
20627
  );
20537
- const counters = useMemo4(
20628
+ const counters = useMemo5(
20538
20629
  () => computeCounters(components, closures, selectionStateByKey),
20539
20630
  [components, closures, selectionStateByKey]
20540
20631
  );
@@ -20995,7 +21086,7 @@ var init_ScopeGateStep = __esm({
20995
21086
 
20996
21087
  // packages/experience-design-system-cli/src/import/tui/steps/AtomicScopeGateStep.tsx
20997
21088
  import { Box as Box39, Text as Text41, useStdout as useStdout5 } from "ink";
20998
- import React21, { useMemo as useMemo5, useState as useState22 } from "react";
21089
+ import React21, { useMemo as useMemo6, useState as useState22 } from "react";
20999
21090
  import { jsx as jsx42, jsxs as jsxs41 } from "react/jsx-runtime";
21000
21091
  function truncateReason(reason) {
21001
21092
  if (reason === null || reason === void 0 || reason === "") return "<no reason given>";
@@ -21142,7 +21233,7 @@ function AtomicScopeGateStep({
21142
21233
  }
21143
21234
  });
21144
21235
  const total = flatList.length;
21145
- const includedCount = useMemo5(
21236
+ const includedCount = useMemo6(
21146
21237
  () => flatList.filter((c2) => isIncluded(c2)).length,
21147
21238
  [components, userExcluded, userUnExcluded]
21148
21239
  );
@@ -23667,7 +23758,7 @@ var init_history = __esm({
23667
23758
  });
23668
23759
 
23669
23760
  // packages/experience-design-system-cli/src/import/tui/steps/GenerateReviewStep.tsx
23670
- import { useEffect as useEffect13, useMemo as useMemo6, useRef as useRef7, useState as useState26 } from "react";
23761
+ import { useEffect as useEffect13, useMemo as useMemo7, useRef as useRef7, useState as useState26 } from "react";
23671
23762
  import { Box as Box44, Text as Text46, useStdout as useStdout6 } from "ink";
23672
23763
  import { Fragment as Fragment14, jsx as jsx47, jsxs as jsxs46 } from "react/jsx-runtime";
23673
23764
  function sortComponentsForSidebar2(components, cycleParticipants) {
@@ -23963,12 +24054,12 @@ function GenerateReviewStep({
23963
24054
  } catch {
23964
24055
  }
23965
24056
  };
23966
- const componentGraph = useMemo6(() => buildComponentGraph(components), [components]);
23967
- const sidebarGraph = useMemo6(
24057
+ const componentGraph = useMemo7(() => buildComponentGraph(components), [components]);
24058
+ const sidebarGraph = useMemo7(
23968
24059
  () => buildComponentGraph(components, { stripRejectedEdges: true }),
23969
24060
  [components]
23970
24061
  );
23971
- const closures = useMemo6(() => computeAllClosures(componentGraph), [componentGraph]);
24062
+ const closures = useMemo7(() => computeAllClosures(componentGraph), [componentGraph]);
23972
24063
  useEffect13(() => {
23973
24064
  if (seededGroupsRef.current) return;
23974
24065
  if (closures.size === 0 && slotCycles.length === 0) return;
@@ -23977,14 +24068,14 @@ function GenerateReviewStep({
23977
24068
  for (const cyc of slotCycles) for (const p of cyc.path) seed.add(p);
23978
24069
  setExpandedGroups(seed);
23979
24070
  }, [closures, slotCycles]);
23980
- const directIssues = useMemo6(() => {
24071
+ const directIssues = useMemo7(() => {
23981
24072
  const m = /* @__PURE__ */ new Map();
23982
24073
  for (const c2 of components) {
23983
24074
  if (c2.status === "rejected") m.set(c2.key, "error");
23984
24075
  }
23985
24076
  return m;
23986
24077
  }, [components]);
23987
- const cycleView = useMemo6(() => computeCycleView(components), [components]);
24078
+ const cycleView = useMemo7(() => computeCycleView(components), [components]);
23988
24079
  useEffect13(() => {
23989
24080
  const decision = computeAutoRejectDecision({
23990
24081
  loading,
@@ -24094,7 +24185,7 @@ function GenerateReviewStep({
24094
24185
  setLoadError(String(e));
24095
24186
  }
24096
24187
  };
24097
- const groupedItemsMemo = useMemo6(
24188
+ const groupedItemsMemo = useMemo7(
24098
24189
  () => components.map((c2) => ({
24099
24190
  key: c2.key,
24100
24191
  entry: c2.entry,
@@ -24102,12 +24193,12 @@ function GenerateReviewStep({
24102
24193
  })),
24103
24194
  [components, directIssues]
24104
24195
  );
24105
- const brokenKeys = useMemo6(
24196
+ const brokenKeys = useMemo7(
24106
24197
  () => new Set(breakingChanges.map((b) => b.componentName)),
24107
24198
  [breakingChanges]
24108
24199
  );
24109
- const breakingRows = useMemo6(() => buildBreakingRows(breakingChanges), [breakingChanges]);
24110
- const filterVisibleKeys = useMemo6(() => {
24200
+ const breakingRows = useMemo7(() => buildBreakingRows(breakingChanges), [breakingChanges]);
24201
+ const filterVisibleKeys = useMemo7(() => {
24111
24202
  if (jumpFilterTarget) {
24112
24203
  return findAllAncestors2(jumpFilterTarget, sidebarGraph);
24113
24204
  }
@@ -24123,7 +24214,7 @@ function GenerateReviewStep({
24123
24214
  })();
24124
24215
  return intersectFilterKeys(categoryKeys, searchKeys);
24125
24216
  }, [jumpFilterTarget, activeFilters, cycleView, brokenKeys, searchQuery, groupedItemsMemo, sidebarGraph]);
24126
- const visibleRowsMemo = useMemo6(
24217
+ const visibleRowsMemo = useMemo7(
24127
24218
  () => buildVisibleRows({
24128
24219
  items: groupedItemsMemo,
24129
24220
  cycleParticipants: cycleView.structural,
@@ -24134,7 +24225,7 @@ function GenerateReviewStep({
24134
24225
  }),
24135
24226
  [groupedItemsMemo, cycleView, expandedGroups, columnOneView, sidebarGraph, filterVisibleKeys]
24136
24227
  );
24137
- const selectableRowPositions = useMemo6(() => {
24228
+ const selectableRowPositions = useMemo7(() => {
24138
24229
  const out = [];
24139
24230
  for (let i = 0; i < visibleRowsMemo.length; i++) {
24140
24231
  if (visibleRowsMemo[i].itemIdx >= 0) out.push(i);
@@ -24191,7 +24282,7 @@ function GenerateReviewStep({
24191
24282
  db.close();
24192
24283
  }
24193
24284
  }, [selectedIdx, components, extractSessionId]);
24194
- const renderStatusByKey = useMemo6(() => {
24285
+ const renderStatusByKey = useMemo7(() => {
24195
24286
  const merged = /* @__PURE__ */ new Map();
24196
24287
  for (const closure of closures.values()) {
24197
24288
  const per = computeRenderStatuses(closure, directIssues);
@@ -24204,7 +24295,7 @@ function GenerateReviewStep({
24204
24295
  }
24205
24296
  return merged;
24206
24297
  }, [closures, directIssues]);
24207
- const selectionStateByKey = useMemo6(() => {
24298
+ const selectionStateByKey = useMemo7(() => {
24208
24299
  const map = /* @__PURE__ */ new Map();
24209
24300
  for (const c2 of components) {
24210
24301
  if (c2.status === "accepted") map.set(c2.key, "accepted");
@@ -24213,7 +24304,7 @@ function GenerateReviewStep({
24213
24304
  }
24214
24305
  return map;
24215
24306
  }, [components]);
24216
- const searchMatches = useMemo6(() => {
24307
+ const searchMatches = useMemo7(() => {
24217
24308
  if (!searchQuery) return [];
24218
24309
  const out = [];
24219
24310
  for (const pos of selectableRowPositions) {
@@ -24223,7 +24314,7 @@ function GenerateReviewStep({
24223
24314
  }
24224
24315
  return out;
24225
24316
  }, [searchQuery, selectableRowPositions, visibleRowsMemo, components]);
24226
- const searchMatchCount = useMemo6(() => {
24317
+ const searchMatchCount = useMemo7(() => {
24227
24318
  if (searchMatches.length === 0) return 0;
24228
24319
  const seen = /* @__PURE__ */ new Set();
24229
24320
  for (const pos of searchMatches) {
@@ -24232,7 +24323,7 @@ function GenerateReviewStep({
24232
24323
  }
24233
24324
  return seen.size;
24234
24325
  }, [searchMatches, visibleRowsMemo]);
24235
- const dimPredicate = useMemo6(
24326
+ const dimPredicate = useMemo7(
24236
24327
  () => buildFlatDimPredicate({
24237
24328
  viewMode: columnOneView,
24238
24329
  searchQuery,
@@ -24300,7 +24391,7 @@ function GenerateReviewStep({
24300
24391
  setDraftValue("");
24301
24392
  setSaveError(null);
24302
24393
  };
24303
- const breakEdges = useMemo6(() => {
24394
+ const breakEdges = useMemo7(() => {
24304
24395
  const cycle = slotCycles[cyclesCursor];
24305
24396
  if (!cycle) return [];
24306
24397
  return enumerateCycleBreaks(cycle, components);
@@ -27467,6 +27558,19 @@ If using a custom --host, make sure the space exists on that host.`
27467
27558
  summary
27468
27559
  };
27469
27560
  }
27561
+ const pushSucceeded = pushResult.componentTypes.failed === 0 && pushResult.designTokens.failed === 0 && operation.sys.status !== "failed";
27562
+ if (pushSucceeded && state.lastRunId) {
27563
+ try {
27564
+ await updateRun(state.lastRunId, {
27565
+ pushedTo: { spaceId, environmentId, host: resolvedHost }
27566
+ });
27567
+ } catch (err) {
27568
+ process.stderr.write(
27569
+ `Warning: failed to record push target on run: ${err instanceof Error ? err.message : String(err)}
27570
+ `
27571
+ );
27572
+ }
27573
+ }
27470
27574
  update({ step: "done", pushResult });
27471
27575
  } catch (e) {
27472
27576
  let msg;
@@ -0,0 +1,24 @@
1
+ export type LabelInput = {
2
+ id: string;
3
+ projectPath: string;
4
+ };
5
+ /**
6
+ * Map each run to a display label. Labels start as the project path's leaf
7
+ * directory and expand one segment at a time (`<parent>/<leaf>`,
8
+ * `<gp>/<parent>/<leaf>`, …) until every label in the input set is unique.
9
+ * When two rows share the exact same absolute path, the collision is broken
10
+ * with numeric suffixes (`(#1)`, `(#2)`, …) in input order.
11
+ */
12
+ export declare function disambiguateLabels(runs: readonly LabelInput[]): Map<string, string>;
13
+ /**
14
+ * Format an ISO-8601 timestamp relative to `now`. Buckets:
15
+ * < 60s → "just now"
16
+ * < 60 min → "Nm ago"
17
+ * < 24 h → "Nh ago"
18
+ * < 7 days → "Nd ago"
19
+ * otherwise → "YYYY-MM-DD HH:MM" (local time)
20
+ *
21
+ * Future timestamps (created after `now`) also render as "just now" — they
22
+ * only occur with clock skew and the delta is not worth surfacing.
23
+ */
24
+ export declare function formatRelativeTime(iso: string, now?: Date): string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contentful/experience-design-system-cli",
3
- "version": "2.27.3-dev-build-7b25e3f.0",
3
+ "version": "2.27.3-dev-build-90d1ffe.0",
4
4
  "description": "Contentful Experiences design system import CLI",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -39,7 +39,7 @@
39
39
  "svelte": "^5.56.4",
40
40
  "ts-morph": "^27.0.2",
41
41
  "typescript": "^5.9.3",
42
- "@contentful/experience-design-system-types": "2.27.3-dev-build-7b25e3f.0"
42
+ "@contentful/experience-design-system-types": "2.27.3-dev-build-90d1ffe.0"
43
43
  },
44
44
  "devDependencies": {
45
45
  "@tsconfig/node24": "^24.0.4",
@@ -51,9 +51,9 @@
51
51
  "ink-testing-library": "^4.0.0",
52
52
  "typescript-eslint": "^8.67.0",
53
53
  "vitest": "^4.0.16",
54
- "@contentful/experience-design-system-extraction": "2.27.3-dev-build-7b25e3f.0",
55
- "@contentful/experience-design-system-generation": "2.27.3-dev-build-7b25e3f.0",
56
- "@contentful/experience-design-system-client": "2.27.3-dev-build-7b25e3f.0"
54
+ "@contentful/experience-design-system-extraction": "2.27.3-dev-build-90d1ffe.0",
55
+ "@contentful/experience-design-system-generation": "2.27.3-dev-build-90d1ffe.0",
56
+ "@contentful/experience-design-system-client": "2.27.3-dev-build-90d1ffe.0"
57
57
  },
58
58
  "repository": {
59
59
  "type": "git",