@contentful/experience-design-system-cli 2.42.1-dev-build-1c5e1331.0 → 2.42.1-dev-build-774b3e20.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/app.js CHANGED
@@ -3054,6 +3054,19 @@ import { Box as Box8, Text as Text8 } from "ink";
3054
3054
  import { ProgressBar, Spinner, ThemeProvider } from "@inkjs/ui";
3055
3055
 
3056
3056
  // packages/experience-design-system-cli/src/tui/import/shared/running-step/logic.ts
3057
+ function lineState(line) {
3058
+ if (line.state) return line.state;
3059
+ return line.complete ? "done" : "running";
3060
+ }
3061
+ function formatDuration(ms) {
3062
+ return ms < 1e3 ? "<1s" : formatElapsed(Math.round(ms / 1e3));
3063
+ }
3064
+ function trackFinished(previous, rows, elapsedMs) {
3065
+ return rows.map((row, index) => previous[index] ?? (lineState(row) === "running" ? void 0 : elapsedMs));
3066
+ }
3067
+ function withTimes(rows, rowMs) {
3068
+ return rows.map((row, index) => rowMs[index] === void 0 ? row : { ...row, ms: rowMs[index] });
3069
+ }
3057
3070
  function progressPercent(progress) {
3058
3071
  if (progress.total <= 0) return 0;
3059
3072
  return Math.min(100, Math.max(0, Math.round(progress.done / progress.total * 100)));
@@ -3089,6 +3102,9 @@ function useElapsed() {
3089
3102
 
3090
3103
  // packages/experience-design-system-cli/src/tui/import/shared/running-step/running-step.tsx
3091
3104
  import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
3105
+ var STATE_ICON = { done: "\u2713", warning: "!", failed: "\u2717" };
3106
+ var STATE_COLOR = { done: PALETTE.success, warning: PALETTE.warning, failed: PALETTE.error };
3107
+ var textColor = (state2) => state2 === "warning" || state2 === "failed" ? STATE_COLOR[state2] : PALETTE.muted;
3092
3108
  function Line({ line }) {
3093
3109
  if (line.progress) {
3094
3110
  return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", gap: 1, children: [
@@ -3100,12 +3116,14 @@ function Line({ line }) {
3100
3116
  line.progress.total
3101
3117
  ] })
3102
3118
  ] }),
3103
- /* @__PURE__ */ jsx8(Text8, { color: PALETTE.muted, children: line.text })
3119
+ /* @__PURE__ */ jsx8(Text8, { color: textColor(lineState(line)), children: line.text })
3104
3120
  ] });
3105
3121
  }
3122
+ const state2 = lineState(line);
3106
3123
  return /* @__PURE__ */ jsxs8(Box8, { gap: 1, children: [
3107
- line.complete ? /* @__PURE__ */ jsx8(Text8, { color: PALETTE.success, children: "\u2713" }) : /* @__PURE__ */ jsx8(Spinner, {}),
3108
- /* @__PURE__ */ jsx8(Text8, { color: PALETTE.muted, children: line.text })
3124
+ state2 === "running" ? /* @__PURE__ */ jsx8(Spinner, {}) : /* @__PURE__ */ jsx8(Text8, { color: STATE_COLOR[state2], children: STATE_ICON[state2] }),
3125
+ /* @__PURE__ */ jsx8(Text8, { color: textColor(state2), children: line.text }),
3126
+ line.ms !== void 0 && /* @__PURE__ */ jsx8(Text8, { color: PALETTE.muted, children: formatDuration(line.ms) })
3109
3127
  ] });
3110
3128
  }
3111
3129
  function RunningStep({
@@ -18751,7 +18769,7 @@ function plural(count, noun) {
18751
18769
  function compositionDone(progress) {
18752
18770
  return progress.composition === "done" || progress.composition === "cache-hit";
18753
18771
  }
18754
- function progressRows(progress, agent) {
18772
+ function progressRows(progress, agent, rowMs = []) {
18755
18773
  const { scan, composition, selection, existingEntities, tokens } = progress;
18756
18774
  const scanned = scan?.scanned ?? 0;
18757
18775
  const scanComplete = (scan?.total ?? 0) > 0;
@@ -18772,16 +18790,20 @@ function progressRows(progress, agent) {
18772
18790
  if (existingEntities !== "idle") {
18773
18791
  rows.push({
18774
18792
  text: existingEntities === "running" ? "Fetching existing components and tokens..." : existingEntities === "complete" ? "Existing components and tokens ready" : "Existing entities unavailable; continuing without them",
18775
- complete: existingEntities !== "running"
18793
+ complete: existingEntities !== "running",
18794
+ // The import carries on without them, so this is not shown as a success.
18795
+ ...existingEntities === "failed" ? { state: "warning" } : {}
18776
18796
  });
18777
18797
  }
18778
18798
  if (tokens !== "idle") {
18779
18799
  rows.push({
18780
18800
  text: tokens === "complete" ? "Token definitions ready" : tokens === "failed" ? "Token definition generation failed" : `Generating token definitions via ${agent}...`,
18781
- complete: tokens === "complete"
18801
+ complete: tokens === "complete",
18802
+ // A failed job is not still running.
18803
+ ...tokens === "failed" ? { state: "failed" } : {}
18782
18804
  });
18783
18805
  }
18784
- return rows;
18806
+ return withTimes(rows, rowMs);
18785
18807
  }
18786
18808
  function noComponentsMessage(projectPath) {
18787
18809
  return `No components found in ${projectPath}.
@@ -18810,13 +18832,13 @@ function resolveAgentChoice(flag, stored) {
18810
18832
 
18811
18833
  // packages/experience-design-system-cli/src/tui/import/steps/06-extraction/screen.tsx
18812
18834
  import { jsx as jsx16 } from "react/jsx-runtime";
18813
- function ExtractionScreen({ progress, agent }) {
18835
+ function ExtractionScreen({ progress, agent, rowMs }) {
18814
18836
  return /* @__PURE__ */ jsx16(
18815
18837
  RunningStep,
18816
18838
  {
18817
18839
  step: "extraction",
18818
18840
  description: "Extracting context from your source files.",
18819
- lines: progressRows(progress, agent)
18841
+ lines: progressRows(progress, agent, rowMs)
18820
18842
  }
18821
18843
  );
18822
18844
  }
@@ -19245,9 +19267,12 @@ function useExtraction(input) {
19245
19267
  progress: initialProgress({
19246
19268
  hasCredentials: input.credentials !== null,
19247
19269
  hasRawTokens: input.rawTokensPath !== ""
19248
- })
19270
+ }),
19271
+ rowMs: []
19249
19272
  });
19250
19273
  let lastProgress;
19274
+ const startedAt = Date.now();
19275
+ let rowMs = [];
19251
19276
  startDebugRun({
19252
19277
  flow: "import/extraction",
19253
19278
  step: "06-extraction",
@@ -19256,7 +19281,8 @@ function useExtraction(input) {
19256
19281
  });
19257
19282
  void runExtraction(input, (progress) => {
19258
19283
  lastProgress = progress;
19259
- if (current.current === input) setState({ status: "running", progress });
19284
+ rowMs = trackFinished(rowMs, progressRows(progress, input.agent), Date.now() - startedAt);
19285
+ if (current.current === input) setState({ status: "running", progress, rowMs });
19260
19286
  }).then((result) => {
19261
19287
  if (current.current !== input) return;
19262
19288
  void finishDebugRun({
@@ -22181,23 +22207,34 @@ function describeGeneration(input) {
22181
22207
  return `${formatAcceptanceSummary({ accepted: input.acceptedCount, autoRejected: 0 })}
22182
22208
  ${agent} is reading each selected component and writing a Contentful component definition for it.${input.hasTokens ? "\nUsing your design tokens for prop resolution." : ""}`;
22183
22209
  }
22184
- function progressRows2(progress, agent) {
22210
+ function componentsRow(components, name) {
22211
+ if (!components) return { text: `Starting up ${name}...`, complete: false };
22212
+ const { done, total, current, failed } = components;
22213
+ if (total > 0 && done >= total) {
22214
+ return failed > 0 ? {
22215
+ text: `Generated ${total - failed} of ${total} components, ${failed} failed`,
22216
+ complete: false,
22217
+ state: "failed"
22218
+ } : { text: `Generated ${total} component${total === 1 ? "" : "s"}`, complete: true };
22219
+ }
22220
+ return {
22221
+ text: failed > 0 ? `${current} (${failed} failed so far)` : current,
22222
+ complete: false,
22223
+ progress: { done, total },
22224
+ ...failed > 0 ? { state: "warning" } : {}
22225
+ };
22226
+ }
22227
+ function progressRows2(progress, agent, rowMs = []) {
22185
22228
  const name = capitalize(agent);
22186
22229
  const { components, mapTokens } = progress;
22187
- const rows = [
22188
- {
22189
- text: components ? components.current : `Starting up ${name}...`,
22190
- complete: false,
22191
- ...components ? { progress: { done: components.done, total: components.total } } : {}
22192
- }
22193
- ];
22230
+ const rows = [componentsRow(components, name)];
22194
22231
  if (mapTokens !== "idle") {
22195
22232
  rows.push({
22196
22233
  text: mapTokens === "running" ? `Mapping token restrictions via ${name}...` : "Token restrictions ready",
22197
22234
  complete: mapTokens === "complete"
22198
22235
  });
22199
22236
  }
22200
- return rows;
22237
+ return withTimes(rows, rowMs);
22201
22238
  }
22202
22239
 
22203
22240
  // packages/experience-design-system-cli/src/tui/import/steps/08-generation/screen.tsx
@@ -22206,14 +22243,15 @@ function GenerationScreen({
22206
22243
  progress,
22207
22244
  agent,
22208
22245
  acceptedCount,
22209
- hasTokens
22246
+ hasTokens,
22247
+ rowMs
22210
22248
  }) {
22211
22249
  return /* @__PURE__ */ jsx30(
22212
22250
  RunningStep,
22213
22251
  {
22214
22252
  step: "generation",
22215
22253
  description: describeGeneration({ acceptedCount, agent, hasTokens }),
22216
- lines: progressRows2(progress, agent)
22254
+ lines: progressRows2(progress, agent, rowMs)
22217
22255
  }
22218
22256
  );
22219
22257
  }
@@ -22373,11 +22411,17 @@ function appendGeneratePromptOverride(input) {
22373
22411
  return [...input.promptOverrides, `generate=${input.generatePromptPath}`];
22374
22412
  }
22375
22413
  function applyProgressEvent2(event, previous, total) {
22414
+ const failed = previous?.failed ?? 0;
22376
22415
  if (event.kind === "component:started") {
22377
- return { done: previous?.done ?? 0, total: event.total || total, current: event.name };
22416
+ return { done: previous?.done ?? 0, total: event.total || total, current: event.name, failed };
22378
22417
  }
22379
22418
  if (event.kind === "component:completed" || event.kind === "component:failed" || event.kind === "component:cached") {
22380
- return { done: (previous?.done ?? 0) + 1, total: event.total || total, current: event.name };
22419
+ return {
22420
+ done: (previous?.done ?? 0) + 1,
22421
+ total: event.total || total,
22422
+ current: event.name,
22423
+ failed: failed + (event.kind === "component:failed" ? 1 : 0)
22424
+ };
22381
22425
  }
22382
22426
  return previous;
22383
22427
  }
@@ -22392,8 +22436,10 @@ function useGeneration(input) {
22392
22436
  setState(void 0);
22393
22437
  return;
22394
22438
  }
22395
- setState({ status: "running", progress: initialProgress2() });
22439
+ setState({ status: "running", progress: initialProgress2(), rowMs: [] });
22396
22440
  let lastProgress;
22441
+ const startedAt = Date.now();
22442
+ let rowMs = [];
22397
22443
  startDebugRun({
22398
22444
  flow: "import/generation",
22399
22445
  step: "08-generation",
@@ -22402,7 +22448,8 @@ function useGeneration(input) {
22402
22448
  });
22403
22449
  void runGeneration(input, (progress) => {
22404
22450
  lastProgress = progress;
22405
- if (current.current === input) setState({ status: "running", progress });
22451
+ rowMs = trackFinished(rowMs, progressRows2(progress, input.agent), Date.now() - startedAt);
22452
+ if (current.current === input) setState({ status: "running", progress, rowMs });
22406
22453
  }).then((result) => {
22407
22454
  if (current.current !== input) return;
22408
22455
  void finishDebugRun({
@@ -28716,6 +28763,10 @@ function PushingStep({ progress, produced, counts }) {
28716
28763
  "/",
28717
28764
  progress.total,
28718
28765
  " entities"
28766
+ ] }),
28767
+ progress.failed > 0 && /* @__PURE__ */ jsxs43(Text45, { color: PALETTE.error, children: [
28768
+ progress.failed,
28769
+ " failed"
28719
28770
  ] })
28720
28771
  ] }) }),
28721
28772
  showCurrent && /* @__PURE__ */ jsxs43(Box43, { gap: 1, children: [
@@ -29782,7 +29833,9 @@ async function runPush(input, deps, onPatch) {
29782
29833
  const items = op.items ?? [];
29783
29834
  const lastDone = items.length > 0 ? items[items.length - 1] : null;
29784
29835
  const current = lastDone && lastDone.status === "succeeded" ? lastDone.id : null;
29785
- onPatch({ pushProgress: { kind: "progress", processed: done, total: summary.total, current } });
29836
+ onPatch({
29837
+ pushProgress: { kind: "progress", processed: done, total: summary.total, failed: summary.failed, current }
29838
+ });
29786
29839
  }
29787
29840
  safeLog(deps, { pollTick: { attempt: pollCount, status: op.sys.status, summary: op.summary } });
29788
29841
  }
@@ -31828,7 +31881,14 @@ function App({ importOptions, inkClear }) {
31828
31881
  return /* @__PURE__ */ jsx66(ErrorStep, { stepName: extraction.result.step, message: extraction.result.message, onExit: leaveImport });
31829
31882
  }
31830
31883
  if (extraction?.status === "running") {
31831
- return /* @__PURE__ */ jsx66(ExtractionScreen, { progress: extraction.progress, agent: extractionRun.input.agent });
31884
+ return /* @__PURE__ */ jsx66(
31885
+ ExtractionScreen,
31886
+ {
31887
+ progress: extraction.progress,
31888
+ agent: extractionRun.input.agent,
31889
+ rowMs: extraction.rowMs
31890
+ }
31891
+ );
31832
31892
  }
31833
31893
  return /* @__PURE__ */ jsx66(Fragment22, {});
31834
31894
  }
@@ -31857,7 +31917,8 @@ function App({ importOptions, inkClear }) {
31857
31917
  progress: generation.progress,
31858
31918
  agent: scopeRun.input.agent,
31859
31919
  acceptedCount: scopeFlow.decisions.accepted.length,
31860
- hasTokens: scopeRun.extraction.tokensPath !== ""
31920
+ hasTokens: scopeRun.extraction.tokensPath !== "",
31921
+ rowMs: generation.rowMs
31861
31922
  }
31862
31923
  );
31863
31924
  }
package/dist/index.js CHANGED
@@ -20138,6 +20138,19 @@ var init_overview_box = __esm({
20138
20138
  });
20139
20139
 
20140
20140
  // packages/experience-design-system-cli/src/tui/import/shared/running-step/logic.ts
20141
+ function lineState(line) {
20142
+ if (line.state) return line.state;
20143
+ return line.complete ? "done" : "running";
20144
+ }
20145
+ function formatDuration(ms) {
20146
+ return ms < 1e3 ? "<1s" : formatElapsed(Math.round(ms / 1e3));
20147
+ }
20148
+ function trackFinished(previous, rows, elapsedMs) {
20149
+ return rows.map((row, index) => previous[index] ?? (lineState(row) === "running" ? void 0 : elapsedMs));
20150
+ }
20151
+ function withTimes(rows, rowMs) {
20152
+ return rows.map((row, index) => rowMs[index] === void 0 ? row : { ...row, ms: rowMs[index] });
20153
+ }
20141
20154
  function progressPercent(progress) {
20142
20155
  if (progress.total <= 0) return 0;
20143
20156
  return Math.min(100, Math.max(0, Math.round(progress.done / progress.total * 100)));
@@ -20204,12 +20217,14 @@ function Line({ line }) {
20204
20217
  line.progress.total
20205
20218
  ] })
20206
20219
  ] }),
20207
- /* @__PURE__ */ jsx8(Text8, { color: PALETTE.muted, children: line.text })
20220
+ /* @__PURE__ */ jsx8(Text8, { color: textColor(lineState(line)), children: line.text })
20208
20221
  ] });
20209
20222
  }
20223
+ const state2 = lineState(line);
20210
20224
  return /* @__PURE__ */ jsxs8(Box8, { gap: 1, children: [
20211
- line.complete ? /* @__PURE__ */ jsx8(Text8, { color: PALETTE.success, children: "\u2713" }) : /* @__PURE__ */ jsx8(Spinner, {}),
20212
- /* @__PURE__ */ jsx8(Text8, { color: PALETTE.muted, children: line.text })
20225
+ state2 === "running" ? /* @__PURE__ */ jsx8(Spinner, {}) : /* @__PURE__ */ jsx8(Text8, { color: STATE_COLOR[state2], children: STATE_ICON[state2] }),
20226
+ /* @__PURE__ */ jsx8(Text8, { color: textColor(state2), children: line.text }),
20227
+ line.ms !== void 0 && /* @__PURE__ */ jsx8(Text8, { color: PALETTE.muted, children: formatDuration(line.ms) })
20213
20228
  ] });
20214
20229
  }
20215
20230
  function RunningStep({
@@ -20230,6 +20245,7 @@ function RunningStep({
20230
20245
  ] })
20231
20246
  ] });
20232
20247
  }
20248
+ var STATE_ICON, STATE_COLOR, textColor;
20233
20249
  var init_running_step = __esm({
20234
20250
  "packages/experience-design-system-cli/src/tui/import/shared/running-step/running-step.tsx"() {
20235
20251
  "use strict";
@@ -20238,6 +20254,9 @@ var init_running_step = __esm({
20238
20254
  init_theme2();
20239
20255
  init_StepHeader();
20240
20256
  init_use_elapsed();
20257
+ STATE_ICON = { done: "\u2713", warning: "!", failed: "\u2717" };
20258
+ STATE_COLOR = { done: PALETTE.success, warning: PALETTE.warning, failed: PALETTE.error };
20259
+ textColor = (state2) => state2 === "warning" || state2 === "failed" ? STATE_COLOR[state2] : PALETTE.muted;
20241
20260
  }
20242
20261
  });
20243
20262
 
@@ -21535,7 +21554,7 @@ function plural(count, noun) {
21535
21554
  function compositionDone(progress) {
21536
21555
  return progress.composition === "done" || progress.composition === "cache-hit";
21537
21556
  }
21538
- function progressRows(progress, agent) {
21557
+ function progressRows(progress, agent, rowMs = []) {
21539
21558
  const { scan, composition, selection, existingEntities, tokens } = progress;
21540
21559
  const scanned = scan?.scanned ?? 0;
21541
21560
  const scanComplete = (scan?.total ?? 0) > 0;
@@ -21556,16 +21575,20 @@ function progressRows(progress, agent) {
21556
21575
  if (existingEntities !== "idle") {
21557
21576
  rows.push({
21558
21577
  text: existingEntities === "running" ? "Fetching existing components and tokens..." : existingEntities === "complete" ? "Existing components and tokens ready" : "Existing entities unavailable; continuing without them",
21559
- complete: existingEntities !== "running"
21578
+ complete: existingEntities !== "running",
21579
+ // The import carries on without them, so this is not shown as a success.
21580
+ ...existingEntities === "failed" ? { state: "warning" } : {}
21560
21581
  });
21561
21582
  }
21562
21583
  if (tokens !== "idle") {
21563
21584
  rows.push({
21564
21585
  text: tokens === "complete" ? "Token definitions ready" : tokens === "failed" ? "Token definition generation failed" : `Generating token definitions via ${agent}...`,
21565
- complete: tokens === "complete"
21586
+ complete: tokens === "complete",
21587
+ // A failed job is not still running.
21588
+ ...tokens === "failed" ? { state: "failed" } : {}
21566
21589
  });
21567
21590
  }
21568
- return rows;
21591
+ return withTimes(rows, rowMs);
21569
21592
  }
21570
21593
  function noComponentsMessage(projectPath) {
21571
21594
  return `No components found in ${projectPath}.
@@ -21596,18 +21619,19 @@ var init_logic9 = __esm({
21596
21619
  "use strict";
21597
21620
  init_src3();
21598
21621
  init_debug_trail();
21622
+ init_logic4();
21599
21623
  }
21600
21624
  });
21601
21625
 
21602
21626
  // packages/experience-design-system-cli/src/tui/import/steps/06-extraction/screen.tsx
21603
21627
  import { jsx as jsx16 } from "react/jsx-runtime";
21604
- function ExtractionScreen({ progress, agent }) {
21628
+ function ExtractionScreen({ progress, agent, rowMs }) {
21605
21629
  return /* @__PURE__ */ jsx16(
21606
21630
  RunningStep,
21607
21631
  {
21608
21632
  step: "extraction",
21609
21633
  description: "Extracting context from your source files.",
21610
- lines: progressRows(progress, agent)
21634
+ lines: progressRows(progress, agent, rowMs)
21611
21635
  }
21612
21636
  );
21613
21637
  }
@@ -22092,9 +22116,12 @@ function useExtraction(input) {
22092
22116
  progress: initialProgress({
22093
22117
  hasCredentials: input.credentials !== null,
22094
22118
  hasRawTokens: input.rawTokensPath !== ""
22095
- })
22119
+ }),
22120
+ rowMs: []
22096
22121
  });
22097
22122
  let lastProgress;
22123
+ const startedAt = Date.now();
22124
+ let rowMs = [];
22098
22125
  startDebugRun({
22099
22126
  flow: "import/extraction",
22100
22127
  step: "06-extraction",
@@ -22103,7 +22130,8 @@ function useExtraction(input) {
22103
22130
  });
22104
22131
  void runExtraction(input, (progress) => {
22105
22132
  lastProgress = progress;
22106
- if (current.current === input) setState({ status: "running", progress });
22133
+ rowMs = trackFinished(rowMs, progressRows(progress, input.agent), Date.now() - startedAt);
22134
+ if (current.current === input) setState({ status: "running", progress, rowMs });
22107
22135
  }).then((result) => {
22108
22136
  if (current.current !== input) return;
22109
22137
  void finishDebugRun({
@@ -22122,6 +22150,7 @@ var init_use_extraction = __esm({
22122
22150
  "packages/experience-design-system-cli/src/tui/import/steps/06-extraction/use-extraction.ts"() {
22123
22151
  "use strict";
22124
22152
  init_debug_store();
22153
+ init_logic4();
22125
22154
  init_logic9();
22126
22155
  init_run();
22127
22156
  }
@@ -25315,28 +25344,40 @@ function describeGeneration(input) {
25315
25344
  return `${formatAcceptanceSummary({ accepted: input.acceptedCount, autoRejected: 0 })}
25316
25345
  ${agent} is reading each selected component and writing a Contentful component definition for it.${input.hasTokens ? "\nUsing your design tokens for prop resolution." : ""}`;
25317
25346
  }
25318
- function progressRows2(progress, agent) {
25347
+ function componentsRow(components, name) {
25348
+ if (!components) return { text: `Starting up ${name}...`, complete: false };
25349
+ const { done, total, current, failed } = components;
25350
+ if (total > 0 && done >= total) {
25351
+ return failed > 0 ? {
25352
+ text: `Generated ${total - failed} of ${total} components, ${failed} failed`,
25353
+ complete: false,
25354
+ state: "failed"
25355
+ } : { text: `Generated ${total} component${total === 1 ? "" : "s"}`, complete: true };
25356
+ }
25357
+ return {
25358
+ text: failed > 0 ? `${current} (${failed} failed so far)` : current,
25359
+ complete: false,
25360
+ progress: { done, total },
25361
+ ...failed > 0 ? { state: "warning" } : {}
25362
+ };
25363
+ }
25364
+ function progressRows2(progress, agent, rowMs = []) {
25319
25365
  const name = capitalize(agent);
25320
25366
  const { components, mapTokens } = progress;
25321
- const rows = [
25322
- {
25323
- text: components ? components.current : `Starting up ${name}...`,
25324
- complete: false,
25325
- ...components ? { progress: { done: components.done, total: components.total } } : {}
25326
- }
25327
- ];
25367
+ const rows = [componentsRow(components, name)];
25328
25368
  if (mapTokens !== "idle") {
25329
25369
  rows.push({
25330
25370
  text: mapTokens === "running" ? `Mapping token restrictions via ${name}...` : "Token restrictions ready",
25331
25371
  complete: mapTokens === "complete"
25332
25372
  });
25333
25373
  }
25334
- return rows;
25374
+ return withTimes(rows, rowMs);
25335
25375
  }
25336
25376
  var capitalize;
25337
25377
  var init_logic11 = __esm({
25338
25378
  "packages/experience-design-system-cli/src/tui/import/steps/08-generation/logic.ts"() {
25339
25379
  "use strict";
25380
+ init_logic4();
25340
25381
  capitalize = (name) => name.charAt(0).toUpperCase() + name.slice(1);
25341
25382
  }
25342
25383
  });
@@ -25347,14 +25388,15 @@ function GenerationScreen({
25347
25388
  progress,
25348
25389
  agent,
25349
25390
  acceptedCount,
25350
- hasTokens
25391
+ hasTokens,
25392
+ rowMs
25351
25393
  }) {
25352
25394
  return /* @__PURE__ */ jsx30(
25353
25395
  RunningStep,
25354
25396
  {
25355
25397
  step: "generation",
25356
25398
  description: describeGeneration({ acceptedCount, agent, hasTokens }),
25357
- lines: progressRows2(progress, agent)
25399
+ lines: progressRows2(progress, agent, rowMs)
25358
25400
  }
25359
25401
  );
25360
25402
  }
@@ -25517,11 +25559,17 @@ function appendGeneratePromptOverride(input) {
25517
25559
  return [...input.promptOverrides, `generate=${input.generatePromptPath}`];
25518
25560
  }
25519
25561
  function applyProgressEvent2(event, previous, total) {
25562
+ const failed = previous?.failed ?? 0;
25520
25563
  if (event.kind === "component:started") {
25521
- return { done: previous?.done ?? 0, total: event.total || total, current: event.name };
25564
+ return { done: previous?.done ?? 0, total: event.total || total, current: event.name, failed };
25522
25565
  }
25523
25566
  if (event.kind === "component:completed" || event.kind === "component:failed" || event.kind === "component:cached") {
25524
- return { done: (previous?.done ?? 0) + 1, total: event.total || total, current: event.name };
25567
+ return {
25568
+ done: (previous?.done ?? 0) + 1,
25569
+ total: event.total || total,
25570
+ current: event.name,
25571
+ failed: failed + (event.kind === "component:failed" ? 1 : 0)
25572
+ };
25525
25573
  }
25526
25574
  return previous;
25527
25575
  }
@@ -25559,8 +25607,10 @@ function useGeneration(input) {
25559
25607
  setState(void 0);
25560
25608
  return;
25561
25609
  }
25562
- setState({ status: "running", progress: initialProgress2() });
25610
+ setState({ status: "running", progress: initialProgress2(), rowMs: [] });
25563
25611
  let lastProgress;
25612
+ const startedAt = Date.now();
25613
+ let rowMs = [];
25564
25614
  startDebugRun({
25565
25615
  flow: "import/generation",
25566
25616
  step: "08-generation",
@@ -25569,7 +25619,8 @@ function useGeneration(input) {
25569
25619
  });
25570
25620
  void runGeneration(input, (progress) => {
25571
25621
  lastProgress = progress;
25572
- if (current.current === input) setState({ status: "running", progress });
25622
+ rowMs = trackFinished(rowMs, progressRows2(progress, input.agent), Date.now() - startedAt);
25623
+ if (current.current === input) setState({ status: "running", progress, rowMs });
25573
25624
  }).then((result) => {
25574
25625
  if (current.current !== input) return;
25575
25626
  void finishDebugRun({
@@ -25588,6 +25639,7 @@ var init_use_generation = __esm({
25588
25639
  "packages/experience-design-system-cli/src/tui/import/steps/08-generation/use-generation.ts"() {
25589
25640
  "use strict";
25590
25641
  init_debug_store();
25642
+ init_logic4();
25591
25643
  init_logic11();
25592
25644
  init_run2();
25593
25645
  }
@@ -32426,6 +32478,10 @@ function PushingStep({ progress, produced, counts }) {
32426
32478
  "/",
32427
32479
  progress.total,
32428
32480
  " entities"
32481
+ ] }),
32482
+ progress.failed > 0 && /* @__PURE__ */ jsxs43(Text45, { color: PALETTE.error, children: [
32483
+ progress.failed,
32484
+ " failed"
32429
32485
  ] })
32430
32486
  ] }) }),
32431
32487
  showCurrent && /* @__PURE__ */ jsxs43(Box43, { gap: 1, children: [
@@ -33554,7 +33610,9 @@ async function runPush(input, deps, onPatch) {
33554
33610
  const items = op.items ?? [];
33555
33611
  const lastDone = items.length > 0 ? items[items.length - 1] : null;
33556
33612
  const current = lastDone && lastDone.status === "succeeded" ? lastDone.id : null;
33557
- onPatch({ pushProgress: { kind: "progress", processed: done, total: summary.total, current } });
33613
+ onPatch({
33614
+ pushProgress: { kind: "progress", processed: done, total: summary.total, failed: summary.failed, current }
33615
+ });
33558
33616
  }
33559
33617
  safeLog(deps, { pollTick: { attempt: pollCount, status: op.sys.status, summary: op.summary } });
33560
33618
  }
@@ -35685,7 +35743,14 @@ function App({ importOptions, inkClear }) {
35685
35743
  return /* @__PURE__ */ jsx66(ErrorStep, { stepName: extraction.result.step, message: extraction.result.message, onExit: leaveImport });
35686
35744
  }
35687
35745
  if (extraction?.status === "running") {
35688
- return /* @__PURE__ */ jsx66(ExtractionScreen, { progress: extraction.progress, agent: extractionRun.input.agent });
35746
+ return /* @__PURE__ */ jsx66(
35747
+ ExtractionScreen,
35748
+ {
35749
+ progress: extraction.progress,
35750
+ agent: extractionRun.input.agent,
35751
+ rowMs: extraction.rowMs
35752
+ }
35753
+ );
35689
35754
  }
35690
35755
  return /* @__PURE__ */ jsx66(Fragment22, {});
35691
35756
  }
@@ -35714,7 +35779,8 @@ function App({ importOptions, inkClear }) {
35714
35779
  progress: generation.progress,
35715
35780
  agent: scopeRun.input.agent,
35716
35781
  acceptedCount: scopeFlow.decisions.accepted.length,
35717
- hasTokens: scopeRun.extraction.tokensPath !== ""
35782
+ hasTokens: scopeRun.extraction.tokensPath !== "",
35783
+ rowMs: generation.rowMs
35718
35784
  }
35719
35785
  );
35720
35786
  }
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contentful/experience-design-system-cli",
3
- "version": "2.42.1-dev-build-1c5e1331.0",
3
+ "version": "2.42.1-dev-build-774b3e20.0",
4
4
  "description": "Contentful Experiences design system import CLI",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -5,7 +5,23 @@ export interface Progress {
5
5
  export interface RunningLine {
6
6
  text: string;
7
7
  complete?: boolean;
8
+ /** Set for a row that ended badly. A warning carries on without it; a failure does not. Otherwise `complete` decides. */
9
+ state?: 'warning' | 'failed';
8
10
  progress?: Progress;
11
+ /** How long the row took, once it has finished. */
12
+ ms?: number;
9
13
  }
14
+ export type LineState = 'running' | 'done' | 'warning' | 'failed';
15
+ /** What a row looks like. A row that ended badly is never shown as running or as done. */
16
+ export declare function lineState(line: RunningLine): LineState;
17
+ export declare function formatDuration(ms: number): string;
18
+ /**
19
+ * How long each row took, by position, for the rows that have finished. A row's time is how long the run had been going
20
+ * when it was first seen finished, and it does not change after that. Rows keep their position for the whole run, so a row
21
+ * that appears later is added at the end.
22
+ */
23
+ export declare function trackFinished(previous: ReadonlyArray<number | undefined>, rows: readonly RunningLine[], elapsedMs: number): Array<number | undefined>;
24
+ /** The rows with the time each finished row took, by position. */
25
+ export declare function withTimes(rows: RunningLine[], rowMs: ReadonlyArray<number | undefined>): RunningLine[];
10
26
  export declare function progressPercent(progress: Progress): number;
11
27
  export declare function formatElapsed(totalSeconds: number): string;
@@ -1,4 +1,5 @@
1
1
  import type { ExtractAndComposeProgress } from '@contentful/experience-design-system-backend-pipeline';
2
+ import { type RunningLine } from '../../shared/running-step/logic.js';
2
3
  import type { ExtractionInput, ExtractionProgress, ExtractionResult } from './types.js';
3
4
  /** Structured progress events emitted by the orchestrator (extraction + composition). */
4
5
  export type ProgressEvent = ExtractAndComposeProgress;
@@ -24,11 +25,11 @@ export declare function initialProgress(input: {
24
25
  hasRawTokens: boolean;
25
26
  }): ExtractionProgress;
26
27
  export declare function applyProgressEvent(progress: ExtractionProgress, event: ProgressEvent): ExtractionProgress;
27
- /** The rows the screen shows, in the order the wizard showed them. Rows that do not apply are left out. */
28
- export declare function progressRows(progress: ExtractionProgress, agent: string): Array<{
29
- text: string;
30
- complete: boolean;
31
- }>;
28
+ /**
29
+ * The rows the screen shows, in the order the wizard showed them. Rows that do not apply are left out. `rowMs` is how long
30
+ * each finished row took, by position (see `trackFinished`).
31
+ */
32
+ export declare function progressRows(progress: ExtractionProgress, agent: string, rowMs?: ReadonlyArray<number | undefined>): RunningLine[];
32
33
  /** True when every job is already done, so the screen would only flash. The wizard shows nothing in this case. */
33
34
  export declare function isFullCacheHit(progress: ExtractionProgress): boolean;
34
35
  export declare function noComponentsMessage(projectPath: string): string;
@@ -3,6 +3,8 @@ import type { ExtractionProgress } from './types.js';
3
3
  interface ExtractionScreenProps {
4
4
  progress: ExtractionProgress;
5
5
  agent: string;
6
+ /** How long each finished row took, by position. */
7
+ rowMs?: ReadonlyArray<number | undefined>;
6
8
  }
7
- export declare function ExtractionScreen({ progress, agent }: ExtractionScreenProps): React.ReactElement;
9
+ export declare function ExtractionScreen({ progress, agent, rowMs }: ExtractionScreenProps): React.ReactElement;
8
10
  export {};
@@ -2,6 +2,7 @@ import type { ExtractionInput, ExtractionProgress, ExtractionResult } from './ty
2
2
  export type ExtractionState = {
3
3
  status: 'running';
4
4
  progress: ExtractionProgress;
5
+ rowMs: Array<number | undefined>;
5
6
  } | {
6
7
  status: 'done';
7
8
  result: ExtractionResult;
@@ -1,3 +1,4 @@
1
+ import { type RunningLine } from '../../shared/running-step/logic.js';
1
2
  import type { GenerationInput, GenerationProgress, GenerationResult } from './types.js';
2
3
  /** What the debug log says the stage started with. The counts are logged, not the lists of names. */
3
4
  export declare function generationLogInputs(input: GenerationInput): Record<string, unknown>;
@@ -20,11 +21,5 @@ export declare function describeGeneration(input: {
20
21
  agent: string;
21
22
  hasTokens: boolean;
22
23
  }): string;
23
- export declare function progressRows(progress: GenerationProgress, agent: string): Array<{
24
- text: string;
25
- complete: boolean;
26
- progress?: {
27
- done: number;
28
- total: number;
29
- };
30
- }>;
24
+ /** `rowMs` is how long each finished row took, by position (see `trackFinished`). */
25
+ export declare function progressRows(progress: GenerationProgress, agent: string, rowMs?: ReadonlyArray<number | undefined>): RunningLine[];
@@ -5,6 +5,8 @@ interface GenerationScreenProps {
5
5
  agent: string;
6
6
  acceptedCount: number;
7
7
  hasTokens: boolean;
8
+ /** How long each finished row took, by position. */
9
+ rowMs?: ReadonlyArray<number | undefined>;
8
10
  }
9
- export declare function GenerationScreen({ progress, agent, acceptedCount, hasTokens, }: GenerationScreenProps): React.ReactElement;
11
+ export declare function GenerationScreen({ progress, agent, acceptedCount, hasTokens, rowMs, }: GenerationScreenProps): React.ReactElement;
10
12
  export {};
@@ -26,11 +26,15 @@ export interface GenerationInput {
26
26
  }
27
27
  /** One line per thing the screen shows, in the order it shows them. */
28
28
  export interface GenerationProgress {
29
- /** Components finished, out of the total, and the one being worked on. Null until the first progress line. */
29
+ /**
30
+ * Components finished, out of the total, and the one being worked on. `failed` counts the finished ones that failed: the
31
+ * run carries on through the rest and only fails at the end. Null until the first progress line.
32
+ */
30
33
  components: {
31
34
  done: number;
32
35
  total: number;
33
36
  current: string;
37
+ failed: number;
34
38
  } | null;
35
39
  mapTokens: 'idle' | 'running' | 'complete';
36
40
  /** Whether token mapping will run at all; unknown until the generated components have been looked at. */
@@ -2,6 +2,7 @@ import type { GenerationInput, GenerationProgress, GenerationResult } from './ty
2
2
  export type GenerationState = {
3
3
  status: 'running';
4
4
  progress: GenerationProgress;
5
+ rowMs: Array<number | undefined>;
5
6
  } | {
6
7
  status: 'done';
7
8
  result: GenerationResult;
@@ -5,5 +5,6 @@ export type PushProgress = {
5
5
  kind: 'progress';
6
6
  processed: number;
7
7
  total: number;
8
+ failed: number;
8
9
  current: string | null;
9
10
  } | null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contentful/experience-design-system-cli",
3
- "version": "2.42.1-dev-build-1c5e1331.0",
3
+ "version": "2.42.1-dev-build-774b3e20.0",
4
4
  "description": "Contentful Experiences design system import CLI",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -45,7 +45,7 @@
45
45
  "ts-morph": "^27.0.2",
46
46
  "typescript": "^5.9.3",
47
47
  "zod": "^4.6.5",
48
- "@contentful/experience-design-system-types": "2.42.1-dev-build-1c5e1331.0"
48
+ "@contentful/experience-design-system-types": "2.42.1-dev-build-774b3e20.0"
49
49
  },
50
50
  "devDependencies": {
51
51
  "@tsconfig/node24": "^24.0.4",
@@ -59,7 +59,7 @@
59
59
  "ink-testing-library": "^4.0.0",
60
60
  "typescript-eslint": "^8.67.0",
61
61
  "vitest": "^4.0.16",
62
- "@contentful/experience-design-system-backend-pipeline": "2.42.1-dev-build-1c5e1331.0"
62
+ "@contentful/experience-design-system-backend-pipeline": "2.42.1-dev-build-774b3e20.0"
63
63
  },
64
64
  "repository": {
65
65
  "type": "git",