@contentful/experience-design-system-generation 2.34.2-dev-build-cfb3467.0 → 2.34.2-dev-build-3cd48dd.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 +3 -20
- package/dist/src/agent-runner.js +21 -63
- package/dist/src/index.d.ts +1 -2
- package/dist/src/index.js +1 -3
- package/package.json +2 -2
- package/dist/src/lib/binary-launch.d.ts +0 -56
- package/dist/src/lib/binary-launch.js +0 -115
package/dist/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contentful/experience-design-system-generation",
|
|
3
|
-
"version": "2.34.2-dev-build-
|
|
3
|
+
"version": "2.34.2-dev-build-3cd48dd.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,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
|
-
*
|
|
141
|
-
*
|
|
142
|
-
*
|
|
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. */
|
package/dist/src/agent-runner.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
2
|
export { AGENT_NAMES, DEFAULT_AGENT_NAME, isAgentName } from './agent-names.js';
|
|
3
3
|
const VALID_SELECT_TOOL_NAMES = new Set(['select_component', 'reject_component']);
|
|
4
4
|
function findJsonObjectEnd(line) {
|
|
@@ -355,62 +355,15 @@ function codexBedrockConfigArgs() {
|
|
|
355
355
|
const region = process.env.AWS_REGION?.trim() || process.env.AWS_DEFAULT_REGION?.trim() || DEFAULT_CODEX_BEDROCK_REGION;
|
|
356
356
|
return ['-c', 'model_provider=amazon-bedrock', '-c', `model_providers.amazon-bedrock.region=${region}`];
|
|
357
357
|
}
|
|
358
|
-
/**
|
|
359
|
-
* Agents that can read the prompt from stdin instead of argv.
|
|
360
|
-
*
|
|
361
|
-
* copilot cannot: its `-p` flag requires the prompt as the flag's value (see
|
|
362
|
-
* buildArgs), so there is nowhere for stdin to go.
|
|
363
|
-
*/
|
|
364
|
-
const STDIN_CAPABLE_AGENTS = new Set(['claude', 'codex', 'opencode', 'cursor']);
|
|
365
|
-
export function agentSupportsStdinPrompt(agent) {
|
|
366
|
-
return STDIN_CAPABLE_AGENTS.has(agent);
|
|
367
|
-
}
|
|
368
|
-
/**
|
|
369
|
-
* Windows caps a command line at 8191 characters through cmd.exe, and 32767 in
|
|
370
|
-
* CreateProcess. Our skill prompts are far larger than both — generate-components
|
|
371
|
-
* alone is ~50KB — so passing one as an argv positional cannot work there. POSIX
|
|
372
|
-
* is far more generous (ARG_MAX ~1MB on macOS) but not unlimited.
|
|
373
|
-
*
|
|
374
|
-
* Kept deliberately low: stdin is the better path for any prompt of real size, and
|
|
375
|
-
* there is no benefit to argv beyond the few agents that require it.
|
|
376
|
-
*/
|
|
377
|
-
const ARGV_PROMPT_LIMIT = 4096;
|
|
378
|
-
/**
|
|
379
|
-
* Decide how to deliver the prompt.
|
|
380
|
-
*
|
|
381
|
-
* Prefer stdin whenever the agent supports it and the prompt is large enough for
|
|
382
|
-
* argv limits to matter. This is what makes `generate components` work on Windows,
|
|
383
|
-
* and it removes a latent ARG_MAX failure on macOS as the skills grow.
|
|
384
|
-
*
|
|
385
|
-
* Exported so callers can detect the case that has no answer: a large prompt for an
|
|
386
|
-
* agent that can only accept argv.
|
|
387
|
-
*/
|
|
388
|
-
export function shouldUseStdinPrompt(agent, prompt) {
|
|
389
|
-
return agentSupportsStdinPrompt(agent) && prompt.length > ARGV_PROMPT_LIMIT;
|
|
390
|
-
}
|
|
391
|
-
/** True when the prompt cannot be delivered to this agent on this platform. */
|
|
392
|
-
export function promptExceedsArgvLimit(agent, prompt, platform = process.platform) {
|
|
393
|
-
if (agentSupportsStdinPrompt(agent))
|
|
394
|
-
return false;
|
|
395
|
-
// 8191 is the cmd.exe ceiling; every Windows launch of a .cmd shim goes through it.
|
|
396
|
-
return platform === 'win32' && prompt.length > 8191;
|
|
397
|
-
}
|
|
398
358
|
export function buildArgs(agent, prompt, model, promptViaStdin = false, bedrock = false) {
|
|
399
359
|
// codex with no configured model resolves to undefined — omit --model
|
|
400
360
|
// entirely so the CLI picks its own account-compatible default.
|
|
401
361
|
const resolvedModel = resolveAgentModel(agent, model, bedrock);
|
|
402
362
|
const modelArg = resolvedModel ? ['--model', resolvedModel] : [];
|
|
403
|
-
//
|
|
404
|
-
//
|
|
405
|
-
//
|
|
406
|
-
|
|
407
|
-
const useStdin = promptViaStdin && agentSupportsStdinPrompt(agent);
|
|
408
|
-
// When the prompt is delivered on stdin, omit it from argv — a large prompt as
|
|
409
|
-
// a command-line argument overflows ARG_MAX on POSIX (E2BIG) and cannot be
|
|
410
|
-
// passed at all on Windows, whose command line caps at 8191 characters through
|
|
411
|
-
// cmd.exe. These CLIs read the prompt from stdin when it isn't passed
|
|
412
|
-
// positionally.
|
|
413
|
-
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];
|
|
414
367
|
switch (agent) {
|
|
415
368
|
case 'claude':
|
|
416
369
|
return ['--print', ...modelArg, ...promptArg];
|
|
@@ -453,11 +406,7 @@ export async function runAgent(options) {
|
|
|
453
406
|
// call sites that forget to thread the flag through by hand.
|
|
454
407
|
const bedrock = options.bedrock ?? process.env.EDS_BEDROCK === '1';
|
|
455
408
|
const binary = resolveBinary(agent);
|
|
456
|
-
|
|
457
|
-
// prompt exceeds every Windows command-line limit, so argv simply cannot carry
|
|
458
|
-
// it. Honour an explicit promptViaStdin for smaller prompts, but never route to
|
|
459
|
-
// stdin for an agent that can't read it (copilot).
|
|
460
|
-
const useStdin = agentSupportsStdinPrompt(agent) && (!!promptViaStdin || shouldUseStdinPrompt(agent, prompt));
|
|
409
|
+
const useStdin = !!promptViaStdin;
|
|
461
410
|
const args = buildArgs(agent, prompt, model, useStdin, bedrock);
|
|
462
411
|
const startedAt = Date.now();
|
|
463
412
|
onDebugEvent?.('run.start', {
|
|
@@ -471,7 +420,7 @@ export async function runAgent(options) {
|
|
|
471
420
|
});
|
|
472
421
|
return new Promise((resolve) => {
|
|
473
422
|
const bedrockEnv = bedrock ? BEDROCK_ENV_BY_AGENT[agent] : undefined;
|
|
474
|
-
const child =
|
|
423
|
+
const child = spawn(binary, args, {
|
|
475
424
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
476
425
|
...(bedrockEnv ? { env: { ...process.env, ...bedrockEnv } } : {}),
|
|
477
426
|
});
|
|
@@ -528,10 +477,19 @@ export async function runAgent(options) {
|
|
|
528
477
|
export async function checkAgentAuth(agent) {
|
|
529
478
|
const binary = resolveBinary(agent);
|
|
530
479
|
// Verify the selected agent's binary exists first — for EVERY agent, not
|
|
531
|
-
// just claude.
|
|
532
|
-
//
|
|
533
|
-
|
|
534
|
-
|
|
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)
|
|
535
493
|
return 'not-found';
|
|
536
494
|
// Only Claude exposes `auth status --json`. Non-Claude agents are considered
|
|
537
495
|
// authenticated once their binary is present — never gate them on claude
|
|
@@ -541,7 +499,7 @@ export async function checkAgentAuth(agent) {
|
|
|
541
499
|
// Use `claude auth status` — fast, no API call, works regardless of which
|
|
542
500
|
// auth provider (direct, Bedrock, Vertex) or whether AWS_PROFILE is set.
|
|
543
501
|
return new Promise((resolve) => {
|
|
544
|
-
const child =
|
|
502
|
+
const child = spawn(binary, ['auth', 'status', '--json'], {
|
|
545
503
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
546
504
|
});
|
|
547
505
|
let stdout = '';
|
package/dist/src/index.d.ts
CHANGED
|
@@ -1,10 +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,
|
|
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, spawnBinary } 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,
|
|
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, spawnBinary } 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.2-dev-build-
|
|
3
|
+
"version": "2.34.2-dev-build-3cd48dd.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.2-dev-build-
|
|
25
|
+
"@contentful/experience-design-system-types": "2.34.2-dev-build-3cd48dd.0"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
28
|
"@tsconfig/node24": "^24.0.4",
|
|
@@ -1,56 +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 { type ChildProcess, type SpawnOptions } from 'node:child_process';
|
|
21
|
-
/** Resolve a command to an absolute path, or null when it isn't on PATH. */
|
|
22
|
-
export declare function findBinary(binary: string, platform?: NodeJS.Platform): string | null;
|
|
23
|
-
/** True when `binary` resolves to something executable. */
|
|
24
|
-
export declare function binaryExists(binary: string, platform?: NodeJS.Platform): boolean;
|
|
25
|
-
export type SpawnSpec = {
|
|
26
|
-
command: string;
|
|
27
|
-
args: string[];
|
|
28
|
-
/** Set when `args` are pre-quoted and Node must pass them through untouched. */
|
|
29
|
-
windowsVerbatimArguments?: boolean;
|
|
30
|
-
};
|
|
31
|
-
/**
|
|
32
|
-
* Build the argv for launching an already-resolved executable. A real `.exe`, and
|
|
33
|
-
* anything off Windows, passes straight through.
|
|
34
|
-
*
|
|
35
|
-
* The quoting is deliberately simple, and is only safe because the arguments
|
|
36
|
-
* reaching it are our own flags and model names — prompts travel over stdin and
|
|
37
|
-
* must keep doing so. If user-controlled text ever needs to go through argv here,
|
|
38
|
-
* switch to `cross-spawn` rather than extending this: it implements the full
|
|
39
|
-
* cmd.exe rules, including the double-escaping `node_modules/.bin` shims need.
|
|
40
|
-
*/
|
|
41
|
-
export declare function spawnSpec(resolved: string, args: string[], platform?: NodeJS.Platform): SpawnSpec;
|
|
42
|
-
/**
|
|
43
|
-
* Resolve a command and build its launch spec in one step. Returns null when the
|
|
44
|
-
* command isn't installed, so callers can report that distinctly from a failure
|
|
45
|
-
* to run.
|
|
46
|
-
*/
|
|
47
|
-
export declare function resolveSpawn(binary: string, args: string[], platform?: NodeJS.Platform): SpawnSpec | null;
|
|
48
|
-
/**
|
|
49
|
-
* `child_process.spawn`, with Windows shim resolution applied.
|
|
50
|
-
*
|
|
51
|
-
* Use this instead of `spawn` for anything installed by a package manager. When
|
|
52
|
-
* the command can't be resolved it is passed through unchanged, so a missing
|
|
53
|
-
* binary still surfaces as the caller's usual `error` event rather than throwing
|
|
54
|
-
* from here.
|
|
55
|
-
*/
|
|
56
|
-
export declare function spawnBinary(command: string, args: string[], options?: SpawnOptions): ChildProcess;
|
|
@@ -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 { spawn } from 'node:child_process';
|
|
21
|
-
import { accessSync, constants } from 'node:fs';
|
|
22
|
-
import { delimiter, isAbsolute, join } from 'node:path';
|
|
23
|
-
/** Suffixes to try for a bare command name; POSIX names carry their own. */
|
|
24
|
-
function executableExtensions(platform) {
|
|
25
|
-
return platform === 'win32' ? ['.exe', '.cmd', '.bat', '.com'] : [''];
|
|
26
|
-
}
|
|
27
|
-
/** Resolve a command to an absolute path, or null when it isn't on PATH. */
|
|
28
|
-
export function findBinary(binary, platform = process.platform) {
|
|
29
|
-
const extensions = executableExtensions(platform);
|
|
30
|
-
if (isAbsolute(binary)) {
|
|
31
|
-
// An explicit path may already carry its extension, or (on Windows) omit it.
|
|
32
|
-
for (const extension of ['', ...extensions]) {
|
|
33
|
-
try {
|
|
34
|
-
accessSync(binary + extension, constants.F_OK);
|
|
35
|
-
return binary + extension;
|
|
36
|
-
}
|
|
37
|
-
catch {
|
|
38
|
-
continue;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
return null;
|
|
42
|
-
}
|
|
43
|
-
for (const directory of (process.env['PATH'] ?? '').split(delimiter)) {
|
|
44
|
-
// Skip relative entries: resolving against the cwd would make the result
|
|
45
|
-
// depend on where the CLI was run from.
|
|
46
|
-
if (!directory || !isAbsolute(directory))
|
|
47
|
-
continue;
|
|
48
|
-
for (const extension of extensions) {
|
|
49
|
-
const candidate = join(directory, binary + extension);
|
|
50
|
-
try {
|
|
51
|
-
accessSync(candidate, constants.X_OK);
|
|
52
|
-
return candidate;
|
|
53
|
-
}
|
|
54
|
-
catch {
|
|
55
|
-
continue;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
return null;
|
|
60
|
-
}
|
|
61
|
-
/** True when `binary` resolves to something executable. */
|
|
62
|
-
export function binaryExists(binary, platform = process.platform) {
|
|
63
|
-
return findBinary(binary, platform) !== null;
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* Build the argv for launching an already-resolved executable. A real `.exe`, and
|
|
67
|
-
* anything off Windows, passes straight through.
|
|
68
|
-
*
|
|
69
|
-
* The quoting is deliberately simple, and is only safe because the arguments
|
|
70
|
-
* reaching it are our own flags and model names — prompts travel over stdin and
|
|
71
|
-
* must keep doing so. If user-controlled text ever needs to go through argv here,
|
|
72
|
-
* switch to `cross-spawn` rather than extending this: it implements the full
|
|
73
|
-
* cmd.exe rules, including the double-escaping `node_modules/.bin` shims need.
|
|
74
|
-
*/
|
|
75
|
-
export function spawnSpec(resolved, args, platform = process.platform) {
|
|
76
|
-
if (platform !== 'win32' || /\.(exe|com)$/i.test(resolved)) {
|
|
77
|
-
return { command: resolved, args };
|
|
78
|
-
}
|
|
79
|
-
// `||` not `??`: an empty ComSpec is as unusable as an absent one.
|
|
80
|
-
const shell = process.env['ComSpec'] || 'cmd.exe';
|
|
81
|
-
const quote = (value) => `"${value.replace(/"/g, '""')}"`;
|
|
82
|
-
const commandLine = [resolved, ...args].map(quote).join(' ');
|
|
83
|
-
return {
|
|
84
|
-
command: shell,
|
|
85
|
-
// /d skips AutoRun scripts, /s keeps the outer quotes intact, /c runs and exits.
|
|
86
|
-
args: ['/d', '/s', '/c', `"${commandLine}"`],
|
|
87
|
-
windowsVerbatimArguments: true,
|
|
88
|
-
};
|
|
89
|
-
}
|
|
90
|
-
/**
|
|
91
|
-
* Resolve a command and build its launch spec in one step. Returns null when the
|
|
92
|
-
* command isn't installed, so callers can report that distinctly from a failure
|
|
93
|
-
* to run.
|
|
94
|
-
*/
|
|
95
|
-
export function resolveSpawn(binary, args, platform = process.platform) {
|
|
96
|
-
const resolved = findBinary(binary, platform);
|
|
97
|
-
if (!resolved)
|
|
98
|
-
return null;
|
|
99
|
-
return spawnSpec(resolved, args, platform);
|
|
100
|
-
}
|
|
101
|
-
/**
|
|
102
|
-
* `child_process.spawn`, with Windows shim resolution applied.
|
|
103
|
-
*
|
|
104
|
-
* Use this instead of `spawn` for anything installed by a package manager. When
|
|
105
|
-
* the command can't be resolved it is passed through unchanged, so a missing
|
|
106
|
-
* binary still surfaces as the caller's usual `error` event rather than throwing
|
|
107
|
-
* from here.
|
|
108
|
-
*/
|
|
109
|
-
export function spawnBinary(command, args, options = {}) {
|
|
110
|
-
const launch = resolveSpawn(command, args) ?? { command, args };
|
|
111
|
-
return spawn(launch.command, launch.args, {
|
|
112
|
-
...options,
|
|
113
|
-
...(launch.windowsVerbatimArguments ? { windowsVerbatimArguments: true } : {}),
|
|
114
|
-
});
|
|
115
|
-
}
|