@contentful/experience-design-system-cli 2.35.1-dev-build-9605c7ee.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.
@@ -173,497 +173,263 @@ var init_agent_names = __esm({
173
173
  }
174
174
  });
175
175
 
176
- // packages/experience-design-system-generation/dist/src/controller/helpers/validate-generation-request.js
177
- function validateGenerationRequest(request2) {
178
- if (request2 === null || typeof request2 !== "object") {
179
- throw new TypeError("createGenerationEndpoint requires a request object");
180
- }
181
- if (!isAgentName(request2.agent)) {
182
- throw new TypeError(`createGenerationEndpoint requires agent to be a valid agent name, got: ${String(request2.agent)}`);
183
- }
184
- if (typeof request2.timeoutMs !== "number" || request2.timeoutMs <= 0) {
185
- throw new TypeError("createGenerationEndpoint requires timeoutMs to be a positive number");
186
- }
187
- if (request2.promptOptions === null || typeof request2.promptOptions !== "object") {
188
- throw new TypeError("createGenerationEndpoint requires promptOptions to be an object");
189
- }
190
- if (request2.onOutput !== void 0 && typeof request2.onOutput !== "function") {
191
- throw new TypeError("createGenerationEndpoint requires onOutput to be a function when provided");
192
- }
193
- }
194
- var init_validate_generation_request = __esm({
195
- "packages/experience-design-system-generation/dist/src/controller/helpers/validate-generation-request.js"() {
196
- "use strict";
197
- init_agent_names();
198
- }
199
- });
200
-
201
- // packages/experience-design-system-generation/dist/src/services/prompts/helpers/resolve-skill-file.js
202
- import { existsSync } from "node:fs";
203
- import { readFile as readFile2 } from "node:fs/promises";
204
- import { dirname, join as join2, resolve } from "node:path";
205
- import { fileURLToPath } from "node:url";
206
- function resolveSkillPath(skill) {
207
- if (!(skill in SKILL_FILES))
208
- throw new Error(`Invalid skill: ${skill}`);
209
- const thisDir = dirname(fileURLToPath(import.meta.url));
210
- let dir = thisDir;
211
- for (; ; ) {
212
- const candidate = join2(dir, "skills");
213
- if (existsSync(candidate))
214
- return join2(candidate, SKILL_FILES[skill]);
215
- const parent = resolve(dir, "..");
216
- if (parent === dir) {
217
- 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;
218
194
  }
219
- dir = parent;
220
195
  }
196
+ return -1;
221
197
  }
222
- function formatCustomPromptBanner(skill, path) {
223
- return `WARNING: Custom prompt active for ${skill}: ${path}
224
- Bundled invariants (utility-wrapper rejection, description content rules) do NOT apply.
225
- You are responsible for the prompt's correctness.
226
- `;
227
- }
228
- async function readSkillFile(skill, override) {
229
- if (override) {
230
- 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;
231
211
  try {
232
- return await readFile2(skillPath2, "utf8");
212
+ parsed = JSON.parse(line.slice(0, end + 1));
233
213
  } catch {
234
- 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);
235
223
  }
236
224
  }
237
- const skillPath = resolveSkillPath(skill);
238
- try {
239
- return await readFile2(skillPath, "utf8");
240
- } catch {
241
- throw new Error(`skill file missing from CLI installation \u2014 try reinstalling the CLI (looked for: ${skillPath})`);
242
- }
225
+ return { objects, warnings };
243
226
  }
244
- var SKILL_FILES;
245
- var init_resolve_skill_file = __esm({
246
- "packages/experience-design-system-generation/dist/src/services/prompts/helpers/resolve-skill-file.js"() {
247
- "use strict";
248
- SKILL_FILES = {
249
- components: "generate-components.md",
250
- tokens: "generate-tokens.md",
251
- select: "select-components.md",
252
- "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
253
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);
254
251
  }
255
- });
256
-
257
- // packages/experience-design-system-generation/dist/src/services/prompts/helpers/format-token-candidates.js
258
- import { flattenDTCG } from "@contentful/experience-design-system-types";
259
- function inferFenceLang(filename) {
260
- if (!filename)
261
- return "json";
262
- const ext = filename.split(".").pop()?.toLowerCase() ?? "";
263
- const map = {
264
- js: "js",
265
- mjs: "js",
266
- cjs: "js",
267
- ts: "ts",
268
- mts: "ts",
269
- cts: "ts",
270
- tsx: "tsx",
271
- jsx: "jsx",
272
- vue: "vue",
273
- svelte: "svelte",
274
- astro: "astro",
275
- scss: "scss",
276
- sass: "scss",
277
- css: "css",
278
- json: "json",
279
- json5: "json"
280
- };
281
- return map[ext] ?? "text";
252
+ return { calls, warnings };
282
253
  }
283
- function filterDesignTokenProps(cdf) {
284
- const result = {};
285
- const kinds = /* @__PURE__ */ new Set();
286
- let hasUnscoped = false;
287
- for (const [componentName, component] of Object.entries(cdf)) {
288
- const properties = component.$properties;
289
- 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)}`);
290
260
  continue;
291
- const filteredProps = {};
292
- for (const [propName, prop] of Object.entries(properties)) {
293
- if (prop.$type === "token" && prop.$category === "design") {
294
- const { "$token.allowed": _tokenAllowed, ...rest } = prop;
295
- filteredProps[propName] = rest;
296
- const kind = prop["$token.kind"];
297
- if (typeof kind === "string" && kind.length > 0) {
298
- kinds.add(kind);
299
- } else {
300
- hasUnscoped = true;
301
- }
302
- }
303
261
  }
304
- if (Object.keys(filteredProps).length > 0) {
305
- 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);
306
339
  }
307
340
  }
308
- return { filtered: result, kinds: [...kinds].sort(), hasUnscoped };
309
- }
310
- function buildTokenCandidateSections(tokenTree, filteredTokenProps) {
311
- const index = flattenDTCG(tokenTree, "").sort((a, b) => a.path.localeCompare(b.path));
312
- if (index.length === 0)
313
- return [];
314
- const sections = [];
315
- const renderSection = (kind, entries) => {
316
- const label = kind ? `Token path index \u2014 ${kind} candidates only` : "Token path index \u2014 full tree (no $token.kind to scope by)";
317
- const lines = entries.map((e) => `${e.path} \xB7 ${e.$type}`).join("\n");
318
- return `${label}, one leaf token per line as \`path \xB7 type\`, no \`$value\`:
319
- ${lines}`;
320
- };
321
- if (filteredTokenProps) {
322
- const { kinds, hasUnscoped } = filteredTokenProps;
323
- for (const kind of kinds) {
324
- const scoped = index.filter((e) => e.$type === kind);
325
- if (scoped.length > 0)
326
- sections.push(renderSection(kind, scoped));
327
- }
328
- if (hasUnscoped)
329
- sections.push(renderSection(null, index));
330
- } else {
331
- sections.push(renderSection(null, index));
332
- }
333
- return sections;
341
+ return { calls, warnings };
334
342
  }
335
- var init_format_token_candidates = __esm({
336
- "packages/experience-design-system-generation/dist/src/services/prompts/helpers/format-token-candidates.js"() {
337
- "use strict";
338
- }
339
- });
340
-
341
- // packages/experience-design-system-generation/dist/src/services/prompts/helpers/format-source-refs.js
342
- function formatSourceRefBlock(ref) {
343
- const mainBlock = `#### ${ref.component} (\`${ref.sourcePath}\`)
344
- \`\`\`${inferFenceLang(ref.sourcePath)}
345
- ${ref.content}
346
- \`\`\``;
347
- const siblingBlocks = (ref.siblingFiles ?? []).map((sibling) => `##### ${ref.component} \u2014 imported file \`${sibling.path}\`
348
- \`\`\`${inferFenceLang(sibling.path)}
349
- ${sibling.content}
350
- \`\`\``);
351
- const truncationNote = ref.truncatedSiblingCount && ref.truncatedSiblingCount > 0 ? [
352
- `##### ${ref.component} \u2014 +${ref.truncatedSiblingCount} more imported file${ref.truncatedSiblingCount === 1 ? "" : "s"} not shown (evidence may be incomplete)`
353
- ] : [];
354
- const notShownNote = ref.usesNotShown && ref.usesNotShown.length > 0 ? [
355
- `##### ${ref.component} \u2014 uses not shown: ${ref.usesNotShown.join(", ")}
356
-
357
- 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.`
358
- ] : [];
359
- return [mainBlock, ...siblingBlocks, ...truncationNote, ...notShownNote].join("\n\n");
360
- }
361
- function formatSourceRefsSection(refs, skill) {
362
- const sections = [];
363
- const withContent = refs.filter((ref) => ref.content != null);
364
- const withoutContent = refs.filter((ref) => ref.content == null);
365
- if (withContent.length > 0) {
366
- sections.push(`### Component source references
367
-
368
- ${withContent.map(formatSourceRefBlock).join("\n\n")}`);
369
- }
370
- if (withoutContent.length > 0) {
371
- 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";
372
- sections.push(`Component source unavailable for (JSON) \u2014 ${guidance}:
373
- \`\`\`json
374
- ${JSON.stringify(withoutContent.map((ref) => ({ component: ref.component, sourcePath: ref.sourcePath })))}
375
- \`\`\``);
376
- }
377
- return sections;
378
- }
379
- var init_format_source_refs = __esm({
380
- "packages/experience-design-system-generation/dist/src/services/prompts/helpers/format-source-refs.js"() {
381
- "use strict";
382
- init_format_token_candidates();
383
- }
384
- });
385
-
386
- // packages/experience-design-system-generation/dist/src/services/prompts/helpers/build-skill-preambles.js
387
- function buildComponentsAutonomousPreamble(inputBlock) {
388
- 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.
389
-
390
- 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:
391
- - **design**: controls how the component looks (variant, size, color, layout toggles)
392
- - **content**: the data a content editor fills in (text, images, URLs, rich text)
393
- - **state**: runtime behavioral flags (disabled, loading, expanded, identifiers)
394
-
395
- 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.
396
-
397
- All input data is provided inline below \u2014 do not read any additional files.${inputBlock}
398
-
399
- ## Output protocol
400
-
401
- 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.
402
-
403
- The four tool calls you may emit are:
404
-
405
- \`\`\`
406
- {"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>"}}
407
-
408
- {"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>"}
409
-
410
- {"tool":"exclude_prop","prop":"<propName>","reason":"<why excluded>"}
411
-
412
- {"tool":"classify_slot","slot":"<slotName>","required":<bool>,"allowed_components":["ComponentName"],"description":"<reason>","rationale":"<why this slot was kept in the catalog>"}
413
- \`\`\`
414
-
415
- Rules:
416
- - Emit exactly one JSON object per line. No multi-line JSON. No markdown fences around the lines.
417
- - Every prop in the input must have exactly one call: either classify_prop or exclude_prop.
418
- - Every slot in the input must have exactly one classify_slot call.
419
- - Valid cdf_type values: string, richtext, media, enum, token, boolean
420
- - Valid cdf_category values: content, design, state
421
- - For enum type, always include \`values\` (non-empty string array of the variant names the prop accepts).
422
- - 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.
423
- - Never emit both "values" and "token_kind" on one prop.
424
- - \`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.
425
- - Q2: is the value written straight into a style or attribute (\`rx={radius}\`, \`padding: \${padding}\`)? no \u2192 not \`token\`, apply the type rules.
426
- - 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.
427
- - 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".
428
- - 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.
429
- - 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.
430
- - 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.
431
- - You may emit prose lines (not starting with {) anywhere \u2014 they are ignored by the parser and serve as your reasoning log.`;
432
- }
433
- function buildSelectAutonomousPreamble(inputBlock) {
434
- 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.
435
-
436
- 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.
437
-
438
- 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.
439
-
440
- All input data is provided inline below \u2014 do not read any additional files.${inputBlock}
441
-
442
- ## Output protocol
443
-
444
- 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.
445
-
446
- The two tool calls \u2014 emit exactly one per input component:
447
-
448
- \`\`\`
449
- {"tool":"select_component","name":"<ComponentName>","reason":"<brief reason>"}
450
-
451
- {"tool":"reject_component","name":"<ComponentName>","reason":"<brief reason>"}
452
- \`\`\`
453
-
454
- Rules:
455
- - Emit exactly one JSON object per line. No multi-line JSON. No markdown fences.
456
- - 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.
457
- - You may emit prose lines (not starting with {) to reason before each tool call \u2014 they are ignored by the parser.`;
458
- }
459
- function buildMapTokensAutonomousPreamble(inputBlock) {
460
- 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.
461
-
462
- 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.
463
-
464
- All input data is provided inline below \u2014 do not read any additional files.${inputBlock}
465
-
466
- ## Output protocol
467
-
468
- 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.
469
-
470
- The one tool call you may emit:
471
-
472
- \`\`\`
473
- {"tool":"map_token_prop","component":"<ComponentName>","prop":"<propName>","token_allowed":["colors.brand.primary","colors.brand.secondary"]}
474
- \`\`\`
475
-
476
- Rules:
477
- - Emit exactly one JSON object per line. No multi-line JSON. No markdown fences around the lines.
478
- - Only emit a call for a prop that appears in the "Generated CDF so far" section.
479
- - 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.
480
- - \`token_allowed\` is required and must be non-empty when the call is emitted.
481
- - 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.
482
- - You may emit prose lines (not starting with \`{\`) anywhere \u2014 they are ignored by the parser and serve as your reasoning log.`;
483
- }
484
- function buildTokensAutonomousPreamble(inputBlock) {
485
- 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.
486
-
487
- 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.
488
-
489
- All input data is provided inline below \u2014 do not read any additional files.${inputBlock}
490
-
491
- ## Output protocol
492
-
493
- 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.
494
-
495
- The two tool calls you may emit are:
496
-
497
- \`\`\`
498
- {"tool":"set_group","path":"<dot.notation.path>","description":"<optional group description>"}
499
-
500
- {"tool":"set_token","path":"<dot.notation.path>","type":"<DTCG type>","value":<value>,"description":"<reason>"}
501
- \`\`\`
502
-
503
- Rules:
504
- - Emit exactly one JSON object per line. No multi-line JSON. No markdown fences.
505
- - Emit a set_group call for every intermediate group node in the tree.
506
- - Emit a set_token call for every leaf token.
507
- - "path" is dot-notation, e.g. "colors.brand.primary" \u2014 no leading dots or slashes.
508
- - "type" must be one of the 13 valid DTCG types: color, dimension, fontFamily, fontWeight, duration, cubicBezier, number, strokeStyle, border, transition, shadow, gradient, typography.
509
- - "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.
510
- - Emit set_group calls before the set_token calls that fall under them.
511
- - You may emit prose lines (not starting with {) anywhere \u2014 they are ignored by the parser and serve as your reasoning log.`;
512
- }
513
- var init_build_skill_preambles = __esm({
514
- "packages/experience-design-system-generation/dist/src/services/prompts/helpers/build-skill-preambles.js"() {
515
- "use strict";
516
- }
517
- });
518
-
519
- // packages/experience-design-system-generation/dist/src/services/prompts/helpers/build-preamble.js
520
- function buildPreamble(options) {
521
- const { skill, rawComponentsInline, rawTokensInline, rawTokensFilename, tokensInline, tokenMapInline, generatedCdf, tokenTree, componentSourceRefs, existingComponentsInline, existingTokensInline, componentAllowlistInline } = options;
522
- const sections = [];
523
- if (existingComponentsInline) {
524
- sections.push(`Existing components in the target Contentful space (JSON) \u2014 use for alignment, not as a hard filter:
525
- \`\`\`json
526
- ${existingComponentsInline}
527
- \`\`\``);
528
- }
529
- if (existingTokensInline) {
530
- sections.push(`Existing design tokens in the target Contentful space (JSON) \u2014 prefer binding to these paths over inventing new ones:
531
- \`\`\`json
532
- ${existingTokensInline}
533
- \`\`\``);
534
- }
535
- if (componentAllowlistInline) {
536
- sections.push(`Known component names for slot allowed_components (hard allowlist; never use any other name):
537
- \`\`\`json
538
- ${componentAllowlistInline}
539
- \`\`\``);
540
- }
541
- if (rawComponentsInline) {
542
- sections.push(`Raw component data (JSON):
543
- \`\`\`json
544
- ${rawComponentsInline}
545
- \`\`\``);
546
- }
547
- if (rawTokensInline) {
548
- const lang = inferFenceLang(rawTokensFilename);
549
- const label = rawTokensFilename ? `Raw token source (${rawTokensFilename})` : "Raw token source";
550
- sections.push(`${label}:
551
- \`\`\`${lang}
552
- ${rawTokensInline}
553
- \`\`\``);
554
- }
555
- if (tokensInline) {
556
- sections.push(`DTCG token data (for token kind lookups):
557
- \`\`\`json
558
- ${tokensInline}
559
- \`\`\``);
560
- }
561
- if (tokenMapInline) {
562
- sections.push(`Token-name sidecar (raw name \u2192 DTCG path):
563
- \`\`\`json
564
- ${tokenMapInline}
565
- \`\`\``);
566
- }
567
- const filteredTokenProps = generatedCdf ? filterDesignTokenProps(generatedCdf) : void 0;
568
- if (filteredTokenProps && Object.keys(filteredTokenProps.filtered).length > 0) {
569
- sections.push(`Generated CDF so far \u2014 design-category token props only (JSON):
570
- \`\`\`json
571
- ${JSON.stringify(filteredTokenProps.filtered)}
572
- \`\`\``);
573
- }
574
- if (tokenTree) {
575
- sections.push(...buildTokenCandidateSections(tokenTree, filteredTokenProps));
576
- }
577
- if (componentSourceRefs && componentSourceRefs.length > 0) {
578
- 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
+ }
579
376
  }
580
- const inputBlock = sections.length > 0 ? `
581
-
582
- ${sections.join("\n\n")}` : "";
583
- if (skill === "components")
584
- return buildComponentsAutonomousPreamble(inputBlock);
585
- if (skill === "select")
586
- return buildSelectAutonomousPreamble(inputBlock);
587
- if (skill === "map-tokens")
588
- return buildMapTokensAutonomousPreamble(inputBlock);
589
- return buildTokensAutonomousPreamble(inputBlock);
377
+ return { calls, warnings };
590
378
  }
591
- var init_build_preamble = __esm({
592
- "packages/experience-design-system-generation/dist/src/services/prompts/helpers/build-preamble.js"() {
593
- "use strict";
594
- init_format_token_candidates();
595
- init_format_source_refs();
596
- init_build_skill_preambles();
597
- }
598
- });
599
-
600
- // packages/experience-design-system-generation/dist/src/services/prompts/build-prompt.js
601
- async function buildPrompt(options) {
602
- const skillContent = options.skillContentOverride ?? await readSkillFile(options.skill, options.skillPathOverride);
603
- const preamble = buildPreamble(options);
604
- return `${preamble}
605
-
606
- Skill instructions follow:
607
- ---
608
- ${skillContent}`;
379
+ function isStringArray(value) {
380
+ return Array.isArray(value) && value.every((v) => typeof v === "string");
609
381
  }
610
- var init_build_prompt = __esm({
611
- "packages/experience-design-system-generation/dist/src/services/prompts/build-prompt.js"() {
612
- "use strict";
613
- init_resolve_skill_file();
614
- init_build_preamble();
615
- 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);
616
420
  }
617
- });
618
-
619
- // packages/experience-design-system-generation/dist/src/orchestrator/execute-generation-orchestrator.js
620
- async function executeGenerationOrchestrator(request2) {
621
- const prompt = await buildPrompt(request2.promptOptions);
622
- return request2.invoker.invoke({
623
- agent: request2.agent,
624
- model: request2.model,
625
- bedrock: request2.bedrock,
626
- prompt,
627
- timeoutMs: request2.timeoutMs,
628
- onOutput: request2.onOutput
629
- });
421
+ return { calls, warnings };
630
422
  }
631
- var init_execute_generation_orchestrator = __esm({
632
- "packages/experience-design-system-generation/dist/src/orchestrator/execute-generation-orchestrator.js"() {
633
- "use strict";
634
- init_build_prompt();
635
- }
636
- });
637
-
638
- // packages/experience-design-system-generation/dist/src/services/agent/helpers/resolve-agent-binary.js
639
- function resolveAgentBinary(agent) {
423
+ function resolveBinary(agent) {
640
424
  const envKey = `EDS_AGENT_BINARY_${agent.toUpperCase()}`;
641
425
  const override = process.env[envKey];
642
426
  if (override && override.trim())
643
427
  return override.trim();
644
428
  return AGENT_BINARIES[agent];
645
429
  }
646
- var AGENT_BINARIES;
647
- var init_resolve_agent_binary = __esm({
648
- "packages/experience-design-system-generation/dist/src/services/agent/helpers/resolve-agent-binary.js"() {
649
- "use strict";
650
- AGENT_BINARIES = {
651
- claude: "claude",
652
- codex: "codex",
653
- opencode: "opencode",
654
- cursor: "cursor-agent",
655
- copilot: "copilot"
656
- };
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];
@@ -692,65 +461,22 @@ function buildAgentArgs(agent, prompt, model, promptViaStdin = false, bedrock =
692
461
  return ["exec", ...bedrockArgs, ...modelArg, "--dangerously-bypass-approvals-and-sandbox", ...promptArg];
693
462
  }
694
463
  case "opencode":
695
- return ["run", ...modelArg, ...promptArg];
696
- case "cursor":
697
- return ["--print", ...modelArg, ...promptArg];
698
- case "copilot": {
699
- const copilotModel = resolveAgentModel("copilot", model);
700
- const copilotModelArg = !copilotModel || copilotModel === "Auto" ? [] : ["--model", copilotModel];
701
- return ["-p", ...promptArg, ...copilotModelArg, "--allow-all-tools"];
702
- }
703
- }
704
- }
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/run-agent.js
726
- import { spawn } from "node:child_process";
727
- function describeAgentFailure(result, maxDetail = 800) {
728
- const base = result.exitCode !== 0 ? `agent exited with code ${result.exitCode}` : "agent produced no tool calls";
729
- const detail = (result.stderr.trim() || result.stdout.trim()).slice(-maxDetail).trim();
730
- return detail ? `${base} \u2014 ${detail}` : base;
731
- }
732
- function extractSentinelOutput(stdout) {
733
- const START = "<<<EDS_OUTPUT_START>>>";
734
- const END = "<<<EDS_OUTPUT_END>>>";
735
- const startIdx = stdout.indexOf(START);
736
- const endIdx = stdout.indexOf(END);
737
- if (startIdx === -1 || endIdx === -1 || endIdx <= startIdx)
738
- return null;
739
- const secondStart = stdout.indexOf(START, startIdx + START.length);
740
- if (secondStart !== -1 && secondStart < endIdx)
741
- return "multiple";
742
- const afterStart = stdout.indexOf(END, startIdx);
743
- const secondEnd = stdout.indexOf(END, afterStart + END.length);
744
- if (secondEnd !== -1)
745
- return "multiple";
746
- return stdout.slice(startIdx + START.length, endIdx).trim();
464
+ return ["run", ...modelArg, ...promptArg];
465
+ case "cursor":
466
+ return ["--print", ...modelArg, ...promptArg];
467
+ case "copilot": {
468
+ const copilotModel = resolveAgentModel("copilot", model);
469
+ const copilotModelArg = !copilotModel || copilotModel === "Auto" ? [] : ["--model", copilotModel];
470
+ return ["-p", ...promptArg, ...copilotModelArg, "--allow-all-tools"];
471
+ }
472
+ }
747
473
  }
748
474
  async function runAgent(options) {
749
475
  const { agent, prompt, timeoutMs, model, onOutput, promptViaStdin, onDebugEvent } = options;
750
476
  const bedrock = options.bedrock ?? process.env.EDS_BEDROCK === "1";
751
- const binary = resolveAgentBinary(agent);
477
+ const binary = resolveBinary(agent);
752
478
  const useStdin2 = !!promptViaStdin;
753
- const args = buildAgentArgs(agent, prompt, model, useStdin2, bedrock);
479
+ const args = buildArgs(agent, prompt, model, useStdin2, bedrock);
754
480
  const startedAt = Date.now();
755
481
  onDebugEvent?.("run.start", {
756
482
  agent,
@@ -814,24 +540,14 @@ async function runAgent(options) {
814
540
  });
815
541
  });
816
542
  }
817
- var init_run_agent = __esm({
818
- "packages/experience-design-system-generation/dist/src/services/agent/run-agent.js"() {
819
- "use strict";
820
- init_resolve_agent_binary();
821
- init_build_agent_args();
822
- }
823
- });
824
-
825
- // packages/experience-design-system-generation/dist/src/services/agent/helpers/check-agent-auth.js
826
- import { spawn as spawn2 } from "node:child_process";
827
543
  async function checkAgentAuth(agent) {
828
- const binary = resolveAgentBinary(agent);
544
+ const binary = resolveBinary(agent);
829
545
  const binaryExists2 = await new Promise((resolve21) => {
830
546
  if (binary.startsWith("/")) {
831
547
  import("node:fs/promises").then((fs2) => fs2.access(binary).then(() => resolve21(true), () => resolve21(false)));
832
548
  return;
833
549
  }
834
- const child = spawn2(process.platform === "win32" ? "where" : "which", [binary], { stdio: "ignore" });
550
+ const child = spawn(process.platform === "win32" ? "where" : "which", [binary], { stdio: "ignore" });
835
551
  child.on("close", (code) => resolve21(code === 0));
836
552
  });
837
553
  if (!binaryExists2)
@@ -839,7 +555,7 @@ async function checkAgentAuth(agent) {
839
555
  if (agent !== "claude")
840
556
  return "ok";
841
557
  return new Promise((resolve21) => {
842
- const child = spawn2(binary, ["auth", "status", "--json"], {
558
+ const child = spawn(binary, ["auth", "status", "--json"], {
843
559
  stdio: ["ignore", "pipe", "pipe"]
844
560
  });
845
561
  let stdout = "";
@@ -872,14 +588,63 @@ async function checkAgentAuth(agent) {
872
588
  });
873
589
  });
874
590
  }
875
- var init_check_agent_auth = __esm({
876
- "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"() {
877
615
  "use strict";
878
- init_resolve_agent_binary();
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";
879
644
  }
880
645
  });
881
646
 
882
- // 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
883
648
  function createLocalCliAgentInvoker(options = {}) {
884
649
  const { onDebugEvent } = options;
885
650
  return {
@@ -891,310 +656,381 @@ function createLocalCliAgentInvoker(options = {}) {
891
656
  }
892
657
  };
893
658
  }
894
- var init_local_cli_agent_invoker = __esm({
895
- "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"() {
896
661
  "use strict";
897
- init_run_agent();
898
- init_check_agent_auth();
662
+ init_agent_runner();
899
663
  }
900
664
  });
901
665
 
902
- // packages/experience-design-system-generation/dist/src/controller/create-generation-endpoint.js
903
- function createGenerationEndpoint(options = {}) {
904
- const invoker2 = createLocalCliAgentInvoker({ onDebugEvent: options.onDebugEvent });
905
- return {
906
- async run(request2) {
907
- validateGenerationRequest(request2);
908
- return executeGenerationOrchestrator({ ...request2, invoker: invoker2 });
909
- },
910
- checkAuth(agent) {
911
- return invoker2.checkAuth(agent);
912
- }
913
- };
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
+ `;
914
677
  }
915
- var init_create_generation_endpoint = __esm({
916
- "packages/experience-design-system-generation/dist/src/controller/create-generation-endpoint.js"() {
917
- "use strict";
918
- init_validate_generation_request();
919
- init_execute_generation_orchestrator();
920
- init_local_cli_agent_invoker();
921
- }
922
- });
678
+ async function buildPrompt(options) {
679
+ const skillContent = options.skillContentOverride ?? await readSkillFile(options.skill, options.skillPathOverride);
680
+ const preamble = buildPreamble(options);
681
+ return `${preamble}
923
682
 
924
- // packages/experience-design-system-generation/dist/src/services/parsing/helpers/read-tool-call-objects.js
925
- function findJsonObjectEnd(line) {
926
- let depth = 0;
927
- let inString = false;
928
- let escaped = false;
929
- for (let i = 0; i < line.length; i++) {
930
- const ch = line[i];
931
- if (escaped) {
932
- escaped = false;
933
- } else if (ch === "\\" && inString) {
934
- escaped = true;
935
- } else if (ch === '"') {
936
- inString = !inString;
937
- } else if (!inString && ch === "{") {
938
- depth++;
939
- } else if (!inString && ch === "}" && --depth === 0) {
940
- 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})`);
941
699
  }
700
+ dir = parent;
942
701
  }
943
- return -1;
944
702
  }
945
- function readToolCallObjects(stdout) {
946
- const objects = [];
947
- const warnings = [];
948
- for (const raw of stdout.split("\n")) {
949
- const line = raw.trim();
950
- if (!line.startsWith("{"))
951
- continue;
952
- const end = findJsonObjectEnd(line);
953
- if (end === -1) {
954
- warnings.push(`unparseable line: ${line.slice(0, 120)}`);
955
- continue;
956
- }
957
- let parsed;
703
+ async function readSkillFile(skill, override) {
704
+ if (override) {
705
+ const skillPath2 = resolve(override);
958
706
  try {
959
- parsed = JSON.parse(line.slice(0, end + 1));
707
+ return await readFile2(skillPath2, "utf8");
960
708
  } catch {
961
- warnings.push(`unparseable line: ${line.slice(0, 120)}`);
962
- continue;
963
- }
964
- const trailing = line.slice(end + 1);
965
- if (trailing.trim()) {
966
- warnings.push(`ignored trailing content after JSON: ${trailing.trim().slice(0, 120)}`);
967
- }
968
- if (typeof parsed === "object" && parsed !== null && "tool" in parsed) {
969
- objects.push(parsed);
709
+ throw new Error(`custom prompt file not found (skill: ${skill}, path: ${skillPath2})`);
970
710
  }
971
711
  }
972
- return { objects, warnings };
973
- }
974
- var init_read_tool_call_objects = __esm({
975
- "packages/experience-design-system-generation/dist/src/services/parsing/helpers/read-tool-call-objects.js"() {
976
- "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})`);
977
717
  }
978
- });
979
-
980
- // packages/experience-design-system-generation/dist/src/services/parsing/parse-prop-tool-calls.js
981
- function parsePropToolCallLines(stdout) {
982
- const calls = [];
983
- const { objects, warnings } = readToolCallObjects(stdout);
984
- for (const rec of objects) {
985
- if (!VALID_TOOL_NAMES.has(rec.tool)) {
986
- warnings.push(`unknown tool: ${String(rec.tool)}`);
987
- continue;
988
- }
989
- const tool = rec.tool;
990
- if (tool === "classify_prop") {
991
- if (typeof rec.prop !== "string" || !rec.prop) {
992
- warnings.push("classify_prop missing prop name \u2014 skipped");
993
- continue;
994
- }
995
- if (typeof rec.cdf_type !== "string" || !VALID_CDF_TYPES.has(rec.cdf_type)) {
996
- warnings.push(`classify_prop '${rec.prop}': invalid cdf_type '${String(rec.cdf_type)}' \u2014 skipped`);
997
- continue;
998
- }
999
- if (typeof rec.cdf_category !== "string" || !VALID_CATEGORIES.has(rec.cdf_category)) {
1000
- warnings.push(`classify_prop '${rec.prop}': invalid cdf_category '${String(rec.cdf_category)}' \u2014 skipped`);
1001
- continue;
1002
- }
1003
- const call = {
1004
- tool: "classify_prop",
1005
- prop: rec.prop,
1006
- cdf_type: rec.cdf_type,
1007
- cdf_category: rec.cdf_category
1008
- };
1009
- if (Array.isArray(rec.values) && rec.values.every((v) => typeof v === "string"))
1010
- call.values = rec.values;
1011
- if (typeof rec.token_kind === "string")
1012
- call.token_kind = rec.token_kind;
1013
- if (typeof rec.required === "boolean")
1014
- call.required = rec.required;
1015
- if (typeof rec.description === "string")
1016
- call.description = rec.description;
1017
- if (typeof rec.default === "string" || typeof rec.default === "boolean")
1018
- call.default = rec.default;
1019
- if (typeof rec.reason === "string")
1020
- call.reason = rec.reason;
1021
- calls.push(call);
1022
- } else if (tool === "exclude_prop") {
1023
- if (typeof rec.prop !== "string" || !rec.prop) {
1024
- warnings.push("exclude_prop missing prop name \u2014 skipped");
1025
- continue;
1026
- }
1027
- calls.push({ tool: "exclude_prop", prop: rec.prop, reason: typeof rec.reason === "string" ? rec.reason : "" });
1028
- } else if (tool === "classify_component") {
1029
- const call = { tool: "classify_component" };
1030
- if (typeof rec.description === "string")
1031
- call.description = rec.description;
1032
- if (typeof rec.rationale === "object" && rec.rationale !== null) {
1033
- const r = rec.rationale;
1034
- const rationale = {};
1035
- if (typeof r.description === "string")
1036
- rationale.description = r.description;
1037
- if (typeof r.props === "string")
1038
- rationale.props = r.props;
1039
- if (typeof r.slots === "string")
1040
- rationale.slots = r.slots;
1041
- if (Object.keys(rationale).length > 0)
1042
- call.rationale = rationale;
1043
- }
1044
- calls.push(call);
1045
- } else if (tool === "classify_slot") {
1046
- if (typeof rec.slot !== "string" || !rec.slot) {
1047
- warnings.push("classify_slot missing slot name \u2014 skipped");
1048
- continue;
1049
- }
1050
- const call = { tool: "classify_slot", slot: rec.slot };
1051
- if (typeof rec.required === "boolean")
1052
- call.required = rec.required;
1053
- if (Array.isArray(rec.allowed_components) && rec.allowed_components.every((v) => typeof v === "string")) {
1054
- 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
+ }
1055
762
  }
1056
- if (typeof rec.description === "string")
1057
- call.description = rec.description;
1058
- if (typeof rec.rationale === "string")
1059
- call.rationale = rec.rationale;
1060
- calls.push(call);
763
+ }
764
+ if (Object.keys(filteredProps).length > 0) {
765
+ result[componentName] = { ...component, $properties: filteredProps };
1061
766
  }
1062
767
  }
1063
- return { calls, warnings };
768
+ return { filtered: result, kinds: [...kinds].sort(), hasUnscoped };
1064
769
  }
1065
- var VALID_TOOL_NAMES, VALID_CDF_TYPES, VALID_CATEGORIES;
1066
- var init_parse_prop_tool_calls = __esm({
1067
- "packages/experience-design-system-generation/dist/src/services/parsing/parse-prop-tool-calls.js"() {
1068
- "use strict";
1069
- init_read_tool_call_objects();
1070
- VALID_TOOL_NAMES = /* @__PURE__ */ new Set(["classify_prop", "exclude_prop", "classify_component", "classify_slot"]);
1071
- VALID_CDF_TYPES = /* @__PURE__ */ new Set(["string", "richtext", "media", "enum", "token", "boolean"]);
1072
- 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
+ \`\`\``);
1073
786
  }
1074
- });
1075
-
1076
- // packages/experience-design-system-generation/dist/src/services/parsing/parse-select-tool-calls.js
1077
- function parseSelectToolCallLines(stdout) {
1078
- const calls = [];
1079
- const { objects, warnings } = readToolCallObjects(stdout);
1080
- for (const rec of objects) {
1081
- if (!VALID_SELECT_TOOL_NAMES.has(rec.tool))
1082
- continue;
1083
- if (typeof rec.name !== "string" || !rec.name) {
1084
- warnings.push(`${String(rec.tool)} missing name \u2014 skipped`);
1085
- continue;
1086
- }
1087
- const call = { tool: rec.tool, name: rec.name };
1088
- if (typeof rec.reason === "string")
1089
- call.reason = rec.reason;
1090
- if (typeof rec.confidence === "number" && rec.confidence >= 1 && rec.confidence <= 5) {
1091
- if (call.tool === "select_component") {
1092
- 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));
1093
844
  } else {
1094
- call.confidence = rec.confidence;
845
+ sections.push(renderTokenCandidateSection(null, index));
1095
846
  }
1096
847
  }
1097
- calls.push(call);
1098
848
  }
1099
- return { calls, warnings };
1100
- }
1101
- var VALID_SELECT_TOOL_NAMES;
1102
- var init_parse_select_tool_calls = __esm({
1103
- "packages/experience-design-system-generation/dist/src/services/parsing/parse-select-tool-calls.js"() {
1104
- "use strict";
1105
- init_read_tool_call_objects();
1106
- VALID_SELECT_TOOL_NAMES = /* @__PURE__ */ new Set(["select_component", "reject_component"]);
1107
- }
1108
- });
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(", ")}
1109
867
 
1110
- // packages/experience-design-system-generation/dist/src/services/parsing/parse-token-tool-calls.js
1111
- function parseTokenToolCallLines(stdout) {
1112
- const calls = [];
1113
- const { objects, warnings } = readToolCallObjects(stdout);
1114
- for (const rec of objects) {
1115
- if (!VALID_TOKEN_TOOL_NAMES.has(rec.tool))
1116
- continue;
1117
- if (rec.tool === "set_token") {
1118
- if (typeof rec.path !== "string" || !rec.path) {
1119
- warnings.push("set_token missing path \u2014 skipped");
1120
- continue;
1121
- }
1122
- if (typeof rec.type !== "string" || !rec.type) {
1123
- warnings.push(`set_token '${rec.path}': missing type \u2014 skipped`);
1124
- continue;
1125
- }
1126
- if (!("value" in rec)) {
1127
- warnings.push(`set_token '${rec.path}': missing value \u2014 skipped`);
1128
- continue;
1129
- }
1130
- const call = { tool: "set_token", path: rec.path, type: rec.type, value: rec.value };
1131
- if (typeof rec.description === "string")
1132
- call.description = rec.description;
1133
- calls.push(call);
1134
- } else if (rec.tool === "set_group") {
1135
- if (typeof rec.path !== "string" || !rec.path) {
1136
- warnings.push("set_group missing path \u2014 skipped");
1137
- continue;
1138
- }
1139
- const call = { tool: "set_group", path: rec.path };
1140
- if (typeof rec.description === "string")
1141
- call.description = rec.description;
1142
- 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
+ \`\`\``);
1143
882
  }
1144
883
  }
1145
- return { calls, warnings };
1146
- }
1147
- var VALID_TOKEN_TOOL_NAMES;
1148
- var init_parse_token_tool_calls = __esm({
1149
- "packages/experience-design-system-generation/dist/src/services/parsing/parse-token-tool-calls.js"() {
1150
- "use strict";
1151
- init_read_tool_call_objects();
1152
- 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);
1153
889
  }
1154
- });
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:
1155
982
 
1156
- // packages/experience-design-system-generation/dist/src/services/parsing/parse-map-token-tool-calls.js
1157
- function isStringArray(value) {
1158
- 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.`;
1159
994
  }
1160
- function parseMapTokenPropToolCallLines(stdout) {
1161
- const calls = [];
1162
- const warnings = [];
1163
- for (const raw of stdout.split("\n")) {
1164
- const line = raw.trim();
1165
- if (!line.startsWith("{"))
1166
- continue;
1167
- let obj;
1168
- try {
1169
- obj = JSON.parse(line);
1170
- } catch {
1171
- warnings.push(`unparseable line: ${line.slice(0, 120)}`);
1172
- continue;
1173
- }
1174
- if (typeof obj !== "object" || obj === null || !("tool" in obj))
1175
- continue;
1176
- const rec = obj;
1177
- if (rec.tool !== "map_token_prop")
1178
- continue;
1179
- if (typeof rec.component !== "string" || !rec.component) {
1180
- warnings.push("map_token_prop missing component \u2014 skipped");
1181
- continue;
1182
- }
1183
- if (typeof rec.prop !== "string" || !rec.prop) {
1184
- warnings.push(`map_token_prop '${rec.component}': missing prop \u2014 skipped`);
1185
- continue;
1186
- }
1187
- if (!isStringArray(rec.token_allowed) || rec.token_allowed.length === 0) {
1188
- warnings.push(`map_token_prop '${rec.component}.${String(rec.prop)}': missing or empty token_allowed \u2014 skipped`);
1189
- continue;
1190
- }
1191
- calls.push({ tool: "map_token_prop", component: rec.component, prop: rec.prop, token_allowed: rec.token_allowed });
1192
- }
1193
- 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.`;
1194
1023
  }
1195
- var init_parse_map_token_tool_calls = __esm({
1196
- "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"() {
1197
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
+ };
1198
1034
  }
1199
1035
  });
1200
1036
 
@@ -1214,13 +1050,11 @@ __export(src_exports, {
1214
1050
  AGENT_NAMES: () => AGENT_NAMES,
1215
1051
  DEFAULT_AGENT_NAME: () => DEFAULT_AGENT_NAME,
1216
1052
  agentSupportsBedrock: () => agentSupportsBedrock,
1217
- buildArgs: () => buildAgentArgs,
1053
+ buildArgs: () => buildArgs,
1218
1054
  buildPrompt: () => buildPrompt,
1219
1055
  checkAgentAuth: () => checkAgentAuth,
1220
- createGenerationEndpoint: () => createGenerationEndpoint,
1221
1056
  createLocalCliAgentInvoker: () => createLocalCliAgentInvoker,
1222
1057
  describeAgentFailure: () => describeAgentFailure,
1223
- executeGenerationOrchestrator: () => executeGenerationOrchestrator,
1224
1058
  extractSentinelOutput: () => extractSentinelOutput,
1225
1059
  formatCustomPromptBanner: () => formatCustomPromptBanner,
1226
1060
  formatGenerateProgressLine: () => formatGenerateProgressLine,
@@ -1228,9 +1062,9 @@ __export(src_exports, {
1228
1062
  parseMapTokenPropToolCallLines: () => parseMapTokenPropToolCallLines,
1229
1063
  parseSelectToolCallLines: () => parseSelectToolCallLines,
1230
1064
  parseTokenToolCallLines: () => parseTokenToolCallLines,
1231
- parseToolCallLines: () => parsePropToolCallLines,
1065
+ parseToolCallLines: () => parseToolCallLines,
1232
1066
  resolveAgentModel: () => resolveAgentModel,
1233
- resolveBinary: () => resolveAgentBinary,
1067
+ resolveBinary: () => resolveBinary,
1234
1068
  resolveSkillPath: () => resolveSkillPath,
1235
1069
  runAgent: () => runAgent
1236
1070
  });
@@ -1238,19 +1072,10 @@ var init_src = __esm({
1238
1072
  "packages/experience-design-system-generation/dist/src/index.js"() {
1239
1073
  "use strict";
1240
1074
  init_agent_names();
1241
- init_create_generation_endpoint();
1242
- init_execute_generation_orchestrator();
1243
- init_build_agent_args();
1244
- init_resolve_agent_binary();
1245
- init_check_agent_auth();
1246
- init_run_agent();
1247
- init_parse_prop_tool_calls();
1248
- init_parse_select_tool_calls();
1249
- init_parse_token_tool_calls();
1250
- init_parse_map_token_tool_calls();
1251
- init_build_prompt();
1075
+ init_agent_runner();
1076
+ init_agent_invoker();
1077
+ init_prompt_builder();
1252
1078
  init_progress();
1253
- init_local_cli_agent_invoker();
1254
1079
  }
1255
1080
  });
1256
1081
 
@@ -1388,8 +1213,8 @@ function makeSessionTimestamp() {
1388
1213
  const override = process.env["EDSI_DEBUG_TS"];
1389
1214
  if (override) return override;
1390
1215
  const now = /* @__PURE__ */ new Date();
1391
- const pad = (n, w = 2) => n.toString().padStart(w, "0");
1392
- 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`;
1393
1218
  }
1394
1219
  function initDebugLogger(opts) {
1395
1220
  if (singleton) return singleton;
@@ -2186,8 +2011,8 @@ function deleteRawTokensForSession(db, sessionId2) {
2186
2011
  }
2187
2012
  function createRawTokenGroups(db, sessionId2, groups) {
2188
2013
  const insertGroup = db.prepare(`INSERT INTO raw_token_groups (session_id, path, description) VALUES (?, ?, ?)`);
2189
- for (const group of groups) {
2190
- insertGroup.run(sessionId2, group.path, group.$description ?? null);
2014
+ for (const group2 of groups) {
2015
+ insertGroup.run(sessionId2, group2.path, group2.$description ?? null);
2191
2016
  }
2192
2017
  }
2193
2018
  function createRawTokens(db, sessionId2, tokens) {
@@ -5085,7 +4910,7 @@ async function readFileInline(path) {
5085
4910
  return parts.filter(Boolean).join("\n\n");
5086
4911
  }
5087
4912
  function printFallbackInstructions(options) {
5088
- const binary = resolveAgentBinary(options.agent);
4913
+ const binary = resolveBinary(options.agent);
5089
4914
  const skillPath = resolveSkillPath(options.skill);
5090
4915
  const lines = [
5091
4916
  `Error: agent '${options.agent}' not found in $PATH (looked for binary: ${binary}).`,
@@ -5300,7 +5125,7 @@ ${outputBuf}`);
5300
5125
  lastError = describeAgentFailure(result);
5301
5126
  continue;
5302
5127
  }
5303
- const { calls, warnings } = parsePropToolCallLines(result.stdout);
5128
+ const { calls, warnings } = parseToolCallLines(result.stdout);
5304
5129
  if (calls.length === 0) {
5305
5130
  lastError = describeAgentFailure(result);
5306
5131
  continue;
@@ -5546,7 +5371,7 @@ async function runGenerateSkill(skill, opts, verbose = false) {
5546
5371
  process.stdout.write(prompt + "\n");
5547
5372
  await exitWithAnalytics(0);
5548
5373
  }
5549
- const binary = resolveAgentBinary(agent);
5374
+ const binary = resolveBinary(agent);
5550
5375
  if (!await assertBinaryInPath(binary)) {
5551
5376
  printFallbackInstructions({
5552
5377
  agent,
@@ -7066,24 +6891,24 @@ function parseEdsiError(rawInput) {
7066
6891
  }
7067
6892
  }
7068
6893
  const cleaned = stripLambdaLogPrefix(body);
7069
- const json = parseJsonBody(cleaned) ?? parseJsonBody(body);
7070
- 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;
7071
6896
  if (bindingFromJson) {
7072
6897
  return {
7073
- code: bindingFromJson.code ?? json?.code ?? null,
6898
+ code: bindingFromJson.code ?? json2?.code ?? null,
7074
6899
  message: bindingFromJson.message ?? cleaned,
7075
6900
  cycle: null,
7076
6901
  raw: false,
7077
6902
  ...bindingFromJson.diagnostics ? { diagnostics: bindingFromJson.diagnostics } : {}
7078
6903
  };
7079
6904
  }
7080
- if (json && (json.code || json.message || json.cycle)) {
6905
+ if (json2 && (json2.code || json2.message || json2.cycle)) {
7081
6906
  return {
7082
- code: json.code ?? null,
7083
- message: json.message ?? (cleaned || prefix),
7084
- cycle: json.cycle ?? null,
6907
+ code: json2.code ?? null,
6908
+ message: json2.message ?? (cleaned || prefix),
6909
+ cycle: json2.cycle ?? null,
7085
6910
  raw: false,
7086
- ...json.diagnostics ? { diagnostics: json.diagnostics } : {}
6911
+ ...json2.diagnostics ? { diagnostics: json2.diagnostics } : {}
7087
6912
  };
7088
6913
  }
7089
6914
  const binding = parseBindingDiagnostics(cleaned);
@@ -8623,8 +8448,8 @@ async function resolveSession(sessionFlag, command) {
8623
8448
  }
8624
8449
  function rebuildDTCGTree(groups, tokens) {
8625
8450
  const root = {};
8626
- for (const group of groups) {
8627
- const segments = group.path.split(".");
8451
+ for (const group2 of groups) {
8452
+ const segments = group2.path.split(".");
8628
8453
  let node = root;
8629
8454
  for (const seg of segments) {
8630
8455
  if (typeof node[seg] !== "object" || node[seg] === null) {
@@ -8632,8 +8457,8 @@ function rebuildDTCGTree(groups, tokens) {
8632
8457
  }
8633
8458
  node = node[seg];
8634
8459
  }
8635
- if (group.$description) {
8636
- node["$description"] = group.$description;
8460
+ if (group2.$description) {
8461
+ node["$description"] = group2.$description;
8637
8462
  }
8638
8463
  }
8639
8464
  for (const token of tokens) {
@@ -9207,7 +9032,7 @@ ${defaultDiagnostics.map((diagnostic) => ` ${diagnostic}`).join("\n")}
9207
9032
  return;
9208
9033
  }
9209
9034
  }
9210
- const binary = resolveAgentBinary(agent);
9035
+ const binary = resolveBinary(agent);
9211
9036
  if (!await assertBinaryInPath(binary)) {
9212
9037
  die(
9213
9038
  `Error: agent '${agent}' not found in $PATH (looked for binary: ${binary}).
@@ -9376,6 +9201,214 @@ var init_run_teaser = __esm({
9376
9201
  }
9377
9202
  });
9378
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
+
9379
9412
  // packages/experience-design-system-cli-legacy/src/tui/use-blinking-cursor.ts
9380
9413
  import { useEffect as useEffect2, useState as useState3 } from "react";
9381
9414
  function useBlinkingCursor() {
@@ -9395,8 +9428,8 @@ var init_use_blinking_cursor = __esm({
9395
9428
  // packages/experience-design-system-cli-legacy/src/runs/path-prompt.tsx
9396
9429
  import { useState as useState4 } from "react";
9397
9430
  import { Box as Box6, Text as Text7 } from "ink";
9398
- import { readdirSync } from "node:fs";
9399
- 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";
9400
9433
  import { jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
9401
9434
  function autocomplete(partial) {
9402
9435
  if (!partial) return null;
@@ -9405,19 +9438,19 @@ function autocomplete(partial) {
9405
9438
  const base = basename2(normalized);
9406
9439
  let entries;
9407
9440
  try {
9408
- entries = readdirSync(dir);
9441
+ entries = readdirSync2(dir);
9409
9442
  } catch {
9410
9443
  return null;
9411
9444
  }
9412
9445
  const matches = entries.filter((e) => e.startsWith(base));
9413
9446
  if (matches.length === 0) return null;
9414
- if (matches.length === 1) return join10(dir, matches[0]);
9447
+ if (matches.length === 1) return join11(dir, matches[0]);
9415
9448
  let prefix = matches[0];
9416
9449
  for (const m of matches) {
9417
9450
  while (!m.startsWith(prefix)) prefix = prefix.slice(0, -1);
9418
9451
  if (!prefix) break;
9419
9452
  }
9420
- return prefix.length > base.length ? join10(dir, prefix) : null;
9453
+ return prefix.length > base.length ? join11(dir, prefix) : null;
9421
9454
  }
9422
9455
  function PathPrompt({
9423
9456
  defaultPath,
@@ -9482,12 +9515,12 @@ var init_path_prompt = __esm({
9482
9515
 
9483
9516
  // packages/experience-design-system-cli-legacy/src/runs/save-path-resolver.ts
9484
9517
  import { access as access4 } from "node:fs/promises";
9485
- import { join as join11 } from "node:path";
9518
+ import { join as join12 } from "node:path";
9486
9519
  async function listConflictingFiles(path) {
9487
9520
  const conflicts = [];
9488
9521
  for (const name of SAVE_FILES) {
9489
9522
  try {
9490
- await access4(join11(path, name));
9523
+ await access4(join12(path, name));
9491
9524
  conflicts.push(name);
9492
9525
  } catch {
9493
9526
  }
@@ -9507,7 +9540,7 @@ function buildTimestampedSubdir(base, now = /* @__PURE__ */ new Date()) {
9507
9540
  const hh = pad2(now.getHours());
9508
9541
  const mm = pad2(now.getMinutes());
9509
9542
  const ss = pad2(now.getSeconds());
9510
- return join11(base, `dsi-${y}${m}${d}-${hh}${mm}${ss}`);
9543
+ return join12(base, `dsi-${y}${m}${d}-${hh}${mm}${ss}`);
9511
9544
  }
9512
9545
  var SAVE_FILES;
9513
9546
  var init_save_path_resolver = __esm({
@@ -9519,7 +9552,7 @@ var init_save_path_resolver = __esm({
9519
9552
 
9520
9553
  // packages/experience-design-system-cli-legacy/src/runs/store.ts
9521
9554
  import { readFile as readFile12, writeFile as writeFile4, mkdir as mkdir4, rename } from "node:fs/promises";
9522
- import { join as join12 } from "node:path";
9555
+ import { join as join13 } from "node:path";
9523
9556
  import { homedir as homedir6 } from "node:os";
9524
9557
  import { randomBytes as randomBytes2 } from "node:crypto";
9525
9558
  function encodeBase32(bytes, length) {
@@ -9615,8 +9648,8 @@ var init_store = __esm({
9615
9648
  RUNS_FILE_VERSION = 3;
9616
9649
  RUNS_FILE_CAP = 200;
9617
9650
  READABLE_VERSIONS = /* @__PURE__ */ new Set([1, 2, 3]);
9618
- RUNS_DIR = join12(homedir6(), ".config", "experiences");
9619
- RUNS_PATH = join12(RUNS_DIR, "runs.json");
9651
+ RUNS_DIR = join13(homedir6(), ".config", "experiences");
9652
+ RUNS_PATH = join13(RUNS_DIR, "runs.json");
9620
9653
  CROCKFORD = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
9621
9654
  }
9622
9655
  });
@@ -9773,7 +9806,7 @@ var init_WelcomeStep = __esm({
9773
9806
  import { useState as useState6, useEffect as useEffect3 } from "react";
9774
9807
  import { Box as Box9, Text as Text10 } from "ink";
9775
9808
  import { promises as fs } from "node:fs";
9776
- import { join as join13 } from "node:path";
9809
+ import { join as join14 } from "node:path";
9777
9810
  import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
9778
9811
  async function countFiles(dir) {
9779
9812
  const counts = {
@@ -9797,7 +9830,7 @@ async function countFiles(dir) {
9797
9830
  await Promise.all(
9798
9831
  entries.map(async (entry) => {
9799
9832
  if (IGNORE_DIRS.has(entry)) return;
9800
- const full = join13(current, entry);
9833
+ const full = join14(current, entry);
9801
9834
  let stat7;
9802
9835
  try {
9803
9836
  stat7 = await fs.stat(full);
@@ -10873,6 +10906,7 @@ function WizardPreviewStep({
10873
10906
  environmentId,
10874
10907
  stepNumber,
10875
10908
  totalSteps,
10909
+ droppedTokenDefaults = [],
10876
10910
  onConfirm,
10877
10911
  onEdit,
10878
10912
  onQuit
@@ -10965,6 +10999,13 @@ function WizardPreviewStep({
10965
10999
  }
10966
11000
  )
10967
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
+ ] }),
10968
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." }) }),
10969
11010
  /* @__PURE__ */ jsx19(SpaceEnvironment, { spaceId, environmentId }),
10970
11011
  /* @__PURE__ */ jsxs16(Box16, { gap: 3, marginTop: 1, children: [
@@ -11016,7 +11057,7 @@ function DoneStep({
11016
11057
  });
11017
11058
  const totalFailed = componentTypes.failed + designTokens.failed;
11018
11059
  const totalPushed = componentTypes.created + componentTypes.updated + componentTypes.removed + designTokens.created + designTokens.updated + designTokens.removed;
11019
- const success = totalFailed === 0;
11060
+ const success = totalFailed === 0 && (summary?.failed ?? 0) === 0;
11020
11061
  function EntityRows({ entity, label }) {
11021
11062
  return /* @__PURE__ */ jsxs17(Fragment5, { children: [
11022
11063
  entity.created > 0 && /* @__PURE__ */ jsxs17(Box17, { gap: 1, children: [
@@ -11062,7 +11103,7 @@ function DoneStep({
11062
11103
  ] });
11063
11104
  }
11064
11105
  return /* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", gap: 1, paddingX: 2, paddingY: 1, children: [
11065
- 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" }),
11066
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: [
11067
11108
  /* @__PURE__ */ jsx20(EntityRows, { entity: componentTypes, label: "Component Type" }),
11068
11109
  /* @__PURE__ */ jsx20(EntityRows, { entity: designTokens, label: "Design Token" }),
@@ -11482,8 +11523,8 @@ var init_types = __esm({
11482
11523
  });
11483
11524
 
11484
11525
  // packages/experience-design-system-extraction/dist/src/extract/tsx-shared.js
11485
- import { existsSync as existsSync3, readFileSync as readFileSync5 } from "node:fs";
11486
- 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";
11487
11528
  import { Node, Project, SyntaxKind } from "ts-morph";
11488
11529
  import ts from "typescript";
11489
11530
  function createTsxProject(filePaths) {
@@ -11682,8 +11723,8 @@ function findNearestTsConfigPath(filePath) {
11682
11723
  let currentDir = dirname6(filePath);
11683
11724
  while (true) {
11684
11725
  for (const candidateName of ["tsconfig.json", "jsconfig.json"]) {
11685
- const candidatePath = join14(currentDir, candidateName);
11686
- if (existsSync3(candidatePath)) {
11726
+ const candidatePath = join15(currentDir, candidateName);
11727
+ if (existsSync4(candidatePath)) {
11687
11728
  nearestTsConfigPathCache.set(filePath, candidatePath);
11688
11729
  return candidatePath;
11689
11730
  }
@@ -11739,12 +11780,12 @@ function resolveImportSourcePath(basePath) {
11739
11780
  `${basePath}.tsx`,
11740
11781
  `${basePath}.js`,
11741
11782
  `${basePath}.jsx`,
11742
- join14(basePath, "index.ts"),
11743
- join14(basePath, "index.tsx"),
11744
- join14(basePath, "index.js"),
11745
- join14(basePath, "index.jsx")
11783
+ join15(basePath, "index.ts"),
11784
+ join15(basePath, "index.tsx"),
11785
+ join15(basePath, "index.js"),
11786
+ join15(basePath, "index.jsx")
11746
11787
  ];
11747
- return candidates.find((candidatePath) => existsSync3(candidatePath));
11788
+ return candidates.find((candidatePath) => existsSync4(candidatePath));
11748
11789
  }
11749
11790
  function findProjectSourceFileByImportPath(project, resolvedPath) {
11750
11791
  const candidatePaths = [
@@ -11753,10 +11794,10 @@ function findProjectSourceFileByImportPath(project, resolvedPath) {
11753
11794
  `${resolvedPath}.tsx`,
11754
11795
  `${resolvedPath}.js`,
11755
11796
  `${resolvedPath}.jsx`,
11756
- join14(resolvedPath, "index.ts"),
11757
- join14(resolvedPath, "index.tsx"),
11758
- join14(resolvedPath, "index.js"),
11759
- join14(resolvedPath, "index.jsx")
11797
+ join15(resolvedPath, "index.ts"),
11798
+ join15(resolvedPath, "index.tsx"),
11799
+ join15(resolvedPath, "index.js"),
11800
+ join15(resolvedPath, "index.jsx")
11760
11801
  ];
11761
11802
  for (const candidatePath of candidatePaths) {
11762
11803
  const sourceFile = project.getSourceFile(candidatePath);
@@ -11777,10 +11818,10 @@ function findWorkspacePackageEntrySourceFile(originSourceFile, moduleSpecifier)
11777
11818
  if (!packageRootDir)
11778
11819
  return void 0;
11779
11820
  const preferredEntryPaths = [
11780
- join14(packageRootDir, "src/index.ts"),
11781
- join14(packageRootDir, "src/index.tsx"),
11782
- join14(packageRootDir, "index.ts"),
11783
- 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")
11784
11825
  ];
11785
11826
  for (const entryPath of preferredEntryPaths) {
11786
11827
  const entrySourceFile = project.getSourceFile(entryPath);
@@ -11788,7 +11829,7 @@ function findWorkspacePackageEntrySourceFile(originSourceFile, moduleSpecifier)
11788
11829
  return entrySourceFile;
11789
11830
  }
11790
11831
  }
11791
- return candidateSourceFiles.find((sourceFile) => sourceFile.getDirectoryPath() === join14(packageRootDir, "src"));
11832
+ return candidateSourceFiles.find((sourceFile) => sourceFile.getDirectoryPath() === join15(packageRootDir, "src"));
11792
11833
  }
11793
11834
  function getWorkspacePackageManifestForSourceFile(sourceFile) {
11794
11835
  const packageRootDir = findNearestPackageRootDir(sourceFile.getFilePath());
@@ -11797,7 +11838,7 @@ function getWorkspacePackageManifestForSourceFile(sourceFile) {
11797
11838
  if (workspacePackageManifestCache.has(packageRootDir)) {
11798
11839
  return workspacePackageManifestCache.get(packageRootDir) ?? void 0;
11799
11840
  }
11800
- const packageJsonPath = join14(packageRootDir, "package.json");
11841
+ const packageJsonPath = join15(packageRootDir, "package.json");
11801
11842
  try {
11802
11843
  const packageJson = JSON.parse(readFileSync5(packageJsonPath, "utf8"));
11803
11844
  const manifest = typeof packageJson.name === "string" ? { name: packageJson.name, rootDir: packageRootDir } : null;
@@ -11814,7 +11855,7 @@ function findNearestPackageRootDir(filePath) {
11814
11855
  }
11815
11856
  let currentDir = dirname6(filePath);
11816
11857
  while (true) {
11817
- if (existsSync3(join14(currentDir, "package.json"))) {
11858
+ if (existsSync4(join15(currentDir, "package.json"))) {
11818
11859
  packageRootByFilePathCache.set(filePath, currentDir);
11819
11860
  return currentDir;
11820
11861
  }
@@ -14876,8 +14917,8 @@ var init_vue_tsx = __esm({
14876
14917
  });
14877
14918
 
14878
14919
  // packages/experience-design-system-extraction/dist/src/extract/resolve-local-module.js
14879
- import { existsSync as existsSync4, statSync as statSync2 } from "node:fs";
14880
- 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";
14881
14922
  function resolveLocalModule(importingFilePath, specifier, options = {}) {
14882
14923
  const basePath = resolve13(dirname7(importingFilePath), specifier);
14883
14924
  const candidates = [
@@ -14886,18 +14927,18 @@ function resolveLocalModule(importingFilePath, specifier, options = {}) {
14886
14927
  `${basePath}.ts`,
14887
14928
  `${basePath}.mjs`,
14888
14929
  `${basePath}.cjs`,
14889
- join15(basePath, "index.js"),
14890
- join15(basePath, "index.ts"),
14891
- join15(basePath, "index.mjs"),
14892
- join15(basePath, "index.cjs")
14930
+ join16(basePath, "index.js"),
14931
+ join16(basePath, "index.ts"),
14932
+ join16(basePath, "index.mjs"),
14933
+ join16(basePath, "index.cjs")
14893
14934
  ];
14894
14935
  for (const candidate of candidates) {
14895
- if (existsSync4(candidate) && statSync2(candidate).isFile())
14936
+ if (existsSync5(candidate) && statSync2(candidate).isFile())
14896
14937
  return candidate;
14897
14938
  }
14898
14939
  if (options.allowJavaScriptExtensionFallback && basePath.endsWith(".js")) {
14899
14940
  const tsPath = `${basePath.slice(0, -".js".length)}.ts`;
14900
- if (existsSync4(tsPath) && statSync2(tsPath).isFile())
14941
+ if (existsSync5(tsPath) && statSync2(tsPath).isFile())
14901
14942
  return tsPath;
14902
14943
  }
14903
14944
  return null;
@@ -14928,9 +14969,9 @@ var init_resolve_type_property = __esm({
14928
14969
 
14929
14970
  // packages/experience-design-system-extraction/dist/src/extract/vue.js
14930
14971
  import os from "node:os";
14931
- 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";
14932
14973
  import { readFile as readFile15 } from "node:fs/promises";
14933
- 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";
14934
14975
  import { parse as parseSFC } from "@vue/compiler-sfc";
14935
14976
  import { Project as Project3, Node as Node6 } from "ts-morph";
14936
14977
  async function extractVueComponents(filePaths, onProgress) {
@@ -15143,11 +15184,11 @@ function findWorkspaceRoot(startDir) {
15143
15184
  return workspaceRootCache.get(startDir);
15144
15185
  let dir = startDir;
15145
15186
  while (true) {
15146
- const pkgJsonPath = join16(dir, "package.json");
15147
- if (existsSync5(pkgJsonPath)) {
15187
+ const pkgJsonPath = join17(dir, "package.json");
15188
+ if (existsSync6(pkgJsonPath)) {
15148
15189
  try {
15149
15190
  const pkg4 = JSON.parse(readFileSync6(pkgJsonPath, "utf8"));
15150
- if (pkg4.workspaces || existsSync5(join16(dir, "pnpm-workspace.yaml"))) {
15191
+ if (pkg4.workspaces || existsSync6(join17(dir, "pnpm-workspace.yaml"))) {
15151
15192
  workspaceRootCache.set(startDir, dir);
15152
15193
  return dir;
15153
15194
  }
@@ -15167,8 +15208,8 @@ function getWorkspacePackageDirs(workspaceRoot) {
15167
15208
  return workspacePackageDirsCache.get(workspaceRoot);
15168
15209
  }
15169
15210
  const packageMap = /* @__PURE__ */ new Map();
15170
- const packagesDir = join16(workspaceRoot, "packages");
15171
- if (!existsSync5(packagesDir)) {
15211
+ const packagesDir = join17(workspaceRoot, "packages");
15212
+ if (!existsSync6(packagesDir)) {
15172
15213
  workspacePackageDirsCache.set(workspaceRoot, packageMap);
15173
15214
  return packageMap;
15174
15215
  }
@@ -15177,12 +15218,12 @@ function getWorkspacePackageDirs(workspaceRoot) {
15177
15218
  return;
15178
15219
  let entries;
15179
15220
  try {
15180
- entries = readdirSync2(dir);
15221
+ entries = readdirSync3(dir);
15181
15222
  } catch {
15182
15223
  return;
15183
15224
  }
15184
- const pkgJsonPath = join16(dir, "package.json");
15185
- if (existsSync5(pkgJsonPath)) {
15225
+ const pkgJsonPath = join17(dir, "package.json");
15226
+ if (existsSync6(pkgJsonPath)) {
15186
15227
  try {
15187
15228
  const pkg4 = JSON.parse(readFileSync6(pkgJsonPath, "utf8"));
15188
15229
  if (typeof pkg4.name === "string") {
@@ -15194,7 +15235,7 @@ function getWorkspacePackageDirs(workspaceRoot) {
15194
15235
  for (const entry of entries) {
15195
15236
  if (entry === "node_modules" || entry === ".git" || entry.startsWith("."))
15196
15237
  continue;
15197
- const entryPath = join16(dir, entry);
15238
+ const entryPath = join17(dir, entry);
15198
15239
  try {
15199
15240
  const stat7 = statSync3(entryPath);
15200
15241
  if (stat7.isDirectory()) {
@@ -15234,28 +15275,28 @@ function resolveWorkspaceVueImport(specifier, importingFilePath) {
15234
15275
  const packageDir = packageDirs.get(packageName);
15235
15276
  if (!packageDir)
15236
15277
  return null;
15237
- const pkgJsonPath = join16(packageDir, "package.json");
15278
+ const pkgJsonPath = join17(packageDir, "package.json");
15238
15279
  try {
15239
15280
  const pkg4 = JSON.parse(readFileSync6(pkgJsonPath, "utf8"));
15240
15281
  if (pkg4.exports && subpath !== ".") {
15241
15282
  const exportValue = pkg4.exports[subpath];
15242
15283
  if (typeof exportValue === "string" && exportValue.endsWith(".vue")) {
15243
15284
  const resolved = resolve14(packageDir, exportValue);
15244
- if (existsSync5(resolved))
15285
+ if (existsSync6(resolved))
15245
15286
  return resolved;
15246
15287
  }
15247
15288
  }
15248
15289
  if (subpath !== ".") {
15249
15290
  const subDir = resolve14(packageDir, subpath.replace(/^\.\//, ""));
15250
- for (const base of [join16(packageDir, "src", subpath.replace(/^\.\//, "")), subDir]) {
15251
- const subPkgPath = join16(base, "package.json");
15252
- 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)) {
15253
15294
  try {
15254
15295
  const subPkg = JSON.parse(readFileSync6(subPkgPath, "utf8"));
15255
15296
  const main = subPkg.main || subPkg.module;
15256
15297
  if (typeof main === "string" && main.endsWith(".vue")) {
15257
15298
  const resolved = resolve14(base, main);
15258
- if (existsSync5(resolved))
15299
+ if (existsSync6(resolved))
15259
15300
  return resolved;
15260
15301
  }
15261
15302
  } catch {
@@ -15267,7 +15308,7 @@ function resolveWorkspaceVueImport(specifier, importingFilePath) {
15267
15308
  const main = pkg4.main || pkg4.module;
15268
15309
  if (typeof main === "string" && main.endsWith(".vue")) {
15269
15310
  const resolved = resolve14(packageDir, main);
15270
- if (existsSync5(resolved))
15311
+ if (existsSync6(resolved))
15271
15312
  return resolved;
15272
15313
  }
15273
15314
  }
@@ -15709,7 +15750,7 @@ var init_astro = __esm({
15709
15750
  });
15710
15751
 
15711
15752
  // packages/experience-design-system-extraction/dist/src/extract/web-components.js
15712
- 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";
15713
15754
  import { Project as Project5, Node as Node8, SyntaxKind as SyntaxKind6 } from "ts-morph";
15714
15755
  function normalizeComponentName(input) {
15715
15756
  return input.replace(/[^a-zA-Z0-9]/g, "").toLowerCase();
@@ -16362,14 +16403,14 @@ function resolveImportSourcePath2(fromFilePath, specifier) {
16362
16403
  if (!specifier.startsWith(spectrumPrefix)) {
16363
16404
  return null;
16364
16405
  }
16365
- const packagesMarker = `${join17("2nd-gen", "packages")}${fromFilePath.includes("\\") ? "\\" : "/"}`;
16406
+ const packagesMarker = `${join18("2nd-gen", "packages")}${fromFilePath.includes("\\") ? "\\" : "/"}`;
16366
16407
  const markerIndex = fromFilePath.lastIndexOf(packagesMarker);
16367
16408
  if (markerIndex === -1) {
16368
16409
  return null;
16369
16410
  }
16370
16411
  const packagesRoot = fromFilePath.slice(0, markerIndex + packagesMarker.length - 1);
16371
16412
  const componentPath = specifier.slice(spectrumPrefix.length);
16372
- return join17(packagesRoot, "core", "components", componentPath, "index.ts");
16413
+ return join18(packagesRoot, "core", "components", componentPath, "index.ts");
16373
16414
  }
16374
16415
  function getImportedBaseClass(classDecl, project, visitedFiles) {
16375
16416
  const extendsClause = classDecl.getHeritageClauses().find((clause) => clause.getToken() === SyntaxKind6.ExtendsKeyword);
@@ -16636,8 +16677,8 @@ var init_scoring = __esm({
16636
16677
 
16637
16678
  // packages/experience-design-system-extraction/dist/src/extract/svelte.js
16638
16679
  import os3 from "node:os";
16639
- import { basename as basename6, dirname as dirname10, resolve as resolve16, join as join18 } from "node:path";
16640
- 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";
16641
16682
  import { createRequire } from "node:module";
16642
16683
  import { parse as parseSvelte } from "svelte/compiler";
16643
16684
  import { Project as Project6, Node as Node9, ScriptTarget, ModuleKind, ts as ts2 } from "ts-morph";
@@ -16770,8 +16811,8 @@ async function maybeRunResolveUnreachableRetry(components, warnings, retryContex
16770
16811
  function findNearestTsconfig(startDir) {
16771
16812
  let dir = startDir;
16772
16813
  for (let i = 0; i < 16; i++) {
16773
- const candidate = join18(dir, "tsconfig.json");
16774
- if (existsSync6(candidate))
16814
+ const candidate = join19(dir, "tsconfig.json");
16815
+ if (existsSync7(candidate))
16775
16816
  return candidate;
16776
16817
  const parent = dirname10(dir);
16777
16818
  if (!parent || parent === dir)
@@ -16906,29 +16947,29 @@ function locateDtsForSpecifier(req, specifier, parentFile) {
16906
16947
  const seedDir = resolvedJs ? dirname10(resolvedJs) : dirname10(parentFile);
16907
16948
  const pkgRoot = findPackageRootForSpecifier(seedDir, specifier);
16908
16949
  if (pkgRoot) {
16909
- const pkgJsonPath = join18(pkgRoot, "package.json");
16910
- if (existsSync6(pkgJsonPath)) {
16950
+ const pkgJsonPath = join19(pkgRoot, "package.json");
16951
+ if (existsSync7(pkgJsonPath)) {
16911
16952
  try {
16912
16953
  const pkgRaw = readFileSync7(pkgJsonPath, "utf-8");
16913
16954
  const pkg4 = JSON.parse(pkgRaw);
16914
16955
  const typesField = pkg4.types ?? pkg4.typings;
16915
16956
  if (typeof typesField === "string") {
16916
16957
  const candidate = resolve16(pkgRoot, typesField);
16917
- if (existsSync6(candidate))
16958
+ if (existsSync7(candidate))
16918
16959
  return candidate;
16919
16960
  }
16920
16961
  const exportsTypes = extractTypesFromExports(pkg4.exports);
16921
16962
  if (exportsTypes) {
16922
16963
  const candidate = resolve16(pkgRoot, exportsTypes);
16923
- if (existsSync6(candidate))
16964
+ if (existsSync7(candidate))
16924
16965
  return candidate;
16925
16966
  }
16926
16967
  } catch {
16927
16968
  }
16928
16969
  }
16929
16970
  for (const entry of ["index.d.ts", "index.d.mts"]) {
16930
- const candidate = join18(pkgRoot, entry);
16931
- if (existsSync6(candidate))
16971
+ const candidate = join19(pkgRoot, entry);
16972
+ if (existsSync7(candidate))
16932
16973
  return candidate;
16933
16974
  }
16934
16975
  }
@@ -16936,7 +16977,7 @@ function locateDtsForSpecifier(req, specifier, parentFile) {
16936
16977
  const noExt = resolvedJs.replace(/\.(m?js|cjs)$/, "");
16937
16978
  for (const ext of [".d.ts", ".d.mts"]) {
16938
16979
  const candidate = `${noExt}${ext}`;
16939
- if (existsSync6(candidate))
16980
+ if (existsSync7(candidate))
16940
16981
  return candidate;
16941
16982
  }
16942
16983
  }
@@ -16945,9 +16986,9 @@ function locateDtsForSpecifier(req, specifier, parentFile) {
16945
16986
  function findPackageRootForSpecifier(seedDir, specifier) {
16946
16987
  let dir = seedDir;
16947
16988
  for (let i = 0; i < 32; i++) {
16948
- if (existsSync6(join18(dir, "package.json"))) {
16989
+ if (existsSync7(join19(dir, "package.json"))) {
16949
16990
  try {
16950
- const pkgRaw = readFileSync7(join18(dir, "package.json"), "utf-8");
16991
+ const pkgRaw = readFileSync7(join19(dir, "package.json"), "utf-8");
16951
16992
  const pkg4 = JSON.parse(pkgRaw);
16952
16993
  if (pkg4.name === specifier)
16953
16994
  return dir;
@@ -18919,9 +18960,9 @@ var init_wizard_generate_progress = __esm({
18919
18960
  });
18920
18961
 
18921
18962
  // packages/experience-design-system-cli-legacy/src/import/tui/spawn-generate.ts
18922
- import { spawn as spawn3 } from "node:child_process";
18963
+ import { spawn as spawn2 } from "node:child_process";
18923
18964
  function spawnGenerateChild(opts) {
18924
- const child = spawn3(opts.command, opts.args);
18965
+ const child = spawn2(opts.command, opts.args);
18925
18966
  let stdout = "";
18926
18967
  let stderr = "";
18927
18968
  child.stdout?.on("data", (d) => {
@@ -18960,6 +19001,88 @@ var init_spawn_generate = __esm({
18960
19001
  }
18961
19002
  });
18962
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
+
18963
19086
  // packages/experience-design-system-cli-legacy/src/analyze/composite-closure.ts
18964
19087
  function edgesFrom(component, known) {
18965
19088
  if (!component) return [];
@@ -20301,17 +20424,17 @@ function buildCycleUnits(slotCycles) {
20301
20424
  const groups = /* @__PURE__ */ new Map();
20302
20425
  for (const node of parent.keys()) {
20303
20426
  const root = find(node);
20304
- let group = groups.get(root);
20305
- if (!group) {
20306
- group = /* @__PURE__ */ new Set();
20307
- groups.set(root, group);
20427
+ let group2 = groups.get(root);
20428
+ if (!group2) {
20429
+ group2 = /* @__PURE__ */ new Set();
20430
+ groups.set(root, group2);
20308
20431
  }
20309
- group.add(node);
20432
+ group2.add(node);
20310
20433
  }
20311
20434
  const out = /* @__PURE__ */ new Map();
20312
- for (const group of groups.values()) {
20313
- for (const node of group) {
20314
- out.set(node, group);
20435
+ for (const group2 of groups.values()) {
20436
+ for (const node of group2) {
20437
+ out.set(node, group2);
20315
20438
  }
20316
20439
  }
20317
20440
  return out;
@@ -21805,10 +21928,10 @@ function swapValues(values, firstIndex, secondIndex) {
21805
21928
  [next[firstIndex], next[secondIndex]] = [next[secondIndex], next[firstIndex]];
21806
21929
  return next;
21807
21930
  }
21808
- function parseToState(json) {
21931
+ function parseToState(json2) {
21809
21932
  let parsed;
21810
21933
  try {
21811
- parsed = JSON.parse(json);
21934
+ parsed = JSON.parse(json2);
21812
21935
  } catch (e) {
21813
21936
  return {
21814
21937
  state: { componentDescription: "", props: [], slots: [] },
@@ -22661,11 +22784,11 @@ function FieldEditor({
22661
22784
  setEditorState(next);
22662
22785
  onChange(serializeState(next, value));
22663
22786
  };
22664
- const canonicalize = React14.useCallback((json) => {
22787
+ const canonicalize = React14.useCallback((json2) => {
22665
22788
  try {
22666
- return JSON.stringify(JSON.parse(json));
22789
+ return JSON.stringify(JSON.parse(json2));
22667
22790
  } catch {
22668
- return `__unparseable__:${json}`;
22791
+ return `__unparseable__:${json2}`;
22669
22792
  }
22670
22793
  }, []);
22671
22794
  const initialStateRef = React14.useRef(initialState);
@@ -23239,14 +23362,14 @@ function FieldEditor({
23239
23362
  })();
23240
23363
  const rows = [];
23241
23364
  rows.push({ kind: "component-description" });
23242
- for (const group of propGroups.filter((candidate) => candidate.kind !== "hidden")) {
23243
- if (group.indexes.length === 0) continue;
23365
+ for (const group2 of propGroups.filter((candidate) => candidate.kind !== "hidden")) {
23366
+ if (group2.indexes.length === 0) continue;
23244
23367
  rows.push({
23245
23368
  kind: "header",
23246
- label: `${group.label} (${group.indexes.length}) `,
23247
- section: group.kind
23369
+ label: `${group2.label} (${group2.indexes.length}) `,
23370
+ section: group2.kind
23248
23371
  });
23249
- group.indexes.forEach((idx) => rows.push({ kind: "prop", idx }));
23372
+ group2.indexes.forEach((idx) => rows.push({ kind: "prop", idx }));
23250
23373
  }
23251
23374
  if (slots.length > 0) {
23252
23375
  rows.push({
@@ -23256,7 +23379,7 @@ function FieldEditor({
23256
23379
  });
23257
23380
  slots.forEach((_, i) => rows.push({ kind: "slot", idx: i }));
23258
23381
  }
23259
- const hiddenGroup = propGroups.find((group) => group.kind === "hidden");
23382
+ const hiddenGroup = propGroups.find((group2) => group2.kind === "hidden");
23260
23383
  if (hiddenGroup && hiddenGroup.indexes.length > 0) {
23261
23384
  rows.push({
23262
23385
  kind: "header",
@@ -26998,26 +27121,8 @@ var init_runScopeGate = __esm({
26998
27121
  }
26999
27122
  });
27000
27123
 
27001
- // packages/experience-design-system-cli-legacy/src/helpers/build-contentful-management-client.ts
27002
- import { createClient as createClient2 } from "contentful-management";
27003
- function buildContentfulManagementClient(opts) {
27004
- return createClient2(
27005
- {
27006
- accessToken: opts.cmaToken,
27007
- ...opts.host ? { host: toConfiguredHost(opts.host) } : {}
27008
- },
27009
- { type: "plain" }
27010
- );
27011
- }
27012
- var init_build_contentful_management_client = __esm({
27013
- "packages/experience-design-system-cli-legacy/src/helpers/build-contentful-management-client.ts"() {
27014
- "use strict";
27015
- init_host_utils();
27016
- }
27017
- });
27018
-
27019
27124
  // packages/experience-design-system-cli-legacy/src/helpers/fetch-existing-contentful-entities.ts
27020
- import { fetchAll } from "contentful-management";
27125
+ import { fetchAll as fetchAll2 } from "contentful-management";
27021
27126
  async function fetchExistingContentfulEntitiesFromContentful(client2, params) {
27022
27127
  const componentScope = {
27023
27128
  spaceId: params.spaceId,
@@ -27029,8 +27134,8 @@ async function fetchExistingContentfulEntitiesFromContentful(client2, params) {
27029
27134
  environmentId: params.environmentId,
27030
27135
  query: { cursor: true, limit: 1e3 }
27031
27136
  };
27032
- const components = await fetchAll(client2.component.getMany, componentScope);
27033
- 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);
27034
27139
  return { components, tokens };
27035
27140
  }
27036
27141
  var init_fetch_existing_contentful_entities = __esm({
@@ -27041,7 +27146,7 @@ var init_fetch_existing_contentful_entities = __esm({
27041
27146
 
27042
27147
  // packages/experience-design-system-cli-legacy/src/helpers/fetch-and-persist-existing-contentful-entities.ts
27043
27148
  import { writeFile as writeFile5 } from "node:fs/promises";
27044
- import { join as join19 } from "node:path";
27149
+ import { join as join20 } from "node:path";
27045
27150
  async function fetchAndPersistExistingContentfulEntities(params) {
27046
27151
  const t0 = Date.now();
27047
27152
  try {
@@ -27053,7 +27158,7 @@ async function fetchAndPersistExistingContentfulEntities(params) {
27053
27158
  spaceId: params.spaceId,
27054
27159
  environmentId: params.environmentId
27055
27160
  });
27056
- const path = join19(params.outDir, ".existing-entities.json");
27161
+ const path = join20(params.outDir, ".existing-entities.json");
27057
27162
  await writeFile5(path, JSON.stringify(entities, null, 2), "utf8");
27058
27163
  return { ok: true, path, durationMs: Date.now() - t0, entities };
27059
27164
  } catch (error) {
@@ -27230,11 +27335,11 @@ __export(WizardApp_exports, {
27230
27335
  });
27231
27336
  import { useEffect as useEffect15, useRef as useRef10, useState as useState23 } from "react";
27232
27337
  import { Box as Box42, Text as Text46 } from "ink";
27233
- import { join as join20, resolve as resolve17 } from "node:path";
27234
- 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";
27235
27340
  import { access as access7, stat as stat5, writeFile as writeFile6 } from "node:fs/promises";
27236
27341
  import { tmpdir } from "node:os";
27237
- import { execFile as execFile2, spawn as spawn4 } from "node:child_process";
27342
+ import { execFile as execFile2, spawn as spawn3 } from "node:child_process";
27238
27343
  import { mkdir as mkdir5 } from "node:fs/promises";
27239
27344
  import { buildCDF as buildCDF3, validateCDF as validateCDF3, validateSlotReferences as validateSlotReferences2 } from "@contentful/experience-design-system-types";
27240
27345
  import { jsx as jsx50, jsxs as jsxs43 } from "react/jsx-runtime";
@@ -27296,7 +27401,7 @@ function runCli(args) {
27296
27401
  }
27297
27402
  function runSpawnedCli(args, onStderr, onStdout) {
27298
27403
  return new Promise((res) => {
27299
- const child = spawn4("node", args);
27404
+ const child = spawn3("node", args);
27300
27405
  let stdout = "";
27301
27406
  let stderr = "";
27302
27407
  child.stdout.on("data", (d) => {
@@ -27371,7 +27476,7 @@ function WizardApp({
27371
27476
  const logInit = useRef10(false);
27372
27477
  const initialAgentAuthRef = useRef10(initialAgentAuth ?? null);
27373
27478
  if (!logInit.current) {
27374
- writeFileSync(WIZARD_LOG, `--- experiences import session ${(/* @__PURE__ */ new Date()).toISOString()} ---
27479
+ writeFileSync2(WIZARD_LOG, `--- experiences import session ${(/* @__PURE__ */ new Date()).toISOString()} ---
27375
27480
  `);
27376
27481
  logInit.current = true;
27377
27482
  }
@@ -27380,6 +27485,7 @@ function WizardApp({
27380
27485
  tokensPath: ""
27381
27486
  });
27382
27487
  const allowEmptyDeleteAllRef = useRef10(false);
27488
+ const pushDebugRef = useRef10(null);
27383
27489
  const generateChildRef = useRef10(null);
27384
27490
  const generationCachePreflightRef = useRef10(null);
27385
27491
  const selectionToReviewStartedAtRef = useRef10(null);
@@ -27398,7 +27504,7 @@ function WizardApp({
27398
27504
  const rawTokensEntryReady = !!initialRawTokensPath;
27399
27505
  const effectiveNoCache = resolveNoCacheForGenerate({ cliNoCache: noCache });
27400
27506
  const initialStepResolved = rawTokensEntryReady ? initialProjectPath ? "path-validation" : "credentials" : initialProjectPath ? "token-input" : "welcome";
27401
- const initialOutDir = initialProjectPath ? join20(resolve17(initialProjectPath), ".contentful") : "";
27507
+ const initialOutDir = initialProjectPath ? join21(resolve17(initialProjectPath), ".contentful") : "";
27402
27508
  const [state, setState] = useState23({
27403
27509
  step: initialStepResolved,
27404
27510
  agent: initialAgent ?? "claude",
@@ -27454,6 +27560,7 @@ function WizardApp({
27454
27560
  existingEntitiesStatus: "idle",
27455
27561
  lastRunId: null,
27456
27562
  finalizeErrorBanner: null,
27563
+ droppedTokenDefaults: [],
27457
27564
  finalReviewPassed: false
27458
27565
  });
27459
27566
  useEffect15(() => {
@@ -27596,7 +27703,7 @@ If you are using AWS Bedrock, run:
27596
27703
  }
27597
27704
  const sessionMatch = /^session=(.+)$/m.exec(result.stdout);
27598
27705
  const tokenSessionId = sessionMatch ? sessionMatch[1].trim() : null;
27599
- const tokensPath = join20(outDir, "tokens.json");
27706
+ const tokensPath = join21(outDir, "tokens.json");
27600
27707
  const printArgs = ["print", "tokens", "--out", tokensPath];
27601
27708
  if (tokenSessionId) printArgs.push("--session", tokenSessionId);
27602
27709
  const r = await runCli(printArgs);
@@ -27618,7 +27725,7 @@ If you are using AWS Bedrock, run:
27618
27725
  tokenGenerationStatus: "complete",
27619
27726
  skipComponents: true,
27620
27727
  acceptedCount: 0,
27621
- outDir: state.outDir || join20(process.cwd(), ".contentful")
27728
+ outDir: state.outDir || join21(process.cwd(), ".contentful")
27622
27729
  });
27623
27730
  update({ step: "credentials" });
27624
27731
  return true;
@@ -27759,7 +27866,7 @@ If you are using AWS Bedrock, run:
27759
27866
  return promise;
27760
27867
  };
27761
27868
  const runExtract = async (projectPath, showProgress = true) => {
27762
- const outDir = join20(resolve17(projectPath), ".contentful");
27869
+ const outDir = join21(resolve17(projectPath), ".contentful");
27763
27870
  const existingEntitiesExpected = !state.credentialsSkipped && Boolean(state.spaceId && state.environmentId && state.cmaToken && projectPath);
27764
27871
  update({
27765
27872
  ...showProgress ? { step: "extracting" } : {},
@@ -28434,12 +28541,30 @@ Make sure this path contains TypeScript/React/Vue component files (.tsx, .ts, .v
28434
28541
  void runSaveAndPush();
28435
28542
  };
28436
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;
28437
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
+ });
28438
28564
  update(buildSkippedPreviewTransition());
28439
28565
  return;
28440
28566
  }
28441
28567
  update({ step: "previewing" });
28442
- const resolvedHost = resolveWizardHost(host2);
28443
28568
  try {
28444
28569
  const client2 = new ImportApiClient({
28445
28570
  cmaToken,
@@ -28447,6 +28572,7 @@ Make sure this path contains TypeScript/React/Vue component files (.tsx, .ts, .v
28447
28572
  environmentId,
28448
28573
  host: resolvedHost
28449
28574
  });
28575
+ pushDebug.event("Preview started", { note: `POST ${resolvedHost}/\u2026/design_systems/imports/preview` });
28450
28576
  let components = [];
28451
28577
  if (extractSessionId) {
28452
28578
  const db = openPipelineDb();
@@ -28462,7 +28588,16 @@ Make sure this path contains TypeScript/React/Vue component files (.tsx, .ts, .v
28462
28588
  tokens = await readTokensFromPath("tokens", tokensPath);
28463
28589
  }
28464
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
+ });
28465
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
+ });
28466
28601
  if (extractSessionId) {
28467
28602
  let needsRepreview = false;
28468
28603
  const db = openPipelineDb();
@@ -28482,15 +28617,27 @@ Make sure this path contains TypeScript/React/Vue component files (.tsx, .ts, .v
28482
28617
  if (seededDefaults > 0) needsRepreview = true;
28483
28618
  }
28484
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
+ });
28485
28623
  components = loadCDFComponents(db, extractSessionId);
28486
28624
  cdf = buildCDF3(components, toCDFTokens(tokens), { deleteAll: allowEmptyDeleteAllRef.current });
28487
28625
  preview = await client2.previewImport(cdf);
28626
+ pushDebug.event("Server previewed the updated CDF", {
28627
+ data: summarizePreview(preview),
28628
+ requestId: client2.getLastRequestId()
28629
+ });
28488
28630
  }
28489
28631
  } finally {
28490
28632
  db.close();
28491
28633
  }
28492
28634
  }
28493
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
+ });
28494
28641
  update({
28495
28642
  step: "done",
28496
28643
  serverPreview: preview,
@@ -28502,14 +28649,44 @@ Make sure this path contains TypeScript/React/Vue component files (.tsx, .ts, .v
28502
28649
  });
28503
28650
  return;
28504
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
+ });
28505
28676
  update({
28506
28677
  step: "preview-gate",
28507
28678
  serverPreview: preview,
28508
- cdf,
28679
+ cdf: cdfToPush,
28680
+ droppedTokenDefaults,
28509
28681
  finalizeErrorBanner: null,
28510
28682
  ...clearedValidationErrorState()
28511
28683
  });
28512
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
+ });
28513
28690
  if (e instanceof ApiError) {
28514
28691
  if (e.status === 401 || e.status === 403) {
28515
28692
  let bodyMsg = "";
@@ -28572,7 +28749,18 @@ If using a custom host configuration, make sure the space exists on that host.`
28572
28749
  }
28573
28750
  };
28574
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;
28575
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
+ });
28576
28764
  update(buildSkippedPushTransition());
28577
28765
  return;
28578
28766
  }
@@ -28580,6 +28768,11 @@ If using a custom host configuration, make sure the space exists on that host.`
28580
28768
  const hasComponentChanges = preview.components.new.length > 0 || preview.components.changed.length > 0 || preview.components.removed.length > 0;
28581
28769
  const hasTokenChanges = preview.tokens.new.length > 0 || preview.tokens.changed.length > 0 || preview.tokens.removed.length > 0;
28582
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
+ });
28583
28776
  update({
28584
28777
  step: "done",
28585
28778
  pushResult: {
@@ -28592,6 +28785,11 @@ If using a custom host configuration, make sure the space exists on that host.`
28592
28785
  }
28593
28786
  const cycles = detectSlotCycles(extractComponents(cdf));
28594
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
+ });
28595
28793
  update({
28596
28794
  step: "error",
28597
28795
  errorStep: "apply",
@@ -28602,6 +28800,11 @@ If using a custom host configuration, make sure the space exists on that host.`
28602
28800
  }
28603
28801
  const unresolvedSlotReferences = validateSlotReferences2(extractComponents(cdf));
28604
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
+ });
28605
28808
  update({
28606
28809
  step: "error",
28607
28810
  errorStep: "apply",
@@ -28611,6 +28814,14 @@ If using a custom host configuration, make sure the space exists on that host.`
28611
28814
  return;
28612
28815
  }
28613
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
+ });
28614
28825
  try {
28615
28826
  const resolvedHost = resolveWizardHost(host2);
28616
28827
  const client2 = new ImportApiClient({
@@ -28620,6 +28831,11 @@ If using a custom host configuration, make sure the space exists on that host.`
28620
28831
  host: resolvedHost
28621
28832
  });
28622
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
+ });
28623
28839
  try {
28624
28840
  logStep({
28625
28841
  applyResponse: {
@@ -28636,9 +28852,15 @@ If using a custom host configuration, make sure the space exists on that host.`
28636
28852
  pushProgress: { kind: "queued", operationId: operation.sys.id }
28637
28853
  });
28638
28854
  let pollCount = 0;
28855
+ let lastPolledStatus = "";
28639
28856
  operation = await client2.pollOperation(operation.sys.id, {
28640
28857
  onProgress: (op) => {
28641
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
+ }
28642
28864
  const s = op.summary;
28643
28865
  if (s) {
28644
28866
  const done = s.total - s.pending;
@@ -28743,6 +28965,29 @@ If using a custom host configuration, make sure the space exists on that host.`
28743
28965
  );
28744
28966
  }
28745
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
+ });
28746
28991
  update({ step: "done", pushResult });
28747
28992
  } catch (e) {
28748
28993
  let msg;
@@ -28753,6 +28998,14 @@ If using a custom host configuration, make sure the space exists on that host.`
28753
28998
  } else {
28754
28999
  msg = "Push failed";
28755
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
+ });
28756
29009
  update({
28757
29010
  step: "error",
28758
29011
  errorStep: "apply",
@@ -28764,7 +29017,7 @@ If using a custom host configuration, make sure the space exists on that host.`
28764
29017
  };
28765
29018
  const runPrintFiles = async (extractSessionId, outDir, opts = {}) => {
28766
29019
  update({ step: "printing" });
28767
- const componentsPath = join20(outDir, "components.json");
29020
+ const componentsPath = join21(outDir, "components.json");
28768
29021
  try {
28769
29022
  const db = openPipelineDb();
28770
29023
  let components = [];
@@ -28867,7 +29120,7 @@ If using a custom host configuration, make sure the space exists on that host.`
28867
29120
  if (tokenReuseChecked.current) return;
28868
29121
  tokenReuseChecked.current = true;
28869
29122
  const tokenNextStep = state.projectPath ? "path-validation" : "credentials";
28870
- const existingTokensPath = join20(state.outDir, "tokens.json");
29123
+ const existingTokensPath = join21(state.outDir, "tokens.json");
28871
29124
  if (effectiveNoCache) {
28872
29125
  tokenGenerationPromiseRef.current = runAgentAuthCheck(tokenNextStep).then(
28873
29126
  (ok2) => ok2 ? runGenerateTokens(state.rawTokensPath, state.outDir) : false
@@ -28918,7 +29171,7 @@ If using a custom host configuration, make sure the space exists on that host.`
28918
29171
  {
28919
29172
  onContinue: (path) => {
28920
29173
  const projectPath = normalizePath(path);
28921
- const outDir = join20(projectPath, ".contentful");
29174
+ const outDir = join21(projectPath, ".contentful");
28922
29175
  update({ step: "token-input", projectPath, outDir });
28923
29176
  },
28924
29177
  onQuit: () => process.exit(0)
@@ -29280,6 +29533,7 @@ If using a custom host configuration, make sure the space exists on that host.`
29280
29533
  environmentId: state.environmentId,
29281
29534
  stepNumber: totalSteps,
29282
29535
  totalSteps,
29536
+ droppedTokenDefaults: state.droppedTokenDefaults,
29283
29537
  onConfirm: (acknowledge) => {
29284
29538
  void runPush(
29285
29539
  state.cdf,
@@ -29416,6 +29670,7 @@ var init_WizardApp = __esm({
29416
29670
  init_theme();
29417
29671
  init_run_teaser();
29418
29672
  init_debug_logger();
29673
+ init_push_debug_log();
29419
29674
  init_credentials_store();
29420
29675
  init_path_prompt();
29421
29676
  init_save_path_resolver();
@@ -29444,6 +29699,8 @@ var init_WizardApp = __esm({
29444
29699
  init_wizard_generate_progress();
29445
29700
  init_spawn_generate();
29446
29701
  init_tokens();
29702
+ init_dangling_token_defaults();
29703
+ init_fetch_existing_token_ids();
29447
29704
  init_preview_utils();
29448
29705
  init_db();
29449
29706
  init_ScopeGateStep();
@@ -29460,7 +29717,7 @@ var init_WizardApp = __esm({
29460
29717
  init_use_terminal_size();
29461
29718
  init_render_with_goodbye();
29462
29719
  SAVE_CONFIRMATION_DELAY_MS = 1e3;
29463
- WIZARD_LOG = join20(tmpdir(), "experiences-import-wizard.log");
29720
+ WIZARD_LOG = join21(tmpdir(), "experiences-import-wizard.log");
29464
29721
  }
29465
29722
  });
29466
29723
 
@@ -29591,7 +29848,7 @@ var init_agent_definitions = __esm({
29591
29848
  });
29592
29849
 
29593
29850
  // packages/experience-design-system-cli-legacy/src/setup/lib/shell.ts
29594
- import { execFile as execFile3, spawn as spawn5 } from "node:child_process";
29851
+ import { execFile as execFile3, spawn as spawn4 } from "node:child_process";
29595
29852
  import { access as access8 } from "node:fs/promises";
29596
29853
  import { promisify as promisify2 } from "node:util";
29597
29854
  async function binaryExists(name) {
@@ -29607,7 +29864,7 @@ async function pathExists3(path) {
29607
29864
  }
29608
29865
  function runSpawn(cmd, args, opts = {}) {
29609
29866
  return new Promise((resolve21) => {
29610
- const child = spawn5(cmd, args, {
29867
+ const child = spawn4(cmd, args, {
29611
29868
  cwd: opts.cwd,
29612
29869
  env: opts.env ?? process.env,
29613
29870
  stdio: ["ignore", "pipe", "pipe"]
@@ -29640,7 +29897,7 @@ var init_shell = __esm({
29640
29897
  });
29641
29898
 
29642
29899
  // packages/experience-design-system-cli-legacy/src/setup/lib/checks.ts
29643
- import { join as join21 } from "node:path";
29900
+ import { join as join22 } from "node:path";
29644
29901
  function checkNodeVersion(nodeVersion = process.versions.node) {
29645
29902
  const major = Number.parseInt(nodeVersion.split(".")[0], 10);
29646
29903
  return {
@@ -29654,7 +29911,7 @@ async function detectNodeVersionManagers(homeDir, deps = {
29654
29911
  binaryExists,
29655
29912
  pathExists: pathExists3
29656
29913
  }) {
29657
- const nvmScript = join21(homeDir, ".nvm", "nvm.sh");
29914
+ const nvmScript = join22(homeDir, ".nvm", "nvm.sh");
29658
29915
  return {
29659
29916
  nvm: await deps.binaryExists("nvm") || await deps.pathExists(nvmScript),
29660
29917
  fnm: await deps.binaryExists("fnm"),
@@ -29733,7 +29990,7 @@ var init_report = __esm({
29733
29990
 
29734
29991
  // packages/experience-design-system-cli-legacy/src/doctor/checks.ts
29735
29992
  import { homedir as homedir7 } from "node:os";
29736
- import { join as join22 } from "node:path";
29993
+ import { join as join23 } from "node:path";
29737
29994
  async function reportNode() {
29738
29995
  section("Checking Node.js version");
29739
29996
  const check = checkNodeVersion();
@@ -29784,12 +30041,12 @@ async function reportPnpm(pkgRoot) {
29784
30041
  }
29785
30042
  async function reportDependencies(pkgRoot) {
29786
30043
  section("Checking dependencies (pnpm install)");
29787
- if (!await pathExists3(join22(pkgRoot, "node_modules"))) {
30044
+ if (!await pathExists3(join23(pkgRoot, "node_modules"))) {
29788
30045
  info("node_modules not found \u2014 running pnpm install...");
29789
30046
  } else {
29790
30047
  info("Running pnpm install to ensure dependencies are up to date...");
29791
30048
  }
29792
- const check = await installDependencies(join22(pkgRoot, "..", ".."));
30049
+ const check = await installDependencies(join23(pkgRoot, "..", ".."));
29793
30050
  if (!check.passed) {
29794
30051
  fail("pnpm install failed");
29795
30052
  info("");
@@ -29806,7 +30063,7 @@ async function reportDependencies(pkgRoot) {
29806
30063
  async function reportBuild(pkgRoot) {
29807
30064
  section("Building CLI");
29808
30065
  info("Running pnpm build...");
29809
- const check = await buildCli(join22(pkgRoot, "..", ".."));
30066
+ const check = await buildCli(join23(pkgRoot, "..", ".."));
29810
30067
  if (!check.passed) {
29811
30068
  fail("Build failed");
29812
30069
  info("");
@@ -31021,9 +31278,9 @@ var init_SetupScreen = __esm({
31021
31278
 
31022
31279
  // packages/experience-design-system-cli-legacy/src/setup/command.ts
31023
31280
  import { readFileSync as readFileSync8 } from "node:fs";
31024
- import { join as join23 } from "node:path";
31281
+ import { join as join24 } from "node:path";
31025
31282
  function getCliVersion() {
31026
- const pkg4 = JSON.parse(readFileSync8(join23(findPkgRoot(), "package.json"), "utf8"));
31283
+ const pkg4 = JSON.parse(readFileSync8(join24(findPkgRoot(), "package.json"), "utf8"));
31027
31284
  return pkg4.version;
31028
31285
  }
31029
31286
  async function runSetup(opts) {
@@ -31035,7 +31292,7 @@ async function runSetup(opts) {
31035
31292
  const { renderWithGoodbye: renderWithGoodbye2 } = await Promise.resolve().then(() => (init_render_with_goodbye(), render_with_goodbye_exports));
31036
31293
  const { createElement: createElement6 } = await import("react");
31037
31294
  const { SetupScreen: SetupScreen2 } = await Promise.resolve().then(() => (init_SetupScreen(), SetupScreen_exports));
31038
- const repoRoot = join23(findPkgRoot(), "..", "..");
31295
+ const repoRoot = join24(findPkgRoot(), "..", "..");
31039
31296
  const completion = { outcome: null };
31040
31297
  let unmountInk = null;
31041
31298
  const { waitUntilExit, unmount } = renderWithGoodbye2(
@@ -31236,15 +31493,15 @@ var init_apply_mapping = __esm({
31236
31493
  });
31237
31494
 
31238
31495
  // packages/experience-design-system-cli-legacy/src/analyze/composition/prompt-loader.ts
31239
- import { existsSync as existsSync7, readFileSync as readFileSync9 } from "node:fs";
31240
- 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";
31241
31498
  import { fileURLToPath as fileURLToPath3 } from "node:url";
31242
31499
  function resolvePromptPath(fileName) {
31243
31500
  const thisDir = dirname11(fileURLToPath3(import.meta.url));
31244
31501
  let dir = thisDir;
31245
31502
  for (; ; ) {
31246
- const candidate = join24(dir, "prompts");
31247
- if (existsSync7(candidate)) return join24(candidate, fileName);
31503
+ const candidate = join25(dir, "prompts");
31504
+ if (existsSync8(candidate)) return join25(candidate, fileName);
31248
31505
  const parent = resolve18(dir, "..");
31249
31506
  if (parent === dir) {
31250
31507
  throw new Error(
@@ -31512,7 +31769,7 @@ var init_manifest_doc_evidence = __esm({
31512
31769
 
31513
31770
  // packages/experience-design-system-cli-legacy/src/analyze/extract-command.ts
31514
31771
  import { mkdir as mkdir6, readdir as readdir3, readFile as readFile18, stat as stat6 } from "node:fs/promises";
31515
- 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";
31516
31773
  function resolveExtractNoCache(opts) {
31517
31774
  return opts.noCache === true || opts.cache === false;
31518
31775
  }
@@ -31550,7 +31807,7 @@ async function collectSourceFiles(directory, onProgress) {
31550
31807
  const entries = await readdir3(currentDirectory, { withFileTypes: true });
31551
31808
  const subdirs = [];
31552
31809
  for (const entry of entries) {
31553
- const fullPath = join25(currentDirectory, entry.name);
31810
+ const fullPath = join26(currentDirectory, entry.name);
31554
31811
  if (entry.isDirectory()) {
31555
31812
  if (!IGNORED_DIRECTORY_NAMES.has(entry.name)) {
31556
31813
  subdirs.push(fullPath);
@@ -31634,7 +31891,7 @@ function registerInternalExtractCommand(program) {
31634
31891
  }
31635
31892
  }
31636
31893
  const projectRoot = resolve19(opts.project);
31637
- const outDir = join25(projectRoot, ".contentful");
31894
+ const outDir = join26(projectRoot, ".contentful");
31638
31895
  let sourceDirectory;
31639
31896
  if (opts.dir !== void 0) {
31640
31897
  sourceDirectory = resolveFromProjectRoot(projectRoot, opts.dir);
@@ -32037,9 +32294,9 @@ __export(program_exports, {
32037
32294
  resolveBedrockFromAncestors: () => resolveBedrockFromAncestors,
32038
32295
  runBuild: () => runBuild
32039
32296
  });
32040
- import { spawn as spawn6 } from "node:child_process";
32297
+ import { spawn as spawn5 } from "node:child_process";
32041
32298
  import { fileURLToPath as fileURLToPath4 } from "node:url";
32042
- 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";
32043
32300
  import { readFileSync as readFileSync10 } from "node:fs";
32044
32301
  import { Command } from "commander";
32045
32302
  async function runBuild(opts) {
@@ -32072,7 +32329,7 @@ function registerBuildCommand(program) {
32072
32329
  const pkgRoot = resolve20(dirname13(fileURLToPath4(import.meta.url)), "..", "..");
32073
32330
  process.stderr.write("\u2699 Building from source...\n");
32074
32331
  const { exitCode } = await runBuild({
32075
- spawnFn: () => spawn6("pnpm", ["build"], { cwd: pkgRoot, stdio: "inherit" }),
32332
+ spawnFn: () => spawn5("pnpm", ["build"], { cwd: pkgRoot, stdio: "inherit" }),
32076
32333
  stderrWrite: (s) => process.stderr.write(s)
32077
32334
  });
32078
32335
  process.exit(exitCode);
@@ -32139,7 +32396,7 @@ var init_program = __esm({
32139
32396
  init_analytics();
32140
32397
  init_credentials_store();
32141
32398
  init_cli_path();
32142
- pkg3 = JSON.parse(readFileSync10(join26(findPkgRoot(), "package.json"), "utf8"));
32399
+ pkg3 = JSON.parse(readFileSync10(join27(findPkgRoot(), "package.json"), "utf8"));
32143
32400
  }
32144
32401
  });
32145
32402