@contentful/experience-design-system-cli 2.35.1-dev-build-45d6c918.0 → 2.35.1-dev-build-3ab9e99e.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.
@@ -164,506 +164,272 @@ var init_render_with_goodbye = __esm({
164
164
  function isAgentName(value) {
165
165
  return AGENT_NAMES.includes(value);
166
166
  }
167
- var AGENT_NAMES, DEFAULT_AGENT_NAME, AGENT_BINARIES;
167
+ var AGENT_NAMES, DEFAULT_AGENT_NAME;
168
168
  var init_agent_names = __esm({
169
169
  "packages/experience-design-system-generation/dist/src/agent-names.js"() {
170
170
  "use strict";
171
171
  AGENT_NAMES = ["claude", "codex", "opencode", "cursor", "copilot"];
172
172
  DEFAULT_AGENT_NAME = "claude";
173
- AGENT_BINARIES = {
174
- claude: "claude",
175
- codex: "codex",
176
- opencode: "opencode",
177
- cursor: "cursor-agent",
178
- copilot: "copilot"
179
- };
180
- }
181
- });
182
-
183
- // packages/experience-design-system-generation/dist/src/controller/helpers/validate-generation-request.js
184
- function validateGenerationRequest(request2) {
185
- if (request2 === null || typeof request2 !== "object") {
186
- throw new TypeError("createGenerationEndpoint requires a request object");
187
- }
188
- if (!isAgentName(request2.agent)) {
189
- throw new TypeError(`createGenerationEndpoint requires agent to be a valid agent name, got: ${String(request2.agent)}`);
190
- }
191
- if (typeof request2.timeoutMs !== "number" || request2.timeoutMs <= 0) {
192
- throw new TypeError("createGenerationEndpoint requires timeoutMs to be a positive number");
193
- }
194
- if (request2.promptOptions === null || typeof request2.promptOptions !== "object") {
195
- throw new TypeError("createGenerationEndpoint requires promptOptions to be an object");
196
- }
197
- if (request2.onOutput !== void 0 && typeof request2.onOutput !== "function") {
198
- throw new TypeError("createGenerationEndpoint requires onOutput to be a function when provided");
199
- }
200
- }
201
- var init_validate_generation_request = __esm({
202
- "packages/experience-design-system-generation/dist/src/controller/helpers/validate-generation-request.js"() {
203
- "use strict";
204
- init_agent_names();
205
173
  }
206
174
  });
207
175
 
208
- // packages/experience-design-system-generation/dist/src/services/prompts/helpers/resolve-skill-file.js
209
- import { existsSync } from "node:fs";
210
- import { readFile as readFile2 } from "node:fs/promises";
211
- import { dirname, join as join2, resolve } from "node:path";
212
- import { fileURLToPath } from "node:url";
213
- function resolveSkillPath(skill) {
214
- if (!(skill in SKILL_FILES))
215
- throw new Error(`Invalid skill: ${skill}`);
216
- const thisDir = dirname(fileURLToPath(import.meta.url));
217
- let dir = thisDir;
218
- for (; ; ) {
219
- const candidate = join2(dir, "skills");
220
- if (existsSync(candidate))
221
- return join2(candidate, SKILL_FILES[skill]);
222
- const parent = resolve(dir, "..");
223
- if (parent === dir) {
224
- throw new Error(`skill file missing from CLI installation (could not locate skills/ directory from: ${thisDir})`);
176
+ // packages/experience-design-system-generation/dist/src/agent-runner.js
177
+ import { spawn } from "node:child_process";
178
+ function findJsonObjectEnd(line) {
179
+ let depth = 0;
180
+ let inString = false;
181
+ let escaped = false;
182
+ for (let i = 0; i < line.length; i++) {
183
+ const ch = line[i];
184
+ if (escaped) {
185
+ escaped = false;
186
+ } else if (ch === "\\" && inString) {
187
+ escaped = true;
188
+ } else if (ch === '"') {
189
+ inString = !inString;
190
+ } else if (!inString && ch === "{") {
191
+ depth++;
192
+ } else if (!inString && ch === "}" && --depth === 0) {
193
+ return i;
225
194
  }
226
- dir = parent;
227
195
  }
196
+ return -1;
228
197
  }
229
- function formatCustomPromptBanner(skill, path) {
230
- return `WARNING: Custom prompt active for ${skill}: ${path}
231
- Bundled invariants (utility-wrapper rejection, description content rules) do NOT apply.
232
- You are responsible for the prompt's correctness.
233
- `;
234
- }
235
- async function readSkillFile(skill, override) {
236
- if (override) {
237
- const skillPath2 = resolve(override);
198
+ function readToolCallObjects(stdout) {
199
+ const objects = [];
200
+ const warnings = [];
201
+ for (const raw of stdout.split("\n")) {
202
+ const line = raw.trim();
203
+ if (!line.startsWith("{"))
204
+ continue;
205
+ const end = findJsonObjectEnd(line);
206
+ if (end === -1) {
207
+ warnings.push(`unparseable line: ${line.slice(0, 120)}`);
208
+ continue;
209
+ }
210
+ let parsed;
238
211
  try {
239
- return await readFile2(skillPath2, "utf8");
212
+ parsed = JSON.parse(line.slice(0, end + 1));
240
213
  } catch {
241
- throw new Error(`custom prompt file not found (skill: ${skill}, path: ${skillPath2})`);
214
+ warnings.push(`unparseable line: ${line.slice(0, 120)}`);
215
+ continue;
216
+ }
217
+ const trailing = line.slice(end + 1);
218
+ if (trailing.trim()) {
219
+ warnings.push(`ignored trailing content after JSON: ${trailing.trim().slice(0, 120)}`);
220
+ }
221
+ if (typeof parsed === "object" && parsed !== null && "tool" in parsed) {
222
+ objects.push(parsed);
242
223
  }
243
224
  }
244
- const skillPath = resolveSkillPath(skill);
245
- try {
246
- return await readFile2(skillPath, "utf8");
247
- } catch {
248
- throw new Error(`skill file missing from CLI installation \u2014 try reinstalling the CLI (looked for: ${skillPath})`);
249
- }
225
+ return { objects, warnings };
250
226
  }
251
- var SKILL_FILES;
252
- var init_resolve_skill_file = __esm({
253
- "packages/experience-design-system-generation/dist/src/services/prompts/helpers/resolve-skill-file.js"() {
254
- "use strict";
255
- SKILL_FILES = {
256
- components: "generate-components.md",
257
- tokens: "generate-tokens.md",
258
- select: "select-components.md",
259
- "map-tokens": "map-tokens.md"
227
+ function parseSelectToolCallLines(stdout) {
228
+ const calls = [];
229
+ const { objects, warnings } = readToolCallObjects(stdout);
230
+ for (const rec of objects) {
231
+ if (!VALID_SELECT_TOOL_NAMES.has(rec.tool))
232
+ continue;
233
+ if (typeof rec.name !== "string" || !rec.name) {
234
+ warnings.push(`${String(rec.tool)} missing name \u2014 skipped`);
235
+ continue;
236
+ }
237
+ const call = {
238
+ tool: rec.tool,
239
+ name: rec.name
260
240
  };
241
+ if (typeof rec.reason === "string")
242
+ call.reason = rec.reason;
243
+ if (typeof rec.confidence === "number" && rec.confidence >= 1 && rec.confidence <= 5) {
244
+ if (call.tool === "select_component") {
245
+ call.confidence = rec.confidence;
246
+ } else {
247
+ call.confidence = rec.confidence;
248
+ }
249
+ }
250
+ calls.push(call);
261
251
  }
262
- });
263
-
264
- // packages/experience-design-system-generation/dist/src/services/prompts/helpers/format-token-candidates.js
265
- import { flattenDTCG } from "@contentful/experience-design-system-types";
266
- function inferFenceLang(filename) {
267
- if (!filename)
268
- return "json";
269
- const ext = filename.split(".").pop()?.toLowerCase() ?? "";
270
- const map = {
271
- js: "js",
272
- mjs: "js",
273
- cjs: "js",
274
- ts: "ts",
275
- mts: "ts",
276
- cts: "ts",
277
- tsx: "tsx",
278
- jsx: "jsx",
279
- vue: "vue",
280
- svelte: "svelte",
281
- astro: "astro",
282
- scss: "scss",
283
- sass: "scss",
284
- css: "css",
285
- json: "json",
286
- json5: "json"
287
- };
288
- return map[ext] ?? "text";
252
+ return { calls, warnings };
289
253
  }
290
- function filterDesignTokenProps(cdf) {
291
- const result = {};
292
- const kinds = /* @__PURE__ */ new Set();
293
- let hasUnscoped = false;
294
- for (const [componentName, component] of Object.entries(cdf)) {
295
- const properties = component.$properties;
296
- if (!properties)
254
+ function parseToolCallLines(stdout) {
255
+ const calls = [];
256
+ const { objects, warnings } = readToolCallObjects(stdout);
257
+ for (const rec of objects) {
258
+ if (!VALID_TOOL_NAMES.has(rec.tool)) {
259
+ warnings.push(`unknown tool: ${String(rec.tool)}`);
297
260
  continue;
298
- const filteredProps = {};
299
- for (const [propName, prop] of Object.entries(properties)) {
300
- if (prop.$type === "token" && prop.$category === "design") {
301
- const { "$token.allowed": _tokenAllowed, ...rest } = prop;
302
- filteredProps[propName] = rest;
303
- const kind = prop["$token.kind"];
304
- if (typeof kind === "string" && kind.length > 0) {
305
- kinds.add(kind);
306
- } else {
307
- hasUnscoped = true;
308
- }
309
- }
310
261
  }
311
- if (Object.keys(filteredProps).length > 0) {
312
- result[componentName] = { ...component, $properties: filteredProps };
262
+ const tool = rec.tool;
263
+ if (tool === "classify_prop") {
264
+ if (typeof rec.prop !== "string" || !rec.prop) {
265
+ warnings.push("classify_prop missing prop name \u2014 skipped");
266
+ continue;
267
+ }
268
+ if (typeof rec.cdf_type !== "string" || !VALID_CDF_TYPES.has(rec.cdf_type)) {
269
+ warnings.push(`classify_prop '${rec.prop}': invalid cdf_type '${String(rec.cdf_type)}' \u2014 skipped`);
270
+ continue;
271
+ }
272
+ if (typeof rec.cdf_category !== "string" || !VALID_CATEGORIES.has(rec.cdf_category)) {
273
+ warnings.push(`classify_prop '${rec.prop}': invalid cdf_category '${String(rec.cdf_category)}' \u2014 skipped`);
274
+ continue;
275
+ }
276
+ const call = {
277
+ tool: "classify_prop",
278
+ prop: rec.prop,
279
+ cdf_type: rec.cdf_type,
280
+ cdf_category: rec.cdf_category
281
+ };
282
+ if (Array.isArray(rec.values) && rec.values.every((v) => typeof v === "string")) {
283
+ call.values = rec.values;
284
+ }
285
+ if (typeof rec.token_kind === "string")
286
+ call.token_kind = rec.token_kind;
287
+ if (typeof rec.required === "boolean")
288
+ call.required = rec.required;
289
+ if (typeof rec.description === "string")
290
+ call.description = rec.description;
291
+ if (typeof rec.default === "string" || typeof rec.default === "boolean")
292
+ call.default = rec.default;
293
+ if (typeof rec.reason === "string")
294
+ call.reason = rec.reason;
295
+ calls.push(call);
296
+ } else if (tool === "exclude_prop") {
297
+ if (typeof rec.prop !== "string" || !rec.prop) {
298
+ warnings.push("exclude_prop missing prop name \u2014 skipped");
299
+ continue;
300
+ }
301
+ calls.push({
302
+ tool: "exclude_prop",
303
+ prop: rec.prop,
304
+ reason: typeof rec.reason === "string" ? rec.reason : ""
305
+ });
306
+ } else if (tool === "classify_component") {
307
+ const call = { tool: "classify_component" };
308
+ if (typeof rec.description === "string")
309
+ call.description = rec.description;
310
+ if (typeof rec.rationale === "object" && rec.rationale !== null) {
311
+ const r = rec.rationale;
312
+ const rationale = {};
313
+ if (typeof r.description === "string")
314
+ rationale.description = r.description;
315
+ if (typeof r.props === "string")
316
+ rationale.props = r.props;
317
+ if (typeof r.slots === "string")
318
+ rationale.slots = r.slots;
319
+ if (Object.keys(rationale).length > 0)
320
+ call.rationale = rationale;
321
+ }
322
+ calls.push(call);
323
+ } else if (tool === "classify_slot") {
324
+ if (typeof rec.slot !== "string" || !rec.slot) {
325
+ warnings.push("classify_slot missing slot name \u2014 skipped");
326
+ continue;
327
+ }
328
+ const call = { tool: "classify_slot", slot: rec.slot };
329
+ if (typeof rec.required === "boolean")
330
+ call.required = rec.required;
331
+ if (Array.isArray(rec.allowed_components) && rec.allowed_components.every((v) => typeof v === "string")) {
332
+ call.allowed_components = rec.allowed_components;
333
+ }
334
+ if (typeof rec.description === "string")
335
+ call.description = rec.description;
336
+ if (typeof rec.rationale === "string")
337
+ call.rationale = rec.rationale;
338
+ calls.push(call);
313
339
  }
314
340
  }
315
- return { filtered: result, kinds: [...kinds].sort(), hasUnscoped };
316
- }
317
- function buildTokenCandidateSections(tokenTree, filteredTokenProps) {
318
- const index = flattenDTCG(tokenTree, "").sort((a, b) => a.path.localeCompare(b.path));
319
- if (index.length === 0)
320
- return [];
321
- const sections = [];
322
- const renderSection = (kind, entries) => {
323
- const label = kind ? `Token path index \u2014 ${kind} candidates only` : "Token path index \u2014 full tree (no $token.kind to scope by)";
324
- const lines = entries.map((e) => `${e.path} \xB7 ${e.$type}`).join("\n");
325
- return `${label}, one leaf token per line as \`path \xB7 type\`, no \`$value\`:
326
- ${lines}`;
327
- };
328
- if (filteredTokenProps) {
329
- const { kinds, hasUnscoped } = filteredTokenProps;
330
- for (const kind of kinds) {
331
- const scoped = index.filter((e) => e.$type === kind);
332
- if (scoped.length > 0)
333
- sections.push(renderSection(kind, scoped));
334
- }
335
- if (hasUnscoped)
336
- sections.push(renderSection(null, index));
337
- } else {
338
- sections.push(renderSection(null, index));
339
- }
340
- return sections;
341
+ return { calls, warnings };
341
342
  }
342
- var init_format_token_candidates = __esm({
343
- "packages/experience-design-system-generation/dist/src/services/prompts/helpers/format-token-candidates.js"() {
344
- "use strict";
345
- }
346
- });
347
-
348
- // packages/experience-design-system-generation/dist/src/services/prompts/helpers/format-source-refs.js
349
- function formatSourceRefBlock(ref) {
350
- const mainBlock = `#### ${ref.component} (\`${ref.sourcePath}\`)
351
- \`\`\`${inferFenceLang(ref.sourcePath)}
352
- ${ref.content}
353
- \`\`\``;
354
- const siblingBlocks = (ref.siblingFiles ?? []).map((sibling) => `##### ${ref.component} \u2014 imported file \`${sibling.path}\`
355
- \`\`\`${inferFenceLang(sibling.path)}
356
- ${sibling.content}
357
- \`\`\``);
358
- const truncationNote = ref.truncatedSiblingCount && ref.truncatedSiblingCount > 0 ? [
359
- `##### ${ref.component} \u2014 +${ref.truncatedSiblingCount} more imported file${ref.truncatedSiblingCount === 1 ? "" : "s"} not shown (evidence may be incomplete)`
360
- ] : [];
361
- const notShownNote = ref.usesNotShown && ref.usesNotShown.length > 0 ? [
362
- `##### ${ref.component} \u2014 uses not shown: ${ref.usesNotShown.join(", ")}
363
-
364
- The files above are excerpts, and each of these properties has at least one use that fell outside the excerpt budget. Treat their consumption as unknown, not absent: do not classify them \`token\` on what is shown, and do not conclude they are unread.`
365
- ] : [];
366
- return [mainBlock, ...siblingBlocks, ...truncationNote, ...notShownNote].join("\n\n");
367
- }
368
- function formatSourceRefsSection(refs, skill) {
369
- const sections = [];
370
- const withContent = refs.filter((ref) => ref.content != null);
371
- const withoutContent = refs.filter((ref) => ref.content == null);
372
- if (withContent.length > 0) {
373
- sections.push(`### Component source references
374
-
375
- ${withContent.map(formatSourceRefBlock).join("\n\n")}`);
376
- }
377
- if (withoutContent.length > 0) {
378
- const guidance = skill === "components" ? "there is no consumption evidence for these, so `token` cannot be earned for any of their props \u2014 classify from the prop signature alone, and any prop that would otherwise be enum-versus-token is `enum` (or `string`)" : "there is no source evidence to narrow from \u2014 emit nothing for their props";
379
- sections.push(`Component source unavailable for (JSON) \u2014 ${guidance}:
380
- \`\`\`json
381
- ${JSON.stringify(withoutContent.map((ref) => ({ component: ref.component, sourcePath: ref.sourcePath })))}
382
- \`\`\``);
383
- }
384
- return sections;
385
- }
386
- var init_format_source_refs = __esm({
387
- "packages/experience-design-system-generation/dist/src/services/prompts/helpers/format-source-refs.js"() {
388
- "use strict";
389
- init_format_token_candidates();
390
- }
391
- });
392
-
393
- // packages/experience-design-system-generation/dist/src/services/prompts/helpers/build-skill-preambles.js
394
- function buildComponentsAutonomousPreamble(inputBlock) {
395
- return `You are running as part of the experience-design-system-cli generate pipeline in AUTONOMOUS mode. The developer is not present to answer questions.
396
-
397
- Context: You are classifying a React component for **Contentful Experience Orchestration**. The result is a Component Type \u2014 a schema that tells Contentful what a marketer can configure. Properties fall into three categories:
398
- - **design**: controls how the component looks (variant, size, color, layout toggles)
399
- - **content**: the data a content editor fills in (text, images, URLs, rich text)
400
- - **state**: runtime behavioral flags (disabled, loading, expanded, identifiers)
401
-
402
- Your task: classify every prop and slot in the component below. Apply all judgment calls yourself \u2014 do not pause to ask for confirmation. Include a "description" field on each tool call to document your reasoning so the developer can review it afterward.
403
-
404
- All input data is provided inline below \u2014 do not read any additional files.${inputBlock}
405
-
406
- ## Output protocol
407
-
408
- Do NOT write any files or emit any JSON blobs. Instead, emit one JSON object per line to stdout for each classification decision. The CLI reads your stdout line by line and writes each decision directly to the pipeline database.
409
-
410
- The four tool calls you may emit are:
411
-
412
- \`\`\`
413
- {"tool":"classify_component","description":"<optional component-level description>","rationale":{"description":"<why this component is classified the way it is>","props":"<why these props were chosen>","slots":"<why these slots were chosen>"}}
414
-
415
- {"tool":"classify_prop","prop":"<propName>","cdf_type":"<type>","cdf_category":"<category>","required":<bool>,"description":"<short customer-facing description>","reason":"<full internal rationale; not customer-facing>","values":["a","b"],"token_kind":"color","default":"<value>"}
416
-
417
- {"tool":"exclude_prop","prop":"<propName>","reason":"<why excluded>"}
418
-
419
- {"tool":"classify_slot","slot":"<slotName>","required":<bool>,"allowed_components":["ComponentName"],"description":"<reason>","rationale":"<why this slot was kept in the catalog>"}
420
- \`\`\`
421
-
422
- Rules:
423
- - Emit exactly one JSON object per line. No multi-line JSON. No markdown fences around the lines.
424
- - Every prop in the input must have exactly one call: either classify_prop or exclude_prop.
425
- - Every slot in the input must have exactly one classify_slot call.
426
- - Valid cdf_type values: string, richtext, media, enum, token, boolean
427
- - Valid cdf_category values: content, design, state
428
- - For enum type, always include \`values\` (non-empty string array of the variant names the prop accepts).
429
- - For token type, always include \`token_kind\` (DTCG $type, e.g. "color"). **Never emit \`values\` for \`cdf_type: "token"\` props** \u2014 an enum prop's list holds variant names; a token prop's list holds design token paths, produced separately and never by you. Emitting \`values\` on a token prop makes the definition invalid.
430
- - Never emit both "values" and "token_kind" on one prop.
431
- - \`enum\` vs \`token\` is decided by three questions answered in order from the source shown \u2014 never from the TypeScript type. Q1: does the component look the value up, switch on it, or have a vocabulary for it (\`tokens[x]\`, \`switch (variant)\`, \`allowedValues\`)? yes \u2192 \`enum\`, stop.
432
- - Q2: is the value written straight into a style or attribute (\`rx={radius}\`, \`padding: \${padding}\`)? no \u2192 not \`token\`, apply the type rules.
433
- - Q3: is there a design-token reference at that use \u2014 a \`tokens.*\` parameter default, a \`tokenReference\`, an inline \`tokens.*\` / \`var(--*)\`? yes \u2192 \`token\` (cite both lines in "reason"); no \u2192 \`string\`. "Ambiguity resolves to \`enum\`" applies only when Q1\u2013Q3 cannot be answered from the source shown.
434
- - CSS design props (className, style, styles, positional/geometric props: top, bottom, left, right, rotation, offset, etc.) \u2192 classify_prop, cdf_type: "string", cdf_category: "design".
435
- - For \`classify_slot.allowed_components\`, use only exact names from the hard allowlist provided below. Never invent a child from an import, JSX element, type name, icon name, or implementation helper; if a child is not listed, omit it.
436
- - On classify_component, "rationale" fields are operator-facing (read-only) but may surface in customer-facing exports. The "rationale.description" field is subject to the description content rules in the skill prompt (no internal initiative names). "rationale.props" and "rationale.slots" describe your reasoning about scope; "classify_slot.rationale" explains why each slot was kept.
437
- - On classify_prop, "reason" is REQUIRED and is the LLM's internal rationale \u2014 shown to the developer reviewing the import, never to end-users. "description" is the customer-facing copy and is subject to the description content rules in the skill prompt. Keep them distinct: "description" is short and customer-facing; "reason" explains your reasoning in detail.
438
- - You may emit prose lines (not starting with {) anywhere \u2014 they are ignored by the parser and serve as your reasoning log.`;
439
- }
440
- function buildSelectAutonomousPreamble(inputBlock) {
441
- return `You are running as part of the experience-design-system-cli import pipeline in AUTONOMOUS mode. The developer is not present to answer questions.
442
-
443
- Your task: review the components provided below and decide whether each belongs in Contentful Experience Orchestration as a Component Type. The input is a JSON array \u2014 you may receive 1\u2013N components in a single message. Emit one tool call per input component, named after the component. Apply all judgment calls yourself \u2014 do not pause to ask for confirmation. Include a brief "reason" to document your reasoning for each decision.
444
-
445
- Key rule: accept any component that renders visible UI \u2014 atoms, molecules, and organisms are all valid Component Types in Contentful Experience Orchestration. Reject only components that produce zero visual output: React hooks, pure context providers, A/B testing or variant-routing wrappers, analytics trackers, and security utilities. Do NOT reject a component because it has few props, is low-level, or has some A/B testing or personalization-related props mixed in \u2014 those props are handled in the generate step.
446
-
447
- All input data is provided inline below \u2014 do not read any additional files.${inputBlock}
448
-
449
- ## Output protocol
450
-
451
- Do NOT write any files or emit any JSON blobs. Instead, emit JSON tool calls one per line to stdout. The CLI reads your stdout line by line.
452
-
453
- The two tool calls \u2014 emit exactly one per input component:
454
-
455
- \`\`\`
456
- {"tool":"select_component","name":"<ComponentName>","reason":"<brief reason>"}
457
-
458
- {"tool":"reject_component","name":"<ComponentName>","reason":"<brief reason>"}
459
- \`\`\`
460
-
461
- Rules:
462
- - Emit exactly one JSON object per line. No multi-line JSON. No markdown fences.
463
- - Emit exactly one tool call per input component. The "name" field must match a component name from the input array exactly. Tool calls may appear in any order.
464
- - You may emit prose lines (not starting with {) to reason before each tool call \u2014 they are ignored by the parser.`;
465
- }
466
- function buildMapTokensAutonomousPreamble(inputBlock) {
467
- return `You are running as part of the experience-design-system-cli generate pipeline in AUTONOMOUS mode. The developer is not present to answer questions.
468
-
469
- Context: The components below already have design-category, token-typed props (\`$token.kind\` set). Your task is to decide, from source evidence, whether to narrow each one to a restricted subset (\`token_allowed\`) of the tokens matching its \`$token.kind\`. Apply all judgment calls yourself \u2014 do not pause to ask for confirmation.
470
-
471
- All input data is provided inline below \u2014 do not read any additional files.${inputBlock}
472
-
473
- ## Output protocol
474
-
475
- Do NOT write any files or emit any JSON blobs. Instead, emit one JSON object per line to stdout for each prop you narrow. The CLI reads your stdout line by line and writes each decision directly to the pipeline database.
476
-
477
- The one tool call you may emit:
478
-
479
- \`\`\`
480
- {"tool":"map_token_prop","component":"<ComponentName>","prop":"<propName>","token_allowed":["colors.brand.primary","colors.brand.secondary"]}
481
- \`\`\`
482
-
483
- Rules:
484
- - Emit exactly one JSON object per line. No multi-line JSON. No markdown fences around the lines.
485
- - Only emit a call for a prop that appears in the "Generated CDF so far" section.
486
- - Each "Token path index" section below is already scoped to one \`$token.kind\` \u2014 a prop only draws candidates from the section matching its own \`$token.kind\` (or the "full tree" section, for a prop with no \`$token.kind\`). Never cross sections, never emit a group/prefix path, and never invent a path \u2014 every entry in \`token_allowed\` must exist verbatim in the matching section.
487
- - \`token_allowed\` is required and must be non-empty when the call is emitted.
488
- - For the judgment call of whether a prop should be narrowed at all, follow the decision tree in the map-tokens skill file: it explains defaults vs. restrictions, misclassified variant-name props, and when to emit nothing.
489
- - You may emit prose lines (not starting with \`{\`) anywhere \u2014 they are ignored by the parser and serve as your reasoning log.`;
490
- }
491
- function buildTokensAutonomousPreamble(inputBlock) {
492
- return `You are running as part of the experience-design-system-cli generate pipeline in AUTONOMOUS mode. The developer is not present to answer questions.
493
-
494
- Your task: classify every raw token from the input below into a DTCG token tree. Apply all judgment calls yourself \u2014 do not pause to ask for confirmation. Include a "description" field on each set_token call to document your reasoning.
495
-
496
- All input data is provided inline below \u2014 do not read any additional files.${inputBlock}
497
-
498
- ## Output protocol
499
-
500
- Do NOT write any files or emit any JSON blobs. Instead, emit one JSON object per line to stdout for each token or group. The CLI reads your stdout line by line and writes each entry directly to the pipeline database.
501
-
502
- The two tool calls you may emit are:
503
-
504
- \`\`\`
505
- {"tool":"set_group","path":"<dot.notation.path>","description":"<optional group description>"}
506
-
507
- {"tool":"set_token","path":"<dot.notation.path>","type":"<DTCG type>","value":<value>,"description":"<reason>"}
508
- \`\`\`
509
-
510
- Rules:
511
- - Emit exactly one JSON object per line. No multi-line JSON. No markdown fences.
512
- - Emit a set_group call for every intermediate group node in the tree.
513
- - Emit a set_token call for every leaf token.
514
- - "path" is dot-notation, e.g. "colors.brand.primary" \u2014 no leading dots or slashes.
515
- - "type" must be one of the 13 valid DTCG types: color, dimension, fontFamily, fontWeight, duration, cubicBezier, number, strokeStyle, border, transition, shadow, gradient, typography.
516
- - "value" must be valid JSON (string, number, array, or object depending on the type). Do NOT wrap it in quotes if it is a complex type.
517
- - Emit set_group calls before the set_token calls that fall under them.
518
- - You may emit prose lines (not starting with {) anywhere \u2014 they are ignored by the parser and serve as your reasoning log.`;
519
- }
520
- var init_build_skill_preambles = __esm({
521
- "packages/experience-design-system-generation/dist/src/services/prompts/helpers/build-skill-preambles.js"() {
522
- "use strict";
523
- }
524
- });
525
-
526
- // packages/experience-design-system-generation/dist/src/services/prompts/helpers/build-preamble.js
527
- function buildPreamble(options) {
528
- const { skill, rawComponentsInline, rawTokensInline, rawTokensFilename, tokensInline, tokenMapInline, generatedCdf, tokenTree, componentSourceRefs, existingComponentsInline, existingTokensInline, componentAllowlistInline } = options;
529
- const sections = [];
530
- if (existingComponentsInline) {
531
- sections.push(`Existing components in the target Contentful space (JSON) \u2014 use for alignment, not as a hard filter:
532
- \`\`\`json
533
- ${existingComponentsInline}
534
- \`\`\``);
535
- }
536
- if (existingTokensInline) {
537
- sections.push(`Existing design tokens in the target Contentful space (JSON) \u2014 prefer binding to these paths over inventing new ones:
538
- \`\`\`json
539
- ${existingTokensInline}
540
- \`\`\``);
541
- }
542
- if (componentAllowlistInline) {
543
- sections.push(`Known component names for slot allowed_components (hard allowlist; never use any other name):
544
- \`\`\`json
545
- ${componentAllowlistInline}
546
- \`\`\``);
547
- }
548
- if (rawComponentsInline) {
549
- sections.push(`Raw component data (JSON):
550
- \`\`\`json
551
- ${rawComponentsInline}
552
- \`\`\``);
553
- }
554
- if (rawTokensInline) {
555
- const lang = inferFenceLang(rawTokensFilename);
556
- const label = rawTokensFilename ? `Raw token source (${rawTokensFilename})` : "Raw token source";
557
- sections.push(`${label}:
558
- \`\`\`${lang}
559
- ${rawTokensInline}
560
- \`\`\``);
561
- }
562
- if (tokensInline) {
563
- sections.push(`DTCG token data (for token kind lookups):
564
- \`\`\`json
565
- ${tokensInline}
566
- \`\`\``);
567
- }
568
- if (tokenMapInline) {
569
- sections.push(`Token-name sidecar (raw name \u2192 DTCG path):
570
- \`\`\`json
571
- ${tokenMapInline}
572
- \`\`\``);
573
- }
574
- const filteredTokenProps = generatedCdf ? filterDesignTokenProps(generatedCdf) : void 0;
575
- if (filteredTokenProps && Object.keys(filteredTokenProps.filtered).length > 0) {
576
- sections.push(`Generated CDF so far \u2014 design-category token props only (JSON):
577
- \`\`\`json
578
- ${JSON.stringify(filteredTokenProps.filtered)}
579
- \`\`\``);
580
- }
581
- if (tokenTree) {
582
- sections.push(...buildTokenCandidateSections(tokenTree, filteredTokenProps));
583
- }
584
- if (componentSourceRefs && componentSourceRefs.length > 0) {
585
- sections.push(...formatSourceRefsSection(componentSourceRefs, skill));
343
+ function parseTokenToolCallLines(stdout) {
344
+ const calls = [];
345
+ const { objects, warnings } = readToolCallObjects(stdout);
346
+ for (const rec of objects) {
347
+ if (!VALID_TOKEN_TOOL_NAMES.has(rec.tool))
348
+ continue;
349
+ if (rec.tool === "set_token") {
350
+ if (typeof rec.path !== "string" || !rec.path) {
351
+ warnings.push("set_token missing path \u2014 skipped");
352
+ continue;
353
+ }
354
+ if (typeof rec.type !== "string" || !rec.type) {
355
+ warnings.push(`set_token '${rec.path}': missing type \u2014 skipped`);
356
+ continue;
357
+ }
358
+ if (!("value" in rec)) {
359
+ warnings.push(`set_token '${rec.path}': missing value \u2014 skipped`);
360
+ continue;
361
+ }
362
+ const call = { tool: "set_token", path: rec.path, type: rec.type, value: rec.value };
363
+ if (typeof rec.description === "string")
364
+ call.description = rec.description;
365
+ calls.push(call);
366
+ } else if (rec.tool === "set_group") {
367
+ if (typeof rec.path !== "string" || !rec.path) {
368
+ warnings.push("set_group missing path \u2014 skipped");
369
+ continue;
370
+ }
371
+ const call = { tool: "set_group", path: rec.path };
372
+ if (typeof rec.description === "string")
373
+ call.description = rec.description;
374
+ calls.push(call);
375
+ }
586
376
  }
587
- const inputBlock = sections.length > 0 ? `
588
-
589
- ${sections.join("\n\n")}` : "";
590
- if (skill === "components")
591
- return buildComponentsAutonomousPreamble(inputBlock);
592
- if (skill === "select")
593
- return buildSelectAutonomousPreamble(inputBlock);
594
- if (skill === "map-tokens")
595
- return buildMapTokensAutonomousPreamble(inputBlock);
596
- return buildTokensAutonomousPreamble(inputBlock);
377
+ return { calls, warnings };
597
378
  }
598
- var init_build_preamble = __esm({
599
- "packages/experience-design-system-generation/dist/src/services/prompts/helpers/build-preamble.js"() {
600
- "use strict";
601
- init_format_token_candidates();
602
- init_format_source_refs();
603
- init_build_skill_preambles();
604
- }
605
- });
606
-
607
- // packages/experience-design-system-generation/dist/src/services/prompts/build-prompt.js
608
- async function buildPrompt(options) {
609
- const skillContent = options.skillContentOverride ?? await readSkillFile(options.skill, options.skillPathOverride);
610
- const preamble = buildPreamble(options);
611
- return `${preamble}
612
-
613
- Skill instructions follow:
614
- ---
615
- ${skillContent}`;
379
+ function isStringArray(value) {
380
+ return Array.isArray(value) && value.every((v) => typeof v === "string");
616
381
  }
617
- var init_build_prompt = __esm({
618
- "packages/experience-design-system-generation/dist/src/services/prompts/build-prompt.js"() {
619
- "use strict";
620
- init_resolve_skill_file();
621
- init_build_preamble();
622
- init_resolve_skill_file();
382
+ function parseMapTokenPropToolCallLines(stdout) {
383
+ const calls = [];
384
+ const warnings = [];
385
+ for (const raw of stdout.split("\n")) {
386
+ const line = raw.trim();
387
+ if (!line.startsWith("{"))
388
+ continue;
389
+ let obj;
390
+ try {
391
+ obj = JSON.parse(line);
392
+ } catch {
393
+ warnings.push(`unparseable line: ${line.slice(0, 120)}`);
394
+ continue;
395
+ }
396
+ if (typeof obj !== "object" || obj === null || !("tool" in obj))
397
+ continue;
398
+ const rec = obj;
399
+ if (rec.tool !== "map_token_prop")
400
+ continue;
401
+ if (typeof rec.component !== "string" || !rec.component) {
402
+ warnings.push("map_token_prop missing component \u2014 skipped");
403
+ continue;
404
+ }
405
+ if (typeof rec.prop !== "string" || !rec.prop) {
406
+ warnings.push(`map_token_prop '${rec.component}': missing prop \u2014 skipped`);
407
+ continue;
408
+ }
409
+ if (!isStringArray(rec.token_allowed) || rec.token_allowed.length === 0) {
410
+ warnings.push(`map_token_prop '${rec.component}.${String(rec.prop)}': missing or empty token_allowed \u2014 skipped`);
411
+ continue;
412
+ }
413
+ const call = {
414
+ tool: "map_token_prop",
415
+ component: rec.component,
416
+ prop: rec.prop,
417
+ token_allowed: rec.token_allowed
418
+ };
419
+ calls.push(call);
623
420
  }
624
- });
625
-
626
- // packages/experience-design-system-generation/dist/src/orchestrator/execute-generation-orchestrator.js
627
- async function executeGenerationOrchestrator(request2) {
628
- const prompt = await buildPrompt(request2.promptOptions);
629
- return request2.invoker.invoke({
630
- agent: request2.agent,
631
- model: request2.model,
632
- bedrock: request2.bedrock,
633
- prompt,
634
- timeoutMs: request2.timeoutMs,
635
- onOutput: request2.onOutput
636
- });
421
+ return { calls, warnings };
637
422
  }
638
- var init_execute_generation_orchestrator = __esm({
639
- "packages/experience-design-system-generation/dist/src/orchestrator/execute-generation-orchestrator.js"() {
640
- "use strict";
641
- init_build_prompt();
642
- }
643
- });
644
-
645
- // packages/experience-design-system-generation/dist/src/services/agent/helpers/resolve-agent-binary.js
646
- function resolveAgentBinary(agent) {
423
+ function resolveBinary(agent) {
647
424
  const envKey = `EDS_AGENT_BINARY_${agent.toUpperCase()}`;
648
425
  const override = process.env[envKey];
649
426
  if (override && override.trim())
650
427
  return override.trim();
651
428
  return AGENT_BINARIES[agent];
652
429
  }
653
- var init_resolve_agent_binary = __esm({
654
- "packages/experience-design-system-generation/dist/src/services/agent/helpers/resolve-agent-binary.js"() {
655
- "use strict";
656
- init_agent_names();
657
- }
658
- });
659
-
660
- // packages/experience-design-system-generation/dist/src/services/agent/helpers/build-agent-args.js
661
430
  function agentSupportsBedrock(agent) {
662
431
  return BEDROCK_CAPABLE_AGENTS.has(agent);
663
432
  }
664
- function withBedrockProviderPrefix(model) {
665
- return model.includes("/") ? model : `amazon-bedrock/${model}`;
666
- }
667
433
  function resolveAgentModel(agent, explicit, bedrock = false) {
668
434
  if (explicit && explicit.trim())
669
435
  return explicit.trim();
@@ -676,11 +442,14 @@ function resolveAgentModel(agent, explicit, bedrock = false) {
676
442
  return withBedrockProviderPrefix(DEFAULT_OPENCODE_MODEL);
677
443
  return DEFAULT_MODELS[agent];
678
444
  }
445
+ function withBedrockProviderPrefix(model) {
446
+ return model.includes("/") ? model : `amazon-bedrock/${model}`;
447
+ }
679
448
  function codexBedrockConfigArgs() {
680
449
  const region = process.env.AWS_REGION?.trim() || process.env.AWS_DEFAULT_REGION?.trim() || DEFAULT_CODEX_BEDROCK_REGION;
681
450
  return ["-c", "model_provider=amazon-bedrock", "-c", `model_providers.amazon-bedrock.region=${region}`];
682
451
  }
683
- function buildAgentArgs(agent, prompt, model, promptViaStdin = false, bedrock = false) {
452
+ function buildArgs(agent, prompt, model, promptViaStdin = false, bedrock = false) {
684
453
  const resolvedModel = resolveAgentModel(agent, model, bedrock);
685
454
  const modelArg = resolvedModel ? ["--model", resolvedModel] : [];
686
455
  const promptArg = promptViaStdin ? [] : [prompt];
@@ -702,69 +471,12 @@ function buildAgentArgs(agent, prompt, model, promptViaStdin = false, bedrock =
702
471
  }
703
472
  }
704
473
  }
705
- var BEDROCK_ENV_BY_AGENT, BEDROCK_CAPABLE_AGENTS, DEFAULT_CODEX_BEDROCK_REGION, DEFAULT_OPENCODE_MODEL, DEFAULT_CODEX_BEDROCK_MODEL, DEFAULT_MODELS;
706
- var init_build_agent_args = __esm({
707
- "packages/experience-design-system-generation/dist/src/services/agent/helpers/build-agent-args.js"() {
708
- "use strict";
709
- BEDROCK_ENV_BY_AGENT = {
710
- claude: { CLAUDE_CODE_USE_BEDROCK: "1" }
711
- };
712
- BEDROCK_CAPABLE_AGENTS = /* @__PURE__ */ new Set(["claude", "codex", "opencode"]);
713
- DEFAULT_CODEX_BEDROCK_REGION = "us-east-1";
714
- DEFAULT_OPENCODE_MODEL = "claude-haiku-4-5";
715
- DEFAULT_CODEX_BEDROCK_MODEL = "openai.gpt-5.6-luna";
716
- DEFAULT_MODELS = {
717
- claude: "haiku",
718
- opencode: DEFAULT_OPENCODE_MODEL,
719
- cursor: "gpt-mini",
720
- copilot: "Auto"
721
- };
722
- }
723
- });
724
-
725
- // packages/experience-design-system-generation/dist/src/services/agent/helpers/describe-agent-failure.js
726
- function describeAgentFailure(result, maxDetail = 800) {
727
- const base = result.exitCode !== 0 ? `agent exited with code ${result.exitCode}` : "agent produced no tool calls";
728
- const detail = (result.stderr.trim() || result.stdout.trim()).slice(-maxDetail).trim();
729
- return detail ? `${base} \u2014 ${detail}` : base;
730
- }
731
- var init_describe_agent_failure = __esm({
732
- "packages/experience-design-system-generation/dist/src/services/agent/helpers/describe-agent-failure.js"() {
733
- "use strict";
734
- }
735
- });
736
-
737
- // packages/experience-design-system-generation/dist/src/services/agent/helpers/extract-sentinel-output.js
738
- function extractSentinelOutput(stdout) {
739
- const START = "<<<EDS_OUTPUT_START>>>";
740
- const END = "<<<EDS_OUTPUT_END>>>";
741
- const startIdx = stdout.indexOf(START);
742
- const endIdx = stdout.indexOf(END);
743
- if (startIdx === -1 || endIdx === -1 || endIdx <= startIdx)
744
- return null;
745
- const secondStart = stdout.indexOf(START, startIdx + START.length);
746
- if (secondStart !== -1 && secondStart < endIdx)
747
- return "multiple";
748
- const afterStart = stdout.indexOf(END, startIdx);
749
- const secondEnd = stdout.indexOf(END, afterStart + END.length);
750
- if (secondEnd !== -1)
751
- return "multiple";
752
- return stdout.slice(startIdx + START.length, endIdx).trim();
753
- }
754
- var init_extract_sentinel_output = __esm({
755
- "packages/experience-design-system-generation/dist/src/services/agent/helpers/extract-sentinel-output.js"() {
756
- "use strict";
757
- }
758
- });
759
-
760
- // packages/experience-design-system-generation/dist/src/services/agent/run-agent.js
761
- import { spawn } from "node:child_process";
762
474
  async function runAgent(options) {
763
475
  const { agent, prompt, timeoutMs, model, onOutput, promptViaStdin, onDebugEvent } = options;
764
476
  const bedrock = options.bedrock ?? process.env.EDS_BEDROCK === "1";
765
- const binary = resolveAgentBinary(agent);
477
+ const binary = resolveBinary(agent);
766
478
  const useStdin2 = !!promptViaStdin;
767
- const args = buildAgentArgs(agent, prompt, model, useStdin2, bedrock);
479
+ const args = buildArgs(agent, prompt, model, useStdin2, bedrock);
768
480
  const startedAt = Date.now();
769
481
  onDebugEvent?.("run.start", {
770
482
  agent,
@@ -807,7 +519,12 @@ async function runAgent(options) {
807
519
  });
808
520
  child.on("close", (code, signal) => {
809
521
  clearTimeout(timer);
810
- const result = { exitCode: signal ? 1 : code ?? 1, stdout, stderr, timedOut };
522
+ const result = {
523
+ exitCode: signal ? 1 : code ?? 1,
524
+ stdout,
525
+ stderr,
526
+ timedOut
527
+ };
811
528
  onDebugEvent?.("run.end", {
812
529
  agent,
813
530
  model,
@@ -823,21 +540,22 @@ async function runAgent(options) {
823
540
  });
824
541
  });
825
542
  }
826
- var init_run_agent = __esm({
827
- "packages/experience-design-system-generation/dist/src/services/agent/run-agent.js"() {
828
- "use strict";
829
- init_resolve_agent_binary();
830
- init_build_agent_args();
831
- init_describe_agent_failure();
832
- init_extract_sentinel_output();
833
- }
834
- });
835
-
836
- // packages/experience-design-system-generation/dist/src/services/agent/helpers/check-claude-auth.js
837
- import { spawn as spawn2 } from "node:child_process";
838
- function checkClaudeAuth(binary) {
543
+ async function checkAgentAuth(agent) {
544
+ const binary = resolveBinary(agent);
545
+ const binaryExists2 = await new Promise((resolve21) => {
546
+ if (binary.startsWith("/")) {
547
+ import("node:fs/promises").then((fs2) => fs2.access(binary).then(() => resolve21(true), () => resolve21(false)));
548
+ return;
549
+ }
550
+ const child = spawn(process.platform === "win32" ? "where" : "which", [binary], { stdio: "ignore" });
551
+ child.on("close", (code) => resolve21(code === 0));
552
+ });
553
+ if (!binaryExists2)
554
+ return "not-found";
555
+ if (agent !== "claude")
556
+ return "ok";
839
557
  return new Promise((resolve21) => {
840
- const child = spawn2(binary, ["auth", "status", "--json"], {
558
+ const child = spawn(binary, ["auth", "status", "--json"], {
841
559
  stdio: ["ignore", "pipe", "pipe"]
842
560
  });
843
561
  let stdout = "";
@@ -858,51 +576,75 @@ function checkClaudeAuth(binary) {
858
576
  done = true;
859
577
  clearTimeout(timer);
860
578
  if (code !== 0) {
861
- resolve21("unauthenticated");
862
- return;
863
- }
864
- try {
865
- const status = JSON.parse(stdout);
866
- resolve21(status.loggedIn ? "ok" : "unauthenticated");
867
- } catch {
868
- resolve21("unauthenticated");
869
- }
870
- });
871
- });
872
- }
873
- var init_check_claude_auth = __esm({
874
- "packages/experience-design-system-generation/dist/src/services/agent/helpers/check-claude-auth.js"() {
875
- "use strict";
876
- }
877
- });
878
-
879
- // packages/experience-design-system-generation/dist/src/services/agent/helpers/check-agent-auth.js
880
- import { spawn as spawn3 } from "node:child_process";
881
- async function checkAgentAuth(agent) {
882
- const binary = resolveAgentBinary(agent);
883
- const binaryExists2 = await new Promise((resolve21) => {
884
- if (binary.startsWith("/")) {
885
- import("node:fs/promises").then((fs2) => fs2.access(binary).then(() => resolve21(true), () => resolve21(false)));
886
- return;
887
- }
888
- const child = spawn3(process.platform === "win32" ? "where" : "which", [binary], { stdio: "ignore" });
889
- child.on("close", (code) => resolve21(code === 0));
579
+ resolve21("unauthenticated");
580
+ return;
581
+ }
582
+ try {
583
+ const status = JSON.parse(stdout);
584
+ resolve21(status.loggedIn ? "ok" : "unauthenticated");
585
+ } catch {
586
+ resolve21("unauthenticated");
587
+ }
588
+ });
890
589
  });
891
- if (!binaryExists2)
892
- return "not-found";
893
- if (agent !== "claude")
894
- return "ok";
895
- return checkClaudeAuth(binary);
896
590
  }
897
- var init_check_agent_auth = __esm({
898
- "packages/experience-design-system-generation/dist/src/services/agent/helpers/check-agent-auth.js"() {
591
+ function describeAgentFailure(result, maxDetail = 800) {
592
+ const base = result.exitCode !== 0 ? `agent exited with code ${result.exitCode}` : "agent produced no tool calls";
593
+ const detail = (result.stderr.trim() || result.stdout.trim()).slice(-maxDetail).trim();
594
+ return detail ? `${base} \u2014 ${detail}` : base;
595
+ }
596
+ function extractSentinelOutput(stdout) {
597
+ const START = "<<<EDS_OUTPUT_START>>>";
598
+ const END = "<<<EDS_OUTPUT_END>>>";
599
+ const startIdx = stdout.indexOf(START);
600
+ const endIdx = stdout.indexOf(END);
601
+ if (startIdx === -1 || endIdx === -1 || endIdx <= startIdx)
602
+ return null;
603
+ const secondStart = stdout.indexOf(START, startIdx + START.length);
604
+ if (secondStart !== -1 && secondStart < endIdx)
605
+ return "multiple";
606
+ const afterStart = stdout.indexOf(END, startIdx);
607
+ const secondEnd = stdout.indexOf(END, afterStart + END.length);
608
+ if (secondEnd !== -1)
609
+ return "multiple";
610
+ return stdout.slice(startIdx + START.length, endIdx).trim();
611
+ }
612
+ var VALID_SELECT_TOOL_NAMES, VALID_TOOL_NAMES, VALID_TOKEN_TOOL_NAMES, VALID_CDF_TYPES, VALID_CATEGORIES, AGENT_BINARIES, BEDROCK_ENV_BY_AGENT, BEDROCK_CAPABLE_AGENTS, DEFAULT_CODEX_BEDROCK_REGION, DEFAULT_OPENCODE_MODEL, DEFAULT_MODELS, DEFAULT_CODEX_BEDROCK_MODEL;
613
+ var init_agent_runner = __esm({
614
+ "packages/experience-design-system-generation/dist/src/agent-runner.js"() {
899
615
  "use strict";
900
- init_resolve_agent_binary();
901
- init_check_claude_auth();
616
+ init_agent_names();
617
+ VALID_SELECT_TOOL_NAMES = /* @__PURE__ */ new Set(["select_component", "reject_component"]);
618
+ VALID_TOOL_NAMES = /* @__PURE__ */ new Set(["classify_prop", "exclude_prop", "classify_component", "classify_slot"]);
619
+ VALID_TOKEN_TOOL_NAMES = /* @__PURE__ */ new Set(["set_token", "set_group"]);
620
+ VALID_CDF_TYPES = /* @__PURE__ */ new Set(["string", "richtext", "media", "enum", "token", "boolean"]);
621
+ VALID_CATEGORIES = /* @__PURE__ */ new Set(["content", "design", "state"]);
622
+ AGENT_BINARIES = {
623
+ claude: "claude",
624
+ codex: "codex",
625
+ opencode: "opencode",
626
+ cursor: "cursor-agent",
627
+ copilot: "copilot"
628
+ };
629
+ BEDROCK_ENV_BY_AGENT = {
630
+ claude: { CLAUDE_CODE_USE_BEDROCK: "1" }
631
+ };
632
+ BEDROCK_CAPABLE_AGENTS = /* @__PURE__ */ new Set(["claude", "codex", "opencode"]);
633
+ DEFAULT_CODEX_BEDROCK_REGION = "us-east-1";
634
+ DEFAULT_OPENCODE_MODEL = "claude-haiku-4-5";
635
+ DEFAULT_MODELS = {
636
+ claude: "haiku",
637
+ opencode: DEFAULT_OPENCODE_MODEL,
638
+ cursor: "gpt-mini",
639
+ // cursor alias for gpt-5.4-mini-medium; haiku not in cursor's catalog
640
+ copilot: "Auto"
641
+ // the only model guaranteed on every Copilot plan (Free/Pro/Business/Enterprise); Pro+ users override via EDS_AGENT_MODEL_COPILOT
642
+ };
643
+ DEFAULT_CODEX_BEDROCK_MODEL = "openai.gpt-5.6-luna";
902
644
  }
903
645
  });
904
646
 
905
- // packages/experience-design-system-generation/dist/src/services/agent/local-cli-agent-invoker.js
647
+ // packages/experience-design-system-generation/dist/src/agent-invoker.js
906
648
  function createLocalCliAgentInvoker(options = {}) {
907
649
  const { onDebugEvent } = options;
908
650
  return {
@@ -914,310 +656,381 @@ function createLocalCliAgentInvoker(options = {}) {
914
656
  }
915
657
  };
916
658
  }
917
- var init_local_cli_agent_invoker = __esm({
918
- "packages/experience-design-system-generation/dist/src/services/agent/local-cli-agent-invoker.js"() {
659
+ var init_agent_invoker = __esm({
660
+ "packages/experience-design-system-generation/dist/src/agent-invoker.js"() {
919
661
  "use strict";
920
- init_run_agent();
921
- init_check_agent_auth();
662
+ init_agent_runner();
922
663
  }
923
664
  });
924
665
 
925
- // packages/experience-design-system-generation/dist/src/controller/create-generation-endpoint.js
926
- function createGenerationEndpoint(options = {}) {
927
- const invoker2 = createLocalCliAgentInvoker({ onDebugEvent: options.onDebugEvent });
928
- return {
929
- async run(request2) {
930
- validateGenerationRequest(request2);
931
- return executeGenerationOrchestrator({ ...request2, invoker: invoker2 });
932
- },
933
- checkAuth(agent) {
934
- return invoker2.checkAuth(agent);
935
- }
936
- };
666
+ // packages/experience-design-system-generation/dist/src/prompt-builder.js
667
+ import { existsSync } from "node:fs";
668
+ import { readFile as readFile2 } from "node:fs/promises";
669
+ import { dirname, join as join2, resolve } from "node:path";
670
+ import { fileURLToPath } from "node:url";
671
+ import { flattenDTCG } from "@contentful/experience-design-system-types";
672
+ function formatCustomPromptBanner(skill, path) {
673
+ return `WARNING: Custom prompt active for ${skill}: ${path}
674
+ Bundled invariants (utility-wrapper rejection, description content rules) do NOT apply.
675
+ You are responsible for the prompt's correctness.
676
+ `;
937
677
  }
938
- var init_create_generation_endpoint = __esm({
939
- "packages/experience-design-system-generation/dist/src/controller/create-generation-endpoint.js"() {
940
- "use strict";
941
- init_validate_generation_request();
942
- init_execute_generation_orchestrator();
943
- init_local_cli_agent_invoker();
944
- }
945
- });
678
+ async function buildPrompt(options) {
679
+ const skillContent = options.skillContentOverride ?? await readSkillFile(options.skill, options.skillPathOverride);
680
+ const preamble = buildPreamble(options);
681
+ return `${preamble}
946
682
 
947
- // packages/experience-design-system-generation/dist/src/services/parsing/helpers/read-tool-call-objects.js
948
- function findJsonObjectEnd(line) {
949
- let depth = 0;
950
- let inString = false;
951
- let escaped = false;
952
- for (let i = 0; i < line.length; i++) {
953
- const ch = line[i];
954
- if (escaped) {
955
- escaped = false;
956
- } else if (ch === "\\" && inString) {
957
- escaped = true;
958
- } else if (ch === '"') {
959
- inString = !inString;
960
- } else if (!inString && ch === "{") {
961
- depth++;
962
- } else if (!inString && ch === "}" && --depth === 0) {
963
- return i;
683
+ Skill instructions follow:
684
+ ---
685
+ ${skillContent}`;
686
+ }
687
+ function resolveSkillPath(skill) {
688
+ if (!(skill in SKILL_FILES))
689
+ throw new Error(`Invalid skill: ${skill}`);
690
+ const thisDir = dirname(fileURLToPath(import.meta.url));
691
+ let dir = thisDir;
692
+ for (; ; ) {
693
+ const candidate = join2(dir, "skills");
694
+ if (existsSync(candidate))
695
+ return join2(candidate, SKILL_FILES[skill]);
696
+ const parent = resolve(dir, "..");
697
+ if (parent === dir) {
698
+ throw new Error(`skill file missing from CLI installation (could not locate skills/ directory from: ${thisDir})`);
964
699
  }
700
+ dir = parent;
965
701
  }
966
- return -1;
967
702
  }
968
- function readToolCallObjects(stdout) {
969
- const objects = [];
970
- const warnings = [];
971
- for (const raw of stdout.split("\n")) {
972
- const line = raw.trim();
973
- if (!line.startsWith("{"))
974
- continue;
975
- const end = findJsonObjectEnd(line);
976
- if (end === -1) {
977
- warnings.push(`unparseable line: ${line.slice(0, 120)}`);
978
- continue;
979
- }
980
- let parsed;
703
+ async function readSkillFile(skill, override) {
704
+ if (override) {
705
+ const skillPath2 = resolve(override);
981
706
  try {
982
- parsed = JSON.parse(line.slice(0, end + 1));
707
+ return await readFile2(skillPath2, "utf8");
983
708
  } catch {
984
- warnings.push(`unparseable line: ${line.slice(0, 120)}`);
985
- continue;
986
- }
987
- const trailing = line.slice(end + 1);
988
- if (trailing.trim()) {
989
- warnings.push(`ignored trailing content after JSON: ${trailing.trim().slice(0, 120)}`);
990
- }
991
- if (typeof parsed === "object" && parsed !== null && "tool" in parsed) {
992
- objects.push(parsed);
709
+ throw new Error(`custom prompt file not found (skill: ${skill}, path: ${skillPath2})`);
993
710
  }
994
711
  }
995
- return { objects, warnings };
996
- }
997
- var init_read_tool_call_objects = __esm({
998
- "packages/experience-design-system-generation/dist/src/services/parsing/helpers/read-tool-call-objects.js"() {
999
- "use strict";
712
+ const skillPath = resolveSkillPath(skill);
713
+ try {
714
+ return await readFile2(skillPath, "utf8");
715
+ } catch {
716
+ throw new Error(`skill file missing from CLI installation \u2014 try reinstalling the CLI (looked for: ${skillPath})`);
1000
717
  }
1001
- });
1002
-
1003
- // packages/experience-design-system-generation/dist/src/services/parsing/parse-prop-tool-calls.js
1004
- function parsePropToolCallLines(stdout) {
1005
- const calls = [];
1006
- const { objects, warnings } = readToolCallObjects(stdout);
1007
- for (const rec of objects) {
1008
- if (!VALID_TOOL_NAMES.has(rec.tool)) {
1009
- warnings.push(`unknown tool: ${String(rec.tool)}`);
1010
- continue;
1011
- }
1012
- const tool = rec.tool;
1013
- if (tool === "classify_prop") {
1014
- if (typeof rec.prop !== "string" || !rec.prop) {
1015
- warnings.push("classify_prop missing prop name \u2014 skipped");
1016
- continue;
1017
- }
1018
- if (typeof rec.cdf_type !== "string" || !VALID_CDF_TYPES.has(rec.cdf_type)) {
1019
- warnings.push(`classify_prop '${rec.prop}': invalid cdf_type '${String(rec.cdf_type)}' \u2014 skipped`);
1020
- continue;
1021
- }
1022
- if (typeof rec.cdf_category !== "string" || !VALID_CATEGORIES.has(rec.cdf_category)) {
1023
- warnings.push(`classify_prop '${rec.prop}': invalid cdf_category '${String(rec.cdf_category)}' \u2014 skipped`);
1024
- continue;
1025
- }
1026
- const call = {
1027
- tool: "classify_prop",
1028
- prop: rec.prop,
1029
- cdf_type: rec.cdf_type,
1030
- cdf_category: rec.cdf_category
1031
- };
1032
- if (Array.isArray(rec.values) && rec.values.every((v) => typeof v === "string"))
1033
- call.values = rec.values;
1034
- if (typeof rec.token_kind === "string")
1035
- call.token_kind = rec.token_kind;
1036
- if (typeof rec.required === "boolean")
1037
- call.required = rec.required;
1038
- if (typeof rec.description === "string")
1039
- call.description = rec.description;
1040
- if (typeof rec.default === "string" || typeof rec.default === "boolean")
1041
- call.default = rec.default;
1042
- if (typeof rec.reason === "string")
1043
- call.reason = rec.reason;
1044
- calls.push(call);
1045
- } else if (tool === "exclude_prop") {
1046
- if (typeof rec.prop !== "string" || !rec.prop) {
1047
- warnings.push("exclude_prop missing prop name \u2014 skipped");
1048
- continue;
1049
- }
1050
- calls.push({ tool: "exclude_prop", prop: rec.prop, reason: typeof rec.reason === "string" ? rec.reason : "" });
1051
- } else if (tool === "classify_component") {
1052
- const call = { tool: "classify_component" };
1053
- if (typeof rec.description === "string")
1054
- call.description = rec.description;
1055
- if (typeof rec.rationale === "object" && rec.rationale !== null) {
1056
- const r = rec.rationale;
1057
- const rationale = {};
1058
- if (typeof r.description === "string")
1059
- rationale.description = r.description;
1060
- if (typeof r.props === "string")
1061
- rationale.props = r.props;
1062
- if (typeof r.slots === "string")
1063
- rationale.slots = r.slots;
1064
- if (Object.keys(rationale).length > 0)
1065
- call.rationale = rationale;
1066
- }
1067
- calls.push(call);
1068
- } else if (tool === "classify_slot") {
1069
- if (typeof rec.slot !== "string" || !rec.slot) {
1070
- warnings.push("classify_slot missing slot name \u2014 skipped");
1071
- continue;
1072
- }
1073
- const call = { tool: "classify_slot", slot: rec.slot };
1074
- if (typeof rec.required === "boolean")
1075
- call.required = rec.required;
1076
- if (Array.isArray(rec.allowed_components) && rec.allowed_components.every((v) => typeof v === "string")) {
1077
- call.allowed_components = rec.allowed_components;
718
+ }
719
+ function inferFenceLang(filename) {
720
+ if (!filename)
721
+ return "json";
722
+ const ext = filename.split(".").pop()?.toLowerCase() ?? "";
723
+ const map = {
724
+ js: "js",
725
+ mjs: "js",
726
+ cjs: "js",
727
+ ts: "ts",
728
+ mts: "ts",
729
+ cts: "ts",
730
+ tsx: "tsx",
731
+ jsx: "jsx",
732
+ vue: "vue",
733
+ svelte: "svelte",
734
+ astro: "astro",
735
+ scss: "scss",
736
+ sass: "scss",
737
+ css: "css",
738
+ json: "json",
739
+ json5: "json"
740
+ };
741
+ return map[ext] ?? "text";
742
+ }
743
+ function filterDesignTokenProps(cdf) {
744
+ const result = {};
745
+ const kinds = /* @__PURE__ */ new Set();
746
+ let hasUnscoped = false;
747
+ for (const [componentName, component] of Object.entries(cdf)) {
748
+ const properties = component.$properties;
749
+ if (!properties)
750
+ continue;
751
+ const filteredProps = {};
752
+ for (const [propName, prop] of Object.entries(properties)) {
753
+ if (prop.$type === "token" && prop.$category === "design") {
754
+ const { "$token.allowed": _tokenAllowed, ...rest } = prop;
755
+ filteredProps[propName] = rest;
756
+ const kind = prop["$token.kind"];
757
+ if (typeof kind === "string" && kind.length > 0) {
758
+ kinds.add(kind);
759
+ } else {
760
+ hasUnscoped = true;
761
+ }
1078
762
  }
1079
- if (typeof rec.description === "string")
1080
- call.description = rec.description;
1081
- if (typeof rec.rationale === "string")
1082
- call.rationale = rec.rationale;
1083
- calls.push(call);
763
+ }
764
+ if (Object.keys(filteredProps).length > 0) {
765
+ result[componentName] = { ...component, $properties: filteredProps };
1084
766
  }
1085
767
  }
1086
- return { calls, warnings };
768
+ return { filtered: result, kinds: [...kinds].sort(), hasUnscoped };
1087
769
  }
1088
- var VALID_TOOL_NAMES, VALID_CDF_TYPES, VALID_CATEGORIES;
1089
- var init_parse_prop_tool_calls = __esm({
1090
- "packages/experience-design-system-generation/dist/src/services/parsing/parse-prop-tool-calls.js"() {
1091
- "use strict";
1092
- init_read_tool_call_objects();
1093
- VALID_TOOL_NAMES = /* @__PURE__ */ new Set(["classify_prop", "exclude_prop", "classify_component", "classify_slot"]);
1094
- VALID_CDF_TYPES = /* @__PURE__ */ new Set(["string", "richtext", "media", "enum", "token", "boolean"]);
1095
- VALID_CATEGORIES = /* @__PURE__ */ new Set(["content", "design", "state"]);
770
+ function formatTokenCandidateLines(entries) {
771
+ return entries.map((entry) => `${entry.path} \xB7 ${entry.$type}`).join("\n");
772
+ }
773
+ function renderTokenCandidateSection(kind, entries) {
774
+ const label = kind ? `Token path index \u2014 ${kind} candidates only` : "Token path index \u2014 full tree (no $token.kind to scope by)";
775
+ return `${label}, one leaf token per line as \`path \xB7 type\`, no \`$value\`:
776
+ ${formatTokenCandidateLines(entries)}`;
777
+ }
778
+ function buildPreamble(options) {
779
+ const { skill, rawComponentsInline, rawTokensInline, rawTokensFilename, tokensInline, tokenMapInline, generatedCdf, tokenTree, componentSourceRefs, existingComponentsInline, existingTokensInline, componentAllowlistInline } = options;
780
+ const sections = [];
781
+ if (existingComponentsInline) {
782
+ sections.push(`Existing components in the target Contentful space (JSON) \u2014 use for alignment, not as a hard filter:
783
+ \`\`\`json
784
+ ${existingComponentsInline}
785
+ \`\`\``);
1096
786
  }
1097
- });
1098
-
1099
- // packages/experience-design-system-generation/dist/src/services/parsing/parse-select-tool-calls.js
1100
- function parseSelectToolCallLines(stdout) {
1101
- const calls = [];
1102
- const { objects, warnings } = readToolCallObjects(stdout);
1103
- for (const rec of objects) {
1104
- if (!VALID_SELECT_TOOL_NAMES.has(rec.tool))
1105
- continue;
1106
- if (typeof rec.name !== "string" || !rec.name) {
1107
- warnings.push(`${String(rec.tool)} missing name \u2014 skipped`);
1108
- continue;
1109
- }
1110
- const call = { tool: rec.tool, name: rec.name };
1111
- if (typeof rec.reason === "string")
1112
- call.reason = rec.reason;
1113
- if (typeof rec.confidence === "number" && rec.confidence >= 1 && rec.confidence <= 5) {
1114
- if (call.tool === "select_component") {
1115
- call.confidence = rec.confidence;
787
+ if (existingTokensInline) {
788
+ sections.push(`Existing design tokens in the target Contentful space (JSON) \u2014 prefer binding to these paths over inventing new ones:
789
+ \`\`\`json
790
+ ${existingTokensInline}
791
+ \`\`\``);
792
+ }
793
+ if (componentAllowlistInline) {
794
+ sections.push(`Known component names for slot allowed_components (hard allowlist; never use any other name):
795
+ \`\`\`json
796
+ ${componentAllowlistInline}
797
+ \`\`\``);
798
+ }
799
+ if (rawComponentsInline) {
800
+ sections.push(`Raw component data (JSON):
801
+ \`\`\`json
802
+ ${rawComponentsInline}
803
+ \`\`\``);
804
+ }
805
+ if (rawTokensInline) {
806
+ const lang = inferFenceLang(rawTokensFilename);
807
+ const label = rawTokensFilename ? `Raw token source (${rawTokensFilename})` : "Raw token source";
808
+ sections.push(`${label}:
809
+ \`\`\`${lang}
810
+ ${rawTokensInline}
811
+ \`\`\``);
812
+ }
813
+ if (tokensInline) {
814
+ sections.push(`DTCG token data (for token kind lookups):
815
+ \`\`\`json
816
+ ${tokensInline}
817
+ \`\`\``);
818
+ }
819
+ if (tokenMapInline) {
820
+ sections.push(`Token-name sidecar (raw name \u2192 DTCG path):
821
+ \`\`\`json
822
+ ${tokenMapInline}
823
+ \`\`\``);
824
+ }
825
+ const filteredTokenProps = generatedCdf ? filterDesignTokenProps(generatedCdf) : void 0;
826
+ if (filteredTokenProps && Object.keys(filteredTokenProps.filtered).length > 0) {
827
+ sections.push(`Generated CDF so far \u2014 design-category token props only (JSON):
828
+ \`\`\`json
829
+ ${JSON.stringify(filteredTokenProps.filtered)}
830
+ \`\`\``);
831
+ }
832
+ if (tokenTree) {
833
+ const index = flattenDTCG(tokenTree, "").sort((a, b) => a.path.localeCompare(b.path));
834
+ if (index.length > 0) {
835
+ if (filteredTokenProps) {
836
+ const { kinds, hasUnscoped } = filteredTokenProps;
837
+ for (const kind of kinds) {
838
+ const scoped = index.filter((entry) => entry.$type === kind);
839
+ if (scoped.length > 0)
840
+ sections.push(renderTokenCandidateSection(kind, scoped));
841
+ }
842
+ if (hasUnscoped)
843
+ sections.push(renderTokenCandidateSection(null, index));
1116
844
  } else {
1117
- call.confidence = rec.confidence;
845
+ sections.push(renderTokenCandidateSection(null, index));
1118
846
  }
1119
847
  }
1120
- calls.push(call);
1121
848
  }
1122
- return { calls, warnings };
1123
- }
1124
- var VALID_SELECT_TOOL_NAMES;
1125
- var init_parse_select_tool_calls = __esm({
1126
- "packages/experience-design-system-generation/dist/src/services/parsing/parse-select-tool-calls.js"() {
1127
- "use strict";
1128
- init_read_tool_call_objects();
1129
- VALID_SELECT_TOOL_NAMES = /* @__PURE__ */ new Set(["select_component", "reject_component"]);
1130
- }
1131
- });
849
+ if (componentSourceRefs && componentSourceRefs.length > 0) {
850
+ const withContent = componentSourceRefs.filter((ref) => ref.content != null);
851
+ const withoutContent = componentSourceRefs.filter((ref) => ref.content == null);
852
+ if (withContent.length > 0) {
853
+ const blocks = withContent.map((ref) => {
854
+ const mainBlock = `#### ${ref.component} (\`${ref.sourcePath}\`)
855
+ \`\`\`${inferFenceLang(ref.sourcePath)}
856
+ ${ref.content}
857
+ \`\`\``;
858
+ const siblingBlocks = (ref.siblingFiles ?? []).map((sibling) => `##### ${ref.component} \u2014 imported file \`${sibling.path}\`
859
+ \`\`\`${inferFenceLang(sibling.path)}
860
+ ${sibling.content}
861
+ \`\`\``);
862
+ const truncationNote = ref.truncatedSiblingCount && ref.truncatedSiblingCount > 0 ? [
863
+ `##### ${ref.component} \u2014 +${ref.truncatedSiblingCount} more imported file${ref.truncatedSiblingCount === 1 ? "" : "s"} not shown (evidence may be incomplete)`
864
+ ] : [];
865
+ const notShownNote = ref.usesNotShown && ref.usesNotShown.length > 0 ? [
866
+ `##### ${ref.component} \u2014 uses not shown: ${ref.usesNotShown.join(", ")}
1132
867
 
1133
- // packages/experience-design-system-generation/dist/src/services/parsing/parse-token-tool-calls.js
1134
- function parseTokenToolCallLines(stdout) {
1135
- const calls = [];
1136
- const { objects, warnings } = readToolCallObjects(stdout);
1137
- for (const rec of objects) {
1138
- if (!VALID_TOKEN_TOOL_NAMES.has(rec.tool))
1139
- continue;
1140
- if (rec.tool === "set_token") {
1141
- if (typeof rec.path !== "string" || !rec.path) {
1142
- warnings.push("set_token missing path \u2014 skipped");
1143
- continue;
1144
- }
1145
- if (typeof rec.type !== "string" || !rec.type) {
1146
- warnings.push(`set_token '${rec.path}': missing type \u2014 skipped`);
1147
- continue;
1148
- }
1149
- if (!("value" in rec)) {
1150
- warnings.push(`set_token '${rec.path}': missing value \u2014 skipped`);
1151
- continue;
1152
- }
1153
- const call = { tool: "set_token", path: rec.path, type: rec.type, value: rec.value };
1154
- if (typeof rec.description === "string")
1155
- call.description = rec.description;
1156
- calls.push(call);
1157
- } else if (rec.tool === "set_group") {
1158
- if (typeof rec.path !== "string" || !rec.path) {
1159
- warnings.push("set_group missing path \u2014 skipped");
1160
- continue;
1161
- }
1162
- const call = { tool: "set_group", path: rec.path };
1163
- if (typeof rec.description === "string")
1164
- call.description = rec.description;
1165
- calls.push(call);
868
+ The files above are excerpts, and each of these properties has at least one use that fell outside the excerpt budget. Treat their consumption as unknown, not absent: do not classify them \`token\` on what is shown, and do not conclude they are unread.`
869
+ ] : [];
870
+ return [mainBlock, ...siblingBlocks, ...truncationNote, ...notShownNote].join("\n\n");
871
+ });
872
+ sections.push(`### Component source references
873
+
874
+ ${blocks.join("\n\n")}`);
875
+ }
876
+ if (withoutContent.length > 0) {
877
+ const guidance = skill === "components" ? "there is no consumption evidence for these, so `token` cannot be earned for any of their props \u2014 classify from the prop signature alone, and any prop that would otherwise be enum-versus-token is `enum` (or `string`)" : "there is no source evidence to narrow from \u2014 emit nothing for their props";
878
+ sections.push(`Component source unavailable for (JSON) \u2014 ${guidance}:
879
+ \`\`\`json
880
+ ${JSON.stringify(withoutContent.map((ref) => ({ component: ref.component, sourcePath: ref.sourcePath })))}
881
+ \`\`\``);
1166
882
  }
1167
883
  }
1168
- return { calls, warnings };
1169
- }
1170
- var VALID_TOKEN_TOOL_NAMES;
1171
- var init_parse_token_tool_calls = __esm({
1172
- "packages/experience-design-system-generation/dist/src/services/parsing/parse-token-tool-calls.js"() {
1173
- "use strict";
1174
- init_read_tool_call_objects();
1175
- VALID_TOKEN_TOOL_NAMES = /* @__PURE__ */ new Set(["set_token", "set_group"]);
884
+ const inputBlock = sections.length > 0 ? `
885
+
886
+ ${sections.join("\n\n")}` : "";
887
+ if (skill === "components") {
888
+ return buildComponentsAutonomousPreamble(inputBlock);
1176
889
  }
1177
- });
890
+ if (skill === "select") {
891
+ return buildSelectAutonomousPreamble(inputBlock);
892
+ }
893
+ if (skill === "map-tokens") {
894
+ return buildMapTokensAutonomousPreamble(inputBlock);
895
+ }
896
+ return buildTokensAutonomousPreamble(inputBlock);
897
+ }
898
+ function buildComponentsAutonomousPreamble(inputBlock) {
899
+ return `You are running as part of the experience-design-system-cli generate pipeline in AUTONOMOUS mode. The developer is not present to answer questions.
900
+
901
+ Context: You are classifying a React component for **Contentful Experience Orchestration**. The result is a Component Type \u2014 a schema that tells Contentful what a marketer can configure. Properties fall into three categories:
902
+ - **design**: controls how the component looks (variant, size, color, layout toggles)
903
+ - **content**: the data a content editor fills in (text, images, URLs, rich text)
904
+ - **state**: runtime behavioral flags (disabled, loading, expanded, identifiers)
905
+
906
+ Your task: classify every prop and slot in the component below. Apply all judgment calls yourself \u2014 do not pause to ask for confirmation. Include a "description" field on each tool call to document your reasoning so the developer can review it afterward.
907
+
908
+ All input data is provided inline below \u2014 do not read any additional files.${inputBlock}
909
+
910
+ ## Output protocol
911
+
912
+ Do NOT write any files or emit any JSON blobs. Instead, emit one JSON object per line to stdout for each classification decision. The CLI reads your stdout line by line and writes each decision directly to the pipeline database.
913
+
914
+ The four tool calls you may emit are:
915
+
916
+ \`\`\`
917
+ {"tool":"classify_component","description":"<optional component-level description>","rationale":{"description":"<why this component is classified the way it is>","props":"<why these props were chosen>","slots":"<why these slots were chosen>"}}
918
+
919
+ {"tool":"classify_prop","prop":"<propName>","cdf_type":"<type>","cdf_category":"<category>","required":<bool>,"description":"<short customer-facing description>","reason":"<full internal rationale; not customer-facing>","values":["a","b"],"token_kind":"color","default":"<value>"}
920
+
921
+ {"tool":"exclude_prop","prop":"<propName>","reason":"<why excluded>"}
922
+
923
+ {"tool":"classify_slot","slot":"<slotName>","required":<bool>,"allowed_components":["ComponentName"],"description":"<reason>","rationale":"<why this slot was kept in the catalog>"}
924
+ \`\`\`
925
+
926
+ Rules:
927
+ - Emit exactly one JSON object per line. No multi-line JSON. No markdown fences around the lines.
928
+ - Every prop in the input must have exactly one call: either classify_prop or exclude_prop.
929
+ - Every slot in the input must have exactly one classify_slot call.
930
+ - Valid cdf_type values: string, richtext, media, enum, token, boolean
931
+ - Valid cdf_category values: content, design, state
932
+ - For enum type, always include \`values\` (non-empty string array of the variant names the prop accepts).
933
+ - For token type, always include \`token_kind\` (DTCG $type, e.g. "color"). **Never emit \`values\` for \`cdf_type: "token"\` props** \u2014 an enum prop's list holds variant names; a token prop's list holds design token paths, produced separately and never by you. Emitting \`values\` on a token prop makes the definition invalid.
934
+ - Never emit both "values" and "token_kind" on one prop.
935
+ - \`enum\` vs \`token\` is decided by three questions answered in order from the source shown \u2014 never from the TypeScript type. Q1: does the component look the value up, switch on it, or have a vocabulary for it (\`tokens[x]\`, \`switch (variant)\`, \`allowedValues\`)? yes \u2192 \`enum\`, stop.
936
+ - Q2: is the value written straight into a style or attribute (\`rx={radius}\`, \`padding: \${padding}\`)? no \u2192 not \`token\`, apply the type rules.
937
+ - Q3: is there a design-token reference at that use \u2014 a \`tokens.*\` parameter default, a \`tokenReference\`, an inline \`tokens.*\` / \`var(--*)\`? yes \u2192 \`token\` (cite both lines in "reason"); no \u2192 \`string\`. "Ambiguity resolves to \`enum\`" applies only when Q1\u2013Q3 cannot be answered from the source shown.
938
+ - CSS design props (className, style, styles, positional/geometric props: top, bottom, left, right, rotation, offset, etc.) \u2192 classify_prop, cdf_type: "string", cdf_category: "design".
939
+ - For \`classify_slot.allowed_components\`, use only exact names from the hard allowlist provided below. Never invent a child from an import, JSX element, type name, icon name, or implementation helper; if a child is not listed, omit it.
940
+ - On classify_component, "rationale" fields are operator-facing (read-only) but may surface in customer-facing exports. The "rationale.description" field is subject to the description content rules in the skill prompt (no internal initiative names). "rationale.props" and "rationale.slots" describe your reasoning about scope; "classify_slot.rationale" explains why each slot was kept.
941
+ - On classify_prop, "reason" is REQUIRED and is the LLM's internal rationale \u2014 shown to the developer reviewing the import, never to end-users. "description" is the customer-facing copy and is subject to the description content rules in the skill prompt. Keep them distinct: "description" is short and customer-facing; "reason" explains your reasoning in detail.
942
+ - You may emit prose lines (not starting with {) anywhere \u2014 they are ignored by the parser and serve as your reasoning log.`;
943
+ }
944
+ function buildSelectAutonomousPreamble(inputBlock) {
945
+ return `You are running as part of the experience-design-system-cli import pipeline in AUTONOMOUS mode. The developer is not present to answer questions.
946
+
947
+ Your task: review the components provided below and decide whether each belongs in Contentful Experience Orchestration as a Component Type. The input is a JSON array \u2014 you may receive 1\u2013N components in a single message. Emit one tool call per input component, named after the component. Apply all judgment calls yourself \u2014 do not pause to ask for confirmation. Include a brief "reason" to document your reasoning for each decision.
948
+
949
+ Key rule: accept any component that renders visible UI \u2014 atoms, molecules, and organisms are all valid Component Types in Contentful Experience Orchestration. Reject only components that produce zero visual output: React hooks, pure context providers, A/B testing or variant-routing wrappers, analytics trackers, and security utilities. Do NOT reject a component because it has few props, is low-level, or has some A/B testing or personalization-related props mixed in \u2014 those props are handled in the generate step.
950
+
951
+ All input data is provided inline below \u2014 do not read any additional files.${inputBlock}
952
+
953
+ ## Output protocol
954
+
955
+ Do NOT write any files or emit any JSON blobs. Instead, emit JSON tool calls one per line to stdout. The CLI reads your stdout line by line.
956
+
957
+ The two tool calls \u2014 emit exactly one per input component:
958
+
959
+ \`\`\`
960
+ {"tool":"select_component","name":"<ComponentName>","reason":"<brief reason>"}
961
+
962
+ {"tool":"reject_component","name":"<ComponentName>","reason":"<brief reason>"}
963
+ \`\`\`
964
+
965
+ Rules:
966
+ - Emit exactly one JSON object per line. No multi-line JSON. No markdown fences.
967
+ - Emit exactly one tool call per input component. The "name" field must match a component name from the input array exactly. Tool calls may appear in any order.
968
+ - You may emit prose lines (not starting with {) to reason before each tool call \u2014 they are ignored by the parser.`;
969
+ }
970
+ function buildMapTokensAutonomousPreamble(inputBlock) {
971
+ return `You are running as part of the experience-design-system-cli generate pipeline in AUTONOMOUS mode. The developer is not present to answer questions.
972
+
973
+ Context: The components below already have design-category, token-typed props (\`$token.kind\` set). Your task is to decide, from source evidence, whether to narrow each one to a restricted subset (\`token_allowed\`) of the tokens matching its \`$token.kind\`. Apply all judgment calls yourself \u2014 do not pause to ask for confirmation.
974
+
975
+ All input data is provided inline below \u2014 do not read any additional files.${inputBlock}
976
+
977
+ ## Output protocol
978
+
979
+ Do NOT write any files or emit any JSON blobs. Instead, emit one JSON object per line to stdout for each prop you narrow. The CLI reads your stdout line by line and writes each decision directly to the pipeline database.
980
+
981
+ The one tool call you may emit:
1178
982
 
1179
- // packages/experience-design-system-generation/dist/src/services/parsing/parse-map-token-tool-calls.js
1180
- function isStringArray(value) {
1181
- return Array.isArray(value) && value.every((v) => typeof v === "string");
983
+ \`\`\`
984
+ {"tool":"map_token_prop","component":"<ComponentName>","prop":"<propName>","token_allowed":["colors.brand.primary","colors.brand.secondary"]}
985
+ \`\`\`
986
+
987
+ Rules:
988
+ - Emit exactly one JSON object per line. No multi-line JSON. No markdown fences around the lines.
989
+ - Only emit a call for a prop that appears in the "Generated CDF so far" section.
990
+ - Each "Token path index" section below is already scoped to one \`$token.kind\` \u2014 a prop only draws candidates from the section matching its own \`$token.kind\` (or the "full tree" section, for a prop with no \`$token.kind\`). Never cross sections, never emit a group/prefix path, and never invent a path \u2014 every entry in \`token_allowed\` must exist verbatim in the matching section.
991
+ - \`token_allowed\` is required and must be non-empty when the call is emitted.
992
+ - For the judgment call of whether a prop should be narrowed at all, follow the decision tree in the map-tokens skill file: it explains defaults vs. restrictions, misclassified variant-name props, and when to emit nothing.
993
+ - You may emit prose lines (not starting with \`{\`) anywhere \u2014 they are ignored by the parser and serve as your reasoning log.`;
1182
994
  }
1183
- function parseMapTokenPropToolCallLines(stdout) {
1184
- const calls = [];
1185
- const warnings = [];
1186
- for (const raw of stdout.split("\n")) {
1187
- const line = raw.trim();
1188
- if (!line.startsWith("{"))
1189
- continue;
1190
- let obj;
1191
- try {
1192
- obj = JSON.parse(line);
1193
- } catch {
1194
- warnings.push(`unparseable line: ${line.slice(0, 120)}`);
1195
- continue;
1196
- }
1197
- if (typeof obj !== "object" || obj === null || !("tool" in obj))
1198
- continue;
1199
- const rec = obj;
1200
- if (rec.tool !== "map_token_prop")
1201
- continue;
1202
- if (typeof rec.component !== "string" || !rec.component) {
1203
- warnings.push("map_token_prop missing component \u2014 skipped");
1204
- continue;
1205
- }
1206
- if (typeof rec.prop !== "string" || !rec.prop) {
1207
- warnings.push(`map_token_prop '${rec.component}': missing prop \u2014 skipped`);
1208
- continue;
1209
- }
1210
- if (!isStringArray(rec.token_allowed) || rec.token_allowed.length === 0) {
1211
- warnings.push(`map_token_prop '${rec.component}.${String(rec.prop)}': missing or empty token_allowed \u2014 skipped`);
1212
- continue;
1213
- }
1214
- calls.push({ tool: "map_token_prop", component: rec.component, prop: rec.prop, token_allowed: rec.token_allowed });
1215
- }
1216
- return { calls, warnings };
995
+ function buildTokensAutonomousPreamble(inputBlock) {
996
+ return `You are running as part of the experience-design-system-cli generate pipeline in AUTONOMOUS mode. The developer is not present to answer questions.
997
+
998
+ Your task: classify every raw token from the input below into a DTCG token tree. Apply all judgment calls yourself \u2014 do not pause to ask for confirmation. Include a "description" field on each set_token call to document your reasoning.
999
+
1000
+ All input data is provided inline below \u2014 do not read any additional files.${inputBlock}
1001
+
1002
+ ## Output protocol
1003
+
1004
+ Do NOT write any files or emit any JSON blobs. Instead, emit one JSON object per line to stdout for each token or group. The CLI reads your stdout line by line and writes each entry directly to the pipeline database.
1005
+
1006
+ The two tool calls you may emit are:
1007
+
1008
+ \`\`\`
1009
+ {"tool":"set_group","path":"<dot.notation.path>","description":"<optional group description>"}
1010
+
1011
+ {"tool":"set_token","path":"<dot.notation.path>","type":"<DTCG type>","value":<value>,"description":"<reason>"}
1012
+ \`\`\`
1013
+
1014
+ Rules:
1015
+ - Emit exactly one JSON object per line. No multi-line JSON. No markdown fences.
1016
+ - Emit a set_group call for every intermediate group node in the tree.
1017
+ - Emit a set_token call for every leaf token.
1018
+ - "path" is dot-notation, e.g. "colors.brand.primary" \u2014 no leading dots or slashes.
1019
+ - "type" must be one of the 13 valid DTCG types: color, dimension, fontFamily, fontWeight, duration, cubicBezier, number, strokeStyle, border, transition, shadow, gradient, typography.
1020
+ - "value" must be valid JSON (string, number, array, or object depending on the type). Do NOT wrap it in quotes if it is a complex type.
1021
+ - Emit set_group calls before the set_token calls that fall under them.
1022
+ - You may emit prose lines (not starting with {) anywhere \u2014 they are ignored by the parser and serve as your reasoning log.`;
1217
1023
  }
1218
- var init_parse_map_token_tool_calls = __esm({
1219
- "packages/experience-design-system-generation/dist/src/services/parsing/parse-map-token-tool-calls.js"() {
1024
+ var SKILL_FILES;
1025
+ var init_prompt_builder = __esm({
1026
+ "packages/experience-design-system-generation/dist/src/prompt-builder.js"() {
1220
1027
  "use strict";
1028
+ SKILL_FILES = {
1029
+ components: "generate-components.md",
1030
+ tokens: "generate-tokens.md",
1031
+ select: "select-components.md",
1032
+ "map-tokens": "map-tokens.md"
1033
+ };
1221
1034
  }
1222
1035
  });
1223
1036
 
@@ -1234,17 +1047,14 @@ var init_progress = __esm({
1234
1047
  // packages/experience-design-system-generation/dist/src/index.js
1235
1048
  var src_exports = {};
1236
1049
  __export(src_exports, {
1237
- AGENT_BINARIES: () => AGENT_BINARIES,
1238
1050
  AGENT_NAMES: () => AGENT_NAMES,
1239
1051
  DEFAULT_AGENT_NAME: () => DEFAULT_AGENT_NAME,
1240
1052
  agentSupportsBedrock: () => agentSupportsBedrock,
1241
- buildArgs: () => buildAgentArgs,
1053
+ buildArgs: () => buildArgs,
1242
1054
  buildPrompt: () => buildPrompt,
1243
1055
  checkAgentAuth: () => checkAgentAuth,
1244
- createGenerationEndpoint: () => createGenerationEndpoint,
1245
1056
  createLocalCliAgentInvoker: () => createLocalCliAgentInvoker,
1246
1057
  describeAgentFailure: () => describeAgentFailure,
1247
- executeGenerationOrchestrator: () => executeGenerationOrchestrator,
1248
1058
  extractSentinelOutput: () => extractSentinelOutput,
1249
1059
  formatCustomPromptBanner: () => formatCustomPromptBanner,
1250
1060
  formatGenerateProgressLine: () => formatGenerateProgressLine,
@@ -1252,9 +1062,9 @@ __export(src_exports, {
1252
1062
  parseMapTokenPropToolCallLines: () => parseMapTokenPropToolCallLines,
1253
1063
  parseSelectToolCallLines: () => parseSelectToolCallLines,
1254
1064
  parseTokenToolCallLines: () => parseTokenToolCallLines,
1255
- parseToolCallLines: () => parsePropToolCallLines,
1065
+ parseToolCallLines: () => parseToolCallLines,
1256
1066
  resolveAgentModel: () => resolveAgentModel,
1257
- resolveBinary: () => resolveAgentBinary,
1067
+ resolveBinary: () => resolveBinary,
1258
1068
  resolveSkillPath: () => resolveSkillPath,
1259
1069
  runAgent: () => runAgent
1260
1070
  });
@@ -1262,19 +1072,10 @@ var init_src = __esm({
1262
1072
  "packages/experience-design-system-generation/dist/src/index.js"() {
1263
1073
  "use strict";
1264
1074
  init_agent_names();
1265
- init_create_generation_endpoint();
1266
- init_execute_generation_orchestrator();
1267
- init_build_agent_args();
1268
- init_resolve_agent_binary();
1269
- init_check_agent_auth();
1270
- init_run_agent();
1271
- init_parse_prop_tool_calls();
1272
- init_parse_select_tool_calls();
1273
- init_parse_token_tool_calls();
1274
- init_parse_map_token_tool_calls();
1275
- init_build_prompt();
1075
+ init_agent_runner();
1076
+ init_agent_invoker();
1077
+ init_prompt_builder();
1276
1078
  init_progress();
1277
- init_local_cli_agent_invoker();
1278
1079
  }
1279
1080
  });
1280
1081
 
@@ -1412,8 +1213,8 @@ function makeSessionTimestamp() {
1412
1213
  const override = process.env["EDSI_DEBUG_TS"];
1413
1214
  if (override) return override;
1414
1215
  const now = /* @__PURE__ */ new Date();
1415
- const pad = (n, w = 2) => n.toString().padStart(w, "0");
1416
- return `${now.getUTCFullYear()}${pad(now.getUTCMonth() + 1)}${pad(now.getUTCDate())}T${pad(now.getUTCHours())}${pad(now.getUTCMinutes())}${pad(now.getUTCSeconds())}Z`;
1216
+ const pad3 = (n, w = 2) => n.toString().padStart(w, "0");
1217
+ return `${now.getUTCFullYear()}${pad3(now.getUTCMonth() + 1)}${pad3(now.getUTCDate())}T${pad3(now.getUTCHours())}${pad3(now.getUTCMinutes())}${pad3(now.getUTCSeconds())}Z`;
1417
1218
  }
1418
1219
  function initDebugLogger(opts) {
1419
1220
  if (singleton) return singleton;
@@ -2210,8 +2011,8 @@ function deleteRawTokensForSession(db, sessionId2) {
2210
2011
  }
2211
2012
  function createRawTokenGroups(db, sessionId2, groups) {
2212
2013
  const insertGroup = db.prepare(`INSERT INTO raw_token_groups (session_id, path, description) VALUES (?, ?, ?)`);
2213
- for (const group of groups) {
2214
- insertGroup.run(sessionId2, group.path, group.$description ?? null);
2014
+ for (const group2 of groups) {
2015
+ insertGroup.run(sessionId2, group2.path, group2.$description ?? null);
2215
2016
  }
2216
2017
  }
2217
2018
  function createRawTokens(db, sessionId2, tokens) {
@@ -5109,7 +4910,7 @@ async function readFileInline(path) {
5109
4910
  return parts.filter(Boolean).join("\n\n");
5110
4911
  }
5111
4912
  function printFallbackInstructions(options) {
5112
- const binary = resolveAgentBinary(options.agent);
4913
+ const binary = resolveBinary(options.agent);
5113
4914
  const skillPath = resolveSkillPath(options.skill);
5114
4915
  const lines = [
5115
4916
  `Error: agent '${options.agent}' not found in $PATH (looked for binary: ${binary}).`,
@@ -5324,7 +5125,7 @@ ${outputBuf}`);
5324
5125
  lastError = describeAgentFailure(result);
5325
5126
  continue;
5326
5127
  }
5327
- const { calls, warnings } = parsePropToolCallLines(result.stdout);
5128
+ const { calls, warnings } = parseToolCallLines(result.stdout);
5328
5129
  if (calls.length === 0) {
5329
5130
  lastError = describeAgentFailure(result);
5330
5131
  continue;
@@ -5570,7 +5371,7 @@ async function runGenerateSkill(skill, opts, verbose = false) {
5570
5371
  process.stdout.write(prompt + "\n");
5571
5372
  await exitWithAnalytics(0);
5572
5373
  }
5573
- const binary = resolveAgentBinary(agent);
5374
+ const binary = resolveBinary(agent);
5574
5375
  if (!await assertBinaryInPath(binary)) {
5575
5376
  printFallbackInstructions({
5576
5377
  agent,
@@ -7090,24 +6891,24 @@ function parseEdsiError(rawInput) {
7090
6891
  }
7091
6892
  }
7092
6893
  const cleaned = stripLambdaLogPrefix(body);
7093
- const json = parseJsonBody(cleaned) ?? parseJsonBody(body);
7094
- const bindingFromJson = typeof json?.message === "string" ? parseBindingDiagnostics(json.message) : null;
6894
+ const json2 = parseJsonBody(cleaned) ?? parseJsonBody(body);
6895
+ const bindingFromJson = typeof json2?.message === "string" ? parseBindingDiagnostics(json2.message) : null;
7095
6896
  if (bindingFromJson) {
7096
6897
  return {
7097
- code: bindingFromJson.code ?? json?.code ?? null,
6898
+ code: bindingFromJson.code ?? json2?.code ?? null,
7098
6899
  message: bindingFromJson.message ?? cleaned,
7099
6900
  cycle: null,
7100
6901
  raw: false,
7101
6902
  ...bindingFromJson.diagnostics ? { diagnostics: bindingFromJson.diagnostics } : {}
7102
6903
  };
7103
6904
  }
7104
- if (json && (json.code || json.message || json.cycle)) {
6905
+ if (json2 && (json2.code || json2.message || json2.cycle)) {
7105
6906
  return {
7106
- code: json.code ?? null,
7107
- message: json.message ?? (cleaned || prefix),
7108
- cycle: json.cycle ?? null,
6907
+ code: json2.code ?? null,
6908
+ message: json2.message ?? (cleaned || prefix),
6909
+ cycle: json2.cycle ?? null,
7109
6910
  raw: false,
7110
- ...json.diagnostics ? { diagnostics: json.diagnostics } : {}
6911
+ ...json2.diagnostics ? { diagnostics: json2.diagnostics } : {}
7111
6912
  };
7112
6913
  }
7113
6914
  const binding = parseBindingDiagnostics(cleaned);
@@ -8647,8 +8448,8 @@ async function resolveSession(sessionFlag, command) {
8647
8448
  }
8648
8449
  function rebuildDTCGTree(groups, tokens) {
8649
8450
  const root = {};
8650
- for (const group of groups) {
8651
- const segments = group.path.split(".");
8451
+ for (const group2 of groups) {
8452
+ const segments = group2.path.split(".");
8652
8453
  let node = root;
8653
8454
  for (const seg of segments) {
8654
8455
  if (typeof node[seg] !== "object" || node[seg] === null) {
@@ -8656,8 +8457,8 @@ function rebuildDTCGTree(groups, tokens) {
8656
8457
  }
8657
8458
  node = node[seg];
8658
8459
  }
8659
- if (group.$description) {
8660
- node["$description"] = group.$description;
8460
+ if (group2.$description) {
8461
+ node["$description"] = group2.$description;
8661
8462
  }
8662
8463
  }
8663
8464
  for (const token of tokens) {
@@ -9231,7 +9032,7 @@ ${defaultDiagnostics.map((diagnostic) => ` ${diagnostic}`).join("\n")}
9231
9032
  return;
9232
9033
  }
9233
9034
  }
9234
- const binary = resolveAgentBinary(agent);
9035
+ const binary = resolveBinary(agent);
9235
9036
  if (!await assertBinaryInPath(binary)) {
9236
9037
  die(
9237
9038
  `Error: agent '${agent}' not found in $PATH (looked for binary: ${binary}).
@@ -9400,6 +9201,214 @@ var init_run_teaser = __esm({
9400
9201
  }
9401
9202
  });
9402
9203
 
9204
+ // packages/experience-design-system-cli-legacy/src/lib/push-debug-log.ts
9205
+ import { existsSync as existsSync3, mkdirSync as mkdirSync3, readdirSync, writeFileSync } from "node:fs";
9206
+ import { join as join10 } from "node:path";
9207
+ function scrub(key, value) {
9208
+ if (/^cma_?token$/i.test(key)) {
9209
+ return typeof value === "string" && value ? `[present, ${value.length} chars]` : "[not set]";
9210
+ }
9211
+ if (typeof value === "string" && SECRET_VALUE.test(value)) return "[redacted]";
9212
+ return value;
9213
+ }
9214
+ function json(value) {
9215
+ const text = JSON.stringify(value, scrub, 2) ?? "null";
9216
+ return text.length > MAX_BLOCK_CHARS ? `${text.slice(0, MAX_BLOCK_CHARS)}
9217
+ \u2026 truncated, ${text.length - MAX_BLOCK_CHARS} more characters` : text;
9218
+ }
9219
+ function pad(n, width = 2) {
9220
+ return String(n).padStart(width, "0");
9221
+ }
9222
+ function datePrefix(now) {
9223
+ return `${pad(now.getMonth() + 1)}-${pad(now.getDate())}-${now.getFullYear()}`;
9224
+ }
9225
+ function clock(now) {
9226
+ return `${pad(now.getHours())}:${pad(now.getMinutes())}:${pad(now.getSeconds())}.${pad(now.getMilliseconds(), 3)}`;
9227
+ }
9228
+ function nextFilename(dir, now) {
9229
+ const today = datePrefix(now);
9230
+ const pattern = new RegExp(`^${today}-push-attempt-(\\d+)\\.md$`);
9231
+ const existing = existsSync3(dir) ? readdirSync(dir) : [];
9232
+ const max = existing.reduce((acc, entry) => {
9233
+ const match2 = pattern.exec(entry);
9234
+ return match2 ? Math.max(acc, Number(match2[1])) : acc;
9235
+ }, 0);
9236
+ return `${today}-push-attempt-${max + 1}.md`;
9237
+ }
9238
+ function entityName(entry) {
9239
+ if (typeof entry === "string") return entry;
9240
+ if (entry && typeof entry === "object") {
9241
+ const record = entry;
9242
+ for (const field of ["key", "name", "$name", "id"]) {
9243
+ if (typeof record[field] === "string") return record[field];
9244
+ }
9245
+ const current = record["current"];
9246
+ if (current && typeof current === "object" && typeof current["name"] === "string") {
9247
+ return current["name"];
9248
+ }
9249
+ }
9250
+ return "unknown";
9251
+ }
9252
+ function group(diff) {
9253
+ return {
9254
+ new: diff.new.map(entityName),
9255
+ changed: diff.changed.map((entry) => {
9256
+ const breaking = entry && typeof entry === "object" && entry.changeClassification?.classification === "breaking";
9257
+ return breaking ? `${entityName(entry)} (breaking)` : entityName(entry);
9258
+ }),
9259
+ unchanged: diff.unchanged,
9260
+ removed: diff.removed.map(entityName)
9261
+ };
9262
+ }
9263
+ function summarizePreview(preview) {
9264
+ return { components: group(preview.components), tokens: group(preview.tokens) };
9265
+ }
9266
+ function summarizeCdf(cdf) {
9267
+ return Object.entries(cdf).filter(([key]) => !key.startsWith("$") && key !== "allowDeletions").map(([key, value]) => {
9268
+ const entry = value ?? {};
9269
+ const properties = entry["$properties"];
9270
+ const slots = entry["$slots"];
9271
+ return {
9272
+ name: key,
9273
+ type: entry["$type"],
9274
+ properties: properties && typeof properties === "object" ? Object.keys(properties) : [],
9275
+ slots: slots && typeof slots === "object" ? Object.keys(slots) : []
9276
+ };
9277
+ });
9278
+ }
9279
+ function renderEvents(events) {
9280
+ if (events.length === 0) return "_Nothing recorded yet._";
9281
+ return events.map((event, index) => {
9282
+ const note = event.note ? ` \u2014 ${event.note}` : "";
9283
+ const request2 = event.requestId ? ` _(request ${event.requestId})_` : "";
9284
+ return `${index + 1}. \`${clock(event.at)}\` (+${event.sinceStartMs}ms) **${event.title}**${note}${request2}`;
9285
+ }).join("\n");
9286
+ }
9287
+ function renderDetails(events) {
9288
+ const withData = events.map((event, index) => ({ event, index })).filter(({ event }) => event.data && Object.keys(event.data).length > 0);
9289
+ if (withData.length === 0) return "";
9290
+ return withData.map(
9291
+ ({ event, index }) => `<details>
9292
+ <summary>${index + 1}. ${event.title}</summary>
9293
+
9294
+ \`\`\`json
9295
+ ${json(event.data)}
9296
+ \`\`\`
9297
+
9298
+ </details>`
9299
+ ).join("\n\n");
9300
+ }
9301
+ function render2(runId, inputs, events, startedAt, result, durationMs) {
9302
+ const requestIds = [...new Set(events.map((event) => event.requestId).filter(Boolean))];
9303
+ const text = (field) => String(inputs[field] ?? "\u2014");
9304
+ const details = renderDetails(events);
9305
+ return `# Push to Contentful \u2014 debug log
9306
+
9307
+ ## Summary
9308
+
9309
+ | | |
9310
+ |---|---|
9311
+ | **Result** | ${OUTCOME_LABEL[result.outcome]} |
9312
+ | **What happened** | ${result.summary} |
9313
+ | **Space / environment** | \`${text("space_id")}\` / \`${text("environment_id")}\` |
9314
+ | **Host** | ${text("host")} |
9315
+ | **Started** | ${startedAt.toISOString()} |
9316
+ | **Duration** | ${durationMs}ms |
9317
+ | **Request IDs** | ${requestIds.length > 0 ? requestIds.map((id) => `\`${id}\``).join(", ") : "\u2014"} |
9318
+ | **CLI / runtime** | ${cliVersion()} \xB7 ${process.platform} \xB7 Node ${process.version} |
9319
+ | **Run ID** | ${runId} |
9320
+
9321
+ ## Timeline
9322
+
9323
+ ${renderEvents(events)}
9324
+
9325
+ ## Inputs
9326
+
9327
+ \`\`\`json
9328
+ ${json(inputs)}
9329
+ \`\`\`
9330
+
9331
+ ## Result
9332
+
9333
+ \`\`\`json
9334
+ ${json({ outcome: result.outcome, summary: result.summary, ...result.details ?? {} })}
9335
+ \`\`\`
9336
+ ${details ? `
9337
+ ## Details
9338
+
9339
+ ${details}
9340
+ ` : ""}`;
9341
+ }
9342
+ function startPushDebugRun(inputs) {
9343
+ const sessionDir = process.env[DEBUG_SESSION_DIR_ENV];
9344
+ if (!sessionDir) return NOOP_RUN;
9345
+ const startedAt = /* @__PURE__ */ new Date();
9346
+ const runId = `${startedAt.getFullYear()}${pad(startedAt.getMonth() + 1)}${pad(startedAt.getDate())}-${pad(startedAt.getHours())}${pad(startedAt.getMinutes())}${pad(startedAt.getSeconds())}`;
9347
+ const events = [];
9348
+ let result = {
9349
+ outcome: "in-progress",
9350
+ summary: "The push started but no final result was recorded."
9351
+ };
9352
+ let finished = false;
9353
+ let path;
9354
+ const flush = () => {
9355
+ try {
9356
+ if (!path) {
9357
+ const dir = join10(sessionDir, "import");
9358
+ mkdirSync3(dir, { recursive: true });
9359
+ path = join10(dir, nextFilename(dir, startedAt));
9360
+ }
9361
+ writeFileSync(path, render2(runId, inputs, events, startedAt, result, Date.now() - startedAt.getTime()), {
9362
+ mode: 384
9363
+ });
9364
+ } catch {
9365
+ }
9366
+ };
9367
+ flush();
9368
+ return {
9369
+ event(title, options = {}) {
9370
+ if (finished) return;
9371
+ const at = /* @__PURE__ */ new Date();
9372
+ events.push({ at, sinceStartMs: at.getTime() - startedAt.getTime(), title, ...options });
9373
+ flush();
9374
+ },
9375
+ finish(final) {
9376
+ if (finished) return;
9377
+ finished = true;
9378
+ result = final;
9379
+ const at = /* @__PURE__ */ new Date();
9380
+ events.push({
9381
+ at,
9382
+ sinceStartMs: at.getTime() - startedAt.getTime(),
9383
+ title: OUTCOME_LABEL[final.outcome].replace(/^\S+\s/, ""),
9384
+ note: final.summary
9385
+ });
9386
+ flush();
9387
+ }
9388
+ };
9389
+ }
9390
+ var DEBUG_SESSION_DIR_ENV, NOOP_RUN, OUTCOME_LABEL, MAX_BLOCK_CHARS, SECRET_VALUE;
9391
+ var init_push_debug_log = __esm({
9392
+ "packages/experience-design-system-cli-legacy/src/lib/push-debug-log.ts"() {
9393
+ "use strict";
9394
+ init_client();
9395
+ DEBUG_SESSION_DIR_ENV = "EDS_DEBUG_SESSION_DIR";
9396
+ NOOP_RUN = { event: () => void 0, finish: () => void 0 };
9397
+ OUTCOME_LABEL = {
9398
+ "in-progress": "\u23F3 In progress (the process ended before the push finished)",
9399
+ pushed: "\u2705 Pushed",
9400
+ partial: "\u26A0\uFE0F Partly pushed (some items failed)",
9401
+ failed: "\u274C Push failed",
9402
+ "preview-failed": "\u274C Preview failed (nothing was sent to apply)",
9403
+ "nothing-to-push": "\u2139\uFE0F Nothing to push (the server says the space already matches)",
9404
+ skipped: "\u23ED\uFE0F Skipped",
9405
+ superseded: "\u21A9\uFE0F Superseded by a newer attempt"
9406
+ };
9407
+ MAX_BLOCK_CHARS = 1e5;
9408
+ SECRET_VALUE = /CFPAT-[A-Za-z0-9_-]{20,}|^Bearer\s+\S+/;
9409
+ }
9410
+ });
9411
+
9403
9412
  // packages/experience-design-system-cli-legacy/src/tui/use-blinking-cursor.ts
9404
9413
  import { useEffect as useEffect2, useState as useState3 } from "react";
9405
9414
  function useBlinkingCursor() {
@@ -9419,8 +9428,8 @@ var init_use_blinking_cursor = __esm({
9419
9428
  // packages/experience-design-system-cli-legacy/src/runs/path-prompt.tsx
9420
9429
  import { useState as useState4 } from "react";
9421
9430
  import { Box as Box6, Text as Text7 } from "ink";
9422
- import { readdirSync } from "node:fs";
9423
- import { dirname as dirname5, basename as basename2, join as join10 } from "node:path";
9431
+ import { readdirSync as readdirSync2 } from "node:fs";
9432
+ import { dirname as dirname5, basename as basename2, join as join11 } from "node:path";
9424
9433
  import { jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
9425
9434
  function autocomplete(partial) {
9426
9435
  if (!partial) return null;
@@ -9429,19 +9438,19 @@ function autocomplete(partial) {
9429
9438
  const base = basename2(normalized);
9430
9439
  let entries;
9431
9440
  try {
9432
- entries = readdirSync(dir);
9441
+ entries = readdirSync2(dir);
9433
9442
  } catch {
9434
9443
  return null;
9435
9444
  }
9436
9445
  const matches = entries.filter((e) => e.startsWith(base));
9437
9446
  if (matches.length === 0) return null;
9438
- if (matches.length === 1) return join10(dir, matches[0]);
9447
+ if (matches.length === 1) return join11(dir, matches[0]);
9439
9448
  let prefix = matches[0];
9440
9449
  for (const m of matches) {
9441
9450
  while (!m.startsWith(prefix)) prefix = prefix.slice(0, -1);
9442
9451
  if (!prefix) break;
9443
9452
  }
9444
- return prefix.length > base.length ? join10(dir, prefix) : null;
9453
+ return prefix.length > base.length ? join11(dir, prefix) : null;
9445
9454
  }
9446
9455
  function PathPrompt({
9447
9456
  defaultPath,
@@ -9506,12 +9515,12 @@ var init_path_prompt = __esm({
9506
9515
 
9507
9516
  // packages/experience-design-system-cli-legacy/src/runs/save-path-resolver.ts
9508
9517
  import { access as access4 } from "node:fs/promises";
9509
- import { join as join11 } from "node:path";
9518
+ import { join as join12 } from "node:path";
9510
9519
  async function listConflictingFiles(path) {
9511
9520
  const conflicts = [];
9512
9521
  for (const name of SAVE_FILES) {
9513
9522
  try {
9514
- await access4(join11(path, name));
9523
+ await access4(join12(path, name));
9515
9524
  conflicts.push(name);
9516
9525
  } catch {
9517
9526
  }
@@ -9531,7 +9540,7 @@ function buildTimestampedSubdir(base, now = /* @__PURE__ */ new Date()) {
9531
9540
  const hh = pad2(now.getHours());
9532
9541
  const mm = pad2(now.getMinutes());
9533
9542
  const ss = pad2(now.getSeconds());
9534
- return join11(base, `dsi-${y}${m}${d}-${hh}${mm}${ss}`);
9543
+ return join12(base, `dsi-${y}${m}${d}-${hh}${mm}${ss}`);
9535
9544
  }
9536
9545
  var SAVE_FILES;
9537
9546
  var init_save_path_resolver = __esm({
@@ -9543,7 +9552,7 @@ var init_save_path_resolver = __esm({
9543
9552
 
9544
9553
  // packages/experience-design-system-cli-legacy/src/runs/store.ts
9545
9554
  import { readFile as readFile12, writeFile as writeFile4, mkdir as mkdir4, rename } from "node:fs/promises";
9546
- import { join as join12 } from "node:path";
9555
+ import { join as join13 } from "node:path";
9547
9556
  import { homedir as homedir6 } from "node:os";
9548
9557
  import { randomBytes as randomBytes2 } from "node:crypto";
9549
9558
  function encodeBase32(bytes, length) {
@@ -9639,8 +9648,8 @@ var init_store = __esm({
9639
9648
  RUNS_FILE_VERSION = 3;
9640
9649
  RUNS_FILE_CAP = 200;
9641
9650
  READABLE_VERSIONS = /* @__PURE__ */ new Set([1, 2, 3]);
9642
- RUNS_DIR = join12(homedir6(), ".config", "experiences");
9643
- RUNS_PATH = join12(RUNS_DIR, "runs.json");
9651
+ RUNS_DIR = join13(homedir6(), ".config", "experiences");
9652
+ RUNS_PATH = join13(RUNS_DIR, "runs.json");
9644
9653
  CROCKFORD = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
9645
9654
  }
9646
9655
  });
@@ -9797,7 +9806,7 @@ var init_WelcomeStep = __esm({
9797
9806
  import { useState as useState6, useEffect as useEffect3 } from "react";
9798
9807
  import { Box as Box9, Text as Text10 } from "ink";
9799
9808
  import { promises as fs } from "node:fs";
9800
- import { join as join13 } from "node:path";
9809
+ import { join as join14 } from "node:path";
9801
9810
  import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
9802
9811
  async function countFiles(dir) {
9803
9812
  const counts = {
@@ -9821,7 +9830,7 @@ async function countFiles(dir) {
9821
9830
  await Promise.all(
9822
9831
  entries.map(async (entry) => {
9823
9832
  if (IGNORE_DIRS.has(entry)) return;
9824
- const full = join13(current, entry);
9833
+ const full = join14(current, entry);
9825
9834
  let stat7;
9826
9835
  try {
9827
9836
  stat7 = await fs.stat(full);
@@ -10897,6 +10906,7 @@ function WizardPreviewStep({
10897
10906
  environmentId,
10898
10907
  stepNumber,
10899
10908
  totalSteps,
10909
+ droppedTokenDefaults = [],
10900
10910
  onConfirm,
10901
10911
  onEdit,
10902
10912
  onQuit
@@ -10989,6 +10999,13 @@ function WizardPreviewStep({
10989
10999
  }
10990
11000
  )
10991
11001
  ] }) : /* @__PURE__ */ jsx19(Text17, { dimColor: true, children: "Nothing to push \u2014 everything is already up to date." }),
11002
+ droppedTokenDefaults.length > 0 && /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", children: [
11003
+ /* @__PURE__ */ jsx19(Text17, { color: PALETTE.warning, bold: true, children: "\u26A0 Some token defaults will be left out so the push can succeed:" }),
11004
+ droppedTokenDefaults.map((line) => /* @__PURE__ */ jsxs16(Text17, { color: PALETTE.warning, wrap: "truncate-end", children: [
11005
+ " ",
11006
+ line
11007
+ ] }, line))
11008
+ ] }),
10992
11009
  breakingWithImpact && /* @__PURE__ */ jsx19(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx19(Text17, { color: PALETTE.error, bold: true, children: "\u26A0 Breaking changes will affect downstream entities. Press Enter to acknowledge and apply." }) }),
10993
11010
  /* @__PURE__ */ jsx19(SpaceEnvironment, { spaceId, environmentId }),
10994
11011
  /* @__PURE__ */ jsxs16(Box16, { gap: 3, marginTop: 1, children: [
@@ -11040,7 +11057,7 @@ function DoneStep({
11040
11057
  });
11041
11058
  const totalFailed = componentTypes.failed + designTokens.failed;
11042
11059
  const totalPushed = componentTypes.created + componentTypes.updated + componentTypes.removed + designTokens.created + designTokens.updated + designTokens.removed;
11043
- const success = totalFailed === 0;
11060
+ const success = totalFailed === 0 && (summary?.failed ?? 0) === 0;
11044
11061
  function EntityRows({ entity, label }) {
11045
11062
  return /* @__PURE__ */ jsxs17(Fragment5, { children: [
11046
11063
  entity.created > 0 && /* @__PURE__ */ jsxs17(Box17, { gap: 1, children: [
@@ -11086,7 +11103,7 @@ function DoneStep({
11086
11103
  ] });
11087
11104
  }
11088
11105
  return /* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", gap: 1, paddingX: 2, paddingY: 1, children: [
11089
- success ? /* @__PURE__ */ jsx20(Text18, { bold: true, color: PALETTE.success, children: "Done!" }) : /* @__PURE__ */ jsx20(Text18, { bold: true, color: PALETTE.warning, children: "\u26A0 Finished with errors" }),
11106
+ success ? /* @__PURE__ */ jsx20(Text18, { bold: true, color: PALETTE.success, children: "Done!" }) : /* @__PURE__ */ jsx20(Text18, { bold: true, color: PALETTE.error, children: "\u2717 Push failed \u2014 nothing was changed for the items below" }),
11090
11107
  totalPushed === 0 && totalFailed === 0 && !summary ? /* @__PURE__ */ jsx20(Box17, { marginTop: 1, children: /* @__PURE__ */ jsx20(Text18, { dimColor: true, children: "Nothing was pushed \u2014 everything was already up to date." }) }) : /* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", gap: 0, marginTop: 1, children: [
11091
11108
  /* @__PURE__ */ jsx20(EntityRows, { entity: componentTypes, label: "Component Type" }),
11092
11109
  /* @__PURE__ */ jsx20(EntityRows, { entity: designTokens, label: "Design Token" }),
@@ -11506,8 +11523,8 @@ var init_types = __esm({
11506
11523
  });
11507
11524
 
11508
11525
  // packages/experience-design-system-extraction/dist/src/extract/tsx-shared.js
11509
- import { existsSync as existsSync3, readFileSync as readFileSync5 } from "node:fs";
11510
- import { dirname as dirname6, join as join14, resolve as resolve12 } from "node:path";
11526
+ import { existsSync as existsSync4, readFileSync as readFileSync5 } from "node:fs";
11527
+ import { dirname as dirname6, join as join15, resolve as resolve12 } from "node:path";
11511
11528
  import { Node, Project, SyntaxKind } from "ts-morph";
11512
11529
  import ts from "typescript";
11513
11530
  function createTsxProject(filePaths) {
@@ -11706,8 +11723,8 @@ function findNearestTsConfigPath(filePath) {
11706
11723
  let currentDir = dirname6(filePath);
11707
11724
  while (true) {
11708
11725
  for (const candidateName of ["tsconfig.json", "jsconfig.json"]) {
11709
- const candidatePath = join14(currentDir, candidateName);
11710
- if (existsSync3(candidatePath)) {
11726
+ const candidatePath = join15(currentDir, candidateName);
11727
+ if (existsSync4(candidatePath)) {
11711
11728
  nearestTsConfigPathCache.set(filePath, candidatePath);
11712
11729
  return candidatePath;
11713
11730
  }
@@ -11763,12 +11780,12 @@ function resolveImportSourcePath(basePath) {
11763
11780
  `${basePath}.tsx`,
11764
11781
  `${basePath}.js`,
11765
11782
  `${basePath}.jsx`,
11766
- join14(basePath, "index.ts"),
11767
- join14(basePath, "index.tsx"),
11768
- join14(basePath, "index.js"),
11769
- join14(basePath, "index.jsx")
11783
+ join15(basePath, "index.ts"),
11784
+ join15(basePath, "index.tsx"),
11785
+ join15(basePath, "index.js"),
11786
+ join15(basePath, "index.jsx")
11770
11787
  ];
11771
- return candidates.find((candidatePath) => existsSync3(candidatePath));
11788
+ return candidates.find((candidatePath) => existsSync4(candidatePath));
11772
11789
  }
11773
11790
  function findProjectSourceFileByImportPath(project, resolvedPath) {
11774
11791
  const candidatePaths = [
@@ -11777,10 +11794,10 @@ function findProjectSourceFileByImportPath(project, resolvedPath) {
11777
11794
  `${resolvedPath}.tsx`,
11778
11795
  `${resolvedPath}.js`,
11779
11796
  `${resolvedPath}.jsx`,
11780
- join14(resolvedPath, "index.ts"),
11781
- join14(resolvedPath, "index.tsx"),
11782
- join14(resolvedPath, "index.js"),
11783
- join14(resolvedPath, "index.jsx")
11797
+ join15(resolvedPath, "index.ts"),
11798
+ join15(resolvedPath, "index.tsx"),
11799
+ join15(resolvedPath, "index.js"),
11800
+ join15(resolvedPath, "index.jsx")
11784
11801
  ];
11785
11802
  for (const candidatePath of candidatePaths) {
11786
11803
  const sourceFile = project.getSourceFile(candidatePath);
@@ -11801,10 +11818,10 @@ function findWorkspacePackageEntrySourceFile(originSourceFile, moduleSpecifier)
11801
11818
  if (!packageRootDir)
11802
11819
  return void 0;
11803
11820
  const preferredEntryPaths = [
11804
- join14(packageRootDir, "src/index.ts"),
11805
- join14(packageRootDir, "src/index.tsx"),
11806
- join14(packageRootDir, "index.ts"),
11807
- join14(packageRootDir, "index.tsx")
11821
+ join15(packageRootDir, "src/index.ts"),
11822
+ join15(packageRootDir, "src/index.tsx"),
11823
+ join15(packageRootDir, "index.ts"),
11824
+ join15(packageRootDir, "index.tsx")
11808
11825
  ];
11809
11826
  for (const entryPath of preferredEntryPaths) {
11810
11827
  const entrySourceFile = project.getSourceFile(entryPath);
@@ -11812,7 +11829,7 @@ function findWorkspacePackageEntrySourceFile(originSourceFile, moduleSpecifier)
11812
11829
  return entrySourceFile;
11813
11830
  }
11814
11831
  }
11815
- return candidateSourceFiles.find((sourceFile) => sourceFile.getDirectoryPath() === join14(packageRootDir, "src"));
11832
+ return candidateSourceFiles.find((sourceFile) => sourceFile.getDirectoryPath() === join15(packageRootDir, "src"));
11816
11833
  }
11817
11834
  function getWorkspacePackageManifestForSourceFile(sourceFile) {
11818
11835
  const packageRootDir = findNearestPackageRootDir(sourceFile.getFilePath());
@@ -11821,7 +11838,7 @@ function getWorkspacePackageManifestForSourceFile(sourceFile) {
11821
11838
  if (workspacePackageManifestCache.has(packageRootDir)) {
11822
11839
  return workspacePackageManifestCache.get(packageRootDir) ?? void 0;
11823
11840
  }
11824
- const packageJsonPath = join14(packageRootDir, "package.json");
11841
+ const packageJsonPath = join15(packageRootDir, "package.json");
11825
11842
  try {
11826
11843
  const packageJson = JSON.parse(readFileSync5(packageJsonPath, "utf8"));
11827
11844
  const manifest = typeof packageJson.name === "string" ? { name: packageJson.name, rootDir: packageRootDir } : null;
@@ -11838,7 +11855,7 @@ function findNearestPackageRootDir(filePath) {
11838
11855
  }
11839
11856
  let currentDir = dirname6(filePath);
11840
11857
  while (true) {
11841
- if (existsSync3(join14(currentDir, "package.json"))) {
11858
+ if (existsSync4(join15(currentDir, "package.json"))) {
11842
11859
  packageRootByFilePathCache.set(filePath, currentDir);
11843
11860
  return currentDir;
11844
11861
  }
@@ -14900,8 +14917,8 @@ var init_vue_tsx = __esm({
14900
14917
  });
14901
14918
 
14902
14919
  // packages/experience-design-system-extraction/dist/src/extract/resolve-local-module.js
14903
- import { existsSync as existsSync4, statSync as statSync2 } from "node:fs";
14904
- import { dirname as dirname7, join as join15, resolve as resolve13 } from "node:path";
14920
+ import { existsSync as existsSync5, statSync as statSync2 } from "node:fs";
14921
+ import { dirname as dirname7, join as join16, resolve as resolve13 } from "node:path";
14905
14922
  function resolveLocalModule(importingFilePath, specifier, options = {}) {
14906
14923
  const basePath = resolve13(dirname7(importingFilePath), specifier);
14907
14924
  const candidates = [
@@ -14910,18 +14927,18 @@ function resolveLocalModule(importingFilePath, specifier, options = {}) {
14910
14927
  `${basePath}.ts`,
14911
14928
  `${basePath}.mjs`,
14912
14929
  `${basePath}.cjs`,
14913
- join15(basePath, "index.js"),
14914
- join15(basePath, "index.ts"),
14915
- join15(basePath, "index.mjs"),
14916
- join15(basePath, "index.cjs")
14930
+ join16(basePath, "index.js"),
14931
+ join16(basePath, "index.ts"),
14932
+ join16(basePath, "index.mjs"),
14933
+ join16(basePath, "index.cjs")
14917
14934
  ];
14918
14935
  for (const candidate of candidates) {
14919
- if (existsSync4(candidate) && statSync2(candidate).isFile())
14936
+ if (existsSync5(candidate) && statSync2(candidate).isFile())
14920
14937
  return candidate;
14921
14938
  }
14922
14939
  if (options.allowJavaScriptExtensionFallback && basePath.endsWith(".js")) {
14923
14940
  const tsPath = `${basePath.slice(0, -".js".length)}.ts`;
14924
- if (existsSync4(tsPath) && statSync2(tsPath).isFile())
14941
+ if (existsSync5(tsPath) && statSync2(tsPath).isFile())
14925
14942
  return tsPath;
14926
14943
  }
14927
14944
  return null;
@@ -14952,9 +14969,9 @@ var init_resolve_type_property = __esm({
14952
14969
 
14953
14970
  // packages/experience-design-system-extraction/dist/src/extract/vue.js
14954
14971
  import os from "node:os";
14955
- import { basename as basename3, dirname as dirname8, resolve as resolve14, join as join16 } from "node:path";
14972
+ import { basename as basename3, dirname as dirname8, resolve as resolve14, join as join17 } from "node:path";
14956
14973
  import { readFile as readFile15 } from "node:fs/promises";
14957
- import { existsSync as existsSync5, readFileSync as readFileSync6, readdirSync as readdirSync2, statSync as statSync3 } from "node:fs";
14974
+ import { existsSync as existsSync6, readFileSync as readFileSync6, readdirSync as readdirSync3, statSync as statSync3 } from "node:fs";
14958
14975
  import { parse as parseSFC } from "@vue/compiler-sfc";
14959
14976
  import { Project as Project3, Node as Node6 } from "ts-morph";
14960
14977
  async function extractVueComponents(filePaths, onProgress) {
@@ -15167,11 +15184,11 @@ function findWorkspaceRoot(startDir) {
15167
15184
  return workspaceRootCache.get(startDir);
15168
15185
  let dir = startDir;
15169
15186
  while (true) {
15170
- const pkgJsonPath = join16(dir, "package.json");
15171
- if (existsSync5(pkgJsonPath)) {
15187
+ const pkgJsonPath = join17(dir, "package.json");
15188
+ if (existsSync6(pkgJsonPath)) {
15172
15189
  try {
15173
15190
  const pkg4 = JSON.parse(readFileSync6(pkgJsonPath, "utf8"));
15174
- if (pkg4.workspaces || existsSync5(join16(dir, "pnpm-workspace.yaml"))) {
15191
+ if (pkg4.workspaces || existsSync6(join17(dir, "pnpm-workspace.yaml"))) {
15175
15192
  workspaceRootCache.set(startDir, dir);
15176
15193
  return dir;
15177
15194
  }
@@ -15191,8 +15208,8 @@ function getWorkspacePackageDirs(workspaceRoot) {
15191
15208
  return workspacePackageDirsCache.get(workspaceRoot);
15192
15209
  }
15193
15210
  const packageMap = /* @__PURE__ */ new Map();
15194
- const packagesDir = join16(workspaceRoot, "packages");
15195
- if (!existsSync5(packagesDir)) {
15211
+ const packagesDir = join17(workspaceRoot, "packages");
15212
+ if (!existsSync6(packagesDir)) {
15196
15213
  workspacePackageDirsCache.set(workspaceRoot, packageMap);
15197
15214
  return packageMap;
15198
15215
  }
@@ -15201,12 +15218,12 @@ function getWorkspacePackageDirs(workspaceRoot) {
15201
15218
  return;
15202
15219
  let entries;
15203
15220
  try {
15204
- entries = readdirSync2(dir);
15221
+ entries = readdirSync3(dir);
15205
15222
  } catch {
15206
15223
  return;
15207
15224
  }
15208
- const pkgJsonPath = join16(dir, "package.json");
15209
- if (existsSync5(pkgJsonPath)) {
15225
+ const pkgJsonPath = join17(dir, "package.json");
15226
+ if (existsSync6(pkgJsonPath)) {
15210
15227
  try {
15211
15228
  const pkg4 = JSON.parse(readFileSync6(pkgJsonPath, "utf8"));
15212
15229
  if (typeof pkg4.name === "string") {
@@ -15218,7 +15235,7 @@ function getWorkspacePackageDirs(workspaceRoot) {
15218
15235
  for (const entry of entries) {
15219
15236
  if (entry === "node_modules" || entry === ".git" || entry.startsWith("."))
15220
15237
  continue;
15221
- const entryPath = join16(dir, entry);
15238
+ const entryPath = join17(dir, entry);
15222
15239
  try {
15223
15240
  const stat7 = statSync3(entryPath);
15224
15241
  if (stat7.isDirectory()) {
@@ -15258,28 +15275,28 @@ function resolveWorkspaceVueImport(specifier, importingFilePath) {
15258
15275
  const packageDir = packageDirs.get(packageName);
15259
15276
  if (!packageDir)
15260
15277
  return null;
15261
- const pkgJsonPath = join16(packageDir, "package.json");
15278
+ const pkgJsonPath = join17(packageDir, "package.json");
15262
15279
  try {
15263
15280
  const pkg4 = JSON.parse(readFileSync6(pkgJsonPath, "utf8"));
15264
15281
  if (pkg4.exports && subpath !== ".") {
15265
15282
  const exportValue = pkg4.exports[subpath];
15266
15283
  if (typeof exportValue === "string" && exportValue.endsWith(".vue")) {
15267
15284
  const resolved = resolve14(packageDir, exportValue);
15268
- if (existsSync5(resolved))
15285
+ if (existsSync6(resolved))
15269
15286
  return resolved;
15270
15287
  }
15271
15288
  }
15272
15289
  if (subpath !== ".") {
15273
15290
  const subDir = resolve14(packageDir, subpath.replace(/^\.\//, ""));
15274
- for (const base of [join16(packageDir, "src", subpath.replace(/^\.\//, "")), subDir]) {
15275
- const subPkgPath = join16(base, "package.json");
15276
- if (existsSync5(subPkgPath)) {
15291
+ for (const base of [join17(packageDir, "src", subpath.replace(/^\.\//, "")), subDir]) {
15292
+ const subPkgPath = join17(base, "package.json");
15293
+ if (existsSync6(subPkgPath)) {
15277
15294
  try {
15278
15295
  const subPkg = JSON.parse(readFileSync6(subPkgPath, "utf8"));
15279
15296
  const main = subPkg.main || subPkg.module;
15280
15297
  if (typeof main === "string" && main.endsWith(".vue")) {
15281
15298
  const resolved = resolve14(base, main);
15282
- if (existsSync5(resolved))
15299
+ if (existsSync6(resolved))
15283
15300
  return resolved;
15284
15301
  }
15285
15302
  } catch {
@@ -15291,7 +15308,7 @@ function resolveWorkspaceVueImport(specifier, importingFilePath) {
15291
15308
  const main = pkg4.main || pkg4.module;
15292
15309
  if (typeof main === "string" && main.endsWith(".vue")) {
15293
15310
  const resolved = resolve14(packageDir, main);
15294
- if (existsSync5(resolved))
15311
+ if (existsSync6(resolved))
15295
15312
  return resolved;
15296
15313
  }
15297
15314
  }
@@ -15733,7 +15750,7 @@ var init_astro = __esm({
15733
15750
  });
15734
15751
 
15735
15752
  // packages/experience-design-system-extraction/dist/src/extract/web-components.js
15736
- import { basename as basename5, dirname as dirname9, join as join17, resolve as resolve15 } from "node:path";
15753
+ import { basename as basename5, dirname as dirname9, join as join18, resolve as resolve15 } from "node:path";
15737
15754
  import { Project as Project5, Node as Node8, SyntaxKind as SyntaxKind6 } from "ts-morph";
15738
15755
  function normalizeComponentName(input) {
15739
15756
  return input.replace(/[^a-zA-Z0-9]/g, "").toLowerCase();
@@ -16386,14 +16403,14 @@ function resolveImportSourcePath2(fromFilePath, specifier) {
16386
16403
  if (!specifier.startsWith(spectrumPrefix)) {
16387
16404
  return null;
16388
16405
  }
16389
- const packagesMarker = `${join17("2nd-gen", "packages")}${fromFilePath.includes("\\") ? "\\" : "/"}`;
16406
+ const packagesMarker = `${join18("2nd-gen", "packages")}${fromFilePath.includes("\\") ? "\\" : "/"}`;
16390
16407
  const markerIndex = fromFilePath.lastIndexOf(packagesMarker);
16391
16408
  if (markerIndex === -1) {
16392
16409
  return null;
16393
16410
  }
16394
16411
  const packagesRoot = fromFilePath.slice(0, markerIndex + packagesMarker.length - 1);
16395
16412
  const componentPath = specifier.slice(spectrumPrefix.length);
16396
- return join17(packagesRoot, "core", "components", componentPath, "index.ts");
16413
+ return join18(packagesRoot, "core", "components", componentPath, "index.ts");
16397
16414
  }
16398
16415
  function getImportedBaseClass(classDecl, project, visitedFiles) {
16399
16416
  const extendsClause = classDecl.getHeritageClauses().find((clause) => clause.getToken() === SyntaxKind6.ExtendsKeyword);
@@ -16660,8 +16677,8 @@ var init_scoring = __esm({
16660
16677
 
16661
16678
  // packages/experience-design-system-extraction/dist/src/extract/svelte.js
16662
16679
  import os3 from "node:os";
16663
- import { basename as basename6, dirname as dirname10, resolve as resolve16, join as join18 } from "node:path";
16664
- import { existsSync as existsSync6, readFileSync as readFileSync7 } from "node:fs";
16680
+ import { basename as basename6, dirname as dirname10, resolve as resolve16, join as join19 } from "node:path";
16681
+ import { existsSync as existsSync7, readFileSync as readFileSync7 } from "node:fs";
16665
16682
  import { createRequire } from "node:module";
16666
16683
  import { parse as parseSvelte } from "svelte/compiler";
16667
16684
  import { Project as Project6, Node as Node9, ScriptTarget, ModuleKind, ts as ts2 } from "ts-morph";
@@ -16794,8 +16811,8 @@ async function maybeRunResolveUnreachableRetry(components, warnings, retryContex
16794
16811
  function findNearestTsconfig(startDir) {
16795
16812
  let dir = startDir;
16796
16813
  for (let i = 0; i < 16; i++) {
16797
- const candidate = join18(dir, "tsconfig.json");
16798
- if (existsSync6(candidate))
16814
+ const candidate = join19(dir, "tsconfig.json");
16815
+ if (existsSync7(candidate))
16799
16816
  return candidate;
16800
16817
  const parent = dirname10(dir);
16801
16818
  if (!parent || parent === dir)
@@ -16930,29 +16947,29 @@ function locateDtsForSpecifier(req, specifier, parentFile) {
16930
16947
  const seedDir = resolvedJs ? dirname10(resolvedJs) : dirname10(parentFile);
16931
16948
  const pkgRoot = findPackageRootForSpecifier(seedDir, specifier);
16932
16949
  if (pkgRoot) {
16933
- const pkgJsonPath = join18(pkgRoot, "package.json");
16934
- if (existsSync6(pkgJsonPath)) {
16950
+ const pkgJsonPath = join19(pkgRoot, "package.json");
16951
+ if (existsSync7(pkgJsonPath)) {
16935
16952
  try {
16936
16953
  const pkgRaw = readFileSync7(pkgJsonPath, "utf-8");
16937
16954
  const pkg4 = JSON.parse(pkgRaw);
16938
16955
  const typesField = pkg4.types ?? pkg4.typings;
16939
16956
  if (typeof typesField === "string") {
16940
16957
  const candidate = resolve16(pkgRoot, typesField);
16941
- if (existsSync6(candidate))
16958
+ if (existsSync7(candidate))
16942
16959
  return candidate;
16943
16960
  }
16944
16961
  const exportsTypes = extractTypesFromExports(pkg4.exports);
16945
16962
  if (exportsTypes) {
16946
16963
  const candidate = resolve16(pkgRoot, exportsTypes);
16947
- if (existsSync6(candidate))
16964
+ if (existsSync7(candidate))
16948
16965
  return candidate;
16949
16966
  }
16950
16967
  } catch {
16951
16968
  }
16952
16969
  }
16953
16970
  for (const entry of ["index.d.ts", "index.d.mts"]) {
16954
- const candidate = join18(pkgRoot, entry);
16955
- if (existsSync6(candidate))
16971
+ const candidate = join19(pkgRoot, entry);
16972
+ if (existsSync7(candidate))
16956
16973
  return candidate;
16957
16974
  }
16958
16975
  }
@@ -16960,7 +16977,7 @@ function locateDtsForSpecifier(req, specifier, parentFile) {
16960
16977
  const noExt = resolvedJs.replace(/\.(m?js|cjs)$/, "");
16961
16978
  for (const ext of [".d.ts", ".d.mts"]) {
16962
16979
  const candidate = `${noExt}${ext}`;
16963
- if (existsSync6(candidate))
16980
+ if (existsSync7(candidate))
16964
16981
  return candidate;
16965
16982
  }
16966
16983
  }
@@ -16969,9 +16986,9 @@ function locateDtsForSpecifier(req, specifier, parentFile) {
16969
16986
  function findPackageRootForSpecifier(seedDir, specifier) {
16970
16987
  let dir = seedDir;
16971
16988
  for (let i = 0; i < 32; i++) {
16972
- if (existsSync6(join18(dir, "package.json"))) {
16989
+ if (existsSync7(join19(dir, "package.json"))) {
16973
16990
  try {
16974
- const pkgRaw = readFileSync7(join18(dir, "package.json"), "utf-8");
16991
+ const pkgRaw = readFileSync7(join19(dir, "package.json"), "utf-8");
16975
16992
  const pkg4 = JSON.parse(pkgRaw);
16976
16993
  if (pkg4.name === specifier)
16977
16994
  return dir;
@@ -18943,9 +18960,9 @@ var init_wizard_generate_progress = __esm({
18943
18960
  });
18944
18961
 
18945
18962
  // packages/experience-design-system-cli-legacy/src/import/tui/spawn-generate.ts
18946
- import { spawn as spawn4 } from "node:child_process";
18963
+ import { spawn as spawn2 } from "node:child_process";
18947
18964
  function spawnGenerateChild(opts) {
18948
- const child = spawn4(opts.command, opts.args);
18965
+ const child = spawn2(opts.command, opts.args);
18949
18966
  let stdout = "";
18950
18967
  let stderr = "";
18951
18968
  child.stdout?.on("data", (d) => {
@@ -18984,6 +19001,88 @@ var init_spawn_generate = __esm({
18984
19001
  }
18985
19002
  });
18986
19003
 
19004
+ // packages/experience-design-system-cli-legacy/src/apply/dangling-token-defaults.ts
19005
+ import { parseCDFComponents as parseCDFComponents3 } from "@contentful/experience-design-system-types";
19006
+ function isRecord(value) {
19007
+ return typeof value === "object" && value !== null && !Array.isArray(value);
19008
+ }
19009
+ function dropDanglingTokenDefaults(cdf, existingTokenIds) {
19010
+ const known = new Set(existingTokenIds);
19011
+ for (const { path } of parseCDFComponents3(cdf).tokens) known.add(path);
19012
+ const copy = structuredClone(cdf);
19013
+ const dropped = [];
19014
+ const walk = (node, prefix) => {
19015
+ for (const [key, value] of Object.entries(node)) {
19016
+ if (key.startsWith("$") || !isRecord(value)) continue;
19017
+ const path = prefix ? `${prefix}.${key}` : key;
19018
+ const properties = value["$properties"];
19019
+ if (value["$type"] === "component" && isRecord(properties)) {
19020
+ for (const [name, property] of Object.entries(properties)) {
19021
+ if (!isRecord(property) || property["$type"] !== "token") continue;
19022
+ const reference = property["$default"];
19023
+ if (typeof reference === "string" && reference !== "" && !known.has(reference)) {
19024
+ delete property["$default"];
19025
+ dropped.push({ component: path, property: name, token: reference });
19026
+ }
19027
+ }
19028
+ } else {
19029
+ walk(value, path);
19030
+ }
19031
+ }
19032
+ };
19033
+ walk(copy, "");
19034
+ return { cdf: copy, dropped };
19035
+ }
19036
+ function describeDroppedTokenDefaults(dropped) {
19037
+ return dropped.map(
19038
+ ({ component, property, token }) => `${component}.${property}: default "${token}" left out \u2014 that design token does not exist in this environment`
19039
+ );
19040
+ }
19041
+ var init_dangling_token_defaults = __esm({
19042
+ "packages/experience-design-system-cli-legacy/src/apply/dangling-token-defaults.ts"() {
19043
+ "use strict";
19044
+ }
19045
+ });
19046
+
19047
+ // packages/experience-design-system-cli-legacy/src/helpers/build-contentful-management-client.ts
19048
+ import { createClient as createClient2 } from "contentful-management";
19049
+ function buildContentfulManagementClient(opts) {
19050
+ return createClient2(
19051
+ {
19052
+ accessToken: opts.cmaToken,
19053
+ ...opts.host ? { host: toConfiguredHost(opts.host) } : {}
19054
+ },
19055
+ { type: "plain" }
19056
+ );
19057
+ }
19058
+ var init_build_contentful_management_client = __esm({
19059
+ "packages/experience-design-system-cli-legacy/src/helpers/build-contentful-management-client.ts"() {
19060
+ "use strict";
19061
+ init_host_utils();
19062
+ }
19063
+ });
19064
+
19065
+ // packages/experience-design-system-cli-legacy/src/helpers/fetch-existing-token-ids.ts
19066
+ import { fetchAll } from "contentful-management";
19067
+ async function fetchExistingTokenIds(params) {
19068
+ const client2 = buildContentfulManagementClient({
19069
+ cmaToken: params.cmaToken,
19070
+ ...params.host ? { host: params.host } : {}
19071
+ });
19072
+ const tokens = await fetchAll(client2.designToken.getMany, {
19073
+ spaceId: params.spaceId,
19074
+ environmentId: params.environmentId,
19075
+ query: { cursor: true, limit: 1e3 }
19076
+ });
19077
+ return new Set(tokens.map((token) => token.sys.id));
19078
+ }
19079
+ var init_fetch_existing_token_ids = __esm({
19080
+ "packages/experience-design-system-cli-legacy/src/helpers/fetch-existing-token-ids.ts"() {
19081
+ "use strict";
19082
+ init_build_contentful_management_client();
19083
+ }
19084
+ });
19085
+
18987
19086
  // packages/experience-design-system-cli-legacy/src/analyze/composite-closure.ts
18988
19087
  function edgesFrom(component, known) {
18989
19088
  if (!component) return [];
@@ -20325,17 +20424,17 @@ function buildCycleUnits(slotCycles) {
20325
20424
  const groups = /* @__PURE__ */ new Map();
20326
20425
  for (const node of parent.keys()) {
20327
20426
  const root = find(node);
20328
- let group = groups.get(root);
20329
- if (!group) {
20330
- group = /* @__PURE__ */ new Set();
20331
- groups.set(root, group);
20427
+ let group2 = groups.get(root);
20428
+ if (!group2) {
20429
+ group2 = /* @__PURE__ */ new Set();
20430
+ groups.set(root, group2);
20332
20431
  }
20333
- group.add(node);
20432
+ group2.add(node);
20334
20433
  }
20335
20434
  const out = /* @__PURE__ */ new Map();
20336
- for (const group of groups.values()) {
20337
- for (const node of group) {
20338
- out.set(node, group);
20435
+ for (const group2 of groups.values()) {
20436
+ for (const node of group2) {
20437
+ out.set(node, group2);
20339
20438
  }
20340
20439
  }
20341
20440
  return out;
@@ -21829,10 +21928,10 @@ function swapValues(values, firstIndex, secondIndex) {
21829
21928
  [next[firstIndex], next[secondIndex]] = [next[secondIndex], next[firstIndex]];
21830
21929
  return next;
21831
21930
  }
21832
- function parseToState(json) {
21931
+ function parseToState(json2) {
21833
21932
  let parsed;
21834
21933
  try {
21835
- parsed = JSON.parse(json);
21934
+ parsed = JSON.parse(json2);
21836
21935
  } catch (e) {
21837
21936
  return {
21838
21937
  state: { componentDescription: "", props: [], slots: [] },
@@ -22685,11 +22784,11 @@ function FieldEditor({
22685
22784
  setEditorState(next);
22686
22785
  onChange(serializeState(next, value));
22687
22786
  };
22688
- const canonicalize = React14.useCallback((json) => {
22787
+ const canonicalize = React14.useCallback((json2) => {
22689
22788
  try {
22690
- return JSON.stringify(JSON.parse(json));
22789
+ return JSON.stringify(JSON.parse(json2));
22691
22790
  } catch {
22692
- return `__unparseable__:${json}`;
22791
+ return `__unparseable__:${json2}`;
22693
22792
  }
22694
22793
  }, []);
22695
22794
  const initialStateRef = React14.useRef(initialState);
@@ -23263,14 +23362,14 @@ function FieldEditor({
23263
23362
  })();
23264
23363
  const rows = [];
23265
23364
  rows.push({ kind: "component-description" });
23266
- for (const group of propGroups.filter((candidate) => candidate.kind !== "hidden")) {
23267
- if (group.indexes.length === 0) continue;
23365
+ for (const group2 of propGroups.filter((candidate) => candidate.kind !== "hidden")) {
23366
+ if (group2.indexes.length === 0) continue;
23268
23367
  rows.push({
23269
23368
  kind: "header",
23270
- label: `${group.label} (${group.indexes.length}) `,
23271
- section: group.kind
23369
+ label: `${group2.label} (${group2.indexes.length}) `,
23370
+ section: group2.kind
23272
23371
  });
23273
- group.indexes.forEach((idx) => rows.push({ kind: "prop", idx }));
23372
+ group2.indexes.forEach((idx) => rows.push({ kind: "prop", idx }));
23274
23373
  }
23275
23374
  if (slots.length > 0) {
23276
23375
  rows.push({
@@ -23280,7 +23379,7 @@ function FieldEditor({
23280
23379
  });
23281
23380
  slots.forEach((_, i) => rows.push({ kind: "slot", idx: i }));
23282
23381
  }
23283
- const hiddenGroup = propGroups.find((group) => group.kind === "hidden");
23382
+ const hiddenGroup = propGroups.find((group2) => group2.kind === "hidden");
23284
23383
  if (hiddenGroup && hiddenGroup.indexes.length > 0) {
23285
23384
  rows.push({
23286
23385
  kind: "header",
@@ -27022,26 +27121,8 @@ var init_runScopeGate = __esm({
27022
27121
  }
27023
27122
  });
27024
27123
 
27025
- // packages/experience-design-system-cli-legacy/src/helpers/build-contentful-management-client.ts
27026
- import { createClient as createClient2 } from "contentful-management";
27027
- function buildContentfulManagementClient(opts) {
27028
- return createClient2(
27029
- {
27030
- accessToken: opts.cmaToken,
27031
- ...opts.host ? { host: toConfiguredHost(opts.host) } : {}
27032
- },
27033
- { type: "plain" }
27034
- );
27035
- }
27036
- var init_build_contentful_management_client = __esm({
27037
- "packages/experience-design-system-cli-legacy/src/helpers/build-contentful-management-client.ts"() {
27038
- "use strict";
27039
- init_host_utils();
27040
- }
27041
- });
27042
-
27043
27124
  // packages/experience-design-system-cli-legacy/src/helpers/fetch-existing-contentful-entities.ts
27044
- import { fetchAll } from "contentful-management";
27125
+ import { fetchAll as fetchAll2 } from "contentful-management";
27045
27126
  async function fetchExistingContentfulEntitiesFromContentful(client2, params) {
27046
27127
  const componentScope = {
27047
27128
  spaceId: params.spaceId,
@@ -27053,8 +27134,8 @@ async function fetchExistingContentfulEntitiesFromContentful(client2, params) {
27053
27134
  environmentId: params.environmentId,
27054
27135
  query: { cursor: true, limit: 1e3 }
27055
27136
  };
27056
- const components = await fetchAll(client2.component.getMany, componentScope);
27057
- const tokens = await fetchAll(client2.designToken.getMany, tokenScope);
27137
+ const components = await fetchAll2(client2.component.getMany, componentScope);
27138
+ const tokens = await fetchAll2(client2.designToken.getMany, tokenScope);
27058
27139
  return { components, tokens };
27059
27140
  }
27060
27141
  var init_fetch_existing_contentful_entities = __esm({
@@ -27065,7 +27146,7 @@ var init_fetch_existing_contentful_entities = __esm({
27065
27146
 
27066
27147
  // packages/experience-design-system-cli-legacy/src/helpers/fetch-and-persist-existing-contentful-entities.ts
27067
27148
  import { writeFile as writeFile5 } from "node:fs/promises";
27068
- import { join as join19 } from "node:path";
27149
+ import { join as join20 } from "node:path";
27069
27150
  async function fetchAndPersistExistingContentfulEntities(params) {
27070
27151
  const t0 = Date.now();
27071
27152
  try {
@@ -27077,7 +27158,7 @@ async function fetchAndPersistExistingContentfulEntities(params) {
27077
27158
  spaceId: params.spaceId,
27078
27159
  environmentId: params.environmentId
27079
27160
  });
27080
- const path = join19(params.outDir, ".existing-entities.json");
27161
+ const path = join20(params.outDir, ".existing-entities.json");
27081
27162
  await writeFile5(path, JSON.stringify(entities, null, 2), "utf8");
27082
27163
  return { ok: true, path, durationMs: Date.now() - t0, entities };
27083
27164
  } catch (error) {
@@ -27254,11 +27335,11 @@ __export(WizardApp_exports, {
27254
27335
  });
27255
27336
  import { useEffect as useEffect15, useRef as useRef10, useState as useState23 } from "react";
27256
27337
  import { Box as Box42, Text as Text46 } from "ink";
27257
- import { join as join20, resolve as resolve17 } from "node:path";
27258
- import { appendFileSync as appendFileSync2, writeFileSync } from "node:fs";
27338
+ import { join as join21, resolve as resolve17 } from "node:path";
27339
+ import { appendFileSync as appendFileSync2, writeFileSync as writeFileSync2 } from "node:fs";
27259
27340
  import { access as access7, stat as stat5, writeFile as writeFile6 } from "node:fs/promises";
27260
27341
  import { tmpdir } from "node:os";
27261
- import { execFile as execFile2, spawn as spawn5 } from "node:child_process";
27342
+ import { execFile as execFile2, spawn as spawn3 } from "node:child_process";
27262
27343
  import { mkdir as mkdir5 } from "node:fs/promises";
27263
27344
  import { buildCDF as buildCDF3, validateCDF as validateCDF3, validateSlotReferences as validateSlotReferences2 } from "@contentful/experience-design-system-types";
27264
27345
  import { jsx as jsx50, jsxs as jsxs43 } from "react/jsx-runtime";
@@ -27320,7 +27401,7 @@ function runCli(args) {
27320
27401
  }
27321
27402
  function runSpawnedCli(args, onStderr, onStdout) {
27322
27403
  return new Promise((res) => {
27323
- const child = spawn5("node", args);
27404
+ const child = spawn3("node", args);
27324
27405
  let stdout = "";
27325
27406
  let stderr = "";
27326
27407
  child.stdout.on("data", (d) => {
@@ -27395,7 +27476,7 @@ function WizardApp({
27395
27476
  const logInit = useRef10(false);
27396
27477
  const initialAgentAuthRef = useRef10(initialAgentAuth ?? null);
27397
27478
  if (!logInit.current) {
27398
- writeFileSync(WIZARD_LOG, `--- experiences import session ${(/* @__PURE__ */ new Date()).toISOString()} ---
27479
+ writeFileSync2(WIZARD_LOG, `--- experiences import session ${(/* @__PURE__ */ new Date()).toISOString()} ---
27399
27480
  `);
27400
27481
  logInit.current = true;
27401
27482
  }
@@ -27404,6 +27485,7 @@ function WizardApp({
27404
27485
  tokensPath: ""
27405
27486
  });
27406
27487
  const allowEmptyDeleteAllRef = useRef10(false);
27488
+ const pushDebugRef = useRef10(null);
27407
27489
  const generateChildRef = useRef10(null);
27408
27490
  const generationCachePreflightRef = useRef10(null);
27409
27491
  const selectionToReviewStartedAtRef = useRef10(null);
@@ -27422,7 +27504,7 @@ function WizardApp({
27422
27504
  const rawTokensEntryReady = !!initialRawTokensPath;
27423
27505
  const effectiveNoCache = resolveNoCacheForGenerate({ cliNoCache: noCache });
27424
27506
  const initialStepResolved = rawTokensEntryReady ? initialProjectPath ? "path-validation" : "credentials" : initialProjectPath ? "token-input" : "welcome";
27425
- const initialOutDir = initialProjectPath ? join20(resolve17(initialProjectPath), ".contentful") : "";
27507
+ const initialOutDir = initialProjectPath ? join21(resolve17(initialProjectPath), ".contentful") : "";
27426
27508
  const [state, setState] = useState23({
27427
27509
  step: initialStepResolved,
27428
27510
  agent: initialAgent ?? "claude",
@@ -27478,6 +27560,7 @@ function WizardApp({
27478
27560
  existingEntitiesStatus: "idle",
27479
27561
  lastRunId: null,
27480
27562
  finalizeErrorBanner: null,
27563
+ droppedTokenDefaults: [],
27481
27564
  finalReviewPassed: false
27482
27565
  });
27483
27566
  useEffect15(() => {
@@ -27620,7 +27703,7 @@ If you are using AWS Bedrock, run:
27620
27703
  }
27621
27704
  const sessionMatch = /^session=(.+)$/m.exec(result.stdout);
27622
27705
  const tokenSessionId = sessionMatch ? sessionMatch[1].trim() : null;
27623
- const tokensPath = join20(outDir, "tokens.json");
27706
+ const tokensPath = join21(outDir, "tokens.json");
27624
27707
  const printArgs = ["print", "tokens", "--out", tokensPath];
27625
27708
  if (tokenSessionId) printArgs.push("--session", tokenSessionId);
27626
27709
  const r = await runCli(printArgs);
@@ -27642,7 +27725,7 @@ If you are using AWS Bedrock, run:
27642
27725
  tokenGenerationStatus: "complete",
27643
27726
  skipComponents: true,
27644
27727
  acceptedCount: 0,
27645
- outDir: state.outDir || join20(process.cwd(), ".contentful")
27728
+ outDir: state.outDir || join21(process.cwd(), ".contentful")
27646
27729
  });
27647
27730
  update({ step: "credentials" });
27648
27731
  return true;
@@ -27783,7 +27866,7 @@ If you are using AWS Bedrock, run:
27783
27866
  return promise;
27784
27867
  };
27785
27868
  const runExtract = async (projectPath, showProgress = true) => {
27786
- const outDir = join20(resolve17(projectPath), ".contentful");
27869
+ const outDir = join21(resolve17(projectPath), ".contentful");
27787
27870
  const existingEntitiesExpected = !state.credentialsSkipped && Boolean(state.spaceId && state.environmentId && state.cmaToken && projectPath);
27788
27871
  update({
27789
27872
  ...showProgress ? { step: "extracting" } : {},
@@ -28458,12 +28541,30 @@ Make sure this path contains TypeScript/React/Vue component files (.tsx, .ts, .v
28458
28541
  void runSaveAndPush();
28459
28542
  };
28460
28543
  const runPreview = async (extractSessionId, tokensPath, spaceId, environmentId, cmaToken, host2) => {
28544
+ const resolvedHost = resolveWizardHost(host2);
28545
+ pushDebugRef.current?.finish({
28546
+ outcome: "superseded",
28547
+ summary: "A new push attempt started before this one finished."
28548
+ });
28549
+ const pushDebug = startPushDebugRun({
28550
+ space_id: spaceId,
28551
+ environment_id: environmentId,
28552
+ host: resolvedHost,
28553
+ cma_token: cmaToken,
28554
+ extract_session_id: extractSessionId,
28555
+ tokens_file: tokensPath || null,
28556
+ delete_everything_not_listed: allowEmptyDeleteAllRef.current
28557
+ });
28558
+ pushDebugRef.current = pushDebug;
28461
28559
  if (shouldBypassPreview(state)) {
28560
+ pushDebug.finish({
28561
+ outcome: "skipped",
28562
+ summary: "Credentials were skipped, so nothing is previewed or pushed. Files were saved only."
28563
+ });
28462
28564
  update(buildSkippedPreviewTransition());
28463
28565
  return;
28464
28566
  }
28465
28567
  update({ step: "previewing" });
28466
- const resolvedHost = resolveWizardHost(host2);
28467
28568
  try {
28468
28569
  const client2 = new ImportApiClient({
28469
28570
  cmaToken,
@@ -28471,6 +28572,7 @@ Make sure this path contains TypeScript/React/Vue component files (.tsx, .ts, .v
28471
28572
  environmentId,
28472
28573
  host: resolvedHost
28473
28574
  });
28575
+ pushDebug.event("Preview started", { note: `POST ${resolvedHost}/\u2026/design_systems/imports/preview` });
28474
28576
  let components = [];
28475
28577
  if (extractSessionId) {
28476
28578
  const db = openPipelineDb();
@@ -28486,7 +28588,16 @@ Make sure this path contains TypeScript/React/Vue component files (.tsx, .ts, .v
28486
28588
  tokens = await readTokensFromPath("tokens", tokensPath);
28487
28589
  }
28488
28590
  let cdf = buildCDF3(components, toCDFTokens(tokens), { deleteAll: allowEmptyDeleteAllRef.current });
28591
+ pushDebug.event("Built the CDF to send", {
28592
+ note: `${summarizeCdf(cdf).length} entries`,
28593
+ data: { entries: summarizeCdf(cdf), tokens_loaded: tokens.length }
28594
+ });
28489
28595
  let preview = await client2.previewImport(cdf);
28596
+ pushDebug.event("Server previewed the CDF", {
28597
+ note: "what the server would create, change, leave alone or remove",
28598
+ data: summarizePreview(preview),
28599
+ requestId: client2.getLastRequestId()
28600
+ });
28490
28601
  if (extractSessionId) {
28491
28602
  let needsRepreview = false;
28492
28603
  const db = openPipelineDb();
@@ -28506,15 +28617,27 @@ Make sure this path contains TypeScript/React/Vue component files (.tsx, .ts, .v
28506
28617
  if (seededDefaults > 0) needsRepreview = true;
28507
28618
  }
28508
28619
  if (needsRepreview) {
28620
+ pushDebug.event("Re-previewing", {
28621
+ note: "the server listed components as removed or changed that exist locally, so defaults were filled in"
28622
+ });
28509
28623
  components = loadCDFComponents(db, extractSessionId);
28510
28624
  cdf = buildCDF3(components, toCDFTokens(tokens), { deleteAll: allowEmptyDeleteAllRef.current });
28511
28625
  preview = await client2.previewImport(cdf);
28626
+ pushDebug.event("Server previewed the updated CDF", {
28627
+ data: summarizePreview(preview),
28628
+ requestId: client2.getLastRequestId()
28629
+ });
28512
28630
  }
28513
28631
  } finally {
28514
28632
  db.close();
28515
28633
  }
28516
28634
  }
28517
28635
  if (isEmptyPreview(preview)) {
28636
+ pushDebug.finish({
28637
+ outcome: "nothing-to-push",
28638
+ summary: "The server says every component and token in the CDF already matches what is in this space, so no apply request was sent. If the space looks empty, check that this is the space and environment you are viewing.",
28639
+ details: { preview: summarizePreview(preview), request_id: client2.getLastRequestId() }
28640
+ });
28518
28641
  update({
28519
28642
  step: "done",
28520
28643
  serverPreview: preview,
@@ -28526,14 +28649,44 @@ Make sure this path contains TypeScript/React/Vue component files (.tsx, .ts, .v
28526
28649
  });
28527
28650
  return;
28528
28651
  }
28652
+ let cdfToPush = cdf;
28653
+ let droppedTokenDefaults = [];
28654
+ try {
28655
+ const existingTokenIds = await fetchExistingTokenIds({
28656
+ spaceId,
28657
+ environmentId,
28658
+ cmaToken,
28659
+ ...host2 ? { host: host2 } : {}
28660
+ });
28661
+ const checked = dropDanglingTokenDefaults(cdf, existingTokenIds);
28662
+ cdfToPush = checked.cdf;
28663
+ droppedTokenDefaults = describeDroppedTokenDefaults(checked.dropped);
28664
+ pushDebug.event("Checked token references", {
28665
+ note: checked.dropped.length === 0 ? `every token default exists (${existingTokenIds.size} tokens in this environment)` : `${checked.dropped.length} default(s) point at a token that does not exist and will be left out`,
28666
+ data: { tokens_in_environment: existingTokenIds.size, dropped: checked.dropped }
28667
+ });
28668
+ } catch (tokenCheckError) {
28669
+ pushDebug.event("Could not check token references", {
28670
+ note: tokenCheckError instanceof Error ? tokenCheckError.message : String(tokenCheckError)
28671
+ });
28672
+ }
28673
+ pushDebug.event("Waiting for confirmation", {
28674
+ note: "the preview shows changes, so the wizard asks before pushing"
28675
+ });
28529
28676
  update({
28530
28677
  step: "preview-gate",
28531
28678
  serverPreview: preview,
28532
- cdf,
28679
+ cdf: cdfToPush,
28680
+ droppedTokenDefaults,
28533
28681
  finalizeErrorBanner: null,
28534
28682
  ...clearedValidationErrorState()
28535
28683
  });
28536
28684
  } catch (e) {
28685
+ pushDebug.finish({
28686
+ outcome: "preview-failed",
28687
+ summary: e instanceof ApiError ? `The preview request was rejected with HTTP ${e.status}.` : `The preview failed before the server answered: ${e instanceof Error ? e.message : String(e)}`,
28688
+ details: e instanceof ApiError ? { status: e.status, body: (e.body ?? "").slice(0, 4e3) } : { error: e instanceof Error ? e.message : String(e) }
28689
+ });
28537
28690
  if (e instanceof ApiError) {
28538
28691
  if (e.status === 401 || e.status === 403) {
28539
28692
  let bodyMsg = "";
@@ -28596,7 +28749,18 @@ If using a custom host configuration, make sure the space exists on that host.`
28596
28749
  }
28597
28750
  };
28598
28751
  const runPush = async (cdf, spaceId, environmentId, cmaToken, host2, acknowledgeBreakingChanges, preview) => {
28752
+ const pushDebug = pushDebugRef.current ?? startPushDebugRun({
28753
+ space_id: spaceId,
28754
+ environment_id: environmentId,
28755
+ host: resolveWizardHost(host2),
28756
+ cma_token: cmaToken
28757
+ });
28758
+ pushDebugRef.current = pushDebug;
28599
28759
  if (shouldRefusePush(state)) {
28760
+ pushDebug.finish({
28761
+ outcome: "skipped",
28762
+ summary: "Credentials were skipped, so the push was refused. Files were saved only."
28763
+ });
28600
28764
  update(buildSkippedPushTransition());
28601
28765
  return;
28602
28766
  }
@@ -28604,6 +28768,11 @@ If using a custom host configuration, make sure the space exists on that host.`
28604
28768
  const hasComponentChanges = preview.components.new.length > 0 || preview.components.changed.length > 0 || preview.components.removed.length > 0;
28605
28769
  const hasTokenChanges = preview.tokens.new.length > 0 || preview.tokens.changed.length > 0 || preview.tokens.removed.length > 0;
28606
28770
  if (!hasComponentChanges && !hasTokenChanges) {
28771
+ pushDebug.finish({
28772
+ outcome: "nothing-to-push",
28773
+ summary: "The preview had no new, changed or removed items, so no apply request was sent.",
28774
+ details: { preview: summarizePreview(preview) }
28775
+ });
28607
28776
  update({
28608
28777
  step: "done",
28609
28778
  pushResult: {
@@ -28616,6 +28785,11 @@ If using a custom host configuration, make sure the space exists on that host.`
28616
28785
  }
28617
28786
  const cycles = detectSlotCycles(extractComponents(cdf));
28618
28787
  if (cycles.length > 0) {
28788
+ pushDebug.finish({
28789
+ outcome: "failed",
28790
+ summary: "The push was blocked locally because components slot each other in a cycle.",
28791
+ details: { cycles: formatSlotCycleReport(cycles) }
28792
+ });
28619
28793
  update({
28620
28794
  step: "error",
28621
28795
  errorStep: "apply",
@@ -28626,6 +28800,11 @@ If using a custom host configuration, make sure the space exists on that host.`
28626
28800
  }
28627
28801
  const unresolvedSlotReferences = validateSlotReferences2(extractComponents(cdf));
28628
28802
  if (unresolvedSlotReferences.length > 0) {
28803
+ pushDebug.finish({
28804
+ outcome: "failed",
28805
+ summary: "The push was blocked locally because a slot refers to a component that is not in the CDF.",
28806
+ details: { unresolved: formatUnresolvedSlotReferences(unresolvedSlotReferences) }
28807
+ });
28629
28808
  update({
28630
28809
  step: "error",
28631
28810
  errorStep: "apply",
@@ -28635,6 +28814,14 @@ If using a custom host configuration, make sure the space exists on that host.`
28635
28814
  return;
28636
28815
  }
28637
28816
  update({ step: "pushing", pushProgress: null, errorAllowBreakingChangeAcknowledgment: false });
28817
+ pushDebug.event("Apply started", {
28818
+ note: `POST ${resolveWizardHost(host2)}/\u2026/design_systems/imports/apply`,
28819
+ data: {
28820
+ acknowledge_breaking_changes: acknowledgeBreakingChanges,
28821
+ sending: summarizeCdf(cdf),
28822
+ expected: preview ? summarizePreview(preview) : null
28823
+ }
28824
+ });
28638
28825
  try {
28639
28826
  const resolvedHost = resolveWizardHost(host2);
28640
28827
  const client2 = new ImportApiClient({
@@ -28644,6 +28831,11 @@ If using a custom host configuration, make sure the space exists on that host.`
28644
28831
  host: resolvedHost
28645
28832
  });
28646
28833
  let operation = await client2.applyImport(cdf, { acknowledgeBreakingChanges });
28834
+ pushDebug.event("Server accepted the apply request", {
28835
+ note: `operation ${operation.sys.id} is ${operation.sys.status}`,
28836
+ data: { operation_id: operation.sys.id, status: operation.sys.status, summary: operation.summary },
28837
+ requestId: client2.getLastRequestId()
28838
+ });
28647
28839
  try {
28648
28840
  logStep({
28649
28841
  applyResponse: {
@@ -28660,9 +28852,15 @@ If using a custom host configuration, make sure the space exists on that host.`
28660
28852
  pushProgress: { kind: "queued", operationId: operation.sys.id }
28661
28853
  });
28662
28854
  let pollCount = 0;
28855
+ let lastPolledStatus = "";
28663
28856
  operation = await client2.pollOperation(operation.sys.id, {
28664
28857
  onProgress: (op) => {
28665
28858
  pollCount++;
28859
+ const polled = `${op.sys.status} ${op.summary ? `${op.summary.total - op.summary.pending}/${op.summary.total}` : ""}`;
28860
+ if (polled !== lastPolledStatus) {
28861
+ lastPolledStatus = polled;
28862
+ pushDebug.event("Operation status changed", { note: polled.trim(), requestId: client2.getLastRequestId() });
28863
+ }
28666
28864
  const s = op.summary;
28667
28865
  if (s) {
28668
28866
  const done = s.total - s.pending;
@@ -28767,6 +28965,29 @@ If using a custom host configuration, make sure the space exists on that host.`
28767
28965
  );
28768
28966
  }
28769
28967
  }
28968
+ const failedItems = items.filter((item) => item.status === "failed");
28969
+ const pushedCount = items.filter((item) => item.status === "succeeded").length;
28970
+ pushDebug.finish({
28971
+ outcome: pushSucceeded ? "pushed" : pushedCount > 0 ? "partial" : "failed",
28972
+ summary: pushSucceeded ? items.length > 0 ? `The server reports ${pushedCount} of ${items.length} items applied.` : `The operation finished as ${operation.sys.status}, but the server returned no per-item results, so the counts come from the preview.` : `The operation finished as ${operation.sys.status}; ${failedItems.length} item(s) failed.`,
28973
+ details: {
28974
+ operation_id: operation.sys.id,
28975
+ operation_status: operation.sys.status,
28976
+ server_summary: operation.summary,
28977
+ items: items.map((item) => ({
28978
+ type: item.entityType,
28979
+ id: item.id,
28980
+ action: item.action,
28981
+ status: item.status,
28982
+ ...item.error ? { error: formatEdsiError(item.error) } : {}
28983
+ })),
28984
+ shown_to_user: {
28985
+ component_types: pushResult.componentTypes,
28986
+ design_tokens: pushResult.designTokens
28987
+ },
28988
+ request_id: client2.getLastRequestId()
28989
+ }
28990
+ });
28770
28991
  update({ step: "done", pushResult });
28771
28992
  } catch (e) {
28772
28993
  let msg;
@@ -28777,6 +28998,14 @@ If using a custom host configuration, make sure the space exists on that host.`
28777
28998
  } else {
28778
28999
  msg = "Push failed";
28779
29000
  }
29001
+ pushDebug.finish({
29002
+ outcome: "failed",
29003
+ summary: e instanceof ApiError ? `The apply request failed with HTTP ${e.status}.` : `The apply request failed before the server answered: ${msg}`,
29004
+ details: {
29005
+ message: msg,
29006
+ ...e instanceof ApiError ? { status: e.status, body: (e.body ?? "").slice(0, 4e3) } : {}
29007
+ }
29008
+ });
28780
29009
  update({
28781
29010
  step: "error",
28782
29011
  errorStep: "apply",
@@ -28788,7 +29017,7 @@ If using a custom host configuration, make sure the space exists on that host.`
28788
29017
  };
28789
29018
  const runPrintFiles = async (extractSessionId, outDir, opts = {}) => {
28790
29019
  update({ step: "printing" });
28791
- const componentsPath = join20(outDir, "components.json");
29020
+ const componentsPath = join21(outDir, "components.json");
28792
29021
  try {
28793
29022
  const db = openPipelineDb();
28794
29023
  let components = [];
@@ -28891,7 +29120,7 @@ If using a custom host configuration, make sure the space exists on that host.`
28891
29120
  if (tokenReuseChecked.current) return;
28892
29121
  tokenReuseChecked.current = true;
28893
29122
  const tokenNextStep = state.projectPath ? "path-validation" : "credentials";
28894
- const existingTokensPath = join20(state.outDir, "tokens.json");
29123
+ const existingTokensPath = join21(state.outDir, "tokens.json");
28895
29124
  if (effectiveNoCache) {
28896
29125
  tokenGenerationPromiseRef.current = runAgentAuthCheck(tokenNextStep).then(
28897
29126
  (ok2) => ok2 ? runGenerateTokens(state.rawTokensPath, state.outDir) : false
@@ -28942,7 +29171,7 @@ If using a custom host configuration, make sure the space exists on that host.`
28942
29171
  {
28943
29172
  onContinue: (path) => {
28944
29173
  const projectPath = normalizePath(path);
28945
- const outDir = join20(projectPath, ".contentful");
29174
+ const outDir = join21(projectPath, ".contentful");
28946
29175
  update({ step: "token-input", projectPath, outDir });
28947
29176
  },
28948
29177
  onQuit: () => process.exit(0)
@@ -29304,6 +29533,7 @@ If using a custom host configuration, make sure the space exists on that host.`
29304
29533
  environmentId: state.environmentId,
29305
29534
  stepNumber: totalSteps,
29306
29535
  totalSteps,
29536
+ droppedTokenDefaults: state.droppedTokenDefaults,
29307
29537
  onConfirm: (acknowledge) => {
29308
29538
  void runPush(
29309
29539
  state.cdf,
@@ -29440,6 +29670,7 @@ var init_WizardApp = __esm({
29440
29670
  init_theme();
29441
29671
  init_run_teaser();
29442
29672
  init_debug_logger();
29673
+ init_push_debug_log();
29443
29674
  init_credentials_store();
29444
29675
  init_path_prompt();
29445
29676
  init_save_path_resolver();
@@ -29468,6 +29699,8 @@ var init_WizardApp = __esm({
29468
29699
  init_wizard_generate_progress();
29469
29700
  init_spawn_generate();
29470
29701
  init_tokens();
29702
+ init_dangling_token_defaults();
29703
+ init_fetch_existing_token_ids();
29471
29704
  init_preview_utils();
29472
29705
  init_db();
29473
29706
  init_ScopeGateStep();
@@ -29484,7 +29717,7 @@ var init_WizardApp = __esm({
29484
29717
  init_use_terminal_size();
29485
29718
  init_render_with_goodbye();
29486
29719
  SAVE_CONFIRMATION_DELAY_MS = 1e3;
29487
- WIZARD_LOG = join20(tmpdir(), "experiences-import-wizard.log");
29720
+ WIZARD_LOG = join21(tmpdir(), "experiences-import-wizard.log");
29488
29721
  }
29489
29722
  });
29490
29723
 
@@ -29615,7 +29848,7 @@ var init_agent_definitions = __esm({
29615
29848
  });
29616
29849
 
29617
29850
  // packages/experience-design-system-cli-legacy/src/setup/lib/shell.ts
29618
- import { execFile as execFile3, spawn as spawn6 } from "node:child_process";
29851
+ import { execFile as execFile3, spawn as spawn4 } from "node:child_process";
29619
29852
  import { access as access8 } from "node:fs/promises";
29620
29853
  import { promisify as promisify2 } from "node:util";
29621
29854
  async function binaryExists(name) {
@@ -29631,7 +29864,7 @@ async function pathExists3(path) {
29631
29864
  }
29632
29865
  function runSpawn(cmd, args, opts = {}) {
29633
29866
  return new Promise((resolve21) => {
29634
- const child = spawn6(cmd, args, {
29867
+ const child = spawn4(cmd, args, {
29635
29868
  cwd: opts.cwd,
29636
29869
  env: opts.env ?? process.env,
29637
29870
  stdio: ["ignore", "pipe", "pipe"]
@@ -29664,7 +29897,7 @@ var init_shell = __esm({
29664
29897
  });
29665
29898
 
29666
29899
  // packages/experience-design-system-cli-legacy/src/setup/lib/checks.ts
29667
- import { join as join21 } from "node:path";
29900
+ import { join as join22 } from "node:path";
29668
29901
  function checkNodeVersion(nodeVersion = process.versions.node) {
29669
29902
  const major = Number.parseInt(nodeVersion.split(".")[0], 10);
29670
29903
  return {
@@ -29678,7 +29911,7 @@ async function detectNodeVersionManagers(homeDir, deps = {
29678
29911
  binaryExists,
29679
29912
  pathExists: pathExists3
29680
29913
  }) {
29681
- const nvmScript = join21(homeDir, ".nvm", "nvm.sh");
29914
+ const nvmScript = join22(homeDir, ".nvm", "nvm.sh");
29682
29915
  return {
29683
29916
  nvm: await deps.binaryExists("nvm") || await deps.pathExists(nvmScript),
29684
29917
  fnm: await deps.binaryExists("fnm"),
@@ -29757,7 +29990,7 @@ var init_report = __esm({
29757
29990
 
29758
29991
  // packages/experience-design-system-cli-legacy/src/doctor/checks.ts
29759
29992
  import { homedir as homedir7 } from "node:os";
29760
- import { join as join22 } from "node:path";
29993
+ import { join as join23 } from "node:path";
29761
29994
  async function reportNode() {
29762
29995
  section("Checking Node.js version");
29763
29996
  const check = checkNodeVersion();
@@ -29808,12 +30041,12 @@ async function reportPnpm(pkgRoot) {
29808
30041
  }
29809
30042
  async function reportDependencies(pkgRoot) {
29810
30043
  section("Checking dependencies (pnpm install)");
29811
- if (!await pathExists3(join22(pkgRoot, "node_modules"))) {
30044
+ if (!await pathExists3(join23(pkgRoot, "node_modules"))) {
29812
30045
  info("node_modules not found \u2014 running pnpm install...");
29813
30046
  } else {
29814
30047
  info("Running pnpm install to ensure dependencies are up to date...");
29815
30048
  }
29816
- const check = await installDependencies(join22(pkgRoot, "..", ".."));
30049
+ const check = await installDependencies(join23(pkgRoot, "..", ".."));
29817
30050
  if (!check.passed) {
29818
30051
  fail("pnpm install failed");
29819
30052
  info("");
@@ -29830,7 +30063,7 @@ async function reportDependencies(pkgRoot) {
29830
30063
  async function reportBuild(pkgRoot) {
29831
30064
  section("Building CLI");
29832
30065
  info("Running pnpm build...");
29833
- const check = await buildCli(join22(pkgRoot, "..", ".."));
30066
+ const check = await buildCli(join23(pkgRoot, "..", ".."));
29834
30067
  if (!check.passed) {
29835
30068
  fail("Build failed");
29836
30069
  info("");
@@ -31045,9 +31278,9 @@ var init_SetupScreen = __esm({
31045
31278
 
31046
31279
  // packages/experience-design-system-cli-legacy/src/setup/command.ts
31047
31280
  import { readFileSync as readFileSync8 } from "node:fs";
31048
- import { join as join23 } from "node:path";
31281
+ import { join as join24 } from "node:path";
31049
31282
  function getCliVersion() {
31050
- const pkg4 = JSON.parse(readFileSync8(join23(findPkgRoot(), "package.json"), "utf8"));
31283
+ const pkg4 = JSON.parse(readFileSync8(join24(findPkgRoot(), "package.json"), "utf8"));
31051
31284
  return pkg4.version;
31052
31285
  }
31053
31286
  async function runSetup(opts) {
@@ -31059,7 +31292,7 @@ async function runSetup(opts) {
31059
31292
  const { renderWithGoodbye: renderWithGoodbye2 } = await Promise.resolve().then(() => (init_render_with_goodbye(), render_with_goodbye_exports));
31060
31293
  const { createElement: createElement6 } = await import("react");
31061
31294
  const { SetupScreen: SetupScreen2 } = await Promise.resolve().then(() => (init_SetupScreen(), SetupScreen_exports));
31062
- const repoRoot = join23(findPkgRoot(), "..", "..");
31295
+ const repoRoot = join24(findPkgRoot(), "..", "..");
31063
31296
  const completion = { outcome: null };
31064
31297
  let unmountInk = null;
31065
31298
  const { waitUntilExit, unmount } = renderWithGoodbye2(
@@ -31260,15 +31493,15 @@ var init_apply_mapping = __esm({
31260
31493
  });
31261
31494
 
31262
31495
  // packages/experience-design-system-cli-legacy/src/analyze/composition/prompt-loader.ts
31263
- import { existsSync as existsSync7, readFileSync as readFileSync9 } from "node:fs";
31264
- import { dirname as dirname11, join as join24, resolve as resolve18 } from "node:path";
31496
+ import { existsSync as existsSync8, readFileSync as readFileSync9 } from "node:fs";
31497
+ import { dirname as dirname11, join as join25, resolve as resolve18 } from "node:path";
31265
31498
  import { fileURLToPath as fileURLToPath3 } from "node:url";
31266
31499
  function resolvePromptPath(fileName) {
31267
31500
  const thisDir = dirname11(fileURLToPath3(import.meta.url));
31268
31501
  let dir = thisDir;
31269
31502
  for (; ; ) {
31270
- const candidate = join24(dir, "prompts");
31271
- if (existsSync7(candidate)) return join24(candidate, fileName);
31503
+ const candidate = join25(dir, "prompts");
31504
+ if (existsSync8(candidate)) return join25(candidate, fileName);
31272
31505
  const parent = resolve18(dir, "..");
31273
31506
  if (parent === dir) {
31274
31507
  throw new Error(
@@ -31536,7 +31769,7 @@ var init_manifest_doc_evidence = __esm({
31536
31769
 
31537
31770
  // packages/experience-design-system-cli-legacy/src/analyze/extract-command.ts
31538
31771
  import { mkdir as mkdir6, readdir as readdir3, readFile as readFile18, stat as stat6 } from "node:fs/promises";
31539
- import { isAbsolute as isAbsolute2, join as join25, relative as relative2, resolve as resolve19 } from "node:path";
31772
+ import { isAbsolute as isAbsolute2, join as join26, relative as relative2, resolve as resolve19 } from "node:path";
31540
31773
  function resolveExtractNoCache(opts) {
31541
31774
  return opts.noCache === true || opts.cache === false;
31542
31775
  }
@@ -31574,7 +31807,7 @@ async function collectSourceFiles(directory, onProgress) {
31574
31807
  const entries = await readdir3(currentDirectory, { withFileTypes: true });
31575
31808
  const subdirs = [];
31576
31809
  for (const entry of entries) {
31577
- const fullPath = join25(currentDirectory, entry.name);
31810
+ const fullPath = join26(currentDirectory, entry.name);
31578
31811
  if (entry.isDirectory()) {
31579
31812
  if (!IGNORED_DIRECTORY_NAMES.has(entry.name)) {
31580
31813
  subdirs.push(fullPath);
@@ -31658,7 +31891,7 @@ function registerInternalExtractCommand(program) {
31658
31891
  }
31659
31892
  }
31660
31893
  const projectRoot = resolve19(opts.project);
31661
- const outDir = join25(projectRoot, ".contentful");
31894
+ const outDir = join26(projectRoot, ".contentful");
31662
31895
  let sourceDirectory;
31663
31896
  if (opts.dir !== void 0) {
31664
31897
  sourceDirectory = resolveFromProjectRoot(projectRoot, opts.dir);
@@ -32061,9 +32294,9 @@ __export(program_exports, {
32061
32294
  resolveBedrockFromAncestors: () => resolveBedrockFromAncestors,
32062
32295
  runBuild: () => runBuild
32063
32296
  });
32064
- import { spawn as spawn7 } from "node:child_process";
32297
+ import { spawn as spawn5 } from "node:child_process";
32065
32298
  import { fileURLToPath as fileURLToPath4 } from "node:url";
32066
- import { dirname as dirname13, join as join26, resolve as resolve20 } from "node:path";
32299
+ import { dirname as dirname13, join as join27, resolve as resolve20 } from "node:path";
32067
32300
  import { readFileSync as readFileSync10 } from "node:fs";
32068
32301
  import { Command } from "commander";
32069
32302
  async function runBuild(opts) {
@@ -32096,7 +32329,7 @@ function registerBuildCommand(program) {
32096
32329
  const pkgRoot = resolve20(dirname13(fileURLToPath4(import.meta.url)), "..", "..");
32097
32330
  process.stderr.write("\u2699 Building from source...\n");
32098
32331
  const { exitCode } = await runBuild({
32099
- spawnFn: () => spawn7("pnpm", ["build"], { cwd: pkgRoot, stdio: "inherit" }),
32332
+ spawnFn: () => spawn5("pnpm", ["build"], { cwd: pkgRoot, stdio: "inherit" }),
32100
32333
  stderrWrite: (s) => process.stderr.write(s)
32101
32334
  });
32102
32335
  process.exit(exitCode);
@@ -32163,7 +32396,7 @@ var init_program = __esm({
32163
32396
  init_analytics();
32164
32397
  init_credentials_store();
32165
32398
  init_cli_path();
32166
- pkg3 = JSON.parse(readFileSync10(join26(findPkgRoot(), "package.json"), "utf8"));
32399
+ pkg3 = JSON.parse(readFileSync10(join27(findPkgRoot(), "package.json"), "utf8"));
32167
32400
  }
32168
32401
  });
32169
32402