@contentful/experience-design-system-cli 2.32.1-dev-build-7d7e3cc.0 → 2.32.1-dev-build-81eb804.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-7d7e3cc.0",
3
+ "version": "2.32.1-dev-build-81eb804.0",
4
4
  "description": "Contentful Experiences design system import CLI",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -0,0 +1,13 @@
1
+ import type { CmaClientOptions } from '../../interfaces/clients/cma-client-options.js';
2
+ import type { ExistingEntitiesResponse } from '../../interfaces/responses/existing-entities-response.js';
3
+ export declare class CmaApiClient {
4
+ private host;
5
+ private token;
6
+ private spaceId;
7
+ private environmentId;
8
+ constructor(opts: CmaClientOptions);
9
+ private base;
10
+ validateToken(): Promise<void>;
11
+ listExistingEntities(): Promise<ExistingEntitiesResponse>;
12
+ private listAll;
13
+ }
@@ -0,0 +1,47 @@
1
+ import type { ManifestPayload, ServerPreviewResponse, ApplyOperationResponse, BreakingChange } from '@contentful/experience-design-system-types';
2
+ import type { EdsiClientOptions } from '../../interfaces/clients/edsi-client-options.js';
3
+ import type { PollOptions } from '../../interfaces/clients/poll-options.js';
4
+ export declare const DEFAULT_HOST = "https://api.contentful.com";
5
+ export declare const PREVIEW_ERROR_PREFIX = "preview failed:";
6
+ export declare const APPLY_ERROR_PREFIX = "apply failed:";
7
+ export declare const VALIDATION_FAILED_CODE = "\"ValidationFailed\"";
8
+ export interface PreviewValidationError {
9
+ componentName: string;
10
+ path: string;
11
+ message: string;
12
+ }
13
+ /**
14
+ * Parse the JSON body of a 422 from `previewImport()` into structured
15
+ * per-component validation errors. Returns [] for any malformed input
16
+ * so callers can fall back to the generic error path without try/catch.
17
+ *
18
+ * Path shape: `manifest:components/<Name>/$slots/<key>` or
19
+ * `manifest:components/<Name>/$properties/<key>`. Only the component
20
+ * name is extracted today; `path` and `message` are kept verbatim so
21
+ * future surfaces (debug logging, headless retry in SP-4) can render
22
+ * the field-level detail.
23
+ */
24
+ export declare function parsePreviewValidationErrors(body: string): PreviewValidationError[];
25
+ export declare function sanitizeBreakingChanges(raw: unknown): BreakingChange[];
26
+ export declare class EdsiApiClient {
27
+ private host;
28
+ private token;
29
+ private spaceId;
30
+ private environmentId;
31
+ private retry;
32
+ private lastRequestId?;
33
+ getLastRequestId(): string | undefined;
34
+ private noteRequestId;
35
+ constructor(opts: EdsiClientOptions);
36
+ private base;
37
+ private headers;
38
+ private requestWithRetry;
39
+ validateToken(): Promise<void>;
40
+ checkPreflight(): Promise<void>;
41
+ previewImport(manifest: ManifestPayload, allowDeletions?: boolean): Promise<ServerPreviewResponse>;
42
+ applyImport(manifest: ManifestPayload, options: {
43
+ acknowledgeBreakingChanges: boolean;
44
+ allowDeletions?: boolean;
45
+ }): Promise<ApplyOperationResponse>;
46
+ pollOperation(operationId: string, opts?: PollOptions): Promise<ApplyOperationResponse>;
47
+ }
@@ -0,0 +1,10 @@
1
+ export { CmaApiClient } from './clients/cma-client.js';
2
+ export { EdsiApiClient, DEFAULT_HOST, PREVIEW_ERROR_PREFIX, APPLY_ERROR_PREFIX, VALIDATION_FAILED_CODE, parsePreviewValidationErrors, sanitizeBreakingChanges, } from './clients/edsi-client.js';
3
+ export type { PreviewValidationError } from './clients/edsi-client.js';
4
+ export { ApiError } from '../errors/api-error.js';
5
+ export type { CmaClientOptions } from '../interfaces/clients/cma-client-options.js';
6
+ export type { EdsiClientOptions } from '../interfaces/clients/edsi-client-options.js';
7
+ export type { PollOptions } from '../interfaces/clients/poll-options.js';
8
+ export type { ExistingComponentEntity } from '../interfaces/responses/existing-component-entity.js';
9
+ export type { ExistingTokenEntity } from '../interfaces/responses/existing-token-entity.js';
10
+ export type { ExistingEntitiesResponse } from '../interfaces/responses/existing-entities-response.js';
@@ -1,68 +1,4 @@
1
- import type { ManifestPayload, ServerPreviewResponse, ApplyOperationResponse, BreakingChange } from '@contentful/experience-design-system-types';
2
- export declare const DEFAULT_HOST = "https://api.contentful.com";
3
- export declare const PREVIEW_ERROR_PREFIX = "preview failed:";
4
- export declare const APPLY_ERROR_PREFIX = "apply failed:";
5
- export declare const VALIDATION_FAILED_CODE = "\"ValidationFailed\"";
6
- export interface ApiClientOptions {
7
- host?: string;
8
- cmaToken: string;
9
- spaceId: string;
10
- environmentId: string;
11
- retry?: {
12
- maxAttempts?: number;
13
- initialDelayMs?: number;
14
- maxDelayMs?: number;
15
- sleep?: (delayMs: number) => Promise<void>;
16
- };
17
- }
18
- export declare class ApiError extends Error {
19
- readonly status: number;
20
- readonly body: string;
21
- readonly guidance?: string | undefined;
22
- constructor(message: string, status: number, body: string, guidance?: string | undefined);
23
- }
24
- export interface PreviewValidationError {
25
- componentName: string;
26
- path: string;
27
- message: string;
28
- }
29
- /**
30
- * Parse the JSON body of a 422 from `previewImport()` into structured
31
- * per-component validation errors. Returns [] for any malformed input
32
- * so callers can fall back to the generic error path without try/catch.
33
- *
34
- * Path shape: `manifest:components/<Name>/$slots/<key>` or
35
- * `manifest:components/<Name>/$properties/<key>`. Only the component
36
- * name is extracted today; `path` and `message` are kept verbatim so
37
- * future surfaces (debug logging, headless retry in SP-4) can render
38
- * the field-level detail.
39
- */
40
- export declare function parsePreviewValidationErrors(body: string): PreviewValidationError[];
41
- export declare function sanitizeBreakingChanges(raw: unknown): BreakingChange[];
42
- export declare class ImportApiClient {
43
- private host;
44
- private token;
45
- private spaceId;
46
- private environmentId;
47
- private retry;
48
- private lastRequestId?;
49
- getLastRequestId(): string | undefined;
50
- private noteRequestId;
51
- constructor(opts: ApiClientOptions);
52
- private base;
53
- private headers;
54
- private requestWithRetry;
55
- validateToken(): Promise<void>;
56
- checkPreflight(): Promise<void>;
57
- previewImport(manifest: ManifestPayload, allowDeletions?: boolean): Promise<ServerPreviewResponse>;
58
- applyImport(manifest: ManifestPayload, options: {
59
- acknowledgeBreakingChanges: boolean;
60
- allowDeletions?: boolean;
61
- }): Promise<ApplyOperationResponse>;
62
- pollOperation(operationId: string, opts?: {
63
- intervalMs?: number;
64
- maxIntervalMs?: number;
65
- maxAttempts?: number;
66
- onProgress?: (op: ApplyOperationResponse) => void;
67
- }): Promise<ApplyOperationResponse>;
68
- }
1
+ export { EdsiApiClient, EdsiApiClient as ImportApiClient, DEFAULT_HOST, PREVIEW_ERROR_PREFIX, APPLY_ERROR_PREFIX, VALIDATION_FAILED_CODE, parsePreviewValidationErrors, sanitizeBreakingChanges, } from '../api/clients/edsi-client.js';
2
+ export type { PreviewValidationError } from '../api/clients/edsi-client.js';
3
+ export { ApiError } from '../errors/api-error.js';
4
+ export type { EdsiClientOptions as ApiClientOptions } from '../interfaces/clients/edsi-client-options.js';
@@ -0,0 +1,6 @@
1
+ export declare class ApiError extends Error {
2
+ readonly status: number;
3
+ readonly body: string;
4
+ readonly guidance?: string | undefined;
5
+ constructor(message: string, status: number, body: string, guidance?: string | undefined);
6
+ }
@@ -0,0 +1,4 @@
1
+ export declare function buildHeaders(token: string): Record<string, string>;
2
+ export declare function request(url: string, options: RequestInit & {
3
+ token: string;
4
+ }): Promise<Response>;
@@ -0,0 +1,4 @@
1
+ export declare const DEFAULT_API_HOST = "https://api.contentful.com";
2
+ export declare const DEFAULT_CONFIGURED_HOST = "api.contentful.com";
3
+ export declare function toConfiguredHost(host?: string): string | undefined;
4
+ export declare function toApiHost(host?: string): string;
@@ -1,4 +1 @@
1
- export declare const DEFAULT_API_HOST = "https://api.contentful.com";
2
- export declare const DEFAULT_CONFIGURED_HOST = "api.contentful.com";
3
- export declare function toConfiguredHost(host?: string): string | undefined;
4
- export declare function toApiHost(host?: string): string;
1
+ export { DEFAULT_API_HOST, DEFAULT_CONFIGURED_HOST, toConfiguredHost, toApiHost } from './helpers/url.js';
@@ -27,6 +27,15 @@ export interface PipelineOptions {
27
27
  /** When true, auto-reject cycle participants and retry push instead of surfacing an error. */
28
28
  autoRejectCycles?: boolean;
29
29
  allowDeletions?: boolean;
30
+ /**
31
+ * Fetch existing Components + DesignTokens from the target space+env
32
+ * and persist them under outDir/.existing-entities.json so downstream
33
+ * agent steps can consume them as context. Requires spaceId +
34
+ * environmentId + cmaToken; skipped with a warning otherwise. No-op
35
+ * for the agent flow in this PR — the file is written but nothing
36
+ * reads it yet.
37
+ */
38
+ withSpaceContext?: boolean;
30
39
  compositionMode?: CompositionMode;
31
40
  compositionMap?: string;
32
41
  compositionAgent?: boolean;
package/dist/src/index.js CHANGED
@@ -12576,7 +12576,7 @@ var init_src3 = __esm({
12576
12576
  }
12577
12577
  });
12578
12578
 
12579
- // packages/experience-design-system-cli/src/host-utils.ts
12579
+ // packages/experience-design-system-cli/src/helpers/url.ts
12580
12580
  function trimTrailingSlashes(value) {
12581
12581
  return value.replace(/\/+$/, "");
12582
12582
  }
@@ -12599,8 +12599,8 @@ function toApiHost(host) {
12599
12599
  return `https://${normalized}`;
12600
12600
  }
12601
12601
  var DEFAULT_API_HOST, DEFAULT_CONFIGURED_HOST;
12602
- var init_host_utils = __esm({
12603
- "packages/experience-design-system-cli/src/host-utils.ts"() {
12602
+ var init_url = __esm({
12603
+ "packages/experience-design-system-cli/src/helpers/url.ts"() {
12604
12604
  "use strict";
12605
12605
  DEFAULT_API_HOST = "https://api.contentful.com";
12606
12606
  DEFAULT_CONFIGURED_HOST = "api.contentful.com";
@@ -12807,7 +12807,55 @@ var init_user_agent = __esm({
12807
12807
  }
12808
12808
  });
12809
12809
 
12810
- // packages/experience-design-system-cli/src/apply/api-client.ts
12810
+ // packages/experience-design-system-cli/src/helpers/http.ts
12811
+ function buildHeaders(token) {
12812
+ return {
12813
+ Authorization: `Bearer ${token}`,
12814
+ "Content-Type": "application/json",
12815
+ "X-Contentful-User-Agent": buildUserAgent()
12816
+ };
12817
+ }
12818
+ async function request(url, options) {
12819
+ const init = {
12820
+ method: options.method ?? "GET",
12821
+ headers: buildHeaders(options.token)
12822
+ };
12823
+ if (options.body) init.body = options.body;
12824
+ return fetch(url, init);
12825
+ }
12826
+ var init_http = __esm({
12827
+ "packages/experience-design-system-cli/src/helpers/http.ts"() {
12828
+ "use strict";
12829
+ init_user_agent();
12830
+ }
12831
+ });
12832
+
12833
+ // packages/experience-design-system-cli/src/errors/api-error.ts
12834
+ var ERROR_BODY_LOG_CAP, ApiError;
12835
+ var init_api_error = __esm({
12836
+ "packages/experience-design-system-cli/src/errors/api-error.ts"() {
12837
+ "use strict";
12838
+ ERROR_BODY_LOG_CAP = 16384;
12839
+ ApiError = class extends Error {
12840
+ constructor(message, status, body, guidance) {
12841
+ super(message);
12842
+ this.status = status;
12843
+ this.body = body;
12844
+ this.guidance = guidance;
12845
+ if (body) {
12846
+ const trimmed = body.length > ERROR_BODY_LOG_CAP ? body.slice(0, ERROR_BODY_LOG_CAP) + "\u2026" : body;
12847
+ this.message = `${message}
12848
+ ${trimmed}`;
12849
+ }
12850
+ }
12851
+ status;
12852
+ body;
12853
+ guidance;
12854
+ };
12855
+ }
12856
+ });
12857
+
12858
+ // packages/experience-design-system-cli/src/api/clients/edsi-client.ts
12811
12859
  function defaultSleep(delayMs) {
12812
12860
  return new Promise((resolve27) => setTimeout(resolve27, delayMs));
12813
12861
  }
@@ -12890,48 +12938,20 @@ function isApsDenialBody(body) {
12890
12938
  return false;
12891
12939
  }
12892
12940
  }
12893
- async function request(url, options) {
12894
- const headers = {
12895
- Authorization: `Bearer ${options.token}`,
12896
- "Content-Type": "application/json",
12897
- "X-Contentful-User-Agent": buildUserAgent()
12898
- };
12899
- const init = {
12900
- method: options.method ?? "GET",
12901
- headers
12902
- };
12903
- if (options.body) init.body = options.body;
12904
- return fetch(url, init);
12905
- }
12906
- var PREVIEW_ERROR_PREFIX, APPLY_ERROR_PREFIX, VALIDATION_FAILED_CODE, MAX_RETRY_AFTER_MS, ERROR_BODY_LOG_CAP, ApiError, COMPONENT_PATH_PREFIX, PROPERTY_BREAKING_REASONS, SLOT_BREAKING_REASONS, ImportApiClient;
12907
- var init_api_client = __esm({
12908
- "packages/experience-design-system-cli/src/apply/api-client.ts"() {
12941
+ var PREVIEW_ERROR_PREFIX, APPLY_ERROR_PREFIX, VALIDATION_FAILED_CODE, MAX_RETRY_AFTER_MS, COMPONENT_PATH_PREFIX, PROPERTY_BREAKING_REASONS, SLOT_BREAKING_REASONS, EdsiApiClient;
12942
+ var init_edsi_client = __esm({
12943
+ "packages/experience-design-system-cli/src/api/clients/edsi-client.ts"() {
12909
12944
  "use strict";
12910
12945
  init_src3();
12911
- init_host_utils();
12946
+ init_url();
12912
12947
  init_debug_logger();
12913
12948
  init_user_agent();
12949
+ init_http();
12950
+ init_api_error();
12914
12951
  PREVIEW_ERROR_PREFIX = "preview failed:";
12915
12952
  APPLY_ERROR_PREFIX = "apply failed:";
12916
12953
  VALIDATION_FAILED_CODE = '"ValidationFailed"';
12917
12954
  MAX_RETRY_AFTER_MS = 6e4;
12918
- ERROR_BODY_LOG_CAP = 16384;
12919
- ApiError = class extends Error {
12920
- constructor(message, status, body, guidance) {
12921
- super(message);
12922
- this.status = status;
12923
- this.body = body;
12924
- this.guidance = guidance;
12925
- if (body) {
12926
- const trimmed = body.length > ERROR_BODY_LOG_CAP ? body.slice(0, ERROR_BODY_LOG_CAP) + "\u2026" : body;
12927
- this.message = `${message}
12928
- ${trimmed}`;
12929
- }
12930
- }
12931
- status;
12932
- body;
12933
- guidance;
12934
- };
12935
12955
  COMPONENT_PATH_PREFIX = "manifest:components/";
12936
12956
  PROPERTY_BREAKING_REASONS = /* @__PURE__ */ new Set([
12937
12957
  "removed",
@@ -12940,7 +12960,7 @@ ${trimmed}`;
12940
12960
  "validation_narrowed"
12941
12961
  ]);
12942
12962
  SLOT_BREAKING_REASONS = /* @__PURE__ */ new Set(["slot_removed", "slot_allowed_components_narrowed"]);
12943
- ImportApiClient = class {
12963
+ EdsiApiClient = class {
12944
12964
  host;
12945
12965
  token;
12946
12966
  spaceId;
@@ -13206,6 +13226,15 @@ ${trimmed}`;
13206
13226
  }
13207
13227
  });
13208
13228
 
13229
+ // packages/experience-design-system-cli/src/apply/api-client.ts
13230
+ var init_api_client = __esm({
13231
+ "packages/experience-design-system-cli/src/apply/api-client.ts"() {
13232
+ "use strict";
13233
+ init_edsi_client();
13234
+ init_api_error();
13235
+ }
13236
+ });
13237
+
13209
13238
  // packages/experience-design-system-cli/src/lib/error-parser.ts
13210
13239
  function stripLambdaLogPrefix(body) {
13211
13240
  let out = body.replace(LAMBDA_LOG_PREFIX_RE, "");
@@ -14194,6 +14223,14 @@ var init_strip_allowed_components = __esm({
14194
14223
  }
14195
14224
  });
14196
14225
 
14226
+ // packages/experience-design-system-cli/src/host-utils.ts
14227
+ var init_host_utils = __esm({
14228
+ "packages/experience-design-system-cli/src/host-utils.ts"() {
14229
+ "use strict";
14230
+ init_url();
14231
+ }
14232
+ });
14233
+
14197
14234
  // packages/experience-design-system-cli/src/credentials-store.ts
14198
14235
  var credentials_store_exports = {};
14199
14236
  __export(credentials_store_exports, {
@@ -14809,7 +14846,7 @@ async function resolveSharedInputs(opts) {
14809
14846
  if (opts.tokens) {
14810
14847
  tokens = await readTokensFromPath("--tokens", opts.tokens);
14811
14848
  }
14812
- const client2 = new ImportApiClient({
14849
+ const client2 = new EdsiApiClient({
14813
14850
  host: opts.host,
14814
14851
  cmaToken,
14815
14852
  spaceId,
@@ -15549,7 +15586,7 @@ function App({ sessionId: sessionId2, artifactsRoot, reviewRoot }) {
15549
15586
  tokens
15550
15587
  );
15551
15588
  if (!manifest.componentsManifest) manifest.componentsManifest = {};
15552
- const client2 = new ImportApiClient({ cmaToken, spaceId, environmentId });
15589
+ const client2 = new EdsiApiClient({ cmaToken, spaceId, environmentId });
15553
15590
  const preview = await client2.previewImport(manifest, true);
15554
15591
  const annotations = {};
15555
15592
  for (const item of preview.components.new) {
@@ -16571,7 +16608,7 @@ var init_save_path_resolver = __esm({
16571
16608
  });
16572
16609
 
16573
16610
  // packages/experience-design-system-cli/src/runs/store.ts
16574
- import { readFile as readFile22, writeFile as writeFile5, mkdir as mkdir6, rename } from "node:fs/promises";
16611
+ import { readFile as readFile22, writeFile as writeFile6, mkdir as mkdir6, rename } from "node:fs/promises";
16575
16612
  import { join as join20 } from "node:path";
16576
16613
  import { homedir as homedir7 } from "node:os";
16577
16614
  import { randomBytes as randomBytes2 } from "node:crypto";
@@ -16634,7 +16671,7 @@ async function writeAtomic(file) {
16634
16671
  await mkdir6(RUNS_DIR, { recursive: true });
16635
16672
  const body = JSON.stringify(file, null, 2) + "\n";
16636
16673
  const tmp = `${RUNS_PATH}.${process.pid}.${Date.now()}.tmp`;
16637
- await writeFile5(tmp, body, { mode: 384 });
16674
+ await writeFile6(tmp, body, { mode: 384 });
16638
16675
  await rename(tmp, RUNS_PATH);
16639
16676
  }
16640
16677
  async function appendRun(input) {
@@ -24116,7 +24153,7 @@ async function runLivePreview(opts) {
24116
24153
  tokens = await readTokensFromPath("tokens", tokensPath);
24117
24154
  }
24118
24155
  const manifest = buildManifest3(components, tokens, { deleteAllComponents: opts.deleteAllComponents === true });
24119
- const client2 = new ImportApiClient({ host, cmaToken, spaceId, environmentId });
24156
+ const client2 = new EdsiApiClient({ host, cmaToken, spaceId, environmentId });
24120
24157
  const startedAt = Date.now();
24121
24158
  let timeoutHandle;
24122
24159
  const timeoutPromise = new Promise((_resolve, reject) => {
@@ -28327,7 +28364,7 @@ Make sure this path contains TypeScript/React/Vue component files (.tsx, .ts, .v
28327
28364
  update({ step: "credentials", credentialsValidating: true, credentialsError: "" });
28328
28365
  try {
28329
28366
  const resolvedHost = resolveWizardHost(host2);
28330
- const client2 = new ImportApiClient({
28367
+ const client2 = new EdsiApiClient({
28331
28368
  cmaToken,
28332
28369
  spaceId,
28333
28370
  environmentId,
@@ -28401,7 +28438,7 @@ Make sure this path contains TypeScript/React/Vue component files (.tsx, .ts, .v
28401
28438
  update({ step: "previewing" });
28402
28439
  const resolvedHost = resolveWizardHost(host2);
28403
28440
  try {
28404
- const client2 = new ImportApiClient({
28441
+ const client2 = new EdsiApiClient({
28405
28442
  cmaToken,
28406
28443
  spaceId,
28407
28444
  environmentId,
@@ -28563,7 +28600,7 @@ If using a custom --host, make sure the space exists on that host.`
28563
28600
  update({ step: "pushing", pushProgress: null });
28564
28601
  try {
28565
28602
  const resolvedHost = resolveWizardHost(host2);
28566
- const client2 = new ImportApiClient({
28603
+ const client2 = new EdsiApiClient({
28567
28604
  cmaToken,
28568
28605
  spaceId,
28569
28606
  environmentId,
@@ -34308,14 +34345,72 @@ init_db();
34308
34345
  init_command();
34309
34346
  init_manifest();
34310
34347
  init_api_client();
34348
+ import { mkdir as mkdir5, writeFile as writeFile5 } from "node:fs/promises";
34349
+ import { join as join18, resolve as resolve21 } from "node:path";
34350
+ import { execFile as execFile2 } from "node:child_process";
34351
+
34352
+ // packages/experience-design-system-cli/src/api/clients/cma-client.ts
34353
+ init_url();
34354
+ init_http();
34355
+ init_api_error();
34356
+ var CMA_PAGE_LIMIT = 100;
34357
+ var CmaApiClient = class {
34358
+ host;
34359
+ token;
34360
+ spaceId;
34361
+ environmentId;
34362
+ constructor(opts) {
34363
+ this.host = toApiHost(opts.host);
34364
+ this.token = opts.cmaToken;
34365
+ this.spaceId = opts.spaceId;
34366
+ this.environmentId = opts.environmentId;
34367
+ }
34368
+ base() {
34369
+ return `${this.host}/spaces/${this.spaceId}/environments/${this.environmentId}`;
34370
+ }
34371
+ async validateToken() {
34372
+ const url = `${this.host}/users/me`;
34373
+ const res = await request(url, { token: this.token });
34374
+ if (res.status === 401) {
34375
+ throw new ApiError("CMA token is invalid or revoked", res.status, await res.text());
34376
+ }
34377
+ if (!res.ok) {
34378
+ throw new ApiError(`unexpected error validating token: ${res.status}`, res.status, await res.text());
34379
+ }
34380
+ }
34381
+ async listExistingEntities() {
34382
+ const [components, tokens] = await Promise.all([
34383
+ this.listAll("component_types", "component_types"),
34384
+ this.listAll("design_tokens", "design_tokens")
34385
+ ]);
34386
+ return { components, tokens };
34387
+ }
34388
+ async listAll(resourcePath, opName) {
34389
+ const items = [];
34390
+ let skip = 0;
34391
+ while (true) {
34392
+ const url = `${this.base()}/${resourcePath}?limit=${CMA_PAGE_LIMIT}&skip=${skip}`;
34393
+ const res = await request(url, { token: this.token });
34394
+ if (!res.ok) {
34395
+ throw new ApiError(`${opName} list failed: ${res.status}`, res.status, await res.text());
34396
+ }
34397
+ const page = await res.json();
34398
+ items.push(...page.items);
34399
+ const returned = page.items.length;
34400
+ const total = page.total ?? items.length;
34401
+ if (returned === 0 || items.length >= total) break;
34402
+ skip += returned;
34403
+ }
34404
+ return items;
34405
+ }
34406
+ };
34407
+
34408
+ // packages/experience-design-system-cli/src/import/orchestrator.ts
34311
34409
  init_contentful_urls();
34312
34410
  init_debug_logger();
34313
34411
  init_analytics();
34314
34412
  init_env();
34315
34413
  init_cli_path();
34316
- import { mkdir as mkdir5 } from "node:fs/promises";
34317
- import { join as join18, resolve as resolve21 } from "node:path";
34318
- import { execFile as execFile2 } from "node:child_process";
34319
34414
  async function runStep(args, cliPath, analyticsSessionId, env = {}, streamStderr = false) {
34320
34415
  const debug = getDebugLogger();
34321
34416
  const startedAt = Date.now();
@@ -34423,11 +34518,66 @@ async function runPipeline(opts, progressWriter, cliPathOverride) {
34423
34518
  await mkdir5(outDir, { recursive: true });
34424
34519
  const steps = [];
34425
34520
  let stepNum = 0;
34426
- const totalSteps = 5 + (opts.print ? 1 : 0);
34521
+ const wantsSpaceContext = opts.withSpaceContext === true;
34522
+ const canFetchSpaceContext = wantsSpaceContext && !!opts.spaceId && !!opts.environmentId && !!opts.cmaToken;
34523
+ const totalSteps = 5 + (opts.print ? 1 : 0) + (canFetchSpaceContext ? 1 : 0);
34427
34524
  function stepLabel(name) {
34428
34525
  stepNum++;
34429
34526
  return ` Step ${stepNum}/${totalSteps} ${name} `;
34430
34527
  }
34528
+ if (wantsSpaceContext && !canFetchSpaceContext) {
34529
+ progressWriter(
34530
+ " Note: --with-space-context requires --space-id, --environment-id, and --cma-token; skipping context fetch."
34531
+ );
34532
+ }
34533
+ if (canFetchSpaceContext) {
34534
+ const fetchLabel = stepLabel("Fetching existing components + design tokens");
34535
+ const fetchStepId = createStep(db, sessionId2, "fetch existing entities", {
34536
+ spaceId: opts.spaceId,
34537
+ environmentId: opts.environmentId
34538
+ });
34539
+ const t0 = Date.now();
34540
+ try {
34541
+ const cma = new CmaApiClient({
34542
+ host: opts.host,
34543
+ cmaToken: opts.cmaToken,
34544
+ spaceId: opts.spaceId,
34545
+ environmentId: opts.environmentId
34546
+ });
34547
+ const result = await cma.listExistingEntities();
34548
+ const fetchDurationMs = Date.now() - t0;
34549
+ const existingEntitiesPath = join18(outDir, ".existing-entities.json");
34550
+ await writeFile5(existingEntitiesPath, JSON.stringify(result, null, 2), "utf8");
34551
+ updateStep(db, fetchStepId, "complete", {
34552
+ components: String(result.components.length),
34553
+ tokens: String(result.tokens.length),
34554
+ path: existingEntitiesPath
34555
+ });
34556
+ progressWriter(
34557
+ `${fetchLabel}\u2713 ${result.components.length} component${result.components.length === 1 ? "" : "s"}, ${result.tokens.length} token${result.tokens.length === 1 ? "" : "s"} (${(fetchDurationMs / 1e3).toFixed(1)}s)`
34558
+ );
34559
+ steps.push({
34560
+ step: "fetch existing entities",
34561
+ status: "complete",
34562
+ durationMs: fetchDurationMs,
34563
+ detail: { components: result.components.length, tokens: result.tokens.length }
34564
+ });
34565
+ } catch (error) {
34566
+ const fetchDurationMs = Date.now() - t0;
34567
+ const message = error instanceof Error ? error.message : String(error);
34568
+ updateStep(db, fetchStepId, "failed", {}, message);
34569
+ progressWriter(
34570
+ `${fetchLabel}\u26A0 fetch failed, continuing without space context (${(fetchDurationMs / 1e3).toFixed(1)}s)`
34571
+ );
34572
+ progressWriter(` ${message.split("\n")[0]}`);
34573
+ steps.push({
34574
+ step: "fetch existing entities",
34575
+ status: "failed",
34576
+ durationMs: fetchDurationMs,
34577
+ error: message
34578
+ });
34579
+ }
34580
+ }
34431
34581
  const analyzeLabel = stepLabel("Statically analyzing project");
34432
34582
  const analyzeSkipped = !opts.noCache && opts.skipAnalyze;
34433
34583
  let extractSessionId = null;
@@ -35379,7 +35529,10 @@ function registerImportCommand(program) {
35379
35529
  "Override a stage prompt (repeatable). value is a file path or literal text, e.g. --prompt composition=./p.md",
35380
35530
  (v, acc) => [...acc, v],
35381
35531
  []
35382
- ).option("--auto-reject-cycles", "Automatically reject components involved in slot cycles and retry").option("--auto-filter", "Force the AI auto-filter ON (overrides the credentials.json autoFilter preference)").option(
35532
+ ).option("--auto-reject-cycles", "Automatically reject components involved in slot cycles and retry").option(
35533
+ "--with-space-context",
35534
+ "Fetch existing Components + DesignTokens from the target space+env and persist them under <out>/.existing-entities.json for future agent-context enrichment. Requires --space-id, --environment-id, and --cma-token."
35535
+ ).option("--auto-filter", "Force the AI auto-filter ON (overrides the credentials.json autoFilter preference)").option(
35383
35536
  "--no-auto-filter",
35384
35537
  "Skip the automatic AI pre-filter; jump straight to manual scope-gate (overrides the credentials.json autoFilter preference; no-op when paired with --auto-accept-scope)"
35385
35538
  ).option(
@@ -35714,6 +35867,7 @@ function registerImportCommand(program) {
35714
35867
  dryRun: dryRunForward,
35715
35868
  selectPromptPath: opts.selectPromptPath,
35716
35869
  autoRejectCycles: opts.autoRejectCycles ?? false,
35870
+ withSpaceContext: opts.withSpaceContext ?? false,
35717
35871
  allowDeletions: opts.allowDeletions ?? false,
35718
35872
  compositionMode: headlessCompositionMode,
35719
35873
  ...opts.compositionMap ? { compositionMap: opts.compositionMap } : {},
@@ -0,0 +1,6 @@
1
+ export interface CmaClientOptions {
2
+ host?: string;
3
+ cmaToken: string;
4
+ spaceId: string;
5
+ environmentId: string;
6
+ }
@@ -0,0 +1,12 @@
1
+ export interface EdsiClientOptions {
2
+ host?: string;
3
+ cmaToken: string;
4
+ spaceId: string;
5
+ environmentId: string;
6
+ retry?: {
7
+ maxAttempts?: number;
8
+ initialDelayMs?: number;
9
+ maxDelayMs?: number;
10
+ sleep?: (delayMs: number) => Promise<void>;
11
+ };
12
+ }
@@ -0,0 +1,7 @@
1
+ import type { ApplyOperationResponse } from '@contentful/experience-design-system-types';
2
+ export interface PollOptions {
3
+ intervalMs?: number;
4
+ maxIntervalMs?: number;
5
+ maxAttempts?: number;
6
+ onProgress?: (op: ApplyOperationResponse) => void;
7
+ }
@@ -0,0 +1,8 @@
1
+ export interface ExistingComponentEntity {
2
+ id: string;
3
+ name: string;
4
+ description?: string;
5
+ contentProperties?: unknown[];
6
+ designProperties?: unknown[];
7
+ slots?: unknown[];
8
+ }
@@ -0,0 +1,6 @@
1
+ import type { ExistingComponentEntity } from './existing-component-entity.js';
2
+ import type { ExistingTokenEntity } from './existing-token-entity.js';
3
+ export interface ExistingEntitiesResponse {
4
+ components: ExistingComponentEntity[];
5
+ tokens: ExistingTokenEntity[];
6
+ }
@@ -0,0 +1,6 @@
1
+ export interface ExistingTokenEntity {
2
+ id: string;
3
+ name: string;
4
+ kind: string;
5
+ value?: unknown;
6
+ }
@@ -5,7 +5,7 @@ import type { ToolCall, TokenToolCall, ComponentSourceRef } from '@contentful/ex
5
5
  import type { ComponentTypeSummary } from '@contentful/experience-design-system-types';
6
6
  import type { SlotCycle, SlotEdge } from '../analyze/cycle-detection.js';
7
7
  export type StepStatus = 'pending' | 'complete' | 'failed' | 'interrupted';
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' | 'import';
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';
9
9
  export interface SessionRow {
10
10
  id: string;
11
11
  name: string | 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-7d7e3cc.0",
3
+ "version": "2.32.1-dev-build-81eb804.0",
4
4
  "description": "Contentful Experiences design system import CLI",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -39,8 +39,8 @@
39
39
  "svelte": "^5.56.4",
40
40
  "ts-morph": "^27.0.2",
41
41
  "typescript": "^5.9.3",
42
- "@contentful/experience-design-system-cli-v2": "2.32.1-dev-build-7d7e3cc.0",
43
- "@contentful/experience-design-system-types": "2.32.1-dev-build-7d7e3cc.0"
42
+ "@contentful/experience-design-system-cli-v2": "2.32.1-dev-build-81eb804.0",
43
+ "@contentful/experience-design-system-types": "2.32.1-dev-build-81eb804.0"
44
44
  },
45
45
  "devDependencies": {
46
46
  "@tsconfig/node24": "^24.0.4",
@@ -52,9 +52,9 @@
52
52
  "ink-testing-library": "^4.0.0",
53
53
  "typescript-eslint": "^8.67.0",
54
54
  "vitest": "^4.0.16",
55
- "@contentful/experience-design-system-client": "2.32.1-dev-build-7d7e3cc.0",
56
- "@contentful/experience-design-system-extraction": "2.32.1-dev-build-7d7e3cc.0",
57
- "@contentful/experience-design-system-generation": "2.32.1-dev-build-7d7e3cc.0"
55
+ "@contentful/experience-design-system-client": "2.32.1-dev-build-81eb804.0",
56
+ "@contentful/experience-design-system-generation": "2.32.1-dev-build-81eb804.0",
57
+ "@contentful/experience-design-system-extraction": "2.32.1-dev-build-81eb804.0"
58
58
  },
59
59
  "repository": {
60
60
  "type": "git",