@contentful/experience-design-system-generation 2.34.1-dev-build-cafcfc3.0 → 2.34.1-dev-build-928f202.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 +1 -1
- package/dist/src/agent-runner.d.ts +20 -3
- package/dist/src/agent-runner.js +74 -20
- package/dist/src/index.d.ts +3 -1
- package/dist/src/index.js +3 -1
- package/dist/src/lib/binary-launch.d.ts +40 -0
- package/dist/src/lib/binary-launch.js +115 -0
- package/package.json +2 -2
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-
|
|
3
|
+
"version": "2.34.1-dev-build-928f202.0",
|
|
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,6 +113,20 @@ 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;
|
|
116
130
|
export declare function buildArgs(agent: AgentName, prompt: string, model?: string, promptViaStdin?: boolean, bedrock?: boolean): string[];
|
|
117
131
|
export declare function runAgent(options: {
|
|
118
132
|
agent: AgentName;
|
|
@@ -123,9 +137,12 @@ export declare function runAgent(options: {
|
|
|
123
137
|
bedrock?: boolean;
|
|
124
138
|
onOutput?: (chunk: string) => void;
|
|
125
139
|
/**
|
|
126
|
-
*
|
|
127
|
-
*
|
|
128
|
-
*
|
|
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.
|
|
129
146
|
*/
|
|
130
147
|
promptViaStdin?: boolean;
|
|
131
148
|
/** Optional debug-event sink; callers own how/where events get logged. */
|
package/dist/src/agent-runner.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { spawn } from 'node:child_process';
|
|
2
|
+
import { findBinary, resolveSpawn, spawnSpec } from './lib/binary-launch.js';
|
|
2
3
|
export { AGENT_NAMES, DEFAULT_AGENT_NAME, isAgentName } from './agent-names.js';
|
|
3
4
|
const VALID_SELECT_TOOL_NAMES = new Set(['select_component', 'reject_component']);
|
|
4
5
|
function findJsonObjectEnd(line) {
|
|
@@ -355,15 +356,62 @@ function codexBedrockConfigArgs() {
|
|
|
355
356
|
const region = process.env.AWS_REGION?.trim() || process.env.AWS_DEFAULT_REGION?.trim() || DEFAULT_CODEX_BEDROCK_REGION;
|
|
356
357
|
return ['-c', 'model_provider=amazon-bedrock', '-c', `model_providers.amazon-bedrock.region=${region}`];
|
|
357
358
|
}
|
|
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
|
+
}
|
|
358
399
|
export function buildArgs(agent, prompt, model, promptViaStdin = false, bedrock = false) {
|
|
359
400
|
// codex with no configured model resolves to undefined — omit --model
|
|
360
401
|
// entirely so the CLI picks its own account-compatible default.
|
|
361
402
|
const resolvedModel = resolveAgentModel(agent, model, bedrock);
|
|
362
403
|
const modelArg = resolvedModel ? ['--model', resolvedModel] : [];
|
|
363
|
-
//
|
|
364
|
-
// as
|
|
365
|
-
//
|
|
366
|
-
|
|
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];
|
|
367
415
|
switch (agent) {
|
|
368
416
|
case 'claude':
|
|
369
417
|
return ['--print', ...modelArg, ...promptArg];
|
|
@@ -406,7 +454,11 @@ export async function runAgent(options) {
|
|
|
406
454
|
// call sites that forget to thread the flag through by hand.
|
|
407
455
|
const bedrock = options.bedrock ?? process.env.EDS_BEDROCK === '1';
|
|
408
456
|
const binary = resolveBinary(agent);
|
|
409
|
-
|
|
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));
|
|
410
462
|
const args = buildArgs(agent, prompt, model, useStdin, bedrock);
|
|
411
463
|
const startedAt = Date.now();
|
|
412
464
|
onDebugEvent?.('run.start', {
|
|
@@ -420,8 +472,14 @@ export async function runAgent(options) {
|
|
|
420
472
|
});
|
|
421
473
|
return new Promise((resolve) => {
|
|
422
474
|
const bedrockEnv = bedrock ? BEDROCK_ENV_BY_AGENT[agent] : undefined;
|
|
423
|
-
|
|
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, {
|
|
424
481
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
482
|
+
...(launch.windowsVerbatimArguments ? { windowsVerbatimArguments: true } : {}),
|
|
425
483
|
...(bedrockEnv ? { env: { ...process.env, ...bedrockEnv } } : {}),
|
|
426
484
|
});
|
|
427
485
|
if (useStdin && child.stdin) {
|
|
@@ -477,19 +535,12 @@ export async function runAgent(options) {
|
|
|
477
535
|
export async function checkAgentAuth(agent) {
|
|
478
536
|
const binary = resolveBinary(agent);
|
|
479
537
|
// Verify the selected agent's binary exists first — for EVERY agent, not
|
|
480
|
-
// just claude.
|
|
481
|
-
// EDS_AGENT_BINARY_<AGENT>=/opt/custom/bin
|
|
482
|
-
//
|
|
483
|
-
//
|
|
484
|
-
const
|
|
485
|
-
|
|
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)
|
|
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)
|
|
493
544
|
return 'not-found';
|
|
494
545
|
// Only Claude exposes `auth status --json`. Non-Claude agents are considered
|
|
495
546
|
// authenticated once their binary is present — never gate them on claude
|
|
@@ -499,8 +550,11 @@ export async function checkAgentAuth(agent) {
|
|
|
499
550
|
// Use `claude auth status` — fast, no API call, works regardless of which
|
|
500
551
|
// auth provider (direct, Bedrock, Vertex) or whether AWS_PROFILE is set.
|
|
501
552
|
return new Promise((resolve) => {
|
|
502
|
-
|
|
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, {
|
|
503
556
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
557
|
+
...(launch.windowsVerbatimArguments ? { windowsVerbatimArguments: true } : {}),
|
|
504
558
|
});
|
|
505
559
|
let stdout = '';
|
|
506
560
|
let done = false;
|
package/dist/src/index.d.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
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, buildArgs, checkAgentAuth, describeAgentFailure, extractSentinelOutput, parseMapTokenPropToolCallLines, parseSelectToolCallLines, parseTokenToolCallLines, parseToolCallLines, resolveAgentModel, resolveBinary, runAgent, } from './agent-runner.js';
|
|
3
|
+
export { agentSupportsBedrock, agentSupportsStdinPrompt, buildArgs, checkAgentAuth, describeAgentFailure, extractSentinelOutput, parseMapTokenPropToolCallLines, parseSelectToolCallLines, parseTokenToolCallLines, parseToolCallLines, promptExceedsArgvLimit, resolveAgentModel, resolveBinary, runAgent, shouldUseStdinPrompt, } 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,10 +1,12 @@
|
|
|
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, buildArgs, checkAgentAuth, describeAgentFailure, extractSentinelOutput, parseMapTokenPropToolCallLines, parseSelectToolCallLines, parseTokenToolCallLines, parseToolCallLines, resolveAgentModel, resolveBinary, runAgent, } from './agent-runner.js';
|
|
4
|
+
export { agentSupportsBedrock, agentSupportsStdinPrompt, buildArgs, checkAgentAuth, describeAgentFailure, extractSentinelOutput, parseMapTokenPropToolCallLines, parseSelectToolCallLines, parseTokenToolCallLines, parseToolCallLines, promptExceedsArgvLimit, resolveAgentModel, resolveBinary, runAgent, shouldUseStdinPrompt, } 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';
|
|
@@ -0,0 +1,40 @@
|
|
|
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;
|
|
@@ -0,0 +1,115 @@
|
|
|
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
|
+
}
|
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-
|
|
3
|
+
"version": "2.34.1-dev-build-928f202.0",
|
|
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-
|
|
25
|
+
"@contentful/experience-design-system-types": "2.34.1-dev-build-928f202.0"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
28
|
"@tsconfig/node24": "^24.0.4",
|