@contentful/experience-design-system-cli 2.24.1-dev-build-58e271c.0 → 2.24.1-dev-build-abcd76f.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.
Files changed (38) hide show
  1. package/README.md +0 -23
  2. package/dist/package.json +3 -4
  3. package/dist/src/analyze/command.js +2 -8
  4. package/dist/src/analyze/select/command.js +9 -13
  5. package/dist/src/analyze/select-agent/command.js +11 -14
  6. package/dist/src/apply/api-client.d.ts +0 -3
  7. package/dist/src/apply/api-client.js +1 -14
  8. package/dist/src/apply/command.d.ts +1 -1
  9. package/dist/src/apply/command.js +50 -71
  10. package/dist/src/generate/command.js +9 -15
  11. package/dist/src/generate/edit/command.js +0 -1
  12. package/dist/src/import/orchestrator.js +12 -18
  13. package/dist/src/index.js +1 -6
  14. package/dist/src/print/command.js +13 -16
  15. package/dist/src/program.js +1 -8
  16. package/package.json +7 -8
  17. package/dist/src/analytics/apply.d.ts +0 -6
  18. package/dist/src/analytics/apply.js +0 -30
  19. package/dist/src/analytics/client.d.ts +0 -7
  20. package/dist/src/analytics/client.js +0 -68
  21. package/dist/src/analytics/constants.d.ts +0 -4
  22. package/dist/src/analytics/constants.js +0 -4
  23. package/dist/src/analytics/env.d.ts +0 -4
  24. package/dist/src/analytics/env.js +0 -14
  25. package/dist/src/analytics/exit.d.ts +0 -5
  26. package/dist/src/analytics/exit.js +0 -24
  27. package/dist/src/analytics/index.d.ts +0 -10
  28. package/dist/src/analytics/index.js +0 -9
  29. package/dist/src/analytics/normalize.d.ts +0 -3
  30. package/dist/src/analytics/normalize.js +0 -18
  31. package/dist/src/analytics/os.d.ts +0 -2
  32. package/dist/src/analytics/os.js +0 -13
  33. package/dist/src/analytics/session.d.ts +0 -3
  34. package/dist/src/analytics/session.js +0 -15
  35. package/dist/src/analytics/tracker.d.ts +0 -17
  36. package/dist/src/analytics/tracker.js +0 -126
  37. package/dist/src/analytics/types.d.ts +0 -28
  38. package/dist/src/analytics/types.js +0 -1
package/README.md CHANGED
@@ -451,29 +451,6 @@ Wizard run history is separate: `~/.config/experiences/runs.json`.
451
451
 
452
452
  ---
453
453
 
454
- ## Usage data
455
-
456
- The CLI collects **anonymous usage data** to help us understand which commands are used and where the import workflow succeeds or fails. This data does **not** include your source code, file paths, credentials, prompts, or any content you author.
457
-
458
- What may be included:
459
-
460
- - Command name and duration
461
- - CLI, Node.js, and operating-system version
462
- - Anonymous session identifiers that link steps within a single import run
463
- - Structural counts (for example, how many components were extracted or accepted)
464
- - Space and environment IDs you pass on the command line
465
- - Contentful request IDs from API responses (to correlate failures with server logs)
466
-
467
- You can turn this off at any time:
468
-
469
- ```bash
470
- DISABLE_ANALYTICS=1 experiences import --project ./my-app
471
- ```
472
-
473
- Setting `DISABLE_ANALYTICS` to any value disables collection for that invocation.
474
-
475
- ---
476
-
477
454
  ## Development
478
455
 
479
456
  ```bash
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contentful/experience-design-system-cli",
3
- "version": "2.24.1-dev-build-58e271c.0",
3
+ "version": "2.24.1-dev-build-abcd76f.0",
4
4
  "description": "Contentful Experiences design system import CLI",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -41,17 +41,16 @@
41
41
  "@contentful/experience-design-system-extraction": "workspace:*",
42
42
  "@contentful/experience-design-system-generation": "workspace:*",
43
43
  "@contentful/experience-design-system-types": "workspace:*",
44
- "@segment/analytics-node": "^3.0.0",
45
44
  "commander": "^13.1.0",
46
45
  "ink": "^4.4.1",
47
46
  "react": "^18.3.1",
48
- "react-devtools-core": "^4.19.1",
47
+ "react-devtools-core": "^4.28.5",
49
48
  "react-dom": "^18.3.1"
50
49
  },
51
50
  "devDependencies": {
52
51
  "@tsconfig/node24": "^24.0.4",
53
52
  "@types/node": "^24.0.3",
54
- "@types/react": "^18.3.24",
53
+ "@types/react": "^18.3.31",
55
54
  "eslint": "^9.39.5",
56
55
  "eslint-config-prettier": "^10.1.8",
57
56
  "eslint-plugin-prettier": "^5.5.6",
@@ -24,7 +24,6 @@ import { DEFAULT_AGENT_NAME, isAgentName, runAgent, } from '@contentful/experien
24
24
  import { readExperiencesCredentials } from '../credentials-store.js';
25
25
  import { buildAnalyzeViewRows, partitionGlobalWarnings } from './build-analyze-view-rows.js';
26
26
  import { getInteractiveTerminalSupport } from '../lib/terminal-capabilities.js';
27
- import { bindAnalyticsSessionId, emitSessionStarted, enrichCommandResult, exitWithAnalytics, isPipelineAnalyticsChild, } from '../analytics/index.js';
28
27
  import { getDebugLogger } from '../lib/debug-logger.js';
29
28
  const SCANNED_FILE_EXTENSIONS = new Set(['.astro', '.js', '.jsx', '.svelte', '.ts', '.tsx', '.vue']);
30
29
  /**
@@ -265,10 +264,6 @@ export function registerAnalyzeCommand(program) {
265
264
  inputPath: projectRoot,
266
265
  outDir,
267
266
  });
268
- await bindAnalyticsSessionId(sessionId);
269
- if (!isPipelineAnalyticsChild()) {
270
- await emitSessionStarted('analyze_extract');
271
- }
272
267
  const stepId = createStep(db, sessionId, 'analyze extract', {
273
268
  project: projectRoot,
274
269
  });
@@ -542,7 +537,6 @@ export function registerAnalyzeCommand(program) {
542
537
  storeSlotCycles(db, sessionId, withBreaks);
543
538
  storeScannedFiles(db, sessionId, sourceFiles.map((f) => relative(projectRoot, f)));
544
539
  updateStep(db, stepId, 'complete', { sessionId });
545
- enrichCommandResult({ extracted_component_count: validatedComponents.length });
546
540
  db.close();
547
541
  const allWarnings = [...extraction.warnings, ...filterWarnings];
548
542
  const { rows: componentRows, totalErrors } = buildAnalyzeViewRows(filteredComponents, validatedComponents, allWarnings);
@@ -564,7 +558,7 @@ export function registerAnalyzeCommand(program) {
564
558
  if (getInteractiveTerminalSupport().supported) {
565
559
  const { waitUntilExit } = render(createElement(AnalyzeView, {
566
560
  result: analyzeResult,
567
- onExit: () => void exitWithAnalytics(0),
561
+ onExit: () => process.exit(0),
568
562
  }));
569
563
  await waitUntilExit();
570
564
  }
@@ -591,7 +585,7 @@ export function registerAnalyzeCommand(program) {
591
585
  summaryLines.push('Warnings: none');
592
586
  }
593
587
  process.stderr.write(summaryLines.join('\n') + '\n');
594
- await exitWithAnalytics(0);
588
+ process.exit(0);
595
589
  }
596
590
  });
597
591
  registerAnalyzeEditCommand(analyze);
@@ -8,7 +8,6 @@ import { loadReviewInput } from './parser.js';
8
8
  import { App } from './tui/App.js';
9
9
  import { openPipelineDb, loadRawComponents, storeRawComponents, createStep, updateStep } from '../../session/db.js';
10
10
  import { validateExtractedComponents, shouldExcludeDueToValidation, formatExclusionWarning, } from '@contentful/experience-design-system-extraction';
11
- import { bindAnalyticsSessionId, enrichCommandResult, exitWithAnalytics } from '../../analytics/index.js';
12
11
  const SAFE_PATH_RE = /^[a-zA-Z0-9_.$[\]=]+$/;
13
12
  const PROTO_KEYS = new Set(['__proto__', 'constructor', 'prototype']);
14
13
  function applyDotPath(obj, path, value) {
@@ -103,7 +102,6 @@ async function runNonInteractive(snapshot, opts, paths, sessionId) {
103
102
  }
104
103
  const accepted = snapshot.components.filter((c) => c.status === 'accepted').length;
105
104
  const rejected = snapshot.components.filter((c) => c.status === 'rejected').length + (names.length || 0);
106
- enrichCommandResult({ accepted_component_count: accepted });
107
105
  process.stderr.write(`Accepted: ${accepted} Rejected: ${rejected}\n`);
108
106
  return;
109
107
  }
@@ -132,7 +130,7 @@ async function runNonInteractive(snapshot, opts, paths, sessionId) {
132
130
  lines.push('');
133
131
  lines.push('Re-run with --exclude-invalid to auto-reject these components, or run analyze select interactively to fix them.');
134
132
  process.stderr.write(lines.join('\n') + '\n');
135
- await exitWithAnalytics(1);
133
+ process.exit(1);
136
134
  return;
137
135
  }
138
136
  }
@@ -177,14 +175,14 @@ async function runNonInteractive(snapshot, opts, paths, sessionId) {
177
175
  const parsed = JSON.parse(raw);
178
176
  if (!Array.isArray(parsed)) {
179
177
  process.stderr.write(`Error: --patch file must be a JSON array of patch operations: ${opts.patch}\n`);
180
- await exitWithAnalytics(1);
178
+ process.exit(1);
181
179
  return;
182
180
  }
183
181
  patchOps = parsed;
184
182
  }
185
183
  catch {
186
184
  process.stderr.write(`Error: cannot read or parse --patch file: ${opts.patch}\n`);
187
- await exitWithAnalytics(1);
185
+ process.exit(1);
188
186
  return;
189
187
  }
190
188
  // Warn on unknown component names
@@ -231,7 +229,6 @@ async function runNonInteractive(snapshot, opts, paths, sessionId) {
231
229
  db.close();
232
230
  }
233
231
  }
234
- enrichCommandResult({ accepted_component_count: accepted.length });
235
232
  process.stderr.write(`Accepted: ${accepted.length} Rejected: ${rejected.length}\n`);
236
233
  }
237
234
  /**
@@ -348,7 +345,7 @@ export async function rejectComponentsByName(sessionId, names, opts = {}) {
348
345
  const components = snapshot.components.map((c) => (nameSet.has(c.name) ? { ...c, status: 'rejected' } : c));
349
346
  await saveReviewState(paths.statePath, { ...snapshot, components });
350
347
  }
351
- async function resolveSessionId(sessionFlag) {
348
+ function resolveSessionId(sessionFlag) {
352
349
  if (sessionFlag)
353
350
  return sessionFlag;
354
351
  const db = openPipelineDb();
@@ -363,7 +360,7 @@ async function resolveSessionId(sessionFlag) {
363
360
  .get();
364
361
  if (!row) {
365
362
  process.stderr.write('Error: no completed analyze extract session found. Run analyze extract first, or pass --session <id>.\n');
366
- return await exitWithAnalytics(1);
363
+ process.exit(1);
367
364
  }
368
365
  return row.id;
369
366
  }
@@ -387,8 +384,7 @@ export function registerAnalyzeEditCommand(program) {
387
384
  .option('--exclude-invalid', 'With --select-all: auto-reject components with validation errors instead of failing loud (opt-in bypass for the gate)')
388
385
  .option('--exclude-components <names>', 'Comma-separated component names to force-reject, regardless of other selection flags')
389
386
  .action(async ({ session: sessionFlag, projectRoot, acceptAll, selectAll, reject, deselect, select, patch, excludeInvalid, excludeComponents, }) => {
390
- const sessionId = await resolveSessionId(sessionFlag);
391
- await bindAnalyticsSessionId(sessionId);
387
+ const sessionId = resolveSessionId(sessionFlag);
392
388
  const db = openPipelineDb();
393
389
  let rawComponentCount = 0;
394
390
  try {
@@ -399,7 +395,7 @@ export function registerAnalyzeEditCommand(program) {
399
395
  }
400
396
  if (rawComponentCount === 0) {
401
397
  process.stderr.write(`Error: session '${sessionId}' has no raw components. Run analyze extract first.\n`);
402
- await exitWithAnalytics(1);
398
+ process.exit(1);
403
399
  return;
404
400
  }
405
401
  const artifactsRoot = getRefineArtifactsRoot();
@@ -424,7 +420,7 @@ export function registerAnalyzeEditCommand(program) {
424
420
  }
425
421
  catch (error) {
426
422
  process.stderr.write(`Error: unable to initialize refine session.\n${error instanceof Error ? error.message : String(error)}\n`);
427
- await exitWithAnalytics(1);
423
+ process.exit(1);
428
424
  return;
429
425
  }
430
426
  // Non-interactive path
@@ -469,7 +465,7 @@ export function registerAnalyzeEditCommand(program) {
469
465
  });
470
466
  if (process.stdout.columns !== undefined && process.stdout.columns < 60) {
471
467
  process.stderr.write(`Error: terminal too narrow (${process.stdout.columns} cols). Resize to 60+ columns.\n`);
472
- await exitWithAnalytics(1);
468
+ process.exit(1);
473
469
  }
474
470
  const { waitUntilExit } = render(createElement(App, {
475
471
  sessionId,
@@ -11,7 +11,6 @@ import { buildRepoContextIndex, buildSelectionContext } from './context-builder.
11
11
  import { runShowRationale } from './show-rationale.js';
12
12
  import { isAbsolute, resolve } from 'node:path';
13
13
  import { getDebugLogger } from '../../lib/debug-logger.js';
14
- import { bindAnalyticsSessionId, enrichCommandResult, exitWithAnalytics } from '../../analytics/index.js';
15
14
  import { validateExtractedComponents, shouldExcludeDueToValidation, formatExclusionWarning, } from '@contentful/experience-design-system-extraction';
16
15
  const DEFAULT_TIMEOUT_MS = Number(process.env.EDS_AGENT_TIMEOUT_MS ?? 3 * 60 * 1000);
17
16
  export const DEFAULT_CONCURRENCY = 10;
@@ -28,7 +27,7 @@ function resolveBatchSize() {
28
27
  return DEFAULT_BATCH_SIZE;
29
28
  return Math.floor(n);
30
29
  }
31
- async function resolveSessionId(sessionFlag) {
30
+ function resolveSessionId(sessionFlag) {
32
31
  if (sessionFlag)
33
32
  return sessionFlag;
34
33
  const db = openPipelineDb();
@@ -43,7 +42,7 @@ async function resolveSessionId(sessionFlag) {
43
42
  .get();
44
43
  if (!row) {
45
44
  process.stderr.write('Error: no completed analyze extract session found. Run analyze extract first, or pass --session <id>.\n');
46
- return await exitWithAnalytics(1);
45
+ process.exit(1);
47
46
  }
48
47
  return row.id;
49
48
  }
@@ -330,7 +329,7 @@ export function registerAnalyzeSelectAgentCommand(program) {
330
329
  catch (err) {
331
330
  const message = err instanceof Error ? err.message : String(err);
332
331
  process.stderr.write(`Error: ${message}\n`);
333
- await exitWithAnalytics(1);
332
+ process.exit(1);
334
333
  return;
335
334
  }
336
335
  }
@@ -339,7 +338,7 @@ export function registerAnalyzeSelectAgentCommand(program) {
339
338
  const model = opts.model ?? savedCreds.agentModel;
340
339
  if (!agentName || !isAgentName(agentName)) {
341
340
  process.stderr.write(`Error: no agent configured. Pass --agent <name> or run experiences setup. Accepted values: ${AGENT_NAMES.join(', ')}\n`);
342
- await exitWithAnalytics(1);
341
+ process.exit(1);
343
342
  return;
344
343
  }
345
344
  const agent = agentName;
@@ -353,7 +352,7 @@ export function registerAnalyzeSelectAgentCommand(program) {
353
352
  .catch(() => false);
354
353
  if (!exists) {
355
354
  process.stderr.write(`Error: custom prompt path not found: ${resolvedPath}\n`);
356
- await exitWithAnalytics(1);
355
+ process.exit(1);
357
356
  return;
358
357
  }
359
358
  if (!selectPromptPath.toLowerCase().endsWith('.md')) {
@@ -361,8 +360,7 @@ export function registerAnalyzeSelectAgentCommand(program) {
361
360
  }
362
361
  process.stderr.write(formatCustomPromptBanner('select', resolvedPath));
363
362
  }
364
- const sessionId = await resolveSessionId(opts.session);
365
- await bindAnalyticsSessionId(sessionId);
363
+ const sessionId = resolveSessionId(opts.session);
366
364
  const selectionRoot = resolveProjectRoot(sessionId, opts.projectRoot);
367
365
  const db = openPipelineDb();
368
366
  let rawComponents;
@@ -376,7 +374,7 @@ export function registerAnalyzeSelectAgentCommand(program) {
376
374
  }
377
375
  if (rawComponents.length === 0) {
378
376
  process.stderr.write(`Error: session '${sessionId}' has no raw components. Run analyze extract first.\n`);
379
- await exitWithAnalytics(1);
377
+ process.exit(1);
380
378
  return;
381
379
  }
382
380
  // Re-run validation (not persisted to DB, so always recompute).
@@ -401,7 +399,7 @@ export function registerAnalyzeSelectAgentCommand(program) {
401
399
  lines.push('');
402
400
  lines.push('Re-run with --exclude-invalid to auto-reject these components, or fix them in source first.');
403
401
  process.stderr.write(lines.join('\n') + '\n');
404
- await exitWithAnalytics(1);
402
+ process.exit(1);
405
403
  return;
406
404
  }
407
405
  const componentsForAgent = validatedComponents.filter((comp) => !shouldExcludeDueToValidation(comp));
@@ -428,7 +426,7 @@ export function registerAnalyzeSelectAgentCommand(program) {
428
426
  if (opts.dryRun) {
429
427
  if (selectionCandidates.length === 0) {
430
428
  process.stderr.write('No valid components to preview — all components were excluded due to validation errors.\n');
431
- await exitWithAnalytics(0);
429
+ process.exit(0);
432
430
  return;
433
431
  }
434
432
  const first = selectionCandidates[0];
@@ -440,7 +438,7 @@ export function registerAnalyzeSelectAgentCommand(program) {
440
438
  skillPathOverride: selectPromptPath ? resolve(selectPromptPath) : undefined,
441
439
  });
442
440
  process.stdout.write(prompt + '\n');
443
- await exitWithAnalytics(0);
441
+ process.exit(0);
444
442
  return;
445
443
  }
446
444
  // --no-cache is the global kill-switch; --no-select-cache is the stage-
@@ -506,7 +504,7 @@ export function registerAnalyzeSelectAgentCommand(program) {
506
504
  }
507
505
  catch (error) {
508
506
  process.stderr.write(`Error: unable to initialize select session.\n${error instanceof Error ? error.message : String(error)}\n`);
509
- await exitWithAnalytics(1);
507
+ process.exit(1);
510
508
  return;
511
509
  }
512
510
  const paths = await getRefineSessionPaths(sessionId, artifactsRoot);
@@ -552,7 +550,6 @@ export function registerAnalyzeSelectAgentCommand(program) {
552
550
  finally {
553
551
  stepDb.close();
554
552
  }
555
- enrichCommandResult({ accepted_component_count: accepted.length });
556
553
  process.stderr.write(`Accepted: ${accepted.length} Rejected: ${rejected.length} Needs review: ${unresolved.length}\n`);
557
554
  });
558
555
  }
@@ -45,9 +45,6 @@ export declare class ImportApiClient {
45
45
  private spaceId;
46
46
  private environmentId;
47
47
  private retry;
48
- private lastRequestId?;
49
- getLastRequestId(): string | undefined;
50
- private noteRequestId;
51
48
  constructor(opts: ApiClientOptions);
52
49
  private base;
53
50
  private headers;
@@ -180,15 +180,6 @@ export class ImportApiClient {
180
180
  spaceId;
181
181
  environmentId;
182
182
  retry;
183
- lastRequestId;
184
- getLastRequestId() {
185
- return this.lastRequestId;
186
- }
187
- noteRequestId(response) {
188
- const requestId = response.headers.get('x-contentful-request-id');
189
- if (requestId)
190
- this.lastRequestId = requestId;
191
- }
192
183
  constructor(opts) {
193
184
  this.host = toApiHost(opts.host);
194
185
  this.token = opts.cmaToken;
@@ -246,10 +237,8 @@ export class ImportApiClient {
246
237
  await this.retry.sleep(delayMs);
247
238
  continue;
248
239
  }
249
- if (!isTransientStatus(result.response.status)) {
250
- this.noteRequestId(result.response);
240
+ if (!isTransientStatus(result.response.status))
251
241
  return result;
252
- }
253
242
  if (attempt === this.retry.maxAttempts) {
254
243
  const body = stringifyError(result.error);
255
244
  const guidance = `The ${phase} request failed after ${attempt} attempts because the service remained unavailable. ` +
@@ -284,7 +273,6 @@ export class ImportApiClient {
284
273
  // false positives that don't apply to the design-systems API authorization path.
285
274
  const url = `${this.host}/users/me`;
286
275
  const res = await request(url, { token: this.token });
287
- this.noteRequestId(res);
288
276
  if (res.status === 401) {
289
277
  throw new ApiError('CMA token is invalid or revoked', res.status, await res.text());
290
278
  }
@@ -310,7 +298,6 @@ export class ImportApiClient {
310
298
  catch {
311
299
  return; // network error — don't block; the real call will surface it
312
300
  }
313
- this.noteRequestId(res);
314
301
  if (res.ok)
315
302
  return;
316
303
  if (res.status >= 500)
@@ -11,7 +11,7 @@ export declare function formatSlotCycleReport(cycles: ReturnType<typeof findSlot
11
11
  export declare function assertNoSlotCycles(components: Array<{
12
12
  key: string;
13
13
  entry: CDFComponentEntry;
14
- }>): Promise<void>;
14
+ }>): void;
15
15
  export declare function extractComponentsFromManifest(manifest: {
16
16
  componentsManifest?: Record<string, unknown>;
17
17
  } | null | undefined): Array<{