@contentful/experience-design-system-cli 2.18.1-dev-build-b4ecc99.0 → 2.18.1-dev-build-180092e.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/package.json +5 -5
- package/dist/src/analyze/command.js +3 -3
- package/dist/src/analyze/composition/parse-map-edges.d.ts +1 -1
- package/dist/src/analyze/select-agent/command.js +6 -5
- package/dist/src/generate/command.d.ts +0 -6
- package/dist/src/generate/command.js +7 -17
- package/dist/src/import/tui/WizardApp.js +1 -1
- package/dist/src/lib/agent-model-options.js +1 -1
- package/dist/src/session/cache-keys.d.ts +1 -1
- package/dist/src/session/cache-keys.js +1 -1
- package/dist/src/session/db.d.ts +1 -1
- package/dist/src/session/db.js +1 -1
- package/package.json +8 -8
- package/dist/src/generate/agent-runner.d.ts +0 -125
- package/dist/src/generate/agent-runner.js +0 -427
- package/dist/src/generate/progress.d.ts +0 -9
- package/dist/src/generate/progress.js +0 -11
- package/dist/src/generate/prompt-builder.d.ts +0 -26
- package/dist/src/generate/prompt-builder.js +0 -213
- package/dist/src/lib/agent-names.d.ts +0 -4
- package/dist/src/lib/agent-names.js +0 -5
- package/skills/generate-components.md +0 -427
- package/skills/generate-tokens.md +0 -194
- package/skills/select-components.md +0 -224
|
@@ -1,427 +0,0 @@
|
|
|
1
|
-
import { spawn } from 'node:child_process';
|
|
2
|
-
import { getDebugLogger } from '../lib/debug-logger.js';
|
|
3
|
-
export { AGENT_NAMES, isAgentName } from '../lib/agent-names.js';
|
|
4
|
-
const VALID_SELECT_TOOL_NAMES = new Set(['select_component', 'reject_component']);
|
|
5
|
-
export function parseSelectToolCallLines(stdout) {
|
|
6
|
-
const calls = [];
|
|
7
|
-
const warnings = [];
|
|
8
|
-
for (const raw of stdout.split('\n')) {
|
|
9
|
-
const line = raw.trim();
|
|
10
|
-
if (!line.startsWith('{'))
|
|
11
|
-
continue;
|
|
12
|
-
let obj;
|
|
13
|
-
try {
|
|
14
|
-
obj = JSON.parse(line);
|
|
15
|
-
}
|
|
16
|
-
catch {
|
|
17
|
-
warnings.push(`unparseable line: ${line.slice(0, 120)}`);
|
|
18
|
-
continue;
|
|
19
|
-
}
|
|
20
|
-
if (typeof obj !== 'object' || obj === null || !('tool' in obj))
|
|
21
|
-
continue;
|
|
22
|
-
const rec = obj;
|
|
23
|
-
if (!VALID_SELECT_TOOL_NAMES.has(rec.tool))
|
|
24
|
-
continue;
|
|
25
|
-
if (typeof rec.name !== 'string' || !rec.name) {
|
|
26
|
-
warnings.push(`${String(rec.tool)} missing name — skipped`);
|
|
27
|
-
continue;
|
|
28
|
-
}
|
|
29
|
-
const call = {
|
|
30
|
-
tool: rec.tool,
|
|
31
|
-
name: rec.name,
|
|
32
|
-
};
|
|
33
|
-
if (typeof rec.reason === 'string')
|
|
34
|
-
call.reason = rec.reason;
|
|
35
|
-
if (typeof rec.confidence === 'number' && rec.confidence >= 1 && rec.confidence <= 5) {
|
|
36
|
-
if (call.tool === 'select_component') {
|
|
37
|
-
call.confidence = rec.confidence;
|
|
38
|
-
}
|
|
39
|
-
else {
|
|
40
|
-
call.confidence = rec.confidence;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
calls.push(call);
|
|
44
|
-
}
|
|
45
|
-
return { calls, warnings };
|
|
46
|
-
}
|
|
47
|
-
const VALID_TOOL_NAMES = new Set(['classify_prop', 'exclude_prop', 'classify_component', 'classify_slot']);
|
|
48
|
-
const VALID_TOKEN_TOOL_NAMES = new Set(['set_token', 'set_group']);
|
|
49
|
-
const VALID_CDF_TYPES = new Set(['string', 'richtext', 'media', 'enum', 'token', 'boolean']);
|
|
50
|
-
const VALID_CATEGORIES = new Set(['content', 'design', 'state']);
|
|
51
|
-
export function parseToolCallLines(stdout) {
|
|
52
|
-
const calls = [];
|
|
53
|
-
const warnings = [];
|
|
54
|
-
for (const raw of stdout.split('\n')) {
|
|
55
|
-
const line = raw.trim();
|
|
56
|
-
if (!line.startsWith('{'))
|
|
57
|
-
continue;
|
|
58
|
-
let obj;
|
|
59
|
-
try {
|
|
60
|
-
obj = JSON.parse(line);
|
|
61
|
-
}
|
|
62
|
-
catch {
|
|
63
|
-
warnings.push(`unparseable line: ${line.slice(0, 120)}`);
|
|
64
|
-
continue;
|
|
65
|
-
}
|
|
66
|
-
if (typeof obj !== 'object' || obj === null || !('tool' in obj))
|
|
67
|
-
continue;
|
|
68
|
-
const rec = obj;
|
|
69
|
-
if (!VALID_TOOL_NAMES.has(rec.tool)) {
|
|
70
|
-
warnings.push(`unknown tool: ${String(rec.tool)}`);
|
|
71
|
-
continue;
|
|
72
|
-
}
|
|
73
|
-
const tool = rec.tool;
|
|
74
|
-
if (tool === 'classify_prop') {
|
|
75
|
-
if (typeof rec.prop !== 'string' || !rec.prop) {
|
|
76
|
-
warnings.push('classify_prop missing prop name — skipped');
|
|
77
|
-
continue;
|
|
78
|
-
}
|
|
79
|
-
if (typeof rec.cdf_type !== 'string' || !VALID_CDF_TYPES.has(rec.cdf_type)) {
|
|
80
|
-
warnings.push(`classify_prop '${rec.prop}': invalid cdf_type '${String(rec.cdf_type)}' — skipped`);
|
|
81
|
-
continue;
|
|
82
|
-
}
|
|
83
|
-
if (typeof rec.cdf_category !== 'string' || !VALID_CATEGORIES.has(rec.cdf_category)) {
|
|
84
|
-
warnings.push(`classify_prop '${rec.prop}': invalid cdf_category '${String(rec.cdf_category)}' — skipped`);
|
|
85
|
-
continue;
|
|
86
|
-
}
|
|
87
|
-
const call = {
|
|
88
|
-
tool: 'classify_prop',
|
|
89
|
-
prop: rec.prop,
|
|
90
|
-
cdf_type: rec.cdf_type,
|
|
91
|
-
cdf_category: rec.cdf_category,
|
|
92
|
-
};
|
|
93
|
-
if (Array.isArray(rec.values) && rec.values.every((v) => typeof v === 'string')) {
|
|
94
|
-
call.values = rec.values;
|
|
95
|
-
}
|
|
96
|
-
if (typeof rec.token_kind === 'string')
|
|
97
|
-
call.token_kind = rec.token_kind;
|
|
98
|
-
if (typeof rec.required === 'boolean')
|
|
99
|
-
call.required = rec.required;
|
|
100
|
-
if (typeof rec.description === 'string')
|
|
101
|
-
call.description = rec.description;
|
|
102
|
-
if (typeof rec.default === 'string' || typeof rec.default === 'boolean')
|
|
103
|
-
call.default = rec.default;
|
|
104
|
-
if (typeof rec.reason === 'string')
|
|
105
|
-
call.reason = rec.reason;
|
|
106
|
-
calls.push(call);
|
|
107
|
-
}
|
|
108
|
-
else if (tool === 'exclude_prop') {
|
|
109
|
-
if (typeof rec.prop !== 'string' || !rec.prop) {
|
|
110
|
-
warnings.push('exclude_prop missing prop name — skipped');
|
|
111
|
-
continue;
|
|
112
|
-
}
|
|
113
|
-
calls.push({
|
|
114
|
-
tool: 'exclude_prop',
|
|
115
|
-
prop: rec.prop,
|
|
116
|
-
reason: typeof rec.reason === 'string' ? rec.reason : '',
|
|
117
|
-
});
|
|
118
|
-
}
|
|
119
|
-
else if (tool === 'classify_component') {
|
|
120
|
-
const call = { tool: 'classify_component' };
|
|
121
|
-
if (typeof rec.description === 'string')
|
|
122
|
-
call.description = rec.description;
|
|
123
|
-
if (typeof rec.rationale === 'object' && rec.rationale !== null) {
|
|
124
|
-
const r = rec.rationale;
|
|
125
|
-
const rationale = {};
|
|
126
|
-
if (typeof r.description === 'string')
|
|
127
|
-
rationale.description = r.description;
|
|
128
|
-
if (typeof r.props === 'string')
|
|
129
|
-
rationale.props = r.props;
|
|
130
|
-
if (typeof r.slots === 'string')
|
|
131
|
-
rationale.slots = r.slots;
|
|
132
|
-
if (Object.keys(rationale).length > 0)
|
|
133
|
-
call.rationale = rationale;
|
|
134
|
-
}
|
|
135
|
-
calls.push(call);
|
|
136
|
-
}
|
|
137
|
-
else if (tool === 'classify_slot') {
|
|
138
|
-
if (typeof rec.slot !== 'string' || !rec.slot) {
|
|
139
|
-
warnings.push('classify_slot missing slot name — skipped');
|
|
140
|
-
continue;
|
|
141
|
-
}
|
|
142
|
-
const call = { tool: 'classify_slot', slot: rec.slot };
|
|
143
|
-
if (typeof rec.required === 'boolean')
|
|
144
|
-
call.required = rec.required;
|
|
145
|
-
if (Array.isArray(rec.allowed_components) && rec.allowed_components.every((v) => typeof v === 'string')) {
|
|
146
|
-
call.allowed_components = rec.allowed_components;
|
|
147
|
-
}
|
|
148
|
-
if (typeof rec.description === 'string')
|
|
149
|
-
call.description = rec.description;
|
|
150
|
-
if (typeof rec.rationale === 'string')
|
|
151
|
-
call.rationale = rec.rationale;
|
|
152
|
-
calls.push(call);
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
return { calls, warnings };
|
|
156
|
-
}
|
|
157
|
-
export function parseTokenToolCallLines(stdout) {
|
|
158
|
-
const calls = [];
|
|
159
|
-
const warnings = [];
|
|
160
|
-
for (const raw of stdout.split('\n')) {
|
|
161
|
-
const line = raw.trim();
|
|
162
|
-
if (!line.startsWith('{'))
|
|
163
|
-
continue;
|
|
164
|
-
let obj;
|
|
165
|
-
try {
|
|
166
|
-
obj = JSON.parse(line);
|
|
167
|
-
}
|
|
168
|
-
catch {
|
|
169
|
-
warnings.push(`unparseable line: ${line.slice(0, 120)}`);
|
|
170
|
-
continue;
|
|
171
|
-
}
|
|
172
|
-
if (typeof obj !== 'object' || obj === null || !('tool' in obj))
|
|
173
|
-
continue;
|
|
174
|
-
const rec = obj;
|
|
175
|
-
if (!VALID_TOKEN_TOOL_NAMES.has(rec.tool))
|
|
176
|
-
continue; // not a token call — skip silently
|
|
177
|
-
if (rec.tool === 'set_token') {
|
|
178
|
-
if (typeof rec.path !== 'string' || !rec.path) {
|
|
179
|
-
warnings.push('set_token missing path — skipped');
|
|
180
|
-
continue;
|
|
181
|
-
}
|
|
182
|
-
if (typeof rec.type !== 'string' || !rec.type) {
|
|
183
|
-
warnings.push(`set_token '${rec.path}': missing type — skipped`);
|
|
184
|
-
continue;
|
|
185
|
-
}
|
|
186
|
-
if (!('value' in rec)) {
|
|
187
|
-
warnings.push(`set_token '${rec.path}': missing value — skipped`);
|
|
188
|
-
continue;
|
|
189
|
-
}
|
|
190
|
-
const call = { tool: 'set_token', path: rec.path, type: rec.type, value: rec.value };
|
|
191
|
-
if (typeof rec.description === 'string')
|
|
192
|
-
call.description = rec.description;
|
|
193
|
-
calls.push(call);
|
|
194
|
-
}
|
|
195
|
-
else if (rec.tool === 'set_group') {
|
|
196
|
-
if (typeof rec.path !== 'string' || !rec.path) {
|
|
197
|
-
warnings.push('set_group missing path — skipped');
|
|
198
|
-
continue;
|
|
199
|
-
}
|
|
200
|
-
const call = { tool: 'set_group', path: rec.path };
|
|
201
|
-
if (typeof rec.description === 'string')
|
|
202
|
-
call.description = rec.description;
|
|
203
|
-
calls.push(call);
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
return { calls, warnings };
|
|
207
|
-
}
|
|
208
|
-
// --- Agent invocation ---
|
|
209
|
-
const AGENT_BINARIES = {
|
|
210
|
-
claude: 'claude',
|
|
211
|
-
codex: 'codex',
|
|
212
|
-
opencode: 'opencode',
|
|
213
|
-
cursor: 'cursor-agent',
|
|
214
|
-
};
|
|
215
|
-
export function resolveBinary(agent) {
|
|
216
|
-
const envKey = `EDS_AGENT_BINARY_${agent.toUpperCase()}`;
|
|
217
|
-
const override = process.env[envKey];
|
|
218
|
-
if (override && override.trim())
|
|
219
|
-
return override.trim();
|
|
220
|
-
return AGENT_BINARIES[agent];
|
|
221
|
-
}
|
|
222
|
-
/**
|
|
223
|
-
* Default models per agent — lightweight/fast picks to control cost when no
|
|
224
|
-
* explicit model is configured. cursor uses `gpt-mini` (verified alias from
|
|
225
|
-
* GetUsableModels; haiku is not available in cursor's model catalog).
|
|
226
|
-
*/
|
|
227
|
-
const DEFAULT_MODELS = {
|
|
228
|
-
claude: 'haiku',
|
|
229
|
-
codex: 'gpt-5.4-mini', // requires OPENAI_API_KEY; ChatGPT account users must pass --model
|
|
230
|
-
opencode: 'claude-haiku-4-5',
|
|
231
|
-
cursor: 'gpt-mini', // cursor alias for gpt-5.4-mini-medium; haiku not in cursor's catalog
|
|
232
|
-
};
|
|
233
|
-
/**
|
|
234
|
-
* Resolve the model for an agent. Explicit flag/creds value wins, then a
|
|
235
|
-
* per-agent `EDS_AGENT_MODEL_<AGENT>` env override (mirrors the
|
|
236
|
-
* `EDS_AGENT_BINARY_<AGENT>` pattern), otherwise the lightweight default for
|
|
237
|
-
* that agent.
|
|
238
|
-
*/
|
|
239
|
-
export function resolveAgentModel(agent, explicit) {
|
|
240
|
-
if (explicit && explicit.trim())
|
|
241
|
-
return explicit.trim();
|
|
242
|
-
const override = process.env[`EDS_AGENT_MODEL_${agent.toUpperCase()}`];
|
|
243
|
-
if (override && override.trim())
|
|
244
|
-
return override.trim();
|
|
245
|
-
return DEFAULT_MODELS[agent];
|
|
246
|
-
}
|
|
247
|
-
export function buildArgs(agent, prompt, model, promptViaStdin = false) {
|
|
248
|
-
const modelArg = ['--model', resolveAgentModel(agent, model)];
|
|
249
|
-
// When the prompt is delivered on stdin, omit it from argv — a large prompt
|
|
250
|
-
// as a command-line argument overflows ARG_MAX (spawn E2BIG). All four CLIs
|
|
251
|
-
// read the prompt from stdin when it isn't passed positionally.
|
|
252
|
-
const promptArg = promptViaStdin ? [] : [prompt];
|
|
253
|
-
switch (agent) {
|
|
254
|
-
case 'claude':
|
|
255
|
-
return ['--print', ...modelArg, ...promptArg];
|
|
256
|
-
case 'codex':
|
|
257
|
-
// --dangerously-bypass-approvals-and-sandbox required for non-interactive use
|
|
258
|
-
return ['exec', ...modelArg, '--dangerously-bypass-approvals-and-sandbox', ...promptArg];
|
|
259
|
-
case 'opencode':
|
|
260
|
-
return ['run', ...modelArg, ...promptArg];
|
|
261
|
-
case 'cursor':
|
|
262
|
-
// cursor-agent uses --print for non-interactive stdout output
|
|
263
|
-
return ['--print', ...modelArg, ...promptArg];
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
export async function runAgent(options) {
|
|
267
|
-
const { agent, prompt, interactive, timeoutMs, model, onOutput, promptViaStdin } = options;
|
|
268
|
-
const binary = resolveBinary(agent);
|
|
269
|
-
const useStdin = !!promptViaStdin && !interactive;
|
|
270
|
-
const args = buildArgs(agent, prompt, model, useStdin);
|
|
271
|
-
const debug = getDebugLogger();
|
|
272
|
-
const startedAt = Date.now();
|
|
273
|
-
debug.event('agent', 'run.start', {
|
|
274
|
-
agent,
|
|
275
|
-
binary,
|
|
276
|
-
model,
|
|
277
|
-
interactive,
|
|
278
|
-
timeoutMs,
|
|
279
|
-
promptLen: prompt.length,
|
|
280
|
-
promptHead: prompt.slice(0, 500),
|
|
281
|
-
});
|
|
282
|
-
return new Promise((resolve) => {
|
|
283
|
-
const child = spawn(binary, args, {
|
|
284
|
-
stdio: interactive ? 'inherit' : ['pipe', 'pipe', 'pipe'],
|
|
285
|
-
});
|
|
286
|
-
if (!interactive) {
|
|
287
|
-
if (useStdin && child.stdin) {
|
|
288
|
-
// Guard against EPIPE: the child may close stdin before we finish
|
|
289
|
-
// writing (fast exit, or it stops reading). Swallow the write error —
|
|
290
|
-
// the child's own exit code/stderr is the source of truth.
|
|
291
|
-
child.stdin.on('error', () => { });
|
|
292
|
-
child.stdin.write(prompt, () => {
|
|
293
|
-
child.stdin?.end();
|
|
294
|
-
});
|
|
295
|
-
}
|
|
296
|
-
else {
|
|
297
|
-
child.stdin?.end();
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
let stdout = '';
|
|
301
|
-
let stderr = '';
|
|
302
|
-
let timedOut = false;
|
|
303
|
-
const timer = setTimeout(() => {
|
|
304
|
-
timedOut = true;
|
|
305
|
-
child.kill('SIGTERM');
|
|
306
|
-
}, timeoutMs);
|
|
307
|
-
if (!interactive) {
|
|
308
|
-
child.stdout?.on('data', (chunk) => {
|
|
309
|
-
const text = chunk.toString();
|
|
310
|
-
stdout += text;
|
|
311
|
-
onOutput?.(text);
|
|
312
|
-
});
|
|
313
|
-
child.stderr?.on('data', (chunk) => {
|
|
314
|
-
stderr += chunk.toString();
|
|
315
|
-
});
|
|
316
|
-
}
|
|
317
|
-
child.on('close', (code, signal) => {
|
|
318
|
-
clearTimeout(timer);
|
|
319
|
-
const result = {
|
|
320
|
-
exitCode: signal ? 1 : (code ?? 1),
|
|
321
|
-
stdout,
|
|
322
|
-
stderr,
|
|
323
|
-
timedOut,
|
|
324
|
-
};
|
|
325
|
-
debug.event('agent', 'run.end', {
|
|
326
|
-
agent,
|
|
327
|
-
model,
|
|
328
|
-
durationMs: Date.now() - startedAt,
|
|
329
|
-
exitCode: result.exitCode,
|
|
330
|
-
signal,
|
|
331
|
-
timedOut,
|
|
332
|
-
stdoutLen: stdout.length,
|
|
333
|
-
stderrLen: stderr.length,
|
|
334
|
-
stderrTail: stderr.slice(-1000),
|
|
335
|
-
});
|
|
336
|
-
resolve(result);
|
|
337
|
-
});
|
|
338
|
-
});
|
|
339
|
-
}
|
|
340
|
-
export async function checkAgentAuth(agent) {
|
|
341
|
-
const binary = resolveBinary(agent);
|
|
342
|
-
// Verify the selected agent's binary exists first — for EVERY agent, not
|
|
343
|
-
// just claude. When `binary` is an absolute path (e.g. set via
|
|
344
|
-
// EDS_AGENT_BINARY_<AGENT>=/opt/custom/bin), `which` on some shells doesn't
|
|
345
|
-
// resolve it — check the filesystem directly for absolute paths, and fall
|
|
346
|
-
// back to `which` for bare names on $PATH.
|
|
347
|
-
const binaryExists = await new Promise((resolve) => {
|
|
348
|
-
if (binary.startsWith('/')) {
|
|
349
|
-
import('node:fs/promises').then((fs) => fs.access(binary).then(() => resolve(true), () => resolve(false)));
|
|
350
|
-
return;
|
|
351
|
-
}
|
|
352
|
-
const child = spawn('which', [binary], { stdio: 'ignore' });
|
|
353
|
-
child.on('close', (code) => resolve(code === 0));
|
|
354
|
-
});
|
|
355
|
-
if (!binaryExists)
|
|
356
|
-
return 'not-found';
|
|
357
|
-
// Only Claude exposes `auth status --json`. Non-Claude agents are considered
|
|
358
|
-
// authenticated once their binary is present — never gate them on claude
|
|
359
|
-
// (e.g. Codex-via-Bedrock users would otherwise be blocked by a claude check).
|
|
360
|
-
if (agent !== 'claude')
|
|
361
|
-
return 'ok';
|
|
362
|
-
// Use `claude auth status` — fast, no API call, works regardless of which
|
|
363
|
-
// auth provider (direct, Bedrock, Vertex) or whether AWS_PROFILE is set.
|
|
364
|
-
return new Promise((resolve) => {
|
|
365
|
-
const child = spawn(binary, ['auth', 'status', '--json'], {
|
|
366
|
-
stdio: ['ignore', 'pipe', 'pipe'],
|
|
367
|
-
});
|
|
368
|
-
let stdout = '';
|
|
369
|
-
let done = false;
|
|
370
|
-
const timer = setTimeout(() => {
|
|
371
|
-
if (!done) {
|
|
372
|
-
done = true;
|
|
373
|
-
child.kill('SIGTERM');
|
|
374
|
-
resolve('unauthenticated');
|
|
375
|
-
}
|
|
376
|
-
}, 5000);
|
|
377
|
-
child.stdout?.on('data', (chunk) => {
|
|
378
|
-
stdout += chunk.toString();
|
|
379
|
-
});
|
|
380
|
-
child.on('close', (code) => {
|
|
381
|
-
if (done)
|
|
382
|
-
return;
|
|
383
|
-
done = true;
|
|
384
|
-
clearTimeout(timer);
|
|
385
|
-
if (code !== 0) {
|
|
386
|
-
resolve('unauthenticated');
|
|
387
|
-
return;
|
|
388
|
-
}
|
|
389
|
-
try {
|
|
390
|
-
const status = JSON.parse(stdout);
|
|
391
|
-
resolve(status.loggedIn ? 'ok' : 'unauthenticated');
|
|
392
|
-
}
|
|
393
|
-
catch {
|
|
394
|
-
resolve('unauthenticated');
|
|
395
|
-
}
|
|
396
|
-
});
|
|
397
|
-
});
|
|
398
|
-
}
|
|
399
|
-
/**
|
|
400
|
-
* Build a diagnostic string from a failed agent run, surfacing the agent's own
|
|
401
|
-
* stderr (or stdout, when stderr is empty) so callers never emit a context-free
|
|
402
|
-
* "agent failed". Callers only invoke this on a failed run: either a non-zero
|
|
403
|
-
* exit, or a zero exit that produced no tool calls. A non-zero exit is reported
|
|
404
|
-
* as such; a zero exit is therefore the "produced no tool calls" case.
|
|
405
|
-
*/
|
|
406
|
-
export function describeAgentFailure(result, maxDetail = 800) {
|
|
407
|
-
const base = result.exitCode !== 0 ? `agent exited with code ${result.exitCode}` : 'agent produced no tool calls';
|
|
408
|
-
const detail = (result.stderr.trim() || result.stdout.trim()).slice(-maxDetail).trim();
|
|
409
|
-
return detail ? `${base} — ${detail}` : base;
|
|
410
|
-
}
|
|
411
|
-
export function extractSentinelOutput(stdout) {
|
|
412
|
-
const START = '<<<EDS_OUTPUT_START>>>';
|
|
413
|
-
const END = '<<<EDS_OUTPUT_END>>>';
|
|
414
|
-
const startIdx = stdout.indexOf(START);
|
|
415
|
-
const endIdx = stdout.indexOf(END);
|
|
416
|
-
if (startIdx === -1 || endIdx === -1 || endIdx <= startIdx)
|
|
417
|
-
return null;
|
|
418
|
-
// Check for multiple blocks
|
|
419
|
-
const secondStart = stdout.indexOf(START, startIdx + START.length);
|
|
420
|
-
if (secondStart !== -1 && secondStart < endIdx)
|
|
421
|
-
return 'multiple';
|
|
422
|
-
const afterStart = stdout.indexOf(END, startIdx);
|
|
423
|
-
const secondEnd = stdout.indexOf(END, afterStart + END.length);
|
|
424
|
-
if (secondEnd !== -1)
|
|
425
|
-
return 'multiple';
|
|
426
|
-
return stdout.slice(startIdx + START.length, endIdx).trim();
|
|
427
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Formats a structured generation-progress line for the wizard parser.
|
|
3
|
-
*
|
|
4
|
-
* Emitted at terminal completion of each component (success, cache hit,
|
|
5
|
-
* pinned hit, or final failure). `done` represents the count of completed
|
|
6
|
-
* components, which is monotonically non-decreasing — unlike the legacy
|
|
7
|
-
* `[index+1/total]` line, which reports input position.
|
|
8
|
-
*/
|
|
9
|
-
export declare function formatGenerateProgressLine(done: number, total: number, name: string): string;
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Formats a structured generation-progress line for the wizard parser.
|
|
3
|
-
*
|
|
4
|
-
* Emitted at terminal completion of each component (success, cache hit,
|
|
5
|
-
* pinned hit, or final failure). `done` represents the count of completed
|
|
6
|
-
* components, which is monotonically non-decreasing — unlike the legacy
|
|
7
|
-
* `[index+1/total]` line, which reports input position.
|
|
8
|
-
*/
|
|
9
|
-
export function formatGenerateProgressLine(done, total, name) {
|
|
10
|
-
return `progress=generate:${done}/${total}:${name}`;
|
|
11
|
-
}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
/** `components` — classify component props; `tokens` — classify design tokens; `select` — decide whether a component belongs in Contentful Experience Orchestration */
|
|
2
|
-
export type Skill = 'components' | 'tokens' | 'select';
|
|
3
|
-
export type Mode = 'autonomous' | 'interactive';
|
|
4
|
-
export interface PromptOptions {
|
|
5
|
-
skill: Skill;
|
|
6
|
-
mode: Mode;
|
|
7
|
-
rawComponentsInline?: string;
|
|
8
|
-
rawTokensInline?: string;
|
|
9
|
-
/** Original filename for raw tokens — used to set the correct code fence language. */
|
|
10
|
-
rawTokensFilename?: string;
|
|
11
|
-
tokensInline?: string;
|
|
12
|
-
tokenMapInline?: string;
|
|
13
|
-
outDir: string;
|
|
14
|
-
/** For components skill only: the single component's name (used in error messages). */
|
|
15
|
-
componentName?: string;
|
|
16
|
-
/**
|
|
17
|
-
* Feature 8: custom prompt path override. When set, this absolute or relative
|
|
18
|
-
* `.md` path is read in place of the bundled skill file. The bundled-prompt
|
|
19
|
-
* invariants (utility-wrapper rejection, description content rules, etc.) do
|
|
20
|
-
* NOT apply under an override — callers are responsible for showing the
|
|
21
|
-
* appropriate warning banner.
|
|
22
|
-
*/
|
|
23
|
-
skillPathOverride?: string;
|
|
24
|
-
}
|
|
25
|
-
export declare function buildPrompt(options: PromptOptions): Promise<string>;
|
|
26
|
-
export declare function resolveSkillPath(skill: Skill): string;
|