@contentful/experience-design-system-cli 2.35.1-dev-build-45d6c918.0 → 2.36.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app.js +189 -227
- package/dist/index.js +200 -242
- package/dist/package.json +1 -1
- package/legacy/dist/src/index.js +668 -867
- package/legacy/package.json +1 -1
- package/package.json +2 -2
package/legacy/dist/src/index.js
CHANGED
|
@@ -164,506 +164,272 @@ var init_render_with_goodbye = __esm({
|
|
|
164
164
|
function isAgentName(value) {
|
|
165
165
|
return AGENT_NAMES.includes(value);
|
|
166
166
|
}
|
|
167
|
-
var AGENT_NAMES, DEFAULT_AGENT_NAME
|
|
167
|
+
var AGENT_NAMES, DEFAULT_AGENT_NAME;
|
|
168
168
|
var init_agent_names = __esm({
|
|
169
169
|
"packages/experience-design-system-generation/dist/src/agent-names.js"() {
|
|
170
170
|
"use strict";
|
|
171
171
|
AGENT_NAMES = ["claude", "codex", "opencode", "cursor", "copilot"];
|
|
172
172
|
DEFAULT_AGENT_NAME = "claude";
|
|
173
|
-
AGENT_BINARIES = {
|
|
174
|
-
claude: "claude",
|
|
175
|
-
codex: "codex",
|
|
176
|
-
opencode: "opencode",
|
|
177
|
-
cursor: "cursor-agent",
|
|
178
|
-
copilot: "copilot"
|
|
179
|
-
};
|
|
180
|
-
}
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
// packages/experience-design-system-generation/dist/src/controller/helpers/validate-generation-request.js
|
|
184
|
-
function validateGenerationRequest(request2) {
|
|
185
|
-
if (request2 === null || typeof request2 !== "object") {
|
|
186
|
-
throw new TypeError("createGenerationEndpoint requires a request object");
|
|
187
|
-
}
|
|
188
|
-
if (!isAgentName(request2.agent)) {
|
|
189
|
-
throw new TypeError(`createGenerationEndpoint requires agent to be a valid agent name, got: ${String(request2.agent)}`);
|
|
190
|
-
}
|
|
191
|
-
if (typeof request2.timeoutMs !== "number" || request2.timeoutMs <= 0) {
|
|
192
|
-
throw new TypeError("createGenerationEndpoint requires timeoutMs to be a positive number");
|
|
193
|
-
}
|
|
194
|
-
if (request2.promptOptions === null || typeof request2.promptOptions !== "object") {
|
|
195
|
-
throw new TypeError("createGenerationEndpoint requires promptOptions to be an object");
|
|
196
|
-
}
|
|
197
|
-
if (request2.onOutput !== void 0 && typeof request2.onOutput !== "function") {
|
|
198
|
-
throw new TypeError("createGenerationEndpoint requires onOutput to be a function when provided");
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
var init_validate_generation_request = __esm({
|
|
202
|
-
"packages/experience-design-system-generation/dist/src/controller/helpers/validate-generation-request.js"() {
|
|
203
|
-
"use strict";
|
|
204
|
-
init_agent_names();
|
|
205
173
|
}
|
|
206
174
|
});
|
|
207
175
|
|
|
208
|
-
// packages/experience-design-system-generation/dist/src/
|
|
209
|
-
import {
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
if (
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
176
|
+
// packages/experience-design-system-generation/dist/src/agent-runner.js
|
|
177
|
+
import { spawn } from "node:child_process";
|
|
178
|
+
function findJsonObjectEnd(line) {
|
|
179
|
+
let depth = 0;
|
|
180
|
+
let inString = false;
|
|
181
|
+
let escaped = false;
|
|
182
|
+
for (let i = 0; i < line.length; i++) {
|
|
183
|
+
const ch = line[i];
|
|
184
|
+
if (escaped) {
|
|
185
|
+
escaped = false;
|
|
186
|
+
} else if (ch === "\\" && inString) {
|
|
187
|
+
escaped = true;
|
|
188
|
+
} else if (ch === '"') {
|
|
189
|
+
inString = !inString;
|
|
190
|
+
} else if (!inString && ch === "{") {
|
|
191
|
+
depth++;
|
|
192
|
+
} else if (!inString && ch === "}" && --depth === 0) {
|
|
193
|
+
return i;
|
|
225
194
|
}
|
|
226
|
-
dir = parent;
|
|
227
195
|
}
|
|
196
|
+
return -1;
|
|
228
197
|
}
|
|
229
|
-
function
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
198
|
+
function readToolCallObjects(stdout) {
|
|
199
|
+
const objects = [];
|
|
200
|
+
const warnings = [];
|
|
201
|
+
for (const raw of stdout.split("\n")) {
|
|
202
|
+
const line = raw.trim();
|
|
203
|
+
if (!line.startsWith("{"))
|
|
204
|
+
continue;
|
|
205
|
+
const end = findJsonObjectEnd(line);
|
|
206
|
+
if (end === -1) {
|
|
207
|
+
warnings.push(`unparseable line: ${line.slice(0, 120)}`);
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
210
|
+
let parsed;
|
|
238
211
|
try {
|
|
239
|
-
|
|
212
|
+
parsed = JSON.parse(line.slice(0, end + 1));
|
|
240
213
|
} catch {
|
|
241
|
-
|
|
214
|
+
warnings.push(`unparseable line: ${line.slice(0, 120)}`);
|
|
215
|
+
continue;
|
|
216
|
+
}
|
|
217
|
+
const trailing = line.slice(end + 1);
|
|
218
|
+
if (trailing.trim()) {
|
|
219
|
+
warnings.push(`ignored trailing content after JSON: ${trailing.trim().slice(0, 120)}`);
|
|
220
|
+
}
|
|
221
|
+
if (typeof parsed === "object" && parsed !== null && "tool" in parsed) {
|
|
222
|
+
objects.push(parsed);
|
|
242
223
|
}
|
|
243
224
|
}
|
|
244
|
-
|
|
245
|
-
try {
|
|
246
|
-
return await readFile2(skillPath, "utf8");
|
|
247
|
-
} catch {
|
|
248
|
-
throw new Error(`skill file missing from CLI installation \u2014 try reinstalling the CLI (looked for: ${skillPath})`);
|
|
249
|
-
}
|
|
225
|
+
return { objects, warnings };
|
|
250
226
|
}
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
227
|
+
function parseSelectToolCallLines(stdout) {
|
|
228
|
+
const calls = [];
|
|
229
|
+
const { objects, warnings } = readToolCallObjects(stdout);
|
|
230
|
+
for (const rec of objects) {
|
|
231
|
+
if (!VALID_SELECT_TOOL_NAMES.has(rec.tool))
|
|
232
|
+
continue;
|
|
233
|
+
if (typeof rec.name !== "string" || !rec.name) {
|
|
234
|
+
warnings.push(`${String(rec.tool)} missing name \u2014 skipped`);
|
|
235
|
+
continue;
|
|
236
|
+
}
|
|
237
|
+
const call = {
|
|
238
|
+
tool: rec.tool,
|
|
239
|
+
name: rec.name
|
|
260
240
|
};
|
|
241
|
+
if (typeof rec.reason === "string")
|
|
242
|
+
call.reason = rec.reason;
|
|
243
|
+
if (typeof rec.confidence === "number" && rec.confidence >= 1 && rec.confidence <= 5) {
|
|
244
|
+
if (call.tool === "select_component") {
|
|
245
|
+
call.confidence = rec.confidence;
|
|
246
|
+
} else {
|
|
247
|
+
call.confidence = rec.confidence;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
calls.push(call);
|
|
261
251
|
}
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
// packages/experience-design-system-generation/dist/src/services/prompts/helpers/format-token-candidates.js
|
|
265
|
-
import { flattenDTCG } from "@contentful/experience-design-system-types";
|
|
266
|
-
function inferFenceLang(filename) {
|
|
267
|
-
if (!filename)
|
|
268
|
-
return "json";
|
|
269
|
-
const ext = filename.split(".").pop()?.toLowerCase() ?? "";
|
|
270
|
-
const map = {
|
|
271
|
-
js: "js",
|
|
272
|
-
mjs: "js",
|
|
273
|
-
cjs: "js",
|
|
274
|
-
ts: "ts",
|
|
275
|
-
mts: "ts",
|
|
276
|
-
cts: "ts",
|
|
277
|
-
tsx: "tsx",
|
|
278
|
-
jsx: "jsx",
|
|
279
|
-
vue: "vue",
|
|
280
|
-
svelte: "svelte",
|
|
281
|
-
astro: "astro",
|
|
282
|
-
scss: "scss",
|
|
283
|
-
sass: "scss",
|
|
284
|
-
css: "css",
|
|
285
|
-
json: "json",
|
|
286
|
-
json5: "json"
|
|
287
|
-
};
|
|
288
|
-
return map[ext] ?? "text";
|
|
252
|
+
return { calls, warnings };
|
|
289
253
|
}
|
|
290
|
-
function
|
|
291
|
-
const
|
|
292
|
-
const
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
if (!properties)
|
|
254
|
+
function parseToolCallLines(stdout) {
|
|
255
|
+
const calls = [];
|
|
256
|
+
const { objects, warnings } = readToolCallObjects(stdout);
|
|
257
|
+
for (const rec of objects) {
|
|
258
|
+
if (!VALID_TOOL_NAMES.has(rec.tool)) {
|
|
259
|
+
warnings.push(`unknown tool: ${String(rec.tool)}`);
|
|
297
260
|
continue;
|
|
298
|
-
const filteredProps = {};
|
|
299
|
-
for (const [propName, prop] of Object.entries(properties)) {
|
|
300
|
-
if (prop.$type === "token" && prop.$category === "design") {
|
|
301
|
-
const { "$token.allowed": _tokenAllowed, ...rest } = prop;
|
|
302
|
-
filteredProps[propName] = rest;
|
|
303
|
-
const kind = prop["$token.kind"];
|
|
304
|
-
if (typeof kind === "string" && kind.length > 0) {
|
|
305
|
-
kinds.add(kind);
|
|
306
|
-
} else {
|
|
307
|
-
hasUnscoped = true;
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
261
|
}
|
|
311
|
-
|
|
312
|
-
|
|
262
|
+
const tool = rec.tool;
|
|
263
|
+
if (tool === "classify_prop") {
|
|
264
|
+
if (typeof rec.prop !== "string" || !rec.prop) {
|
|
265
|
+
warnings.push("classify_prop missing prop name \u2014 skipped");
|
|
266
|
+
continue;
|
|
267
|
+
}
|
|
268
|
+
if (typeof rec.cdf_type !== "string" || !VALID_CDF_TYPES.has(rec.cdf_type)) {
|
|
269
|
+
warnings.push(`classify_prop '${rec.prop}': invalid cdf_type '${String(rec.cdf_type)}' \u2014 skipped`);
|
|
270
|
+
continue;
|
|
271
|
+
}
|
|
272
|
+
if (typeof rec.cdf_category !== "string" || !VALID_CATEGORIES.has(rec.cdf_category)) {
|
|
273
|
+
warnings.push(`classify_prop '${rec.prop}': invalid cdf_category '${String(rec.cdf_category)}' \u2014 skipped`);
|
|
274
|
+
continue;
|
|
275
|
+
}
|
|
276
|
+
const call = {
|
|
277
|
+
tool: "classify_prop",
|
|
278
|
+
prop: rec.prop,
|
|
279
|
+
cdf_type: rec.cdf_type,
|
|
280
|
+
cdf_category: rec.cdf_category
|
|
281
|
+
};
|
|
282
|
+
if (Array.isArray(rec.values) && rec.values.every((v) => typeof v === "string")) {
|
|
283
|
+
call.values = rec.values;
|
|
284
|
+
}
|
|
285
|
+
if (typeof rec.token_kind === "string")
|
|
286
|
+
call.token_kind = rec.token_kind;
|
|
287
|
+
if (typeof rec.required === "boolean")
|
|
288
|
+
call.required = rec.required;
|
|
289
|
+
if (typeof rec.description === "string")
|
|
290
|
+
call.description = rec.description;
|
|
291
|
+
if (typeof rec.default === "string" || typeof rec.default === "boolean")
|
|
292
|
+
call.default = rec.default;
|
|
293
|
+
if (typeof rec.reason === "string")
|
|
294
|
+
call.reason = rec.reason;
|
|
295
|
+
calls.push(call);
|
|
296
|
+
} else if (tool === "exclude_prop") {
|
|
297
|
+
if (typeof rec.prop !== "string" || !rec.prop) {
|
|
298
|
+
warnings.push("exclude_prop missing prop name \u2014 skipped");
|
|
299
|
+
continue;
|
|
300
|
+
}
|
|
301
|
+
calls.push({
|
|
302
|
+
tool: "exclude_prop",
|
|
303
|
+
prop: rec.prop,
|
|
304
|
+
reason: typeof rec.reason === "string" ? rec.reason : ""
|
|
305
|
+
});
|
|
306
|
+
} else if (tool === "classify_component") {
|
|
307
|
+
const call = { tool: "classify_component" };
|
|
308
|
+
if (typeof rec.description === "string")
|
|
309
|
+
call.description = rec.description;
|
|
310
|
+
if (typeof rec.rationale === "object" && rec.rationale !== null) {
|
|
311
|
+
const r = rec.rationale;
|
|
312
|
+
const rationale = {};
|
|
313
|
+
if (typeof r.description === "string")
|
|
314
|
+
rationale.description = r.description;
|
|
315
|
+
if (typeof r.props === "string")
|
|
316
|
+
rationale.props = r.props;
|
|
317
|
+
if (typeof r.slots === "string")
|
|
318
|
+
rationale.slots = r.slots;
|
|
319
|
+
if (Object.keys(rationale).length > 0)
|
|
320
|
+
call.rationale = rationale;
|
|
321
|
+
}
|
|
322
|
+
calls.push(call);
|
|
323
|
+
} else if (tool === "classify_slot") {
|
|
324
|
+
if (typeof rec.slot !== "string" || !rec.slot) {
|
|
325
|
+
warnings.push("classify_slot missing slot name \u2014 skipped");
|
|
326
|
+
continue;
|
|
327
|
+
}
|
|
328
|
+
const call = { tool: "classify_slot", slot: rec.slot };
|
|
329
|
+
if (typeof rec.required === "boolean")
|
|
330
|
+
call.required = rec.required;
|
|
331
|
+
if (Array.isArray(rec.allowed_components) && rec.allowed_components.every((v) => typeof v === "string")) {
|
|
332
|
+
call.allowed_components = rec.allowed_components;
|
|
333
|
+
}
|
|
334
|
+
if (typeof rec.description === "string")
|
|
335
|
+
call.description = rec.description;
|
|
336
|
+
if (typeof rec.rationale === "string")
|
|
337
|
+
call.rationale = rec.rationale;
|
|
338
|
+
calls.push(call);
|
|
313
339
|
}
|
|
314
340
|
}
|
|
315
|
-
return {
|
|
316
|
-
}
|
|
317
|
-
function buildTokenCandidateSections(tokenTree, filteredTokenProps) {
|
|
318
|
-
const index = flattenDTCG(tokenTree, "").sort((a, b) => a.path.localeCompare(b.path));
|
|
319
|
-
if (index.length === 0)
|
|
320
|
-
return [];
|
|
321
|
-
const sections = [];
|
|
322
|
-
const renderSection = (kind, entries) => {
|
|
323
|
-
const label = kind ? `Token path index \u2014 ${kind} candidates only` : "Token path index \u2014 full tree (no $token.kind to scope by)";
|
|
324
|
-
const lines = entries.map((e) => `${e.path} \xB7 ${e.$type}`).join("\n");
|
|
325
|
-
return `${label}, one leaf token per line as \`path \xB7 type\`, no \`$value\`:
|
|
326
|
-
${lines}`;
|
|
327
|
-
};
|
|
328
|
-
if (filteredTokenProps) {
|
|
329
|
-
const { kinds, hasUnscoped } = filteredTokenProps;
|
|
330
|
-
for (const kind of kinds) {
|
|
331
|
-
const scoped = index.filter((e) => e.$type === kind);
|
|
332
|
-
if (scoped.length > 0)
|
|
333
|
-
sections.push(renderSection(kind, scoped));
|
|
334
|
-
}
|
|
335
|
-
if (hasUnscoped)
|
|
336
|
-
sections.push(renderSection(null, index));
|
|
337
|
-
} else {
|
|
338
|
-
sections.push(renderSection(null, index));
|
|
339
|
-
}
|
|
340
|
-
return sections;
|
|
341
|
+
return { calls, warnings };
|
|
341
342
|
}
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
${withContent.map(formatSourceRefBlock).join("\n\n")}`);
|
|
376
|
-
}
|
|
377
|
-
if (withoutContent.length > 0) {
|
|
378
|
-
const guidance = skill === "components" ? "there is no consumption evidence for these, so `token` cannot be earned for any of their props \u2014 classify from the prop signature alone, and any prop that would otherwise be enum-versus-token is `enum` (or `string`)" : "there is no source evidence to narrow from \u2014 emit nothing for their props";
|
|
379
|
-
sections.push(`Component source unavailable for (JSON) \u2014 ${guidance}:
|
|
380
|
-
\`\`\`json
|
|
381
|
-
${JSON.stringify(withoutContent.map((ref) => ({ component: ref.component, sourcePath: ref.sourcePath })))}
|
|
382
|
-
\`\`\``);
|
|
383
|
-
}
|
|
384
|
-
return sections;
|
|
385
|
-
}
|
|
386
|
-
var init_format_source_refs = __esm({
|
|
387
|
-
"packages/experience-design-system-generation/dist/src/services/prompts/helpers/format-source-refs.js"() {
|
|
388
|
-
"use strict";
|
|
389
|
-
init_format_token_candidates();
|
|
390
|
-
}
|
|
391
|
-
});
|
|
392
|
-
|
|
393
|
-
// packages/experience-design-system-generation/dist/src/services/prompts/helpers/build-skill-preambles.js
|
|
394
|
-
function buildComponentsAutonomousPreamble(inputBlock) {
|
|
395
|
-
return `You are running as part of the experience-design-system-cli generate pipeline in AUTONOMOUS mode. The developer is not present to answer questions.
|
|
396
|
-
|
|
397
|
-
Context: You are classifying a React component for **Contentful Experience Orchestration**. The result is a Component Type \u2014 a schema that tells Contentful what a marketer can configure. Properties fall into three categories:
|
|
398
|
-
- **design**: controls how the component looks (variant, size, color, layout toggles)
|
|
399
|
-
- **content**: the data a content editor fills in (text, images, URLs, rich text)
|
|
400
|
-
- **state**: runtime behavioral flags (disabled, loading, expanded, identifiers)
|
|
401
|
-
|
|
402
|
-
Your task: classify every prop and slot in the component below. Apply all judgment calls yourself \u2014 do not pause to ask for confirmation. Include a "description" field on each tool call to document your reasoning so the developer can review it afterward.
|
|
403
|
-
|
|
404
|
-
All input data is provided inline below \u2014 do not read any additional files.${inputBlock}
|
|
405
|
-
|
|
406
|
-
## Output protocol
|
|
407
|
-
|
|
408
|
-
Do NOT write any files or emit any JSON blobs. Instead, emit one JSON object per line to stdout for each classification decision. The CLI reads your stdout line by line and writes each decision directly to the pipeline database.
|
|
409
|
-
|
|
410
|
-
The four tool calls you may emit are:
|
|
411
|
-
|
|
412
|
-
\`\`\`
|
|
413
|
-
{"tool":"classify_component","description":"<optional component-level description>","rationale":{"description":"<why this component is classified the way it is>","props":"<why these props were chosen>","slots":"<why these slots were chosen>"}}
|
|
414
|
-
|
|
415
|
-
{"tool":"classify_prop","prop":"<propName>","cdf_type":"<type>","cdf_category":"<category>","required":<bool>,"description":"<short customer-facing description>","reason":"<full internal rationale; not customer-facing>","values":["a","b"],"token_kind":"color","default":"<value>"}
|
|
416
|
-
|
|
417
|
-
{"tool":"exclude_prop","prop":"<propName>","reason":"<why excluded>"}
|
|
418
|
-
|
|
419
|
-
{"tool":"classify_slot","slot":"<slotName>","required":<bool>,"allowed_components":["ComponentName"],"description":"<reason>","rationale":"<why this slot was kept in the catalog>"}
|
|
420
|
-
\`\`\`
|
|
421
|
-
|
|
422
|
-
Rules:
|
|
423
|
-
- Emit exactly one JSON object per line. No multi-line JSON. No markdown fences around the lines.
|
|
424
|
-
- Every prop in the input must have exactly one call: either classify_prop or exclude_prop.
|
|
425
|
-
- Every slot in the input must have exactly one classify_slot call.
|
|
426
|
-
- Valid cdf_type values: string, richtext, media, enum, token, boolean
|
|
427
|
-
- Valid cdf_category values: content, design, state
|
|
428
|
-
- For enum type, always include \`values\` (non-empty string array of the variant names the prop accepts).
|
|
429
|
-
- For token type, always include \`token_kind\` (DTCG $type, e.g. "color"). **Never emit \`values\` for \`cdf_type: "token"\` props** \u2014 an enum prop's list holds variant names; a token prop's list holds design token paths, produced separately and never by you. Emitting \`values\` on a token prop makes the definition invalid.
|
|
430
|
-
- Never emit both "values" and "token_kind" on one prop.
|
|
431
|
-
- \`enum\` vs \`token\` is decided by three questions answered in order from the source shown \u2014 never from the TypeScript type. Q1: does the component look the value up, switch on it, or have a vocabulary for it (\`tokens[x]\`, \`switch (variant)\`, \`allowedValues\`)? yes \u2192 \`enum\`, stop.
|
|
432
|
-
- Q2: is the value written straight into a style or attribute (\`rx={radius}\`, \`padding: \${padding}\`)? no \u2192 not \`token\`, apply the type rules.
|
|
433
|
-
- Q3: is there a design-token reference at that use \u2014 a \`tokens.*\` parameter default, a \`tokenReference\`, an inline \`tokens.*\` / \`var(--*)\`? yes \u2192 \`token\` (cite both lines in "reason"); no \u2192 \`string\`. "Ambiguity resolves to \`enum\`" applies only when Q1\u2013Q3 cannot be answered from the source shown.
|
|
434
|
-
- CSS design props (className, style, styles, positional/geometric props: top, bottom, left, right, rotation, offset, etc.) \u2192 classify_prop, cdf_type: "string", cdf_category: "design".
|
|
435
|
-
- For \`classify_slot.allowed_components\`, use only exact names from the hard allowlist provided below. Never invent a child from an import, JSX element, type name, icon name, or implementation helper; if a child is not listed, omit it.
|
|
436
|
-
- On classify_component, "rationale" fields are operator-facing (read-only) but may surface in customer-facing exports. The "rationale.description" field is subject to the description content rules in the skill prompt (no internal initiative names). "rationale.props" and "rationale.slots" describe your reasoning about scope; "classify_slot.rationale" explains why each slot was kept.
|
|
437
|
-
- On classify_prop, "reason" is REQUIRED and is the LLM's internal rationale \u2014 shown to the developer reviewing the import, never to end-users. "description" is the customer-facing copy and is subject to the description content rules in the skill prompt. Keep them distinct: "description" is short and customer-facing; "reason" explains your reasoning in detail.
|
|
438
|
-
- You may emit prose lines (not starting with {) anywhere \u2014 they are ignored by the parser and serve as your reasoning log.`;
|
|
439
|
-
}
|
|
440
|
-
function buildSelectAutonomousPreamble(inputBlock) {
|
|
441
|
-
return `You are running as part of the experience-design-system-cli import pipeline in AUTONOMOUS mode. The developer is not present to answer questions.
|
|
442
|
-
|
|
443
|
-
Your task: review the components provided below and decide whether each belongs in Contentful Experience Orchestration as a Component Type. The input is a JSON array \u2014 you may receive 1\u2013N components in a single message. Emit one tool call per input component, named after the component. Apply all judgment calls yourself \u2014 do not pause to ask for confirmation. Include a brief "reason" to document your reasoning for each decision.
|
|
444
|
-
|
|
445
|
-
Key rule: accept any component that renders visible UI \u2014 atoms, molecules, and organisms are all valid Component Types in Contentful Experience Orchestration. Reject only components that produce zero visual output: React hooks, pure context providers, A/B testing or variant-routing wrappers, analytics trackers, and security utilities. Do NOT reject a component because it has few props, is low-level, or has some A/B testing or personalization-related props mixed in \u2014 those props are handled in the generate step.
|
|
446
|
-
|
|
447
|
-
All input data is provided inline below \u2014 do not read any additional files.${inputBlock}
|
|
448
|
-
|
|
449
|
-
## Output protocol
|
|
450
|
-
|
|
451
|
-
Do NOT write any files or emit any JSON blobs. Instead, emit JSON tool calls one per line to stdout. The CLI reads your stdout line by line.
|
|
452
|
-
|
|
453
|
-
The two tool calls \u2014 emit exactly one per input component:
|
|
454
|
-
|
|
455
|
-
\`\`\`
|
|
456
|
-
{"tool":"select_component","name":"<ComponentName>","reason":"<brief reason>"}
|
|
457
|
-
|
|
458
|
-
{"tool":"reject_component","name":"<ComponentName>","reason":"<brief reason>"}
|
|
459
|
-
\`\`\`
|
|
460
|
-
|
|
461
|
-
Rules:
|
|
462
|
-
- Emit exactly one JSON object per line. No multi-line JSON. No markdown fences.
|
|
463
|
-
- Emit exactly one tool call per input component. The "name" field must match a component name from the input array exactly. Tool calls may appear in any order.
|
|
464
|
-
- You may emit prose lines (not starting with {) to reason before each tool call \u2014 they are ignored by the parser.`;
|
|
465
|
-
}
|
|
466
|
-
function buildMapTokensAutonomousPreamble(inputBlock) {
|
|
467
|
-
return `You are running as part of the experience-design-system-cli generate pipeline in AUTONOMOUS mode. The developer is not present to answer questions.
|
|
468
|
-
|
|
469
|
-
Context: The components below already have design-category, token-typed props (\`$token.kind\` set). Your task is to decide, from source evidence, whether to narrow each one to a restricted subset (\`token_allowed\`) of the tokens matching its \`$token.kind\`. Apply all judgment calls yourself \u2014 do not pause to ask for confirmation.
|
|
470
|
-
|
|
471
|
-
All input data is provided inline below \u2014 do not read any additional files.${inputBlock}
|
|
472
|
-
|
|
473
|
-
## Output protocol
|
|
474
|
-
|
|
475
|
-
Do NOT write any files or emit any JSON blobs. Instead, emit one JSON object per line to stdout for each prop you narrow. The CLI reads your stdout line by line and writes each decision directly to the pipeline database.
|
|
476
|
-
|
|
477
|
-
The one tool call you may emit:
|
|
478
|
-
|
|
479
|
-
\`\`\`
|
|
480
|
-
{"tool":"map_token_prop","component":"<ComponentName>","prop":"<propName>","token_allowed":["colors.brand.primary","colors.brand.secondary"]}
|
|
481
|
-
\`\`\`
|
|
482
|
-
|
|
483
|
-
Rules:
|
|
484
|
-
- Emit exactly one JSON object per line. No multi-line JSON. No markdown fences around the lines.
|
|
485
|
-
- Only emit a call for a prop that appears in the "Generated CDF so far" section.
|
|
486
|
-
- Each "Token path index" section below is already scoped to one \`$token.kind\` \u2014 a prop only draws candidates from the section matching its own \`$token.kind\` (or the "full tree" section, for a prop with no \`$token.kind\`). Never cross sections, never emit a group/prefix path, and never invent a path \u2014 every entry in \`token_allowed\` must exist verbatim in the matching section.
|
|
487
|
-
- \`token_allowed\` is required and must be non-empty when the call is emitted.
|
|
488
|
-
- For the judgment call of whether a prop should be narrowed at all, follow the decision tree in the map-tokens skill file: it explains defaults vs. restrictions, misclassified variant-name props, and when to emit nothing.
|
|
489
|
-
- You may emit prose lines (not starting with \`{\`) anywhere \u2014 they are ignored by the parser and serve as your reasoning log.`;
|
|
490
|
-
}
|
|
491
|
-
function buildTokensAutonomousPreamble(inputBlock) {
|
|
492
|
-
return `You are running as part of the experience-design-system-cli generate pipeline in AUTONOMOUS mode. The developer is not present to answer questions.
|
|
493
|
-
|
|
494
|
-
Your task: classify every raw token from the input below into a DTCG token tree. Apply all judgment calls yourself \u2014 do not pause to ask for confirmation. Include a "description" field on each set_token call to document your reasoning.
|
|
495
|
-
|
|
496
|
-
All input data is provided inline below \u2014 do not read any additional files.${inputBlock}
|
|
497
|
-
|
|
498
|
-
## Output protocol
|
|
499
|
-
|
|
500
|
-
Do NOT write any files or emit any JSON blobs. Instead, emit one JSON object per line to stdout for each token or group. The CLI reads your stdout line by line and writes each entry directly to the pipeline database.
|
|
501
|
-
|
|
502
|
-
The two tool calls you may emit are:
|
|
503
|
-
|
|
504
|
-
\`\`\`
|
|
505
|
-
{"tool":"set_group","path":"<dot.notation.path>","description":"<optional group description>"}
|
|
506
|
-
|
|
507
|
-
{"tool":"set_token","path":"<dot.notation.path>","type":"<DTCG type>","value":<value>,"description":"<reason>"}
|
|
508
|
-
\`\`\`
|
|
509
|
-
|
|
510
|
-
Rules:
|
|
511
|
-
- Emit exactly one JSON object per line. No multi-line JSON. No markdown fences.
|
|
512
|
-
- Emit a set_group call for every intermediate group node in the tree.
|
|
513
|
-
- Emit a set_token call for every leaf token.
|
|
514
|
-
- "path" is dot-notation, e.g. "colors.brand.primary" \u2014 no leading dots or slashes.
|
|
515
|
-
- "type" must be one of the 13 valid DTCG types: color, dimension, fontFamily, fontWeight, duration, cubicBezier, number, strokeStyle, border, transition, shadow, gradient, typography.
|
|
516
|
-
- "value" must be valid JSON (string, number, array, or object depending on the type). Do NOT wrap it in quotes if it is a complex type.
|
|
517
|
-
- Emit set_group calls before the set_token calls that fall under them.
|
|
518
|
-
- You may emit prose lines (not starting with {) anywhere \u2014 they are ignored by the parser and serve as your reasoning log.`;
|
|
519
|
-
}
|
|
520
|
-
var init_build_skill_preambles = __esm({
|
|
521
|
-
"packages/experience-design-system-generation/dist/src/services/prompts/helpers/build-skill-preambles.js"() {
|
|
522
|
-
"use strict";
|
|
523
|
-
}
|
|
524
|
-
});
|
|
525
|
-
|
|
526
|
-
// packages/experience-design-system-generation/dist/src/services/prompts/helpers/build-preamble.js
|
|
527
|
-
function buildPreamble(options) {
|
|
528
|
-
const { skill, rawComponentsInline, rawTokensInline, rawTokensFilename, tokensInline, tokenMapInline, generatedCdf, tokenTree, componentSourceRefs, existingComponentsInline, existingTokensInline, componentAllowlistInline } = options;
|
|
529
|
-
const sections = [];
|
|
530
|
-
if (existingComponentsInline) {
|
|
531
|
-
sections.push(`Existing components in the target Contentful space (JSON) \u2014 use for alignment, not as a hard filter:
|
|
532
|
-
\`\`\`json
|
|
533
|
-
${existingComponentsInline}
|
|
534
|
-
\`\`\``);
|
|
535
|
-
}
|
|
536
|
-
if (existingTokensInline) {
|
|
537
|
-
sections.push(`Existing design tokens in the target Contentful space (JSON) \u2014 prefer binding to these paths over inventing new ones:
|
|
538
|
-
\`\`\`json
|
|
539
|
-
${existingTokensInline}
|
|
540
|
-
\`\`\``);
|
|
541
|
-
}
|
|
542
|
-
if (componentAllowlistInline) {
|
|
543
|
-
sections.push(`Known component names for slot allowed_components (hard allowlist; never use any other name):
|
|
544
|
-
\`\`\`json
|
|
545
|
-
${componentAllowlistInline}
|
|
546
|
-
\`\`\``);
|
|
547
|
-
}
|
|
548
|
-
if (rawComponentsInline) {
|
|
549
|
-
sections.push(`Raw component data (JSON):
|
|
550
|
-
\`\`\`json
|
|
551
|
-
${rawComponentsInline}
|
|
552
|
-
\`\`\``);
|
|
553
|
-
}
|
|
554
|
-
if (rawTokensInline) {
|
|
555
|
-
const lang = inferFenceLang(rawTokensFilename);
|
|
556
|
-
const label = rawTokensFilename ? `Raw token source (${rawTokensFilename})` : "Raw token source";
|
|
557
|
-
sections.push(`${label}:
|
|
558
|
-
\`\`\`${lang}
|
|
559
|
-
${rawTokensInline}
|
|
560
|
-
\`\`\``);
|
|
561
|
-
}
|
|
562
|
-
if (tokensInline) {
|
|
563
|
-
sections.push(`DTCG token data (for token kind lookups):
|
|
564
|
-
\`\`\`json
|
|
565
|
-
${tokensInline}
|
|
566
|
-
\`\`\``);
|
|
567
|
-
}
|
|
568
|
-
if (tokenMapInline) {
|
|
569
|
-
sections.push(`Token-name sidecar (raw name \u2192 DTCG path):
|
|
570
|
-
\`\`\`json
|
|
571
|
-
${tokenMapInline}
|
|
572
|
-
\`\`\``);
|
|
573
|
-
}
|
|
574
|
-
const filteredTokenProps = generatedCdf ? filterDesignTokenProps(generatedCdf) : void 0;
|
|
575
|
-
if (filteredTokenProps && Object.keys(filteredTokenProps.filtered).length > 0) {
|
|
576
|
-
sections.push(`Generated CDF so far \u2014 design-category token props only (JSON):
|
|
577
|
-
\`\`\`json
|
|
578
|
-
${JSON.stringify(filteredTokenProps.filtered)}
|
|
579
|
-
\`\`\``);
|
|
580
|
-
}
|
|
581
|
-
if (tokenTree) {
|
|
582
|
-
sections.push(...buildTokenCandidateSections(tokenTree, filteredTokenProps));
|
|
583
|
-
}
|
|
584
|
-
if (componentSourceRefs && componentSourceRefs.length > 0) {
|
|
585
|
-
sections.push(...formatSourceRefsSection(componentSourceRefs, skill));
|
|
343
|
+
function parseTokenToolCallLines(stdout) {
|
|
344
|
+
const calls = [];
|
|
345
|
+
const { objects, warnings } = readToolCallObjects(stdout);
|
|
346
|
+
for (const rec of objects) {
|
|
347
|
+
if (!VALID_TOKEN_TOOL_NAMES.has(rec.tool))
|
|
348
|
+
continue;
|
|
349
|
+
if (rec.tool === "set_token") {
|
|
350
|
+
if (typeof rec.path !== "string" || !rec.path) {
|
|
351
|
+
warnings.push("set_token missing path \u2014 skipped");
|
|
352
|
+
continue;
|
|
353
|
+
}
|
|
354
|
+
if (typeof rec.type !== "string" || !rec.type) {
|
|
355
|
+
warnings.push(`set_token '${rec.path}': missing type \u2014 skipped`);
|
|
356
|
+
continue;
|
|
357
|
+
}
|
|
358
|
+
if (!("value" in rec)) {
|
|
359
|
+
warnings.push(`set_token '${rec.path}': missing value \u2014 skipped`);
|
|
360
|
+
continue;
|
|
361
|
+
}
|
|
362
|
+
const call = { tool: "set_token", path: rec.path, type: rec.type, value: rec.value };
|
|
363
|
+
if (typeof rec.description === "string")
|
|
364
|
+
call.description = rec.description;
|
|
365
|
+
calls.push(call);
|
|
366
|
+
} else if (rec.tool === "set_group") {
|
|
367
|
+
if (typeof rec.path !== "string" || !rec.path) {
|
|
368
|
+
warnings.push("set_group missing path \u2014 skipped");
|
|
369
|
+
continue;
|
|
370
|
+
}
|
|
371
|
+
const call = { tool: "set_group", path: rec.path };
|
|
372
|
+
if (typeof rec.description === "string")
|
|
373
|
+
call.description = rec.description;
|
|
374
|
+
calls.push(call);
|
|
375
|
+
}
|
|
586
376
|
}
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
${sections.join("\n\n")}` : "";
|
|
590
|
-
if (skill === "components")
|
|
591
|
-
return buildComponentsAutonomousPreamble(inputBlock);
|
|
592
|
-
if (skill === "select")
|
|
593
|
-
return buildSelectAutonomousPreamble(inputBlock);
|
|
594
|
-
if (skill === "map-tokens")
|
|
595
|
-
return buildMapTokensAutonomousPreamble(inputBlock);
|
|
596
|
-
return buildTokensAutonomousPreamble(inputBlock);
|
|
377
|
+
return { calls, warnings };
|
|
597
378
|
}
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
"use strict";
|
|
601
|
-
init_format_token_candidates();
|
|
602
|
-
init_format_source_refs();
|
|
603
|
-
init_build_skill_preambles();
|
|
604
|
-
}
|
|
605
|
-
});
|
|
606
|
-
|
|
607
|
-
// packages/experience-design-system-generation/dist/src/services/prompts/build-prompt.js
|
|
608
|
-
async function buildPrompt(options) {
|
|
609
|
-
const skillContent = options.skillContentOverride ?? await readSkillFile(options.skill, options.skillPathOverride);
|
|
610
|
-
const preamble = buildPreamble(options);
|
|
611
|
-
return `${preamble}
|
|
612
|
-
|
|
613
|
-
Skill instructions follow:
|
|
614
|
-
---
|
|
615
|
-
${skillContent}`;
|
|
379
|
+
function isStringArray(value) {
|
|
380
|
+
return Array.isArray(value) && value.every((v) => typeof v === "string");
|
|
616
381
|
}
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
382
|
+
function parseMapTokenPropToolCallLines(stdout) {
|
|
383
|
+
const calls = [];
|
|
384
|
+
const warnings = [];
|
|
385
|
+
for (const raw of stdout.split("\n")) {
|
|
386
|
+
const line = raw.trim();
|
|
387
|
+
if (!line.startsWith("{"))
|
|
388
|
+
continue;
|
|
389
|
+
let obj;
|
|
390
|
+
try {
|
|
391
|
+
obj = JSON.parse(line);
|
|
392
|
+
} catch {
|
|
393
|
+
warnings.push(`unparseable line: ${line.slice(0, 120)}`);
|
|
394
|
+
continue;
|
|
395
|
+
}
|
|
396
|
+
if (typeof obj !== "object" || obj === null || !("tool" in obj))
|
|
397
|
+
continue;
|
|
398
|
+
const rec = obj;
|
|
399
|
+
if (rec.tool !== "map_token_prop")
|
|
400
|
+
continue;
|
|
401
|
+
if (typeof rec.component !== "string" || !rec.component) {
|
|
402
|
+
warnings.push("map_token_prop missing component \u2014 skipped");
|
|
403
|
+
continue;
|
|
404
|
+
}
|
|
405
|
+
if (typeof rec.prop !== "string" || !rec.prop) {
|
|
406
|
+
warnings.push(`map_token_prop '${rec.component}': missing prop \u2014 skipped`);
|
|
407
|
+
continue;
|
|
408
|
+
}
|
|
409
|
+
if (!isStringArray(rec.token_allowed) || rec.token_allowed.length === 0) {
|
|
410
|
+
warnings.push(`map_token_prop '${rec.component}.${String(rec.prop)}': missing or empty token_allowed \u2014 skipped`);
|
|
411
|
+
continue;
|
|
412
|
+
}
|
|
413
|
+
const call = {
|
|
414
|
+
tool: "map_token_prop",
|
|
415
|
+
component: rec.component,
|
|
416
|
+
prop: rec.prop,
|
|
417
|
+
token_allowed: rec.token_allowed
|
|
418
|
+
};
|
|
419
|
+
calls.push(call);
|
|
623
420
|
}
|
|
624
|
-
}
|
|
625
|
-
|
|
626
|
-
// packages/experience-design-system-generation/dist/src/orchestrator/execute-generation-orchestrator.js
|
|
627
|
-
async function executeGenerationOrchestrator(request2) {
|
|
628
|
-
const prompt = await buildPrompt(request2.promptOptions);
|
|
629
|
-
return request2.invoker.invoke({
|
|
630
|
-
agent: request2.agent,
|
|
631
|
-
model: request2.model,
|
|
632
|
-
bedrock: request2.bedrock,
|
|
633
|
-
prompt,
|
|
634
|
-
timeoutMs: request2.timeoutMs,
|
|
635
|
-
onOutput: request2.onOutput
|
|
636
|
-
});
|
|
421
|
+
return { calls, warnings };
|
|
637
422
|
}
|
|
638
|
-
|
|
639
|
-
"packages/experience-design-system-generation/dist/src/orchestrator/execute-generation-orchestrator.js"() {
|
|
640
|
-
"use strict";
|
|
641
|
-
init_build_prompt();
|
|
642
|
-
}
|
|
643
|
-
});
|
|
644
|
-
|
|
645
|
-
// packages/experience-design-system-generation/dist/src/services/agent/helpers/resolve-agent-binary.js
|
|
646
|
-
function resolveAgentBinary(agent) {
|
|
423
|
+
function resolveBinary(agent) {
|
|
647
424
|
const envKey = `EDS_AGENT_BINARY_${agent.toUpperCase()}`;
|
|
648
425
|
const override = process.env[envKey];
|
|
649
426
|
if (override && override.trim())
|
|
650
427
|
return override.trim();
|
|
651
428
|
return AGENT_BINARIES[agent];
|
|
652
429
|
}
|
|
653
|
-
var init_resolve_agent_binary = __esm({
|
|
654
|
-
"packages/experience-design-system-generation/dist/src/services/agent/helpers/resolve-agent-binary.js"() {
|
|
655
|
-
"use strict";
|
|
656
|
-
init_agent_names();
|
|
657
|
-
}
|
|
658
|
-
});
|
|
659
|
-
|
|
660
|
-
// packages/experience-design-system-generation/dist/src/services/agent/helpers/build-agent-args.js
|
|
661
430
|
function agentSupportsBedrock(agent) {
|
|
662
431
|
return BEDROCK_CAPABLE_AGENTS.has(agent);
|
|
663
432
|
}
|
|
664
|
-
function withBedrockProviderPrefix(model) {
|
|
665
|
-
return model.includes("/") ? model : `amazon-bedrock/${model}`;
|
|
666
|
-
}
|
|
667
433
|
function resolveAgentModel(agent, explicit, bedrock = false) {
|
|
668
434
|
if (explicit && explicit.trim())
|
|
669
435
|
return explicit.trim();
|
|
@@ -676,11 +442,14 @@ function resolveAgentModel(agent, explicit, bedrock = false) {
|
|
|
676
442
|
return withBedrockProviderPrefix(DEFAULT_OPENCODE_MODEL);
|
|
677
443
|
return DEFAULT_MODELS[agent];
|
|
678
444
|
}
|
|
445
|
+
function withBedrockProviderPrefix(model) {
|
|
446
|
+
return model.includes("/") ? model : `amazon-bedrock/${model}`;
|
|
447
|
+
}
|
|
679
448
|
function codexBedrockConfigArgs() {
|
|
680
449
|
const region = process.env.AWS_REGION?.trim() || process.env.AWS_DEFAULT_REGION?.trim() || DEFAULT_CODEX_BEDROCK_REGION;
|
|
681
450
|
return ["-c", "model_provider=amazon-bedrock", "-c", `model_providers.amazon-bedrock.region=${region}`];
|
|
682
451
|
}
|
|
683
|
-
function
|
|
452
|
+
function buildArgs(agent, prompt, model, promptViaStdin = false, bedrock = false) {
|
|
684
453
|
const resolvedModel = resolveAgentModel(agent, model, bedrock);
|
|
685
454
|
const modelArg = resolvedModel ? ["--model", resolvedModel] : [];
|
|
686
455
|
const promptArg = promptViaStdin ? [] : [prompt];
|
|
@@ -702,69 +471,12 @@ function buildAgentArgs(agent, prompt, model, promptViaStdin = false, bedrock =
|
|
|
702
471
|
}
|
|
703
472
|
}
|
|
704
473
|
}
|
|
705
|
-
var BEDROCK_ENV_BY_AGENT, BEDROCK_CAPABLE_AGENTS, DEFAULT_CODEX_BEDROCK_REGION, DEFAULT_OPENCODE_MODEL, DEFAULT_CODEX_BEDROCK_MODEL, DEFAULT_MODELS;
|
|
706
|
-
var init_build_agent_args = __esm({
|
|
707
|
-
"packages/experience-design-system-generation/dist/src/services/agent/helpers/build-agent-args.js"() {
|
|
708
|
-
"use strict";
|
|
709
|
-
BEDROCK_ENV_BY_AGENT = {
|
|
710
|
-
claude: { CLAUDE_CODE_USE_BEDROCK: "1" }
|
|
711
|
-
};
|
|
712
|
-
BEDROCK_CAPABLE_AGENTS = /* @__PURE__ */ new Set(["claude", "codex", "opencode"]);
|
|
713
|
-
DEFAULT_CODEX_BEDROCK_REGION = "us-east-1";
|
|
714
|
-
DEFAULT_OPENCODE_MODEL = "claude-haiku-4-5";
|
|
715
|
-
DEFAULT_CODEX_BEDROCK_MODEL = "openai.gpt-5.6-luna";
|
|
716
|
-
DEFAULT_MODELS = {
|
|
717
|
-
claude: "haiku",
|
|
718
|
-
opencode: DEFAULT_OPENCODE_MODEL,
|
|
719
|
-
cursor: "gpt-mini",
|
|
720
|
-
copilot: "Auto"
|
|
721
|
-
};
|
|
722
|
-
}
|
|
723
|
-
});
|
|
724
|
-
|
|
725
|
-
// packages/experience-design-system-generation/dist/src/services/agent/helpers/describe-agent-failure.js
|
|
726
|
-
function describeAgentFailure(result, maxDetail = 800) {
|
|
727
|
-
const base = result.exitCode !== 0 ? `agent exited with code ${result.exitCode}` : "agent produced no tool calls";
|
|
728
|
-
const detail = (result.stderr.trim() || result.stdout.trim()).slice(-maxDetail).trim();
|
|
729
|
-
return detail ? `${base} \u2014 ${detail}` : base;
|
|
730
|
-
}
|
|
731
|
-
var init_describe_agent_failure = __esm({
|
|
732
|
-
"packages/experience-design-system-generation/dist/src/services/agent/helpers/describe-agent-failure.js"() {
|
|
733
|
-
"use strict";
|
|
734
|
-
}
|
|
735
|
-
});
|
|
736
|
-
|
|
737
|
-
// packages/experience-design-system-generation/dist/src/services/agent/helpers/extract-sentinel-output.js
|
|
738
|
-
function extractSentinelOutput(stdout) {
|
|
739
|
-
const START = "<<<EDS_OUTPUT_START>>>";
|
|
740
|
-
const END = "<<<EDS_OUTPUT_END>>>";
|
|
741
|
-
const startIdx = stdout.indexOf(START);
|
|
742
|
-
const endIdx = stdout.indexOf(END);
|
|
743
|
-
if (startIdx === -1 || endIdx === -1 || endIdx <= startIdx)
|
|
744
|
-
return null;
|
|
745
|
-
const secondStart = stdout.indexOf(START, startIdx + START.length);
|
|
746
|
-
if (secondStart !== -1 && secondStart < endIdx)
|
|
747
|
-
return "multiple";
|
|
748
|
-
const afterStart = stdout.indexOf(END, startIdx);
|
|
749
|
-
const secondEnd = stdout.indexOf(END, afterStart + END.length);
|
|
750
|
-
if (secondEnd !== -1)
|
|
751
|
-
return "multiple";
|
|
752
|
-
return stdout.slice(startIdx + START.length, endIdx).trim();
|
|
753
|
-
}
|
|
754
|
-
var init_extract_sentinel_output = __esm({
|
|
755
|
-
"packages/experience-design-system-generation/dist/src/services/agent/helpers/extract-sentinel-output.js"() {
|
|
756
|
-
"use strict";
|
|
757
|
-
}
|
|
758
|
-
});
|
|
759
|
-
|
|
760
|
-
// packages/experience-design-system-generation/dist/src/services/agent/run-agent.js
|
|
761
|
-
import { spawn } from "node:child_process";
|
|
762
474
|
async function runAgent(options) {
|
|
763
475
|
const { agent, prompt, timeoutMs, model, onOutput, promptViaStdin, onDebugEvent } = options;
|
|
764
476
|
const bedrock = options.bedrock ?? process.env.EDS_BEDROCK === "1";
|
|
765
|
-
const binary =
|
|
477
|
+
const binary = resolveBinary(agent);
|
|
766
478
|
const useStdin2 = !!promptViaStdin;
|
|
767
|
-
const args =
|
|
479
|
+
const args = buildArgs(agent, prompt, model, useStdin2, bedrock);
|
|
768
480
|
const startedAt = Date.now();
|
|
769
481
|
onDebugEvent?.("run.start", {
|
|
770
482
|
agent,
|
|
@@ -807,7 +519,12 @@ async function runAgent(options) {
|
|
|
807
519
|
});
|
|
808
520
|
child.on("close", (code, signal) => {
|
|
809
521
|
clearTimeout(timer);
|
|
810
|
-
const result = {
|
|
522
|
+
const result = {
|
|
523
|
+
exitCode: signal ? 1 : code ?? 1,
|
|
524
|
+
stdout,
|
|
525
|
+
stderr,
|
|
526
|
+
timedOut
|
|
527
|
+
};
|
|
811
528
|
onDebugEvent?.("run.end", {
|
|
812
529
|
agent,
|
|
813
530
|
model,
|
|
@@ -823,21 +540,22 @@ async function runAgent(options) {
|
|
|
823
540
|
});
|
|
824
541
|
});
|
|
825
542
|
}
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
543
|
+
async function checkAgentAuth(agent) {
|
|
544
|
+
const binary = resolveBinary(agent);
|
|
545
|
+
const binaryExists2 = await new Promise((resolve21) => {
|
|
546
|
+
if (binary.startsWith("/")) {
|
|
547
|
+
import("node:fs/promises").then((fs2) => fs2.access(binary).then(() => resolve21(true), () => resolve21(false)));
|
|
548
|
+
return;
|
|
549
|
+
}
|
|
550
|
+
const child = spawn(process.platform === "win32" ? "where" : "which", [binary], { stdio: "ignore" });
|
|
551
|
+
child.on("close", (code) => resolve21(code === 0));
|
|
552
|
+
});
|
|
553
|
+
if (!binaryExists2)
|
|
554
|
+
return "not-found";
|
|
555
|
+
if (agent !== "claude")
|
|
556
|
+
return "ok";
|
|
839
557
|
return new Promise((resolve21) => {
|
|
840
|
-
const child =
|
|
558
|
+
const child = spawn(binary, ["auth", "status", "--json"], {
|
|
841
559
|
stdio: ["ignore", "pipe", "pipe"]
|
|
842
560
|
});
|
|
843
561
|
let stdout = "";
|
|
@@ -870,39 +588,63 @@ function checkClaudeAuth(binary) {
|
|
|
870
588
|
});
|
|
871
589
|
});
|
|
872
590
|
}
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
}
|
|
877
|
-
}
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
const
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
if (agent !== "claude")
|
|
894
|
-
return "ok";
|
|
895
|
-
return checkClaudeAuth(binary);
|
|
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();
|
|
896
611
|
}
|
|
897
|
-
var
|
|
898
|
-
|
|
612
|
+
var VALID_SELECT_TOOL_NAMES, VALID_TOOL_NAMES, VALID_TOKEN_TOOL_NAMES, VALID_CDF_TYPES, VALID_CATEGORIES, AGENT_BINARIES, BEDROCK_ENV_BY_AGENT, BEDROCK_CAPABLE_AGENTS, DEFAULT_CODEX_BEDROCK_REGION, DEFAULT_OPENCODE_MODEL, DEFAULT_MODELS, DEFAULT_CODEX_BEDROCK_MODEL;
|
|
613
|
+
var init_agent_runner = __esm({
|
|
614
|
+
"packages/experience-design-system-generation/dist/src/agent-runner.js"() {
|
|
899
615
|
"use strict";
|
|
900
|
-
|
|
901
|
-
|
|
616
|
+
init_agent_names();
|
|
617
|
+
VALID_SELECT_TOOL_NAMES = /* @__PURE__ */ new Set(["select_component", "reject_component"]);
|
|
618
|
+
VALID_TOOL_NAMES = /* @__PURE__ */ new Set(["classify_prop", "exclude_prop", "classify_component", "classify_slot"]);
|
|
619
|
+
VALID_TOKEN_TOOL_NAMES = /* @__PURE__ */ new Set(["set_token", "set_group"]);
|
|
620
|
+
VALID_CDF_TYPES = /* @__PURE__ */ new Set(["string", "richtext", "media", "enum", "token", "boolean"]);
|
|
621
|
+
VALID_CATEGORIES = /* @__PURE__ */ new Set(["content", "design", "state"]);
|
|
622
|
+
AGENT_BINARIES = {
|
|
623
|
+
claude: "claude",
|
|
624
|
+
codex: "codex",
|
|
625
|
+
opencode: "opencode",
|
|
626
|
+
cursor: "cursor-agent",
|
|
627
|
+
copilot: "copilot"
|
|
628
|
+
};
|
|
629
|
+
BEDROCK_ENV_BY_AGENT = {
|
|
630
|
+
claude: { CLAUDE_CODE_USE_BEDROCK: "1" }
|
|
631
|
+
};
|
|
632
|
+
BEDROCK_CAPABLE_AGENTS = /* @__PURE__ */ new Set(["claude", "codex", "opencode"]);
|
|
633
|
+
DEFAULT_CODEX_BEDROCK_REGION = "us-east-1";
|
|
634
|
+
DEFAULT_OPENCODE_MODEL = "claude-haiku-4-5";
|
|
635
|
+
DEFAULT_MODELS = {
|
|
636
|
+
claude: "haiku",
|
|
637
|
+
opencode: DEFAULT_OPENCODE_MODEL,
|
|
638
|
+
cursor: "gpt-mini",
|
|
639
|
+
// cursor alias for gpt-5.4-mini-medium; haiku not in cursor's catalog
|
|
640
|
+
copilot: "Auto"
|
|
641
|
+
// the only model guaranteed on every Copilot plan (Free/Pro/Business/Enterprise); Pro+ users override via EDS_AGENT_MODEL_COPILOT
|
|
642
|
+
};
|
|
643
|
+
DEFAULT_CODEX_BEDROCK_MODEL = "openai.gpt-5.6-luna";
|
|
902
644
|
}
|
|
903
645
|
});
|
|
904
646
|
|
|
905
|
-
// packages/experience-design-system-generation/dist/src/
|
|
647
|
+
// packages/experience-design-system-generation/dist/src/agent-invoker.js
|
|
906
648
|
function createLocalCliAgentInvoker(options = {}) {
|
|
907
649
|
const { onDebugEvent } = options;
|
|
908
650
|
return {
|
|
@@ -914,310 +656,381 @@ function createLocalCliAgentInvoker(options = {}) {
|
|
|
914
656
|
}
|
|
915
657
|
};
|
|
916
658
|
}
|
|
917
|
-
var
|
|
918
|
-
"packages/experience-design-system-generation/dist/src/
|
|
659
|
+
var init_agent_invoker = __esm({
|
|
660
|
+
"packages/experience-design-system-generation/dist/src/agent-invoker.js"() {
|
|
919
661
|
"use strict";
|
|
920
|
-
|
|
921
|
-
init_check_agent_auth();
|
|
662
|
+
init_agent_runner();
|
|
922
663
|
}
|
|
923
664
|
});
|
|
924
665
|
|
|
925
|
-
// packages/experience-design-system-generation/dist/src/
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
};
|
|
666
|
+
// packages/experience-design-system-generation/dist/src/prompt-builder.js
|
|
667
|
+
import { existsSync } from "node:fs";
|
|
668
|
+
import { readFile as readFile2 } from "node:fs/promises";
|
|
669
|
+
import { dirname, join as join2, resolve } from "node:path";
|
|
670
|
+
import { fileURLToPath } from "node:url";
|
|
671
|
+
import { flattenDTCG } from "@contentful/experience-design-system-types";
|
|
672
|
+
function formatCustomPromptBanner(skill, path) {
|
|
673
|
+
return `WARNING: Custom prompt active for ${skill}: ${path}
|
|
674
|
+
Bundled invariants (utility-wrapper rejection, description content rules) do NOT apply.
|
|
675
|
+
You are responsible for the prompt's correctness.
|
|
676
|
+
`;
|
|
937
677
|
}
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
init_execute_generation_orchestrator();
|
|
943
|
-
init_local_cli_agent_invoker();
|
|
944
|
-
}
|
|
945
|
-
});
|
|
678
|
+
async function buildPrompt(options) {
|
|
679
|
+
const skillContent = options.skillContentOverride ?? await readSkillFile(options.skill, options.skillPathOverride);
|
|
680
|
+
const preamble = buildPreamble(options);
|
|
681
|
+
return `${preamble}
|
|
946
682
|
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
return i;
|
|
683
|
+
Skill instructions follow:
|
|
684
|
+
---
|
|
685
|
+
${skillContent}`;
|
|
686
|
+
}
|
|
687
|
+
function resolveSkillPath(skill) {
|
|
688
|
+
if (!(skill in SKILL_FILES))
|
|
689
|
+
throw new Error(`Invalid skill: ${skill}`);
|
|
690
|
+
const thisDir = dirname(fileURLToPath(import.meta.url));
|
|
691
|
+
let dir = thisDir;
|
|
692
|
+
for (; ; ) {
|
|
693
|
+
const candidate = join2(dir, "skills");
|
|
694
|
+
if (existsSync(candidate))
|
|
695
|
+
return join2(candidate, SKILL_FILES[skill]);
|
|
696
|
+
const parent = resolve(dir, "..");
|
|
697
|
+
if (parent === dir) {
|
|
698
|
+
throw new Error(`skill file missing from CLI installation (could not locate skills/ directory from: ${thisDir})`);
|
|
964
699
|
}
|
|
700
|
+
dir = parent;
|
|
965
701
|
}
|
|
966
|
-
return -1;
|
|
967
702
|
}
|
|
968
|
-
function
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
for (const raw of stdout.split("\n")) {
|
|
972
|
-
const line = raw.trim();
|
|
973
|
-
if (!line.startsWith("{"))
|
|
974
|
-
continue;
|
|
975
|
-
const end = findJsonObjectEnd(line);
|
|
976
|
-
if (end === -1) {
|
|
977
|
-
warnings.push(`unparseable line: ${line.slice(0, 120)}`);
|
|
978
|
-
continue;
|
|
979
|
-
}
|
|
980
|
-
let parsed;
|
|
703
|
+
async function readSkillFile(skill, override) {
|
|
704
|
+
if (override) {
|
|
705
|
+
const skillPath2 = resolve(override);
|
|
981
706
|
try {
|
|
982
|
-
|
|
707
|
+
return await readFile2(skillPath2, "utf8");
|
|
983
708
|
} catch {
|
|
984
|
-
|
|
985
|
-
continue;
|
|
986
|
-
}
|
|
987
|
-
const trailing = line.slice(end + 1);
|
|
988
|
-
if (trailing.trim()) {
|
|
989
|
-
warnings.push(`ignored trailing content after JSON: ${trailing.trim().slice(0, 120)}`);
|
|
990
|
-
}
|
|
991
|
-
if (typeof parsed === "object" && parsed !== null && "tool" in parsed) {
|
|
992
|
-
objects.push(parsed);
|
|
709
|
+
throw new Error(`custom prompt file not found (skill: ${skill}, path: ${skillPath2})`);
|
|
993
710
|
}
|
|
994
711
|
}
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
712
|
+
const skillPath = resolveSkillPath(skill);
|
|
713
|
+
try {
|
|
714
|
+
return await readFile2(skillPath, "utf8");
|
|
715
|
+
} catch {
|
|
716
|
+
throw new Error(`skill file missing from CLI installation \u2014 try reinstalling the CLI (looked for: ${skillPath})`);
|
|
1000
717
|
}
|
|
1001
|
-
}
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
const
|
|
1006
|
-
const
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
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)
|
|
1010
750
|
continue;
|
|
1011
|
-
}
|
|
1012
|
-
const
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
if (typeof rec.cdf_category !== "string" || !VALID_CATEGORIES.has(rec.cdf_category)) {
|
|
1023
|
-
warnings.push(`classify_prop '${rec.prop}': invalid cdf_category '${String(rec.cdf_category)}' \u2014 skipped`);
|
|
1024
|
-
continue;
|
|
1025
|
-
}
|
|
1026
|
-
const call = {
|
|
1027
|
-
tool: "classify_prop",
|
|
1028
|
-
prop: rec.prop,
|
|
1029
|
-
cdf_type: rec.cdf_type,
|
|
1030
|
-
cdf_category: rec.cdf_category
|
|
1031
|
-
};
|
|
1032
|
-
if (Array.isArray(rec.values) && rec.values.every((v) => typeof v === "string"))
|
|
1033
|
-
call.values = rec.values;
|
|
1034
|
-
if (typeof rec.token_kind === "string")
|
|
1035
|
-
call.token_kind = rec.token_kind;
|
|
1036
|
-
if (typeof rec.required === "boolean")
|
|
1037
|
-
call.required = rec.required;
|
|
1038
|
-
if (typeof rec.description === "string")
|
|
1039
|
-
call.description = rec.description;
|
|
1040
|
-
if (typeof rec.default === "string" || typeof rec.default === "boolean")
|
|
1041
|
-
call.default = rec.default;
|
|
1042
|
-
if (typeof rec.reason === "string")
|
|
1043
|
-
call.reason = rec.reason;
|
|
1044
|
-
calls.push(call);
|
|
1045
|
-
} else if (tool === "exclude_prop") {
|
|
1046
|
-
if (typeof rec.prop !== "string" || !rec.prop) {
|
|
1047
|
-
warnings.push("exclude_prop missing prop name \u2014 skipped");
|
|
1048
|
-
continue;
|
|
1049
|
-
}
|
|
1050
|
-
calls.push({ tool: "exclude_prop", prop: rec.prop, reason: typeof rec.reason === "string" ? rec.reason : "" });
|
|
1051
|
-
} else if (tool === "classify_component") {
|
|
1052
|
-
const call = { tool: "classify_component" };
|
|
1053
|
-
if (typeof rec.description === "string")
|
|
1054
|
-
call.description = rec.description;
|
|
1055
|
-
if (typeof rec.rationale === "object" && rec.rationale !== null) {
|
|
1056
|
-
const r = rec.rationale;
|
|
1057
|
-
const rationale = {};
|
|
1058
|
-
if (typeof r.description === "string")
|
|
1059
|
-
rationale.description = r.description;
|
|
1060
|
-
if (typeof r.props === "string")
|
|
1061
|
-
rationale.props = r.props;
|
|
1062
|
-
if (typeof r.slots === "string")
|
|
1063
|
-
rationale.slots = r.slots;
|
|
1064
|
-
if (Object.keys(rationale).length > 0)
|
|
1065
|
-
call.rationale = rationale;
|
|
1066
|
-
}
|
|
1067
|
-
calls.push(call);
|
|
1068
|
-
} else if (tool === "classify_slot") {
|
|
1069
|
-
if (typeof rec.slot !== "string" || !rec.slot) {
|
|
1070
|
-
warnings.push("classify_slot missing slot name \u2014 skipped");
|
|
1071
|
-
continue;
|
|
1072
|
-
}
|
|
1073
|
-
const call = { tool: "classify_slot", slot: rec.slot };
|
|
1074
|
-
if (typeof rec.required === "boolean")
|
|
1075
|
-
call.required = rec.required;
|
|
1076
|
-
if (Array.isArray(rec.allowed_components) && rec.allowed_components.every((v) => typeof v === "string")) {
|
|
1077
|
-
call.allowed_components = rec.allowed_components;
|
|
751
|
+
const filteredProps = {};
|
|
752
|
+
for (const [propName, prop] of Object.entries(properties)) {
|
|
753
|
+
if (prop.$type === "token" && prop.$category === "design") {
|
|
754
|
+
const { "$token.allowed": _tokenAllowed, ...rest } = prop;
|
|
755
|
+
filteredProps[propName] = rest;
|
|
756
|
+
const kind = prop["$token.kind"];
|
|
757
|
+
if (typeof kind === "string" && kind.length > 0) {
|
|
758
|
+
kinds.add(kind);
|
|
759
|
+
} else {
|
|
760
|
+
hasUnscoped = true;
|
|
761
|
+
}
|
|
1078
762
|
}
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
call.rationale = rec.rationale;
|
|
1083
|
-
calls.push(call);
|
|
763
|
+
}
|
|
764
|
+
if (Object.keys(filteredProps).length > 0) {
|
|
765
|
+
result[componentName] = { ...component, $properties: filteredProps };
|
|
1084
766
|
}
|
|
1085
767
|
}
|
|
1086
|
-
return {
|
|
768
|
+
return { filtered: result, kinds: [...kinds].sort(), hasUnscoped };
|
|
1087
769
|
}
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
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
|
+
\`\`\``);
|
|
786
|
+
}
|
|
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
|
+
\`\`\``);
|
|
1096
831
|
}
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
}
|
|
1110
|
-
const call = { tool: rec.tool, name: rec.name };
|
|
1111
|
-
if (typeof rec.reason === "string")
|
|
1112
|
-
call.reason = rec.reason;
|
|
1113
|
-
if (typeof rec.confidence === "number" && rec.confidence >= 1 && rec.confidence <= 5) {
|
|
1114
|
-
if (call.tool === "select_component") {
|
|
1115
|
-
call.confidence = rec.confidence;
|
|
832
|
+
if (tokenTree) {
|
|
833
|
+
const index = flattenDTCG(tokenTree, "").sort((a, b) => a.path.localeCompare(b.path));
|
|
834
|
+
if (index.length > 0) {
|
|
835
|
+
if (filteredTokenProps) {
|
|
836
|
+
const { kinds, hasUnscoped } = filteredTokenProps;
|
|
837
|
+
for (const kind of kinds) {
|
|
838
|
+
const scoped = index.filter((entry) => entry.$type === kind);
|
|
839
|
+
if (scoped.length > 0)
|
|
840
|
+
sections.push(renderTokenCandidateSection(kind, scoped));
|
|
841
|
+
}
|
|
842
|
+
if (hasUnscoped)
|
|
843
|
+
sections.push(renderTokenCandidateSection(null, index));
|
|
1116
844
|
} else {
|
|
1117
|
-
|
|
845
|
+
sections.push(renderTokenCandidateSection(null, index));
|
|
1118
846
|
}
|
|
1119
847
|
}
|
|
1120
|
-
calls.push(call);
|
|
1121
|
-
}
|
|
1122
|
-
return { calls, warnings };
|
|
1123
|
-
}
|
|
1124
|
-
var VALID_SELECT_TOOL_NAMES;
|
|
1125
|
-
var init_parse_select_tool_calls = __esm({
|
|
1126
|
-
"packages/experience-design-system-generation/dist/src/services/parsing/parse-select-tool-calls.js"() {
|
|
1127
|
-
"use strict";
|
|
1128
|
-
init_read_tool_call_objects();
|
|
1129
|
-
VALID_SELECT_TOOL_NAMES = /* @__PURE__ */ new Set(["select_component", "reject_component"]);
|
|
1130
848
|
}
|
|
1131
|
-
|
|
849
|
+
if (componentSourceRefs && componentSourceRefs.length > 0) {
|
|
850
|
+
const withContent = componentSourceRefs.filter((ref) => ref.content != null);
|
|
851
|
+
const withoutContent = componentSourceRefs.filter((ref) => ref.content == null);
|
|
852
|
+
if (withContent.length > 0) {
|
|
853
|
+
const blocks = withContent.map((ref) => {
|
|
854
|
+
const mainBlock = `#### ${ref.component} (\`${ref.sourcePath}\`)
|
|
855
|
+
\`\`\`${inferFenceLang(ref.sourcePath)}
|
|
856
|
+
${ref.content}
|
|
857
|
+
\`\`\``;
|
|
858
|
+
const siblingBlocks = (ref.siblingFiles ?? []).map((sibling) => `##### ${ref.component} \u2014 imported file \`${sibling.path}\`
|
|
859
|
+
\`\`\`${inferFenceLang(sibling.path)}
|
|
860
|
+
${sibling.content}
|
|
861
|
+
\`\`\``);
|
|
862
|
+
const truncationNote = ref.truncatedSiblingCount && ref.truncatedSiblingCount > 0 ? [
|
|
863
|
+
`##### ${ref.component} \u2014 +${ref.truncatedSiblingCount} more imported file${ref.truncatedSiblingCount === 1 ? "" : "s"} not shown (evidence may be incomplete)`
|
|
864
|
+
] : [];
|
|
865
|
+
const notShownNote = ref.usesNotShown && ref.usesNotShown.length > 0 ? [
|
|
866
|
+
`##### ${ref.component} \u2014 uses not shown: ${ref.usesNotShown.join(", ")}
|
|
1132
867
|
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
continue;
|
|
1148
|
-
}
|
|
1149
|
-
if (!("value" in rec)) {
|
|
1150
|
-
warnings.push(`set_token '${rec.path}': missing value \u2014 skipped`);
|
|
1151
|
-
continue;
|
|
1152
|
-
}
|
|
1153
|
-
const call = { tool: "set_token", path: rec.path, type: rec.type, value: rec.value };
|
|
1154
|
-
if (typeof rec.description === "string")
|
|
1155
|
-
call.description = rec.description;
|
|
1156
|
-
calls.push(call);
|
|
1157
|
-
} else if (rec.tool === "set_group") {
|
|
1158
|
-
if (typeof rec.path !== "string" || !rec.path) {
|
|
1159
|
-
warnings.push("set_group missing path \u2014 skipped");
|
|
1160
|
-
continue;
|
|
1161
|
-
}
|
|
1162
|
-
const call = { tool: "set_group", path: rec.path };
|
|
1163
|
-
if (typeof rec.description === "string")
|
|
1164
|
-
call.description = rec.description;
|
|
1165
|
-
calls.push(call);
|
|
868
|
+
The files above are excerpts, and each of these properties has at least one use that fell outside the excerpt budget. Treat their consumption as unknown, not absent: do not classify them \`token\` on what is shown, and do not conclude they are unread.`
|
|
869
|
+
] : [];
|
|
870
|
+
return [mainBlock, ...siblingBlocks, ...truncationNote, ...notShownNote].join("\n\n");
|
|
871
|
+
});
|
|
872
|
+
sections.push(`### Component source references
|
|
873
|
+
|
|
874
|
+
${blocks.join("\n\n")}`);
|
|
875
|
+
}
|
|
876
|
+
if (withoutContent.length > 0) {
|
|
877
|
+
const guidance = skill === "components" ? "there is no consumption evidence for these, so `token` cannot be earned for any of their props \u2014 classify from the prop signature alone, and any prop that would otherwise be enum-versus-token is `enum` (or `string`)" : "there is no source evidence to narrow from \u2014 emit nothing for their props";
|
|
878
|
+
sections.push(`Component source unavailable for (JSON) \u2014 ${guidance}:
|
|
879
|
+
\`\`\`json
|
|
880
|
+
${JSON.stringify(withoutContent.map((ref) => ({ component: ref.component, sourcePath: ref.sourcePath })))}
|
|
881
|
+
\`\`\``);
|
|
1166
882
|
}
|
|
1167
883
|
}
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
"use strict";
|
|
1174
|
-
init_read_tool_call_objects();
|
|
1175
|
-
VALID_TOKEN_TOOL_NAMES = /* @__PURE__ */ new Set(["set_token", "set_group"]);
|
|
884
|
+
const inputBlock = sections.length > 0 ? `
|
|
885
|
+
|
|
886
|
+
${sections.join("\n\n")}` : "";
|
|
887
|
+
if (skill === "components") {
|
|
888
|
+
return buildComponentsAutonomousPreamble(inputBlock);
|
|
1176
889
|
}
|
|
1177
|
-
|
|
890
|
+
if (skill === "select") {
|
|
891
|
+
return buildSelectAutonomousPreamble(inputBlock);
|
|
892
|
+
}
|
|
893
|
+
if (skill === "map-tokens") {
|
|
894
|
+
return buildMapTokensAutonomousPreamble(inputBlock);
|
|
895
|
+
}
|
|
896
|
+
return buildTokensAutonomousPreamble(inputBlock);
|
|
897
|
+
}
|
|
898
|
+
function buildComponentsAutonomousPreamble(inputBlock) {
|
|
899
|
+
return `You are running as part of the experience-design-system-cli generate pipeline in AUTONOMOUS mode. The developer is not present to answer questions.
|
|
1178
900
|
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
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.`;
|
|
1182
943
|
}
|
|
1183
|
-
function
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
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:
|
|
982
|
+
|
|
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.`;
|
|
994
|
+
}
|
|
995
|
+
function buildTokensAutonomousPreamble(inputBlock) {
|
|
996
|
+
return `You are running as part of the experience-design-system-cli generate pipeline in AUTONOMOUS mode. The developer is not present to answer questions.
|
|
997
|
+
|
|
998
|
+
Your task: classify every raw token from the input below into a DTCG token tree. Apply all judgment calls yourself \u2014 do not pause to ask for confirmation. Include a "description" field on each set_token call to document your reasoning.
|
|
999
|
+
|
|
1000
|
+
All input data is provided inline below \u2014 do not read any additional files.${inputBlock}
|
|
1001
|
+
|
|
1002
|
+
## Output protocol
|
|
1003
|
+
|
|
1004
|
+
Do NOT write any files or emit any JSON blobs. Instead, emit one JSON object per line to stdout for each token or group. The CLI reads your stdout line by line and writes each entry directly to the pipeline database.
|
|
1005
|
+
|
|
1006
|
+
The two tool calls you may emit are:
|
|
1007
|
+
|
|
1008
|
+
\`\`\`
|
|
1009
|
+
{"tool":"set_group","path":"<dot.notation.path>","description":"<optional group description>"}
|
|
1010
|
+
|
|
1011
|
+
{"tool":"set_token","path":"<dot.notation.path>","type":"<DTCG type>","value":<value>,"description":"<reason>"}
|
|
1012
|
+
\`\`\`
|
|
1013
|
+
|
|
1014
|
+
Rules:
|
|
1015
|
+
- Emit exactly one JSON object per line. No multi-line JSON. No markdown fences.
|
|
1016
|
+
- Emit a set_group call for every intermediate group node in the tree.
|
|
1017
|
+
- Emit a set_token call for every leaf token.
|
|
1018
|
+
- "path" is dot-notation, e.g. "colors.brand.primary" \u2014 no leading dots or slashes.
|
|
1019
|
+
- "type" must be one of the 13 valid DTCG types: color, dimension, fontFamily, fontWeight, duration, cubicBezier, number, strokeStyle, border, transition, shadow, gradient, typography.
|
|
1020
|
+
- "value" must be valid JSON (string, number, array, or object depending on the type). Do NOT wrap it in quotes if it is a complex type.
|
|
1021
|
+
- Emit set_group calls before the set_token calls that fall under them.
|
|
1022
|
+
- You may emit prose lines (not starting with {) anywhere \u2014 they are ignored by the parser and serve as your reasoning log.`;
|
|
1217
1023
|
}
|
|
1218
|
-
var
|
|
1219
|
-
|
|
1024
|
+
var SKILL_FILES;
|
|
1025
|
+
var init_prompt_builder = __esm({
|
|
1026
|
+
"packages/experience-design-system-generation/dist/src/prompt-builder.js"() {
|
|
1220
1027
|
"use strict";
|
|
1028
|
+
SKILL_FILES = {
|
|
1029
|
+
components: "generate-components.md",
|
|
1030
|
+
tokens: "generate-tokens.md",
|
|
1031
|
+
select: "select-components.md",
|
|
1032
|
+
"map-tokens": "map-tokens.md"
|
|
1033
|
+
};
|
|
1221
1034
|
}
|
|
1222
1035
|
});
|
|
1223
1036
|
|
|
@@ -1234,17 +1047,14 @@ var init_progress = __esm({
|
|
|
1234
1047
|
// packages/experience-design-system-generation/dist/src/index.js
|
|
1235
1048
|
var src_exports = {};
|
|
1236
1049
|
__export(src_exports, {
|
|
1237
|
-
AGENT_BINARIES: () => AGENT_BINARIES,
|
|
1238
1050
|
AGENT_NAMES: () => AGENT_NAMES,
|
|
1239
1051
|
DEFAULT_AGENT_NAME: () => DEFAULT_AGENT_NAME,
|
|
1240
1052
|
agentSupportsBedrock: () => agentSupportsBedrock,
|
|
1241
|
-
buildArgs: () =>
|
|
1053
|
+
buildArgs: () => buildArgs,
|
|
1242
1054
|
buildPrompt: () => buildPrompt,
|
|
1243
1055
|
checkAgentAuth: () => checkAgentAuth,
|
|
1244
|
-
createGenerationEndpoint: () => createGenerationEndpoint,
|
|
1245
1056
|
createLocalCliAgentInvoker: () => createLocalCliAgentInvoker,
|
|
1246
1057
|
describeAgentFailure: () => describeAgentFailure,
|
|
1247
|
-
executeGenerationOrchestrator: () => executeGenerationOrchestrator,
|
|
1248
1058
|
extractSentinelOutput: () => extractSentinelOutput,
|
|
1249
1059
|
formatCustomPromptBanner: () => formatCustomPromptBanner,
|
|
1250
1060
|
formatGenerateProgressLine: () => formatGenerateProgressLine,
|
|
@@ -1252,9 +1062,9 @@ __export(src_exports, {
|
|
|
1252
1062
|
parseMapTokenPropToolCallLines: () => parseMapTokenPropToolCallLines,
|
|
1253
1063
|
parseSelectToolCallLines: () => parseSelectToolCallLines,
|
|
1254
1064
|
parseTokenToolCallLines: () => parseTokenToolCallLines,
|
|
1255
|
-
parseToolCallLines: () =>
|
|
1065
|
+
parseToolCallLines: () => parseToolCallLines,
|
|
1256
1066
|
resolveAgentModel: () => resolveAgentModel,
|
|
1257
|
-
resolveBinary: () =>
|
|
1067
|
+
resolveBinary: () => resolveBinary,
|
|
1258
1068
|
resolveSkillPath: () => resolveSkillPath,
|
|
1259
1069
|
runAgent: () => runAgent
|
|
1260
1070
|
});
|
|
@@ -1262,19 +1072,10 @@ var init_src = __esm({
|
|
|
1262
1072
|
"packages/experience-design-system-generation/dist/src/index.js"() {
|
|
1263
1073
|
"use strict";
|
|
1264
1074
|
init_agent_names();
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
init_resolve_agent_binary();
|
|
1269
|
-
init_check_agent_auth();
|
|
1270
|
-
init_run_agent();
|
|
1271
|
-
init_parse_prop_tool_calls();
|
|
1272
|
-
init_parse_select_tool_calls();
|
|
1273
|
-
init_parse_token_tool_calls();
|
|
1274
|
-
init_parse_map_token_tool_calls();
|
|
1275
|
-
init_build_prompt();
|
|
1075
|
+
init_agent_runner();
|
|
1076
|
+
init_agent_invoker();
|
|
1077
|
+
init_prompt_builder();
|
|
1276
1078
|
init_progress();
|
|
1277
|
-
init_local_cli_agent_invoker();
|
|
1278
1079
|
}
|
|
1279
1080
|
});
|
|
1280
1081
|
|
|
@@ -5109,7 +4910,7 @@ async function readFileInline(path) {
|
|
|
5109
4910
|
return parts.filter(Boolean).join("\n\n");
|
|
5110
4911
|
}
|
|
5111
4912
|
function printFallbackInstructions(options) {
|
|
5112
|
-
const binary =
|
|
4913
|
+
const binary = resolveBinary(options.agent);
|
|
5113
4914
|
const skillPath = resolveSkillPath(options.skill);
|
|
5114
4915
|
const lines = [
|
|
5115
4916
|
`Error: agent '${options.agent}' not found in $PATH (looked for binary: ${binary}).`,
|
|
@@ -5324,7 +5125,7 @@ ${outputBuf}`);
|
|
|
5324
5125
|
lastError = describeAgentFailure(result);
|
|
5325
5126
|
continue;
|
|
5326
5127
|
}
|
|
5327
|
-
const { calls, warnings } =
|
|
5128
|
+
const { calls, warnings } = parseToolCallLines(result.stdout);
|
|
5328
5129
|
if (calls.length === 0) {
|
|
5329
5130
|
lastError = describeAgentFailure(result);
|
|
5330
5131
|
continue;
|
|
@@ -5570,7 +5371,7 @@ async function runGenerateSkill(skill, opts, verbose = false) {
|
|
|
5570
5371
|
process.stdout.write(prompt + "\n");
|
|
5571
5372
|
await exitWithAnalytics(0);
|
|
5572
5373
|
}
|
|
5573
|
-
const binary =
|
|
5374
|
+
const binary = resolveBinary(agent);
|
|
5574
5375
|
if (!await assertBinaryInPath(binary)) {
|
|
5575
5376
|
printFallbackInstructions({
|
|
5576
5377
|
agent,
|
|
@@ -9231,7 +9032,7 @@ ${defaultDiagnostics.map((diagnostic) => ` ${diagnostic}`).join("\n")}
|
|
|
9231
9032
|
return;
|
|
9232
9033
|
}
|
|
9233
9034
|
}
|
|
9234
|
-
const binary =
|
|
9035
|
+
const binary = resolveBinary(agent);
|
|
9235
9036
|
if (!await assertBinaryInPath(binary)) {
|
|
9236
9037
|
die(
|
|
9237
9038
|
`Error: agent '${agent}' not found in $PATH (looked for binary: ${binary}).
|
|
@@ -18943,9 +18744,9 @@ var init_wizard_generate_progress = __esm({
|
|
|
18943
18744
|
});
|
|
18944
18745
|
|
|
18945
18746
|
// packages/experience-design-system-cli-legacy/src/import/tui/spawn-generate.ts
|
|
18946
|
-
import { spawn as
|
|
18747
|
+
import { spawn as spawn2 } from "node:child_process";
|
|
18947
18748
|
function spawnGenerateChild(opts) {
|
|
18948
|
-
const child =
|
|
18749
|
+
const child = spawn2(opts.command, opts.args);
|
|
18949
18750
|
let stdout = "";
|
|
18950
18751
|
let stderr = "";
|
|
18951
18752
|
child.stdout?.on("data", (d) => {
|
|
@@ -27258,7 +27059,7 @@ import { join as join20, resolve as resolve17 } from "node:path";
|
|
|
27258
27059
|
import { appendFileSync as appendFileSync2, writeFileSync } from "node:fs";
|
|
27259
27060
|
import { access as access7, stat as stat5, writeFile as writeFile6 } from "node:fs/promises";
|
|
27260
27061
|
import { tmpdir } from "node:os";
|
|
27261
|
-
import { execFile as execFile2, spawn as
|
|
27062
|
+
import { execFile as execFile2, spawn as spawn3 } from "node:child_process";
|
|
27262
27063
|
import { mkdir as mkdir5 } from "node:fs/promises";
|
|
27263
27064
|
import { buildCDF as buildCDF3, validateCDF as validateCDF3, validateSlotReferences as validateSlotReferences2 } from "@contentful/experience-design-system-types";
|
|
27264
27065
|
import { jsx as jsx50, jsxs as jsxs43 } from "react/jsx-runtime";
|
|
@@ -27320,7 +27121,7 @@ function runCli(args) {
|
|
|
27320
27121
|
}
|
|
27321
27122
|
function runSpawnedCli(args, onStderr, onStdout) {
|
|
27322
27123
|
return new Promise((res) => {
|
|
27323
|
-
const child =
|
|
27124
|
+
const child = spawn3("node", args);
|
|
27324
27125
|
let stdout = "";
|
|
27325
27126
|
let stderr = "";
|
|
27326
27127
|
child.stdout.on("data", (d) => {
|
|
@@ -29615,7 +29416,7 @@ var init_agent_definitions = __esm({
|
|
|
29615
29416
|
});
|
|
29616
29417
|
|
|
29617
29418
|
// packages/experience-design-system-cli-legacy/src/setup/lib/shell.ts
|
|
29618
|
-
import { execFile as execFile3, spawn as
|
|
29419
|
+
import { execFile as execFile3, spawn as spawn4 } from "node:child_process";
|
|
29619
29420
|
import { access as access8 } from "node:fs/promises";
|
|
29620
29421
|
import { promisify as promisify2 } from "node:util";
|
|
29621
29422
|
async function binaryExists(name) {
|
|
@@ -29631,7 +29432,7 @@ async function pathExists3(path) {
|
|
|
29631
29432
|
}
|
|
29632
29433
|
function runSpawn(cmd, args, opts = {}) {
|
|
29633
29434
|
return new Promise((resolve21) => {
|
|
29634
|
-
const child =
|
|
29435
|
+
const child = spawn4(cmd, args, {
|
|
29635
29436
|
cwd: opts.cwd,
|
|
29636
29437
|
env: opts.env ?? process.env,
|
|
29637
29438
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -32061,7 +31862,7 @@ __export(program_exports, {
|
|
|
32061
31862
|
resolveBedrockFromAncestors: () => resolveBedrockFromAncestors,
|
|
32062
31863
|
runBuild: () => runBuild
|
|
32063
31864
|
});
|
|
32064
|
-
import { spawn as
|
|
31865
|
+
import { spawn as spawn5 } from "node:child_process";
|
|
32065
31866
|
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
32066
31867
|
import { dirname as dirname13, join as join26, resolve as resolve20 } from "node:path";
|
|
32067
31868
|
import { readFileSync as readFileSync10 } from "node:fs";
|
|
@@ -32096,7 +31897,7 @@ function registerBuildCommand(program) {
|
|
|
32096
31897
|
const pkgRoot = resolve20(dirname13(fileURLToPath4(import.meta.url)), "..", "..");
|
|
32097
31898
|
process.stderr.write("\u2699 Building from source...\n");
|
|
32098
31899
|
const { exitCode } = await runBuild({
|
|
32099
|
-
spawnFn: () =>
|
|
31900
|
+
spawnFn: () => spawn5("pnpm", ["build"], { cwd: pkgRoot, stdio: "inherit" }),
|
|
32100
31901
|
stderrWrite: (s) => process.stderr.write(s)
|
|
32101
31902
|
});
|
|
32102
31903
|
process.exit(exitCode);
|