@contentful/experience-design-system-generation 2.34.1-dev-build-e12e553.0 → 2.34.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contentful/experience-design-system-generation",
3
- "version": "2.34.1-dev-build-e12e553.0",
3
+ "version": "2.34.1",
4
4
  "description": "Agent-invocation and skill-prompt engine for the Contentful Experience Design System SDK",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -113,20 +113,6 @@ export declare function agentSupportsBedrock(agent: AgentName): boolean;
113
113
  */
114
114
  export declare function resolveAgentModel(agent: AgentName, explicit?: string, bedrock?: boolean): string | undefined;
115
115
  export type AgentDebugEvent = (name: string, payload?: Record<string, unknown>) => void;
116
- export declare function agentSupportsStdinPrompt(agent: AgentName): boolean;
117
- /**
118
- * Decide how to deliver the prompt.
119
- *
120
- * Prefer stdin whenever the agent supports it and the prompt is large enough for
121
- * argv limits to matter. This is what makes `generate components` work on Windows,
122
- * and it removes a latent ARG_MAX failure on macOS as the skills grow.
123
- *
124
- * Exported so callers can detect the case that has no answer: a large prompt for an
125
- * agent that can only accept argv.
126
- */
127
- export declare function shouldUseStdinPrompt(agent: AgentName, prompt: string): boolean;
128
- /** True when the prompt cannot be delivered to this agent on this platform. */
129
- export declare function promptExceedsArgvLimit(agent: AgentName, prompt: string, platform?: NodeJS.Platform): boolean;
130
116
  export declare function buildArgs(agent: AgentName, prompt: string, model?: string, promptViaStdin?: boolean, bedrock?: boolean): string[];
131
117
  export declare function runAgent(options: {
132
118
  agent: AgentName;
@@ -137,12 +123,9 @@ export declare function runAgent(options: {
137
123
  bedrock?: boolean;
138
124
  onOutput?: (chunk: string) => void;
139
125
  /**
140
- * Force the prompt onto stdin instead of an argv positional.
141
- *
142
- * Usually unnecessary: a prompt large enough for argv limits to matter is sent
143
- * on stdin automatically (see shouldUseStdinPrompt). Set this to opt in for a
144
- * small prompt too. It cannot force stdin for an agent that has no stdin path —
145
- * copilot requires the prompt as its `-p` value.
126
+ * Deliver the prompt on stdin instead of as an argv positional. Required for
127
+ * large prompts (e.g. the composition resolver inlining candidate files),
128
+ * which overflow ARG_MAX when passed as an argument.
146
129
  */
147
130
  promptViaStdin?: boolean;
148
131
  /** Optional debug-event sink; callers own how/where events get logged. */
@@ -1,5 +1,4 @@
1
1
  import { spawn } from 'node:child_process';
2
- import { findBinary, resolveSpawn, spawnSpec } from './lib/binary-launch.js';
3
2
  export { AGENT_NAMES, DEFAULT_AGENT_NAME, isAgentName } from './agent-names.js';
4
3
  const VALID_SELECT_TOOL_NAMES = new Set(['select_component', 'reject_component']);
5
4
  function findJsonObjectEnd(line) {
@@ -356,62 +355,15 @@ function codexBedrockConfigArgs() {
356
355
  const region = process.env.AWS_REGION?.trim() || process.env.AWS_DEFAULT_REGION?.trim() || DEFAULT_CODEX_BEDROCK_REGION;
357
356
  return ['-c', 'model_provider=amazon-bedrock', '-c', `model_providers.amazon-bedrock.region=${region}`];
358
357
  }
359
- /**
360
- * Agents that can read the prompt from stdin instead of argv.
361
- *
362
- * copilot cannot: its `-p` flag requires the prompt as the flag's value (see
363
- * buildArgs), so there is nowhere for stdin to go.
364
- */
365
- const STDIN_CAPABLE_AGENTS = new Set(['claude', 'codex', 'opencode', 'cursor']);
366
- export function agentSupportsStdinPrompt(agent) {
367
- return STDIN_CAPABLE_AGENTS.has(agent);
368
- }
369
- /**
370
- * Windows caps a command line at 8191 characters through cmd.exe, and 32767 in
371
- * CreateProcess. Our skill prompts are far larger than both — generate-components
372
- * alone is ~50KB — so passing one as an argv positional cannot work there. POSIX
373
- * is far more generous (ARG_MAX ~1MB on macOS) but not unlimited.
374
- *
375
- * Kept deliberately low: stdin is the better path for any prompt of real size, and
376
- * there is no benefit to argv beyond the few agents that require it.
377
- */
378
- const ARGV_PROMPT_LIMIT = 4096;
379
- /**
380
- * Decide how to deliver the prompt.
381
- *
382
- * Prefer stdin whenever the agent supports it and the prompt is large enough for
383
- * argv limits to matter. This is what makes `generate components` work on Windows,
384
- * and it removes a latent ARG_MAX failure on macOS as the skills grow.
385
- *
386
- * Exported so callers can detect the case that has no answer: a large prompt for an
387
- * agent that can only accept argv.
388
- */
389
- export function shouldUseStdinPrompt(agent, prompt) {
390
- return agentSupportsStdinPrompt(agent) && prompt.length > ARGV_PROMPT_LIMIT;
391
- }
392
- /** True when the prompt cannot be delivered to this agent on this platform. */
393
- export function promptExceedsArgvLimit(agent, prompt, platform = process.platform) {
394
- if (agentSupportsStdinPrompt(agent))
395
- return false;
396
- // 8191 is the cmd.exe ceiling; every Windows launch of a .cmd shim goes through it.
397
- return platform === 'win32' && prompt.length > 8191;
398
- }
399
358
  export function buildArgs(agent, prompt, model, promptViaStdin = false, bedrock = false) {
400
359
  // codex with no configured model resolves to undefined — omit --model
401
360
  // entirely so the CLI picks its own account-compatible default.
402
361
  const resolvedModel = resolveAgentModel(agent, model, bedrock);
403
362
  const modelArg = resolvedModel ? ['--model', resolvedModel] : [];
404
- // Ignore a stdin request for an agent that has no stdin path. copilot's `-p`
405
- // takes the prompt as its value, so honouring the request would emit a bare
406
- // `-p` and silently drop the prompt. runAgent already avoids asking, but keep
407
- // the guard here so the function can't be misused.
408
- const useStdin = promptViaStdin && agentSupportsStdinPrompt(agent);
409
- // When the prompt is delivered on stdin, omit it from argv — a large prompt as
410
- // a command-line argument overflows ARG_MAX on POSIX (E2BIG) and cannot be
411
- // passed at all on Windows, whose command line caps at 8191 characters through
412
- // cmd.exe. These CLIs read the prompt from stdin when it isn't passed
413
- // positionally.
414
- const promptArg = useStdin ? [] : [prompt];
363
+ // When the prompt is delivered on stdin, omit it from argv — a large prompt
364
+ // as a command-line argument overflows ARG_MAX (spawn E2BIG). All four CLIs
365
+ // read the prompt from stdin when it isn't passed positionally.
366
+ const promptArg = promptViaStdin ? [] : [prompt];
415
367
  switch (agent) {
416
368
  case 'claude':
417
369
  return ['--print', ...modelArg, ...promptArg];
@@ -454,11 +406,7 @@ export async function runAgent(options) {
454
406
  // call sites that forget to thread the flag through by hand.
455
407
  const bedrock = options.bedrock ?? process.env.EDS_BEDROCK === '1';
456
408
  const binary = resolveBinary(agent);
457
- // Send a large prompt on stdin even when the caller didn't ask: a ~50KB skill
458
- // prompt exceeds every Windows command-line limit, so argv simply cannot carry
459
- // it. Honour an explicit promptViaStdin for smaller prompts, but never route to
460
- // stdin for an agent that can't read it (copilot).
461
- const useStdin = agentSupportsStdinPrompt(agent) && (!!promptViaStdin || shouldUseStdinPrompt(agent, prompt));
409
+ const useStdin = !!promptViaStdin;
462
410
  const args = buildArgs(agent, prompt, model, useStdin, bedrock);
463
411
  const startedAt = Date.now();
464
412
  onDebugEvent?.('run.start', {
@@ -472,14 +420,8 @@ export async function runAgent(options) {
472
420
  });
473
421
  return new Promise((resolve) => {
474
422
  const bedrockEnv = bedrock ? BEDROCK_ENV_BY_AGENT[agent] : undefined;
475
- // On Windows the agent CLIs are `.cmd` shims, which spawn can neither find
476
- // (libuv ignores PATHEXT) nor start directly (EINVAL). Resolve and wrap.
477
- // Falling back to the bare name keeps the existing 'error' handling path,
478
- // which reports a missing binary far better than throwing from here.
479
- const launch = resolveSpawn(binary, args) ?? { command: binary, args };
480
- const child = spawn(launch.command, launch.args, {
423
+ const child = spawn(binary, args, {
481
424
  stdio: ['pipe', 'pipe', 'pipe'],
482
- ...(launch.windowsVerbatimArguments ? { windowsVerbatimArguments: true } : {}),
483
425
  ...(bedrockEnv ? { env: { ...process.env, ...bedrockEnv } } : {}),
484
426
  });
485
427
  if (useStdin && child.stdin) {
@@ -535,12 +477,19 @@ export async function runAgent(options) {
535
477
  export async function checkAgentAuth(agent) {
536
478
  const binary = resolveBinary(agent);
537
479
  // Verify the selected agent's binary exists first — for EVERY agent, not
538
- // just claude. findBinary handles both shapes this has to cover: an absolute
539
- // path (e.g. EDS_AGENT_BINARY_<AGENT>=/opt/custom/bin, or C:\tools\claude.cmd)
540
- // and a bare name on PATH. It replaces shelling out to `which`, which doesn't
541
- // exist on Windows, and recognises Windows `.cmd` shims.
542
- const resolvedBinary = findBinary(binary);
543
- if (!resolvedBinary)
480
+ // just claude. When `binary` is an absolute path (e.g. set via
481
+ // EDS_AGENT_BINARY_<AGENT>=/opt/custom/bin), `which` on some shells doesn't
482
+ // resolve it — check the filesystem directly for absolute paths, and fall
483
+ // back to `which` for bare names on $PATH.
484
+ const binaryExists = await new Promise((resolve) => {
485
+ if (binary.startsWith('/')) {
486
+ import('node:fs/promises').then((fs) => fs.access(binary).then(() => resolve(true), () => resolve(false)));
487
+ return;
488
+ }
489
+ const child = spawn('which', [binary], { stdio: 'ignore' });
490
+ child.on('close', (code) => resolve(code === 0));
491
+ });
492
+ if (!binaryExists)
544
493
  return 'not-found';
545
494
  // Only Claude exposes `auth status --json`. Non-Claude agents are considered
546
495
  // authenticated once their binary is present — never gate them on claude
@@ -550,11 +499,8 @@ export async function checkAgentAuth(agent) {
550
499
  // Use `claude auth status` — fast, no API call, works regardless of which
551
500
  // auth provider (direct, Bedrock, Vertex) or whether AWS_PROFILE is set.
552
501
  return new Promise((resolve) => {
553
- // Already resolved above, so wrap the real path rather than looking it up again.
554
- const launch = spawnSpec(resolvedBinary, ['auth', 'status', '--json']);
555
- const child = spawn(launch.command, launch.args, {
502
+ const child = spawn(binary, ['auth', 'status', '--json'], {
556
503
  stdio: ['ignore', 'pipe', 'pipe'],
557
- ...(launch.windowsVerbatimArguments ? { windowsVerbatimArguments: true } : {}),
558
504
  });
559
505
  let stdout = '';
560
506
  let done = false;
@@ -1,11 +1,9 @@
1
1
  export { AGENT_NAMES, DEFAULT_AGENT_NAME, isAgentName } from './agent-names.js';
2
2
  export type { AgentName } from './agent-names.js';
3
- export { agentSupportsBedrock, agentSupportsStdinPrompt, buildArgs, checkAgentAuth, describeAgentFailure, extractSentinelOutput, parseMapTokenPropToolCallLines, parseSelectToolCallLines, parseTokenToolCallLines, parseToolCallLines, promptExceedsArgvLimit, resolveAgentModel, resolveBinary, runAgent, shouldUseStdinPrompt, } from './agent-runner.js';
3
+ export { agentSupportsBedrock, buildArgs, checkAgentAuth, describeAgentFailure, extractSentinelOutput, parseMapTokenPropToolCallLines, parseSelectToolCallLines, parseTokenToolCallLines, parseToolCallLines, resolveAgentModel, resolveBinary, runAgent, } from './agent-runner.js';
4
4
  export type { AgentAuthStatus, AgentDebugEvent, AgentRunResult, ClassifyComponentCall, ClassifyPropCall, ClassifySlotCall, ExcludePropCall, MapTokenPropCall, ParsedMapTokenPropToolCalls, ParsedSelectToolCalls, ParsedTokenToolCalls, ParsedToolCalls, RejectComponentCall, SelectComponentCall, SelectToolCall, SetGroupCall, SetTokenCall, ToolCall, TokenToolCall, } from './agent-runner.js';
5
5
  export { createLocalCliAgentInvoker } from './agent-invoker.js';
6
6
  export type { AgentInvoker, CreateLocalCliAgentInvokerOptions, InvokeAgentOptions } from './agent-invoker.js';
7
7
  export { buildPrompt, formatCustomPromptBanner, resolveSkillPath } from './prompt-builder.js';
8
8
  export type { ComponentSourceRef, GeneratedCdf, Mode, PromptOptions, Skill } from './prompt-builder.js';
9
9
  export { formatGenerateProgressLine } from './progress.js';
10
- export { binaryExists, findBinary, resolveSpawn, spawnSpec } from './lib/binary-launch.js';
11
- export type { SpawnSpec } from './lib/binary-launch.js';
package/dist/src/index.js CHANGED
@@ -1,12 +1,10 @@
1
1
  // Agent identity
2
2
  export { AGENT_NAMES, DEFAULT_AGENT_NAME, isAgentName } from './agent-names.js';
3
3
  // Agent invocation (low-level)
4
- export { agentSupportsBedrock, agentSupportsStdinPrompt, buildArgs, checkAgentAuth, describeAgentFailure, extractSentinelOutput, parseMapTokenPropToolCallLines, parseSelectToolCallLines, parseTokenToolCallLines, parseToolCallLines, promptExceedsArgvLimit, resolveAgentModel, resolveBinary, runAgent, shouldUseStdinPrompt, } from './agent-runner.js';
4
+ export { agentSupportsBedrock, buildArgs, checkAgentAuth, describeAgentFailure, extractSentinelOutput, parseMapTokenPropToolCallLines, parseSelectToolCallLines, parseTokenToolCallLines, parseToolCallLines, resolveAgentModel, resolveBinary, runAgent, } from './agent-runner.js';
5
5
  // Agent invocation (interface)
6
6
  export { createLocalCliAgentInvoker } from './agent-invoker.js';
7
7
  // Prompt building
8
8
  export { buildPrompt, formatCustomPromptBanner, resolveSkillPath } from './prompt-builder.js';
9
9
  // Progress reporting
10
10
  export { formatGenerateProgressLine } from './progress.js';
11
- // Cross-platform binary lookup and launch (Windows .cmd shims, PATHEXT)
12
- export { binaryExists, findBinary, resolveSpawn, spawnSpec } from './lib/binary-launch.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contentful/experience-design-system-generation",
3
- "version": "2.34.1-dev-build-e12e553.0",
3
+ "version": "2.34.1",
4
4
  "description": "Agent-invocation and skill-prompt engine for the Contentful Experience Design System SDK",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -22,7 +22,7 @@
22
22
  "skills/"
23
23
  ],
24
24
  "dependencies": {
25
- "@contentful/experience-design-system-types": "2.34.1-dev-build-e12e553.0"
25
+ "@contentful/experience-design-system-types": "2.34.1"
26
26
  },
27
27
  "devDependencies": {
28
28
  "@tsconfig/node24": "^24.0.4",
@@ -1,40 +0,0 @@
1
- /**
2
- * Resolve a command to an absolute path, or null when it isn't on PATH.
3
- *
4
- * Replaces shelling out to `which`, which doesn't exist on Windows. An absolute
5
- * path is checked directly — on Windows `which` wouldn't resolve one anyway, and
6
- * `isAbsolute` recognises `C:\...` where a `startsWith('/')` test does not.
7
- */
8
- export declare function findBinary(binary: string, platform?: NodeJS.Platform): string | null;
9
- /** True when `binary` resolves to something executable. */
10
- export declare function binaryExists(binary: string, platform?: NodeJS.Platform): boolean;
11
- export type SpawnSpec = {
12
- command: string;
13
- args: string[];
14
- /** Set when `args` are pre-quoted and Node must pass them through untouched. */
15
- windowsVerbatimArguments?: boolean;
16
- };
17
- /**
18
- * Build the argv for launching an already-resolved executable.
19
- *
20
- * Off Windows, and for a real `.exe`/`.com`, this passes straight through. A
21
- * Windows `.cmd`/`.bat` is wrapped in `cmd.exe /d /s /c "..."`, which is the only
22
- * way to start one.
23
- *
24
- * Quoting note: the wrapped form re-parses the command line, so arguments are
25
- * quoted here. That quoting is deliberately simple — double quotes are doubled
26
- * and each argument wrapped — which is sufficient because the arguments reaching
27
- * this path are our own flags and model names. Large or user-controlled text
28
- * (agent prompts) travels over stdin instead, and must keep doing so. If
29
- * user-controlled values ever need to go through argv here, replace this with
30
- * `cross-spawn` rather than extending the escaping: it implements the full
31
- * cmd.exe rules, including the double-escaping that `node_modules/.bin` shims
32
- * require.
33
- */
34
- export declare function spawnSpec(resolved: string, args: string[], platform?: NodeJS.Platform): SpawnSpec;
35
- /**
36
- * Resolve a command and build its launch spec in one step. Returns null when the
37
- * command isn't installed, so callers can report that distinctly from a failure
38
- * to run.
39
- */
40
- export declare function resolveSpawn(binary: string, args: string[], platform?: NodeJS.Platform): SpawnSpec | null;
@@ -1,115 +0,0 @@
1
- /**
2
- * Cross-platform binary lookup and launch.
3
- *
4
- * Two separate Windows problems live here, and they need different fixes:
5
- *
6
- * 1. LOOKUP. libuv's spawn only tries `.com` and `.exe` when resolving a bare
7
- * command name against PATH — it ignores PATHEXT. Every tool installed via
8
- * npm (`claude`, `codex`, `pnpm`) is a `.cmd` shim on Windows, so a bare
9
- * name resolves to nothing and spawn fails with ENOENT. `findBinary` walks
10
- * PATH itself and tries the Windows executable extensions.
11
- *
12
- * 2. LAUNCH. Even with the full path, Node refuses to start a `.bat`/`.cmd`
13
- * directly — it throws EINVAL (a deliberate guard added for CVE-2024-27980).
14
- * Such a file has to run through `cmd.exe /d /s /c`. `spawnSpec` builds that
15
- * argv.
16
- *
17
- * Both take `platform` as an argument so tests can assert Windows behaviour
18
- * while running on macOS or Linux.
19
- */
20
- import { accessSync, constants } from 'node:fs';
21
- import { delimiter, isAbsolute, join } from 'node:path';
22
- /**
23
- * Executable suffixes to try for a bare command name. The POSIX case is a
24
- * single empty string: the name is already the whole filename.
25
- */
26
- function executableExtensions(platform) {
27
- return platform === 'win32' ? ['.exe', '.cmd', '.bat', '.com'] : [''];
28
- }
29
- /**
30
- * Resolve a command to an absolute path, or null when it isn't on PATH.
31
- *
32
- * Replaces shelling out to `which`, which doesn't exist on Windows. An absolute
33
- * path is checked directly — on Windows `which` wouldn't resolve one anyway, and
34
- * `isAbsolute` recognises `C:\...` where a `startsWith('/')` test does not.
35
- */
36
- export function findBinary(binary, platform = process.platform) {
37
- const extensions = executableExtensions(platform);
38
- if (isAbsolute(binary)) {
39
- // An explicit path may already carry its extension, or (on Windows) omit it.
40
- for (const extension of ['', ...extensions]) {
41
- try {
42
- accessSync(binary + extension, constants.F_OK);
43
- return binary + extension;
44
- }
45
- catch {
46
- continue;
47
- }
48
- }
49
- return null;
50
- }
51
- for (const directory of (process.env['PATH'] ?? '').split(delimiter)) {
52
- // Skip empty and relative PATH entries: resolving a command against the cwd
53
- // would make the result depend on where the CLI happens to be run from.
54
- if (!directory || !isAbsolute(directory))
55
- continue;
56
- for (const extension of extensions) {
57
- const candidate = join(directory, binary + extension);
58
- try {
59
- accessSync(candidate, constants.X_OK);
60
- return candidate;
61
- }
62
- catch {
63
- continue;
64
- }
65
- }
66
- }
67
- return null;
68
- }
69
- /** True when `binary` resolves to something executable. */
70
- export function binaryExists(binary, platform = process.platform) {
71
- return findBinary(binary, platform) !== null;
72
- }
73
- /**
74
- * Build the argv for launching an already-resolved executable.
75
- *
76
- * Off Windows, and for a real `.exe`/`.com`, this passes straight through. A
77
- * Windows `.cmd`/`.bat` is wrapped in `cmd.exe /d /s /c "..."`, which is the only
78
- * way to start one.
79
- *
80
- * Quoting note: the wrapped form re-parses the command line, so arguments are
81
- * quoted here. That quoting is deliberately simple — double quotes are doubled
82
- * and each argument wrapped — which is sufficient because the arguments reaching
83
- * this path are our own flags and model names. Large or user-controlled text
84
- * (agent prompts) travels over stdin instead, and must keep doing so. If
85
- * user-controlled values ever need to go through argv here, replace this with
86
- * `cross-spawn` rather than extending the escaping: it implements the full
87
- * cmd.exe rules, including the double-escaping that `node_modules/.bin` shims
88
- * require.
89
- */
90
- export function spawnSpec(resolved, args, platform = process.platform) {
91
- if (platform !== 'win32' || /\.(exe|com)$/i.test(resolved)) {
92
- return { command: resolved, args };
93
- }
94
- // `||` not `??`: an empty ComSpec is as unusable as an absent one.
95
- const shell = process.env['ComSpec'] || 'cmd.exe';
96
- const quote = (value) => `"${value.replace(/"/g, '""')}"`;
97
- const commandLine = [resolved, ...args].map(quote).join(' ');
98
- return {
99
- command: shell,
100
- // /d skips AutoRun scripts, /s keeps the outer quotes intact, /c runs and exits.
101
- args: ['/d', '/s', '/c', `"${commandLine}"`],
102
- windowsVerbatimArguments: true,
103
- };
104
- }
105
- /**
106
- * Resolve a command and build its launch spec in one step. Returns null when the
107
- * command isn't installed, so callers can report that distinctly from a failure
108
- * to run.
109
- */
110
- export function resolveSpawn(binary, args, platform = process.platform) {
111
- const resolved = findBinary(binary, platform);
112
- if (!resolved)
113
- return null;
114
- return spawnSpec(resolved, args, platform);
115
- }