@contentful/experience-design-system-cli 2.34.5-dev-build-a4f15b7e.0 → 2.34.5-dev-build-12a524fb.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.34.5-dev-build-a4f15b7e.0",
3
+ "version": "2.34.5-dev-build-12a524fb.0",
4
4
  "description": "Contentful Experiences design system import CLI",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -1,6 +1,8 @@
1
1
  export type CompositionCliOptions = {
2
2
  /** `--composition-refresh` — force edge emission to run even over resolved residue. */
3
3
  compositionRefresh?: boolean;
4
+ /** `--no-cache` — force the composition agent to rerun with the rest of the pipeline. */
5
+ noCache?: boolean;
4
6
  };
5
7
  export type ResolvedCompositionSources = {
6
8
  forceAgent: boolean;
@@ -1,3 +1,7 @@
1
1
  import type { Command } from 'commander';
2
+ export declare function resolveExtractNoCache(opts: {
3
+ cache?: boolean;
4
+ noCache?: boolean;
5
+ }): boolean;
2
6
  export declare function collectSourceFiles(directory: string, onProgress?: (scannedCount: number) => void): Promise<string[]>;
3
7
  export declare function registerInternalExtractCommand(program: Command): void;
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Resolution chain for the combined `--agent` override on `experiences import`.
3
+ *
4
+ * The wizard path previously hard-defaulted `--agent` to `'claude'` at the
5
+ * commander layer, which (a) shadowed the stored `credentials.json` value when
6
+ * the user passed no flag, and (b) made it impossible to distinguish "user
7
+ * explicitly passed --agent claude" from "user passed nothing". The combined
8
+ * flag accepts either `agent:model` or `agent model`.
9
+ *
10
+ * These helpers produce the resolved values to feed into `WizardApp` /
11
+ * the import wizard:
12
+ *
13
+ * 1. CLI flag wins when provided.
14
+ * 2. Otherwise, the value persisted in `credentials.json` (written by
15
+ * `experiences setup`) is used.
16
+ * 3. Otherwise, the built-in default (currently `'claude'`) is used for
17
+ * the agent. Model has no default — agents pick a small/fast model
18
+ * themselves when no model is included in `--agent`.
19
+ */
20
+ /** Built-in fallback agent when neither a flag nor a stored preference is set. */
21
+ export declare const DEFAULT_AGENT = "claude";
22
+ export declare function parseAgentModel(value: string | undefined): {
23
+ agent?: string;
24
+ model?: string;
25
+ };
26
+ export declare function resolveAgent(flagValue: string | undefined, storedValue: string | undefined): string;
27
+ export declare function resolveModel(flagValue: string | undefined, storedValue: string | undefined): string | undefined;
@@ -17,6 +17,7 @@ export declare function buildGenerateTokensArgs(opts: {
17
17
  model?: string;
18
18
  bedrock?: boolean;
19
19
  noCache?: boolean;
20
+ promptOverrides?: string[];
20
21
  }): string[];
21
22
  export declare function buildMapTokensArgs(opts: {
22
23
  sessionId: string;
@@ -24,6 +25,7 @@ export declare function buildMapTokensArgs(opts: {
24
25
  model?: string;
25
26
  noCache?: boolean;
26
27
  skipAgent?: boolean;
28
+ promptOverrides?: string[];
27
29
  existingEntitiesPath?: string;
28
30
  }): string[];
29
31
  export declare function shouldRunMapTokens(opts: {
@@ -51,7 +53,6 @@ export type WizardAppProps = {
51
53
  bedrock?: boolean;
52
54
  initialProjectPath?: string;
53
55
  host?: string;
54
- compositionMap?: string;
55
56
  promptOverrides?: string[];
56
57
  noCache?: boolean;
57
58
  livePreview?: boolean;
@@ -59,4 +60,4 @@ export type WizardAppProps = {
59
60
  skipMapTokens?: boolean;
60
61
  initialRawTokensPath?: string;
61
62
  };
62
- export declare function WizardApp({ initialSpaceId, initialEnvironmentId, initialCmaToken, initialHost, initialAgent, initialModel, bedrock, initialProjectPath, host, compositionMap, promptOverrides, noCache, livePreview, generatePromptPath, skipMapTokens, initialRawTokensPath, }?: WizardAppProps): React.ReactElement;
63
+ export declare function WizardApp({ initialSpaceId, initialEnvironmentId, initialCmaToken, initialHost, initialAgent, initialModel, bedrock, initialProjectPath, host, promptOverrides, noCache, livePreview, generatePromptPath, skipMapTokens, initialRawTokensPath, }?: WizardAppProps): React.ReactElement;
@@ -0,0 +1,8 @@
1
+ import { type AgentName } from '@contentful/experience-design-system-generation';
2
+ export declare function runSelectionAgent(options: {
3
+ sessionId: string;
4
+ agent: AgentName;
5
+ model?: string;
6
+ promptText?: string;
7
+ promptPath?: string;
8
+ }): Promise<void>;
package/dist/src/index.js CHANGED
@@ -3703,6 +3703,40 @@ async function getCliCacheVersion() {
3703
3703
  return _cliCacheVersionCache;
3704
3704
  }
3705
3705
  }
3706
+ function storeExtractCache(db, filePath, fileHash, cliVersion2, components) {
3707
+ const now = (/* @__PURE__ */ new Date()).toISOString();
3708
+ const componentsJson = JSON.stringify(components);
3709
+ db.prepare(
3710
+ `INSERT INTO extract_cache (file_path, file_hash, cli_version, created_at, updated_at, components_json)
3711
+ VALUES (?, ?, ?, ?, ?, ?)
3712
+ ON CONFLICT(file_hash, cli_version) DO UPDATE SET
3713
+ file_path = excluded.file_path,
3714
+ updated_at = excluded.updated_at,
3715
+ components_json = excluded.components_json`
3716
+ ).run(filePath, fileHash, cliVersion2, now, now, componentsJson);
3717
+ }
3718
+ function lookupExtractCache(db, fileHash, cliVersion2) {
3719
+ const row = db.prepare(
3720
+ `SELECT file_path, file_hash, cli_version, created_at, updated_at, components_json
3721
+ FROM extract_cache
3722
+ WHERE file_hash = ? AND cli_version = ?`
3723
+ ).get(fileHash, cliVersion2);
3724
+ if (!row) return null;
3725
+ let components = [];
3726
+ try {
3727
+ components = JSON.parse(row.components_json);
3728
+ } catch {
3729
+ return null;
3730
+ }
3731
+ return {
3732
+ filePath: row.file_path,
3733
+ fileHash: row.file_hash,
3734
+ cliVersion: row.cli_version,
3735
+ createdAt: row.created_at,
3736
+ updatedAt: row.updated_at,
3737
+ components
3738
+ };
3739
+ }
3706
3740
  function storeCompositionCache(db, inputHash, cliVersion2, agentOutput) {
3707
3741
  const now = (/* @__PURE__ */ new Date()).toISOString();
3708
3742
  db.prepare(
@@ -4135,12 +4169,17 @@ var init_persistence = __esm({
4135
4169
 
4136
4170
  // packages/experience-design-system-cli/src/lib/agent-model-options.ts
4137
4171
  function addAgentModelOptions(cmd, config = {}) {
4138
- const { agentDescription = AGENT_DESCRIPTION, includeModel = true, modelDescription = MODEL_DESCRIPTION } = config;
4172
+ const {
4173
+ agentDescription = AGENT_DESCRIPTION,
4174
+ includeModel = true,
4175
+ includeBedrock = true,
4176
+ modelDescription = MODEL_DESCRIPTION
4177
+ } = config;
4139
4178
  cmd.option("--agent <name>", agentDescription);
4140
4179
  if (includeModel) {
4141
4180
  cmd.option("--model <name>", modelDescription);
4142
4181
  }
4143
- cmd.option("--bedrock", BEDROCK_DESCRIPTION);
4182
+ if (includeBedrock) cmd.option("--bedrock", BEDROCK_DESCRIPTION);
4144
4183
  return cmd;
4145
4184
  }
4146
4185
  var AGENT_DESCRIPTION, MODEL_DESCRIPTION, BEDROCK_AGENTS, BEDROCK_DESCRIPTION;
@@ -4899,7 +4938,8 @@ async function runGenerateSkill(skill, opts, verbose = false) {
4899
4938
  const { overrides: promptOverrides, errors: promptErrors } = parsePromptOverrides(opts.prompt ?? []);
4900
4939
  if (promptErrors.length > 0) die(`Error: ${promptErrors.join("; ")}`);
4901
4940
  let generatePrompt;
4902
- const generateOverride = promptOverrides.get("generate");
4941
+ const promptStage = skill === "tokens" ? "tokens" : "generate";
4942
+ const generateOverride = promptOverrides.get(promptStage);
4903
4943
  if (generateOverride) {
4904
4944
  try {
4905
4945
  generatePrompt = await resolvePromptOverride(generateOverride);
@@ -5249,7 +5289,12 @@ function registerInternalGenerateCommand(program) {
5249
5289
  addAgentFlags(componentsCmd).action(async (opts) => {
5250
5290
  await runGenerateSkill("components", opts, opts.verbose ?? false);
5251
5291
  });
5252
- const tokensCmd = generate.command("tokens").description("Invoke a coding agent to produce tokens.json from raw token data").option("--raw-tokens <path>", "Path to raw token input file");
5292
+ const tokensCmd = generate.command("tokens").description("Invoke a coding agent to produce tokens.json from raw token data").option("--raw-tokens <path>", "Path to raw token input file").option(
5293
+ "--prompt <stage=value>",
5294
+ "Override a stage prompt (repeatable). Used here for the tokens stage.",
5295
+ (v, acc) => [...acc, v],
5296
+ []
5297
+ );
5253
5298
  addAgentFlags(tokensCmd).action(async (opts) => {
5254
5299
  await runGenerateSkill("tokens", opts, opts.verbose ?? false);
5255
5300
  });
@@ -8469,6 +8514,20 @@ async function runMapTokens(opts) {
8469
8514
  );
8470
8515
  }
8471
8516
  const resultAgent = configuredAgent ?? "skipped";
8517
+ const { overrides: promptOverrides, errors: promptErrors } = parsePromptOverrides(opts.prompt ?? []);
8518
+ if (promptErrors.length > 0) die(`Error: ${promptErrors.join("; ")}`);
8519
+ const mapPromptOverride = promptOverrides.get("map-tokens");
8520
+ let mapPromptText;
8521
+ let mapPromptPath;
8522
+ if (mapPromptOverride?.kind === "text") mapPromptText = mapPromptOverride.value;
8523
+ if (mapPromptOverride?.kind === "path") {
8524
+ mapPromptPath = resolve8(mapPromptOverride.value);
8525
+ try {
8526
+ await resolvePromptOverride(mapPromptOverride);
8527
+ } catch (error) {
8528
+ die(`Error: ${error instanceof Error ? error.message : String(error)}`);
8529
+ }
8530
+ }
8472
8531
  const db = openPipelineDb();
8473
8532
  try {
8474
8533
  const sessionId2 = opts.session ?? findLatestSessionForCommand(db, "generate components");
@@ -8578,7 +8637,9 @@ ${defaultDiagnostics.map((diagnostic) => ` ${diagnostic}`).join("\n")}
8578
8637
  tokenTree,
8579
8638
  componentSourceRefs,
8580
8639
  outDir: process.cwd(),
8581
- existingTokensInline
8640
+ existingTokensInline,
8641
+ ...mapPromptText !== void 0 ? { skillContentOverride: mapPromptText } : {},
8642
+ ...mapPromptText === void 0 && mapPromptPath ? { skillPathOverride: mapPromptPath } : {}
8582
8643
  });
8583
8644
  if (opts.printPrompt) {
8584
8645
  const prompt2 = await buildMapPrompt();
@@ -8603,7 +8664,8 @@ ${defaultDiagnostics.map((diagnostic) => ` ${diagnostic}`).join("\n")}
8603
8664
  agent,
8604
8665
  model,
8605
8666
  void 0,
8606
- existingTokensInline ? [hashContent(existingTokensInline)] : []
8667
+ existingTokensInline ? [hashContent(existingTokensInline)] : [],
8668
+ mapPromptText
8607
8669
  );
8608
8670
  const inputHash = computeMapTokensInputHash(db, sessionId2, componentSourceRefs);
8609
8671
  if (!noCache) {
@@ -8651,7 +8713,12 @@ ${warnings.map((w) => ` ${w}`).join("\n")}
8651
8713
  }
8652
8714
  function registerMapTokensCommand(program) {
8653
8715
  const map = program.command("map", { hidden: true }).description("Suggest token restrictions for generated design-token props");
8654
- const tokensCmd = map.command("tokens").description("Invoke a coding agent to suggest $token.allowed for design-category token props").option("--session <id>", "Session ID from generate components (defaults to most recent)").option("--print-prompt", "Print the prompt without invoking the agent").option("--skip-agent", "Resolve token defaults without agentic $token.allowed inference").option("--no-cache", "Bypass the map-tokens cache and force a re-run").option("--token-map <path>", "Path to token-name-map.json sidecar").option(
8716
+ const tokensCmd = map.command("tokens").description("Invoke a coding agent to suggest $token.allowed for design-category token props").option("--session <id>", "Session ID from generate components (defaults to most recent)").option("--print-prompt", "Print the prompt without invoking the agent").option("--skip-agent", "Resolve token defaults without agentic $token.allowed inference").option("--no-cache", "Bypass the map-tokens cache and force a re-run").option(
8717
+ "--prompt <stage=value>",
8718
+ "Override a stage prompt (repeatable). Used here for the map-tokens stage.",
8719
+ (v, acc) => [...acc, v],
8720
+ []
8721
+ ).option("--token-map <path>", "Path to token-name-map.json sidecar").option(
8655
8722
  "--existing-entities-path <path>",
8656
8723
  "Path to the .existing-entities.json file written after CMA credentials are supplied. When present, the agent gets a list of the space's existing design tokens so it can prefer binding to them. Missing/malformed files are treated as no-op."
8657
8724
  );
@@ -8676,6 +8743,7 @@ var init_command4 = __esm({
8676
8743
  init_MapTokensView();
8677
8744
  init_resolve_defaults();
8678
8745
  init_cli_errors();
8746
+ init_prompt_overrides();
8679
8747
  DEFAULT_TIMEOUT_MS2 = Number(process.env.EDS_AGENT_TIMEOUT_MS ?? 5 * 60 * 1e3);
8680
8748
  }
8681
8749
  });
@@ -8703,6 +8771,50 @@ var init_path_utils = __esm({
8703
8771
  }
8704
8772
  });
8705
8773
 
8774
+ // packages/experience-design-system-cli/src/import/agent-model-resolve.ts
8775
+ function parseAgentModel(value) {
8776
+ if (!value?.trim()) return {};
8777
+ const trimmed = value.trim();
8778
+ const separator = trimmed.indexOf(":");
8779
+ if (separator >= 0) {
8780
+ return {
8781
+ agent: trimmed.slice(0, separator).trim() || void 0,
8782
+ model: trimmed.slice(separator + 1).trim() || void 0
8783
+ };
8784
+ }
8785
+ const [agent, ...modelParts] = trimmed.split(/\s+/);
8786
+ return { agent, ...modelParts.length > 0 ? { model: modelParts.join(" ") } : {} };
8787
+ }
8788
+ function resolveAgent(flagValue, storedValue) {
8789
+ if (flagValue && flagValue.length > 0) return flagValue;
8790
+ if (storedValue && storedValue.length > 0) return storedValue;
8791
+ return DEFAULT_AGENT;
8792
+ }
8793
+ function resolveModel(flagValue, storedValue) {
8794
+ if (flagValue && flagValue.length > 0) return flagValue;
8795
+ if (storedValue && storedValue.length > 0) return storedValue;
8796
+ return void 0;
8797
+ }
8798
+ var DEFAULT_AGENT;
8799
+ var init_agent_model_resolve = __esm({
8800
+ "packages/experience-design-system-cli/src/import/agent-model-resolve.ts"() {
8801
+ "use strict";
8802
+ DEFAULT_AGENT = "claude";
8803
+ }
8804
+ });
8805
+
8806
+ // packages/experience-design-system-cli/src/import/composition-options.ts
8807
+ function buildCompositionForwardingOptions(options) {
8808
+ return {
8809
+ ...options.prompt && options.prompt.length > 0 ? { promptOverrides: options.prompt } : {}
8810
+ };
8811
+ }
8812
+ var init_composition_options = __esm({
8813
+ "packages/experience-design-system-cli/src/import/composition-options.ts"() {
8814
+ "use strict";
8815
+ }
8816
+ });
8817
+
8706
8818
  // packages/experience-design-system-cli/src/analyze/select/tui/theme.ts
8707
8819
  var PALETTE;
8708
8820
  var init_theme = __esm({
@@ -26548,6 +26660,70 @@ var init_wizard_state_transitions = __esm({
26548
26660
  }
26549
26661
  });
26550
26662
 
26663
+ // packages/experience-design-system-cli/src/import/tui/run-selection-agent.ts
26664
+ async function runSelectionAgent(options) {
26665
+ const db = openPipelineDb();
26666
+ let components;
26667
+ try {
26668
+ components = loadRawComponents(db, options.sessionId);
26669
+ } finally {
26670
+ db.close();
26671
+ }
26672
+ if (components.length === 0) return;
26673
+ const invoker2 = createLocalCliAgentInvoker({
26674
+ onDebugEvent: (name, payload) => getDebugLogger().event("agent", name, payload)
26675
+ });
26676
+ const prompt = await buildPrompt({
26677
+ skill: "select",
26678
+ mode: "autonomous",
26679
+ rawComponentsInline: JSON.stringify(components, null, 2),
26680
+ outDir: process.cwd(),
26681
+ ...options.promptText !== void 0 ? { skillContentOverride: options.promptText } : {},
26682
+ ...options.promptText === void 0 && options.promptPath ? { skillPathOverride: options.promptPath } : {}
26683
+ });
26684
+ const { result } = await invokeAgentWithOutput(
26685
+ invoker2,
26686
+ { agent: options.agent, model: options.model, prompt, timeoutMs: DEFAULT_TIMEOUT_MS4 },
26687
+ false
26688
+ );
26689
+ if (result.timedOut) throw new Error("selection agent timed out");
26690
+ if (result.exitCode !== 0) throw new Error(`selection agent exited with code ${result.exitCode}`);
26691
+ const { calls, warnings } = parseSelectToolCallLines(result.stdout);
26692
+ for (const warning of warnings) process.stderr.write(`Warning: selection agent: ${warning}
26693
+ `);
26694
+ const byName = new Map(calls.map((call) => [call.name, call]));
26695
+ const writeDb = openPipelineDb();
26696
+ try {
26697
+ const update = writeDb.prepare(
26698
+ `UPDATE raw_components SET status = ?, reject_reason = ? WHERE session_id = ? AND component_id = ?`
26699
+ );
26700
+ for (const component of components) {
26701
+ const call = byName.get(component.name);
26702
+ if (!call) continue;
26703
+ const rejected = call.tool === "reject_component";
26704
+ update.run(
26705
+ rejected ? "rejected" : "accepted",
26706
+ rejected ? call.reason ?? null : null,
26707
+ options.sessionId,
26708
+ component.component_id
26709
+ );
26710
+ }
26711
+ } finally {
26712
+ writeDb.close();
26713
+ }
26714
+ }
26715
+ var DEFAULT_TIMEOUT_MS4;
26716
+ var init_run_selection_agent = __esm({
26717
+ "packages/experience-design-system-cli/src/import/tui/run-selection-agent.ts"() {
26718
+ "use strict";
26719
+ init_src();
26720
+ init_debug_logger();
26721
+ init_agent_output();
26722
+ init_db();
26723
+ DEFAULT_TIMEOUT_MS4 = Number(process.env.EDS_AGENT_TIMEOUT_MS ?? 5 * 60 * 1e3);
26724
+ }
26725
+ });
26726
+
26551
26727
  // packages/experience-design-system-cli/src/import/tui/WizardApp.tsx
26552
26728
  var WizardApp_exports = {};
26553
26729
  __export(WizardApp_exports, {
@@ -26586,6 +26762,7 @@ function buildGenerateTokensArgs(opts) {
26586
26762
  if (opts.model) args.push("--model", opts.model);
26587
26763
  if (opts.bedrock) args.push("--bedrock");
26588
26764
  if (opts.noCache) args.push("--no-cache");
26765
+ for (const prompt of opts.promptOverrides ?? []) args.push("--prompt", prompt);
26589
26766
  return args;
26590
26767
  }
26591
26768
  function buildMapTokensArgs(opts) {
@@ -26593,6 +26770,7 @@ function buildMapTokensArgs(opts) {
26593
26770
  if (opts.model) args.push("--model", opts.model);
26594
26771
  if (opts.noCache) args.push("--no-cache");
26595
26772
  if (opts.skipAgent) args.push("--skip-agent");
26773
+ for (const prompt of opts.promptOverrides ?? []) args.push("--prompt", prompt);
26596
26774
  if (opts.existingEntitiesPath) args.push("--existing-entities-path", opts.existingEntitiesPath);
26597
26775
  return args;
26598
26776
  }
@@ -26668,7 +26846,6 @@ function WizardApp({
26668
26846
  bedrock = false,
26669
26847
  initialProjectPath,
26670
26848
  host,
26671
- compositionMap,
26672
26849
  promptOverrides,
26673
26850
  noCache = false,
26674
26851
  livePreview = true,
@@ -26838,7 +27015,8 @@ If you are using AWS Bedrock, run:
26838
27015
  agent: state.agent,
26839
27016
  ...state.agentModel ? { model: state.agentModel } : {},
26840
27017
  ...state.bedrock ? { bedrock: true } : {},
26841
- noCache: effectiveNoCache
27018
+ noCache: effectiveNoCache,
27019
+ promptOverrides
26842
27020
  });
26843
27021
  const result = await runSpawnedCli(tokenArgs);
26844
27022
  if (result.exitCode !== 0) {
@@ -26918,6 +27096,7 @@ If you are using AWS Bedrock, run:
26918
27096
  ...state.agentModel ? { model: state.agentModel } : {},
26919
27097
  noCache: effectiveNoCache,
26920
27098
  skipAgent: skipMapTokens,
27099
+ promptOverrides,
26921
27100
  ...state.existingEntitiesPath ? { existingEntitiesPath: state.existingEntitiesPath } : {}
26922
27101
  });
26923
27102
  const result = await runCli(args);
@@ -26936,7 +27115,6 @@ If you are using AWS Bedrock, run:
26936
27115
  update({ step: "extracting", outDir, extractProgress: null, compositionPhase: null });
26937
27116
  const extractArgs = [findCliPath(), "__extract", "--project", projectPath];
26938
27117
  if (noCache) extractArgs.push("--composition-refresh");
26939
- if (compositionMap) extractArgs.push("--composition-map", compositionMap);
26940
27118
  for (const p of promptOverrides ?? []) extractArgs.push("--prompt", p);
26941
27119
  if (state.agent) extractArgs.push("--agent", state.agent);
26942
27120
  if (state.bedrock) extractArgs.push("--bedrock");
@@ -27001,6 +27179,34 @@ Make sure this path contains TypeScript/React/Vue component files (.tsx, .ts, .v
27001
27179
  });
27002
27180
  return;
27003
27181
  }
27182
+ try {
27183
+ const { overrides, errors } = parsePromptOverrides(promptOverrides ?? []);
27184
+ if (errors.length > 0) throw new Error(errors.join("; "));
27185
+ const selectOverride = overrides.get("select");
27186
+ let promptText;
27187
+ let promptPath;
27188
+ if (selectOverride?.kind === "text") promptText = selectOverride.value;
27189
+ if (selectOverride?.kind === "path") {
27190
+ promptPath = resolve17(selectOverride.value);
27191
+ await resolvePromptOverride(selectOverride);
27192
+ }
27193
+ if (state.agent) {
27194
+ await runSelectionAgent({
27195
+ sessionId: extractSessionId ?? "",
27196
+ agent: state.agent,
27197
+ ...state.agentModel ? { model: state.agentModel } : {},
27198
+ ...promptText !== void 0 ? { promptText } : {},
27199
+ ...promptPath ? { promptPath } : {}
27200
+ });
27201
+ }
27202
+ } catch (error) {
27203
+ update({
27204
+ step: "error",
27205
+ errorStep: "selection agent",
27206
+ errorMessage: error instanceof Error ? error.message : String(error)
27207
+ });
27208
+ return;
27209
+ }
27004
27210
  update({
27005
27211
  step: "scope-gate",
27006
27212
  extractSessionId
@@ -28247,15 +28453,27 @@ var init_WizardApp = __esm({
28247
28453
  init_fetch_and_persist_existing_contentful_entities();
28248
28454
  init_wizard_state_transitions();
28249
28455
  init_cli_path();
28456
+ init_prompt_overrides();
28457
+ init_run_selection_agent();
28250
28458
  WIZARD_LOG = join20(tmpdir(), "experiences-import-wizard.log");
28251
28459
  }
28252
28460
  });
28253
28461
 
28254
28462
  // packages/experience-design-system-cli/src/import/command.ts
28255
28463
  function registerImportCommand(program) {
28256
- program.command("import").description("Run the full pipeline: analyze \u2192 select \u2192 generate \u2192 push").option("--project <path>", "Path to the project root to analyze", ".").option("--tokens <path>", "Path to a raw token source file to import alongside components").option("--agent <name>", 'Agent to use for generation (overrides credentials.json; falls back to "claude")').option(
28464
+ const cmd = program.command("import").description("Run the full pipeline: analyze \u2192 select \u2192 generate \u2192 push").option("--project <path>", "Path to the project root to analyze", ".");
28465
+ cmd.option(
28466
+ "--tokens <path>",
28467
+ "Path to a raw token source file (SCSS, CSS variables, JS/TS, Style Dictionary, etc.) to classify and import alongside components. Bypasses the interactive token prompt."
28468
+ );
28469
+ addAgentModelOptions(cmd, {
28470
+ agentDescription: 'Agent and optional model as agent:model or "agent model" (overrides credentials.json; falls back to "claude")',
28471
+ includeModel: false,
28472
+ includeBedrock: false
28473
+ });
28474
+ cmd.option(
28257
28475
  "--prompt <stage=value>",
28258
- "Override a stage prompt (repeatable). value is a file path or literal text, e.g. --prompt composition=./p.md",
28476
+ "Override a composition, selection, token, generation, or token-mapping prompt (repeatable). value is a file path or literal text, e.g. --prompt select=./p.md",
28259
28477
  (v, acc) => [...acc, v],
28260
28478
  []
28261
28479
  ).option("--no-cache", "Re-run all steps even if output already exists").action(async (opts) => {
@@ -28281,8 +28499,9 @@ function registerImportCommand(program) {
28281
28499
  const { createElement: createElement6 } = await import("react");
28282
28500
  const { WizardApp: WizardApp2 } = await Promise.resolve().then(() => (init_WizardApp(), WizardApp_exports));
28283
28501
  const creds = await readExperiencesCredentials();
28284
- const resolvedAgent = opts.agent || creds.agent || "claude";
28285
- const resolvedModel = creds.agentModel || void 0;
28502
+ const parsedAgentModel = parseAgentModel(opts.agent);
28503
+ const resolvedAgent = resolveAgent(parsedAgentModel.agent, creds.agent);
28504
+ const resolvedModel = resolveModel(parsedAgentModel.model, creds.agentModel);
28286
28505
  const { waitUntilExit } = render5(
28287
28506
  createElement6(WizardApp2, {
28288
28507
  initialSpaceId: creds.spaceId,
@@ -28292,8 +28511,9 @@ function registerImportCommand(program) {
28292
28511
  initialAgent: resolvedAgent,
28293
28512
  ...resolvedModel ? { initialModel: resolvedModel } : {},
28294
28513
  initialProjectPath: opts.project !== "." ? normalizePath(opts.project) : void 0,
28295
- ...opts.prompt && opts.prompt.length > 0 ? { promptOverrides: opts.prompt } : {},
28514
+ ...buildCompositionForwardingOptions(opts),
28296
28515
  noCache: opts.cache === false,
28516
+ skipMapTokens: false,
28297
28517
  livePreview: true,
28298
28518
  generatePromptPath: creds.generatePromptPath,
28299
28519
  ...opts.tokens ? { initialRawTokensPath: normalizePath(opts.tokens) } : {}
@@ -28308,8 +28528,11 @@ var init_command6 = __esm({
28308
28528
  "packages/experience-design-system-cli/src/import/command.ts"() {
28309
28529
  "use strict";
28310
28530
  init_path_utils();
28531
+ init_agent_model_resolve();
28532
+ init_agent_model_options();
28311
28533
  init_credentials_store();
28312
28534
  init_host_utils();
28535
+ init_composition_options();
28313
28536
  init_terminal_capabilities();
28314
28537
  }
28315
28538
  });
@@ -30096,7 +30319,7 @@ var init_resolve_mapping = __esm({
30096
30319
  // packages/experience-design-system-cli/src/analyze/composition/resolve-mapping-cli.ts
30097
30320
  function resolveCompositionSources(opts) {
30098
30321
  return {
30099
- forceAgent: !!opts.compositionRefresh
30322
+ forceAgent: opts.compositionRefresh === true || opts.noCache === true
30100
30323
  };
30101
30324
  }
30102
30325
  var init_resolve_mapping_cli = __esm({
@@ -30265,12 +30488,26 @@ var init_manifest_doc_evidence = __esm({
30265
30488
  // packages/experience-design-system-cli/src/analyze/extract-command.ts
30266
30489
  import { mkdir as mkdir6, readdir as readdir3, readFile as readFile18, stat as stat6 } from "node:fs/promises";
30267
30490
  import { isAbsolute as isAbsolute2, join as join25, relative as relative2, resolve as resolve19 } from "node:path";
30491
+ function resolveExtractNoCache(opts) {
30492
+ return opts.noCache === true || opts.cache === false;
30493
+ }
30268
30494
  function isDenylistedNoiseFile(name) {
30269
30495
  return DENYLISTED_EXACT_FILE_NAMES.has(name) || DENYLISTED_FILE_NAME_PATTERNS.some((pattern) => pattern.test(name));
30270
30496
  }
30271
30497
  function pluralize(count, singular, plural = `${singular}s`) {
30272
30498
  return `${count} ${count === 1 ? singular : plural}`;
30273
30499
  }
30500
+ async function retryDatabaseWrite(operation, attempts = 8) {
30501
+ for (let attempt = 1; ; attempt++) {
30502
+ try {
30503
+ return operation();
30504
+ } catch (error) {
30505
+ const message = error instanceof Error ? error.message : String(error);
30506
+ if (!/database is locked|database is busy/i.test(message) || attempt >= attempts) throw error;
30507
+ await new Promise((resolve21) => setTimeout(resolve21, Math.min(250 * attempt, 2e3)));
30508
+ }
30509
+ }
30510
+ }
30274
30511
  function resolveFromProjectRoot(projectRoot, inputPath) {
30275
30512
  return isAbsolute2(inputPath) ? inputPath : resolve19(projectRoot, inputPath);
30276
30513
  }
@@ -30343,7 +30580,7 @@ function registerInternalExtractCommand(program) {
30343
30580
  "--resolve-unreachable <mode>",
30344
30581
  "Retry pass for unresolved Svelte Props types: 'auto' (default), 'always', or 'never'",
30345
30582
  "auto"
30346
- ).option("--composition-refresh", "Force the mapping agent to run even where deterministic sources answered").option(
30583
+ ).option("--composition-refresh", "Force the mapping agent to run even where deterministic sources answered").option("--no-cache", "Re-run extraction even when all source files are unchanged").option(
30347
30584
  "--prompt <stage=value>",
30348
30585
  "Override a stage prompt (repeatable). value is a file path or literal text, e.g. --prompt composition=./p.md",
30349
30586
  (v, acc) => [...acc, v],
@@ -30353,6 +30590,7 @@ function registerInternalExtractCommand(program) {
30353
30590
  includeModel: false,
30354
30591
  agentDescription: "Coding agent for composition mapping resolution (claude|codex|opencode|cursor)"
30355
30592
  }).action(async (opts) => {
30593
+ const noCache = resolveExtractNoCache(opts);
30356
30594
  const resolveUnreachable = (() => {
30357
30595
  const v = opts.resolveUnreachable ?? "auto";
30358
30596
  if (v !== "auto" && v !== "always" && v !== "never") {
@@ -30390,16 +30628,50 @@ function registerInternalExtractCommand(program) {
30390
30628
  `);
30391
30629
  }
30392
30630
  });
30393
- const extraction = await extractComponents2(
30394
- sourceFiles,
30395
- ({ filesProcessed, componentsFound }) => {
30631
+ const extractionCacheDb = openPipelineDb();
30632
+ let extraction;
30633
+ let extractionCacheHits = 0;
30634
+ try {
30635
+ const cacheVersion = await getCliCacheVersion();
30636
+ const cachedByPath = /* @__PURE__ */ new Map();
30637
+ if (!noCache && sourceFiles.length > 0) {
30638
+ const hashes = await Promise.all(
30639
+ sourceFiles.map(async (filePath) => [filePath, await hashFile(filePath)])
30640
+ );
30641
+ for (const [filePath, fileHash] of hashes) {
30642
+ cachedByPath.set(filePath, lookupExtractCache(extractionCacheDb, fileHash, cacheVersion));
30643
+ }
30644
+ }
30645
+ const allFilesCached = !noCache && sourceFiles.length > 0 && sourceFiles.every((filePath) => cachedByPath.get(filePath) !== null);
30646
+ if (allFilesCached) {
30647
+ const cachedComponents = sourceFiles.flatMap((filePath) => cachedByPath.get(filePath).components);
30648
+ extractionCacheHits = sourceFiles.length;
30649
+ extraction = { components: cachedComponents, warnings: [] };
30396
30650
  if (!process.stdout.isTTY) {
30397
- process.stderr.write(`progress=extract:${filesProcessed}/${sourceFiles.length}:${componentsFound}
30398
- `);
30651
+ process.stderr.write(
30652
+ `progress=extract:${sourceFiles.length}/${sourceFiles.length}:${cachedComponents.length}
30653
+ `
30654
+ );
30399
30655
  }
30400
- },
30401
- { resolveUnreachable, projectRoot }
30402
- );
30656
+ getDebugLogger().event("analyze", "extract.cache-hit", {
30657
+ files: sourceFiles.length,
30658
+ components: cachedComponents.length
30659
+ });
30660
+ } else {
30661
+ extraction = await extractComponents2(
30662
+ sourceFiles,
30663
+ ({ filesProcessed, componentsFound }) => {
30664
+ if (!process.stdout.isTTY) {
30665
+ process.stderr.write(`progress=extract:${filesProcessed}/${sourceFiles.length}:${componentsFound}
30666
+ `);
30667
+ }
30668
+ },
30669
+ { resolveUnreachable, projectRoot }
30670
+ );
30671
+ }
30672
+ } finally {
30673
+ extractionCacheDb.close();
30674
+ }
30403
30675
  await mkdir6(outDir, { recursive: true });
30404
30676
  const db = openPipelineDb();
30405
30677
  const { sessionId: sessionId2 } = getOrCreateSession(db, void 0, void 0, {
@@ -30414,6 +30686,25 @@ function registerInternalExtractCommand(program) {
30414
30686
  const stepId = createStep(db, sessionId2, "analyze extract", {
30415
30687
  project: projectRoot
30416
30688
  });
30689
+ if (extractionCacheHits === 0 && !noCache) {
30690
+ const cacheVersion = await getCliCacheVersion();
30691
+ const componentsBySourcePath = /* @__PURE__ */ new Map();
30692
+ for (const component of extraction.components) {
30693
+ if (!component.sourcePath) continue;
30694
+ const components = componentsBySourcePath.get(component.sourcePath) ?? [];
30695
+ components.push(component);
30696
+ componentsBySourcePath.set(component.sourcePath, components);
30697
+ }
30698
+ for (const filePath of sourceFiles) {
30699
+ storeExtractCache(
30700
+ db,
30701
+ filePath,
30702
+ await hashFile(filePath),
30703
+ cacheVersion,
30704
+ componentsBySourcePath.get(filePath) ?? []
30705
+ );
30706
+ }
30707
+ }
30417
30708
  const classifiedComponents = extraction.components.map(preClassifyComponent);
30418
30709
  const inspectedComponents = await Promise.all(
30419
30710
  classifiedComponents.map(async (component) => ({
@@ -30458,7 +30749,10 @@ function registerInternalExtractCommand(program) {
30458
30749
  }
30459
30750
  let validatedComponents = validateExtractedComponents(filteredComponents);
30460
30751
  {
30461
- const sources = resolveCompositionSources(opts);
30752
+ const sources = resolveCompositionSources({
30753
+ ...opts,
30754
+ noCache
30755
+ });
30462
30756
  const { overrides: promptOverrides, errors: promptErrors } = parsePromptOverrides(opts.prompt ?? []);
30463
30757
  for (const err of promptErrors) {
30464
30758
  process.stderr.write(`Error: ${err}
@@ -30525,7 +30819,7 @@ function registerInternalExtractCommand(program) {
30525
30819
  files: promptFiles,
30526
30820
  ...compositionPrompt ? { promptOverride: compositionPrompt } : {},
30527
30821
  runAgentFn: async ({ prompt }) => {
30528
- if (!opts.compositionRefresh) {
30822
+ if (!noCache && !opts.compositionRefresh) {
30529
30823
  const cached = lookupCompositionCache(db, agentCacheKey, cacheVersion);
30530
30824
  if (cached !== null) {
30531
30825
  emitCompositionProgress("cache-hit");
@@ -30552,7 +30846,7 @@ function registerInternalExtractCommand(program) {
30552
30846
  validatedComponents = result.components;
30553
30847
  }
30554
30848
  }
30555
- storeRawComponents(db, sessionId2, validatedComponents);
30849
+ await retryDatabaseWrite(() => storeRawComponents(db, sessionId2, validatedComponents));
30556
30850
  const cycleInput = validatedComponents.map((c2) => ({
30557
30851
  name: c2.name,
30558
30852
  slots: c2.slots.map((s) => ({ name: s.name, allowedComponents: s.allowedComponents }))
@@ -30562,13 +30856,13 @@ function registerInternalExtractCommand(program) {
30562
30856
  ...cycle,
30563
30857
  suggestedBreak: suggestCycleBreakEdge(cycle, cycles)
30564
30858
  }));
30565
- storeSlotCycles(db, sessionId2, withBreaks);
30859
+ await retryDatabaseWrite(() => storeSlotCycles(db, sessionId2, withBreaks));
30566
30860
  storeScannedFiles(
30567
30861
  db,
30568
30862
  sessionId2,
30569
30863
  sourceFiles.map((f) => relative2(projectRoot, f))
30570
30864
  );
30571
- updateStep(db, stepId, "complete", { sessionId: sessionId2 });
30865
+ await retryDatabaseWrite(() => updateStep(db, stepId, "complete", { sessionId: sessionId2 }));
30572
30866
  enrichCommandResult({ extracted_component_count: validatedComponents.length });
30573
30867
  db.close();
30574
30868
  const allWarnings = [...extraction.warnings, ...filterWarnings];
@@ -30595,6 +30889,7 @@ var init_extract_command = __esm({
30595
30889
  init_agent_model_options();
30596
30890
  init_src3();
30597
30891
  init_db();
30892
+ init_cache_keys();
30598
30893
  init_cycle_detection();
30599
30894
  init_resolve_mapping();
30600
30895
  init_resolve_mapping_cli();
@@ -4,12 +4,12 @@ export declare const MODEL_DESCRIPTION = "Model to use (defaults to a lightweigh
4
4
  export interface AgentModelOptionsConfig {
5
5
  agentDescription?: string;
6
6
  includeModel?: boolean;
7
+ includeBedrock?: boolean;
7
8
  modelDescription?: string;
8
9
  }
9
10
  /**
10
- * Register --agent, --bedrock, and optional --model flags with a Commander
11
- * command. Pass includeModel: false to omit --model only — --bedrock is
12
- * independent of model selection (it's a routing switch, not a model choice)
13
- * and is always registered alongside --agent.
11
+ * Register --agent plus optional --model and --bedrock flags with a Commander
12
+ * command. The optional flags can be omitted for commands with a narrower
13
+ * public surface.
14
14
  */
15
15
  export declare function addAgentModelOptions(cmd: Command, config?: AgentModelOptionsConfig): Command;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contentful/experience-design-system-cli",
3
- "version": "2.34.5-dev-build-a4f15b7e.0",
3
+ "version": "2.34.5-dev-build-12a524fb.0",
4
4
  "description": "Contentful Experiences design system import CLI",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -41,8 +41,8 @@
41
41
  "svelte": "^5.56.4",
42
42
  "ts-morph": "^27.0.2",
43
43
  "typescript": "^5.9.3",
44
- "@contentful/experience-design-system-cli-v2": "2.34.5-dev-build-a4f15b7e.0",
45
- "@contentful/experience-design-system-types": "2.34.5-dev-build-a4f15b7e.0"
44
+ "@contentful/experience-design-system-cli-v2": "2.34.5-dev-build-12a524fb.0",
45
+ "@contentful/experience-design-system-types": "2.34.5-dev-build-12a524fb.0"
46
46
  },
47
47
  "devDependencies": {
48
48
  "@tsconfig/node24": "^24.0.4",
@@ -54,9 +54,9 @@
54
54
  "ink-testing-library": "^4.0.0",
55
55
  "typescript-eslint": "^8.67.0",
56
56
  "vitest": "^4.0.16",
57
- "@contentful/experience-design-system-extraction": "2.34.5-dev-build-a4f15b7e.0",
58
- "@contentful/experience-design-system-generation": "2.34.5-dev-build-a4f15b7e.0",
59
- "@contentful/experience-design-system-client": "2.34.5-dev-build-a4f15b7e.0"
57
+ "@contentful/experience-design-system-client": "2.34.5-dev-build-12a524fb.0",
58
+ "@contentful/experience-design-system-generation": "2.34.5-dev-build-12a524fb.0",
59
+ "@contentful/experience-design-system-extraction": "2.34.5-dev-build-12a524fb.0"
60
60
  },
61
61
  "repository": {
62
62
  "type": "git",