@hmj-ai/cflow 1.1.0 → 1.2.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/DESIGN.md +2 -1
- package/README.md +7 -6
- package/dist/public/assets/index-C1_cd_s8.css +1 -0
- package/dist/public/assets/index-DsBDM4p-.js +15 -0
- package/dist/public/index.html +2 -2
- package/dist/src/db.js +2 -2
- package/dist/src/runtime-manifest.js +88 -20
- package/dist/src/runtime-process.js +152 -88
- package/dist/src/runtime.js +160 -120
- package/dist/src/server.js +44 -107
- package/dist/src/workspace.js +43 -2
- package/package.json +2 -1
- package/dist/public/assets/index-BqTfYp5s.js +0 -15
- package/dist/public/assets/index-D0BpmA_V.css +0 -1
package/dist/src/runtime.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { isAbsolute, resolve } from 'node:path';
|
|
1
|
+
import { createRequire } from 'node:module';
|
|
2
|
+
import { dirname, isAbsolute, join, resolve } from 'node:path';
|
|
3
3
|
import { Readable, Writable } from 'node:stream';
|
|
4
4
|
import { client as acpClient, methods, ndJsonStream, PROTOCOL_VERSION, } from '@agentclientprotocol/sdk';
|
|
5
5
|
import { isWithinDirectory } from './workspace.js';
|
|
6
|
-
import { loadAgentManifestRecords, } from './runtime-manifest.js';
|
|
7
|
-
import { canChangeWorkspace, discoverAcpCommands, existingAbsoluteDirectory,
|
|
8
|
-
const ADAPTER_BUILD = 'cf-runtime-adapter/
|
|
6
|
+
import { adapterDescriptorForId, adapterDescriptorRecord, externalAdapterDescriptors, loadAgentManifestRecords, } from './runtime-manifest.js';
|
|
7
|
+
import { canChangeWorkspace, describeResolvedCommand, discoverAcpCommands, existingAbsoluteDirectory, existingExecutable, launchProcess, parseJsonOutput, resolveCommandAliases, runtimeIdFromCommand, runtimeNameFromCommand, terminateProcess, } from './runtime-process.js';
|
|
8
|
+
const ADAPTER_BUILD = 'cf-runtime-adapter/4';
|
|
9
|
+
const moduleRequire = createRequire(import.meta.url);
|
|
9
10
|
export class RuntimeExecutionException extends Error {
|
|
10
11
|
details;
|
|
11
12
|
constructor(details) {
|
|
@@ -77,8 +78,14 @@ const profileFromManifest = (record) => {
|
|
|
77
78
|
export const discoverRuntimeProfiles = (options = {}) => {
|
|
78
79
|
const loaded = loadAgentManifestRecords(options);
|
|
79
80
|
const declared = loaded.records.map(profileFromManifest);
|
|
80
|
-
const
|
|
81
|
-
|
|
81
|
+
const external = externalAdapterDescriptors
|
|
82
|
+
.filter((descriptor) => resolveCommandAliases([descriptor.manifest.command, ...(descriptor.commandAliases ?? [])], options))
|
|
83
|
+
.map((descriptor) => profileFromManifest(adapterDescriptorRecord(descriptor, 'path-acp')));
|
|
84
|
+
const declaredCommands = new Set([...declared, ...external].flatMap((profile) => [
|
|
85
|
+
profile.command,
|
|
86
|
+
...(adapterDescriptorForId(profile.id)?.commandAliases ?? []),
|
|
87
|
+
]));
|
|
88
|
+
const generic = discoverAcpCommands(options)
|
|
82
89
|
.filter((command) => !declaredCommands.has(command))
|
|
83
90
|
.sort()
|
|
84
91
|
.map((command) => ({
|
|
@@ -105,7 +112,7 @@ export const discoverRuntimeProfiles = (options = {}) => {
|
|
|
105
112
|
adapterBuild: ADAPTER_BUILD,
|
|
106
113
|
createdAt: new Date(0).toISOString(),
|
|
107
114
|
}));
|
|
108
|
-
const selected = new Map(generic.map((profile) => [profile.id, profile]));
|
|
115
|
+
const selected = new Map([...generic, ...external].map((profile) => [profile.id, profile]));
|
|
109
116
|
for (const profile of declared)
|
|
110
117
|
selected.set(profile.id, profile);
|
|
111
118
|
return { profiles: [...selected.values()], warnings: loaded.warnings };
|
|
@@ -388,7 +395,7 @@ export class RuntimeManager {
|
|
|
388
395
|
status: 'unavailable',
|
|
389
396
|
checkedAt: new Date().toISOString(),
|
|
390
397
|
latencyMs: Date.now() - started,
|
|
391
|
-
stage: this.commandInstalled(profile
|
|
398
|
+
stage: this.commandInstalled(profile) ? 'installed' : undefined,
|
|
392
399
|
authentication: 'unknown',
|
|
393
400
|
error: error instanceof Error ? error.message : String(error),
|
|
394
401
|
};
|
|
@@ -467,32 +474,58 @@ export class RuntimeManager {
|
|
|
467
474
|
: await Promise.reject(new Error(`RUNTIME_BACKEND_UNSUPPORTED:${profile.backend}`));
|
|
468
475
|
return profile.outputMode === 'json' ? parseJsonOutput(text) : { content: text.trim() };
|
|
469
476
|
}
|
|
470
|
-
|
|
477
|
+
commandResolutionOptions(env = process.env) {
|
|
478
|
+
return {
|
|
479
|
+
bundledRoot: this.discoveryOptions.bundledRoot,
|
|
480
|
+
env,
|
|
481
|
+
platform: this.discoveryOptions.platform,
|
|
482
|
+
projectRoot: this.discoveryOptions.projectRoot,
|
|
483
|
+
};
|
|
484
|
+
}
|
|
485
|
+
resolvedCommand(profile, env) {
|
|
486
|
+
if (!profile.command)
|
|
487
|
+
throw new Error('RUNTIME_COMMAND_REQUIRED');
|
|
488
|
+
const descriptor = adapterDescriptorForId(profile.id);
|
|
489
|
+
const resolved = resolveCommandAliases([profile.command, ...(descriptor?.commandAliases ?? [])], this.commandResolutionOptions(env));
|
|
490
|
+
if (!resolved)
|
|
491
|
+
throw new Error(`${profile.backend === 'acp' ? 'ACP_SERVER_NOT_FOUND' : 'AGENT_CLI_NOT_FOUND'}:${profile.command}`);
|
|
492
|
+
return resolved;
|
|
493
|
+
}
|
|
494
|
+
commandInstalled(profile) {
|
|
471
495
|
if (!profile.command)
|
|
472
496
|
return false;
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
497
|
+
try {
|
|
498
|
+
this.resolvedCommand(profile, this.runtimeEnvironment(profile));
|
|
499
|
+
return true;
|
|
500
|
+
}
|
|
501
|
+
catch {
|
|
502
|
+
return false;
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
launchSpec(profile, args, cwd, stdio, effects = []) {
|
|
506
|
+
const env = this.runtimeEnvironment(profile, effects);
|
|
507
|
+
return {
|
|
508
|
+
resolved: this.resolvedCommand(profile, env),
|
|
509
|
+
args,
|
|
510
|
+
cwd,
|
|
511
|
+
env,
|
|
512
|
+
stdio,
|
|
513
|
+
};
|
|
476
514
|
}
|
|
477
515
|
async probeAcp(profile) {
|
|
478
|
-
const
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
windowsHide: true,
|
|
485
|
-
});
|
|
516
|
+
const spec = this.launchSpec(profile, profile.args, profile.workingDirectory ?? process.cwd(), [
|
|
517
|
+
'pipe',
|
|
518
|
+
'pipe',
|
|
519
|
+
'pipe',
|
|
520
|
+
]);
|
|
521
|
+
const child = launchProcess(spec);
|
|
486
522
|
let stderr = Buffer.alloc(0);
|
|
487
|
-
child.stderr
|
|
523
|
+
child.stderr?.on('data', (chunk) => {
|
|
488
524
|
stderr = Buffer.concat([stderr, chunk]);
|
|
489
525
|
if (stderr.length > 8_192)
|
|
490
526
|
stderr = stderr.subarray(stderr.length - 8_192);
|
|
491
527
|
});
|
|
492
|
-
const terminate = () =>
|
|
493
|
-
child.kill('SIGTERM');
|
|
494
|
-
setTimeout(() => child.kill('SIGKILL'), 1_000).unref();
|
|
495
|
-
};
|
|
528
|
+
const terminate = () => terminateProcess(child);
|
|
496
529
|
let timeout;
|
|
497
530
|
try {
|
|
498
531
|
if (!child.stdin || !child.stdout)
|
|
@@ -504,24 +537,29 @@ export class RuntimeManager {
|
|
|
504
537
|
clientCapabilities: { plan: {}, session: {} },
|
|
505
538
|
}));
|
|
506
539
|
const childError = new Promise((_, reject) => child.once('error', reject));
|
|
540
|
+
const childExit = new Promise((_, reject) => child.once('exit', (code, signal) => reject(new Error(`ACP_SERVER_EXITED:${code ?? signal ?? 'unknown'}`))));
|
|
507
541
|
const timedOut = new Promise((_, reject) => {
|
|
508
542
|
timeout = setTimeout(() => {
|
|
509
543
|
terminate();
|
|
510
544
|
reject(new Error('ACP_HANDSHAKE_TIMEOUT'));
|
|
511
|
-
}, 5_000);
|
|
545
|
+
}, this.discoveryOptions.healthTimeoutMs ?? 5_000);
|
|
512
546
|
});
|
|
513
|
-
const response = await Promise.race([initialize, childError, timedOut]);
|
|
547
|
+
const response = await Promise.race([initialize, childError, childExit, timedOut]);
|
|
514
548
|
const agent = response.agentInfo
|
|
515
549
|
? [response.agentInfo.name, response.agentInfo.version].filter(Boolean).join(' ')
|
|
516
550
|
: undefined;
|
|
517
|
-
return [
|
|
551
|
+
return [
|
|
552
|
+
`ACP ${response.protocolVersion}`,
|
|
553
|
+
agent,
|
|
554
|
+
`via ${describeResolvedCommand(spec.resolved)}`,
|
|
555
|
+
]
|
|
518
556
|
.filter(Boolean)
|
|
519
557
|
.join(' · ');
|
|
520
558
|
}
|
|
521
559
|
catch (error) {
|
|
522
560
|
const detail = stderr.toString('utf8').trim().slice(-800);
|
|
523
|
-
if (error instanceof Error
|
|
524
|
-
throw new Error(`${error.message}
|
|
561
|
+
if (error instanceof Error)
|
|
562
|
+
throw new Error(`${error.message}${detail ? `:${detail}` : ''} [launch=${describeResolvedCommand(spec.resolved)}]`);
|
|
525
563
|
throw error;
|
|
526
564
|
}
|
|
527
565
|
finally {
|
|
@@ -531,25 +569,16 @@ export class RuntimeManager {
|
|
|
531
569
|
}
|
|
532
570
|
}
|
|
533
571
|
async probeCli(profile) {
|
|
534
|
-
const
|
|
572
|
+
const spec = this.launchSpec(profile, profile.versionArgs, profile.workingDirectory ?? process.cwd(), ['ignore', 'pipe', 'pipe']);
|
|
535
573
|
if (!profile.versionArgs.length)
|
|
536
|
-
return `CLI via ${
|
|
537
|
-
const child =
|
|
538
|
-
cwd: profile.workingDirectory ?? process.cwd(),
|
|
539
|
-
env: this.acpEnvironment(profile),
|
|
540
|
-
stdio: ['ignore', 'pipe', 'pipe'],
|
|
541
|
-
shell: needsWindowsShell(command),
|
|
542
|
-
windowsHide: true,
|
|
543
|
-
});
|
|
574
|
+
return `CLI via ${describeResolvedCommand(spec.resolved)}`;
|
|
575
|
+
const child = launchProcess(spec);
|
|
544
576
|
const output = [];
|
|
545
577
|
const errors = [];
|
|
546
|
-
child.stdout
|
|
547
|
-
child.stderr
|
|
578
|
+
child.stdout?.on('data', (chunk) => output.push(chunk));
|
|
579
|
+
child.stderr?.on('data', (chunk) => errors.push(chunk));
|
|
548
580
|
let timeout;
|
|
549
|
-
const terminate = () =>
|
|
550
|
-
child.kill('SIGTERM');
|
|
551
|
-
setTimeout(() => child.kill('SIGKILL'), 1_000).unref();
|
|
552
|
-
};
|
|
581
|
+
const terminate = () => terminateProcess(child);
|
|
553
582
|
try {
|
|
554
583
|
const result = await new Promise((resolveExit, reject) => {
|
|
555
584
|
child.once('error', reject);
|
|
@@ -557,13 +586,13 @@ export class RuntimeManager {
|
|
|
557
586
|
timeout = setTimeout(() => {
|
|
558
587
|
terminate();
|
|
559
588
|
reject(new Error('CLI_HEALTHCHECK_TIMEOUT'));
|
|
560
|
-
}, 5_000);
|
|
589
|
+
}, this.discoveryOptions.healthTimeoutMs ?? 5_000);
|
|
561
590
|
});
|
|
562
591
|
const detail = Buffer.concat(errors).toString('utf8').trim().slice(-800);
|
|
563
592
|
if (result.code !== 0)
|
|
564
|
-
throw new Error(`CLI_HEALTHCHECK_EXITED:${result.code ?? result.signal ?? 'unknown'}${detail ? `:${detail}` : ''}`);
|
|
593
|
+
throw new Error(`CLI_HEALTHCHECK_EXITED:${result.code ?? result.signal ?? 'unknown'}${detail ? `:${detail}` : ''} [launch=${describeResolvedCommand(spec.resolved)}]`);
|
|
565
594
|
const version = Buffer.concat(output).toString('utf8').trim().split(/\r?\n/, 1)[0];
|
|
566
|
-
return [version || profile.name, `via ${
|
|
595
|
+
return [version || profile.name, `via ${describeResolvedCommand(spec.resolved)}`].join(' · ');
|
|
567
596
|
}
|
|
568
597
|
finally {
|
|
569
598
|
if (timeout)
|
|
@@ -571,59 +600,86 @@ export class RuntimeManager {
|
|
|
571
600
|
terminate();
|
|
572
601
|
}
|
|
573
602
|
}
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
603
|
+
platformEnvironment() {
|
|
604
|
+
const env = {};
|
|
605
|
+
const required = process.platform === 'win32'
|
|
606
|
+
? [
|
|
607
|
+
'PATH',
|
|
608
|
+
'PATHEXT',
|
|
609
|
+
'SystemRoot',
|
|
610
|
+
'ComSpec',
|
|
611
|
+
'USERPROFILE',
|
|
612
|
+
'HOMEDRIVE',
|
|
613
|
+
'HOMEPATH',
|
|
614
|
+
'APPDATA',
|
|
615
|
+
'LOCALAPPDATA',
|
|
616
|
+
'TEMP',
|
|
617
|
+
'TMP',
|
|
618
|
+
]
|
|
619
|
+
: ['PATH', 'HOME', 'TMPDIR'];
|
|
620
|
+
for (const key of required) {
|
|
621
|
+
const actual = process.platform === 'win32'
|
|
622
|
+
? Object.keys(process.env).find((candidate) => candidate.toLowerCase() === key.toLowerCase())
|
|
623
|
+
: key;
|
|
624
|
+
const value = actual ? process.env[actual] : undefined;
|
|
625
|
+
if (value !== undefined)
|
|
626
|
+
env[key] = value;
|
|
627
|
+
}
|
|
628
|
+
return env;
|
|
598
629
|
}
|
|
599
|
-
|
|
600
|
-
const
|
|
601
|
-
|
|
602
|
-
|
|
630
|
+
bundledCodexPath() {
|
|
631
|
+
const targets = {
|
|
632
|
+
'darwin-x64': ['@openai/codex-darwin-x64', 'x86_64-apple-darwin'],
|
|
633
|
+
'darwin-arm64': ['@openai/codex-darwin-arm64', 'aarch64-apple-darwin'],
|
|
634
|
+
'linux-x64': ['@openai/codex-linux-x64', 'x86_64-unknown-linux-musl'],
|
|
635
|
+
'linux-arm64': ['@openai/codex-linux-arm64', 'aarch64-unknown-linux-musl'],
|
|
636
|
+
'win32-x64': ['@openai/codex-win32-x64', 'x86_64-pc-windows-msvc'],
|
|
637
|
+
'win32-arm64': ['@openai/codex-win32-arm64', 'aarch64-pc-windows-msvc'],
|
|
638
|
+
};
|
|
639
|
+
const target = targets[`${process.platform}-${process.arch}`];
|
|
640
|
+
if (!target)
|
|
641
|
+
throw new Error(`CODEX_BUNDLED_PLATFORM_UNSUPPORTED:${process.platform}-${process.arch}`);
|
|
642
|
+
let packageJson;
|
|
643
|
+
try {
|
|
644
|
+
packageJson = moduleRequire.resolve(`${target[0]}/package.json`);
|
|
645
|
+
}
|
|
646
|
+
catch {
|
|
647
|
+
throw new Error(`CODEX_BUNDLED_CLI_NOT_FOUND:${target[0]}`);
|
|
648
|
+
}
|
|
649
|
+
const executable = join(dirname(packageJson), 'vendor', target[1], 'bin', process.platform === 'win32' ? 'codex.exe' : 'codex');
|
|
650
|
+
const resolved = existingExecutable(executable);
|
|
603
651
|
if (!resolved)
|
|
604
|
-
throw new Error(`
|
|
652
|
+
throw new Error(`CODEX_BUNDLED_CLI_NOT_FOUND:${executable}`);
|
|
605
653
|
return resolved;
|
|
606
654
|
}
|
|
607
|
-
|
|
608
|
-
const env =
|
|
655
|
+
runtimeEnvironment(profile, effects = []) {
|
|
656
|
+
const env = this.platformEnvironment();
|
|
609
657
|
for (const key of profile.envAllowlist) {
|
|
610
658
|
const value = process.env[key];
|
|
611
659
|
if (value !== undefined)
|
|
612
660
|
env[key] = value;
|
|
613
661
|
}
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
:
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
662
|
+
const descriptor = adapterDescriptorForId(profile.id);
|
|
663
|
+
if (descriptor) {
|
|
664
|
+
Object.assign(env, descriptor.staticEnvironment);
|
|
665
|
+
if (profile.model && descriptor.modelEnvironment)
|
|
666
|
+
env[descriptor.modelEnvironment] = JSON.stringify({ model: profile.model });
|
|
667
|
+
if (descriptor.permissionMode)
|
|
668
|
+
env[descriptor.permissionMode.environment] = canChangeWorkspace(effects)
|
|
669
|
+
? descriptor.permissionMode.workspaceWrite
|
|
670
|
+
: descriptor.permissionMode.readOnly;
|
|
671
|
+
if (descriptor.nativeCommand) {
|
|
672
|
+
const override = process.env[descriptor.nativeCommand.overrideEnvironment];
|
|
673
|
+
if (override) {
|
|
674
|
+
const resolved = resolveCommandAliases([override], this.commandResolutionOptions(process.env));
|
|
675
|
+
if (!resolved)
|
|
676
|
+
throw new Error(`${profile.id === 'codex' ? 'CODEX_CLI_NOT_FOUND' : 'CLAUDE_CODE_CLI_NOT_FOUND'}:${override}`);
|
|
677
|
+
env[descriptor.nativeCommand.adapterEnvironment] = resolved.executable;
|
|
678
|
+
}
|
|
679
|
+
else if (descriptor.nativeCommand.bundled === 'codex') {
|
|
680
|
+
env[descriptor.nativeCommand.adapterEnvironment] = this.bundledCodexPath();
|
|
681
|
+
}
|
|
682
|
+
}
|
|
627
683
|
}
|
|
628
684
|
return env;
|
|
629
685
|
}
|
|
@@ -636,30 +692,21 @@ export class RuntimeManager {
|
|
|
636
692
|
}
|
|
637
693
|
async runCli(profile, prompt, signal, effects = [], context, analysis) {
|
|
638
694
|
const cwd = analysis?.cwd ?? context?.workspaceRoot ?? profile.workingDirectory ?? process.cwd();
|
|
639
|
-
const command = this.cliCommand(profile);
|
|
640
695
|
const args = [
|
|
641
696
|
...profile.args,
|
|
642
697
|
...this.cliPermissionArgs(profile, effects, analysis),
|
|
643
698
|
...(profile.promptTransport === 'argument' ? [prompt] : []),
|
|
644
699
|
];
|
|
645
|
-
const
|
|
646
|
-
|
|
647
|
-
env: this.acpEnvironment(profile, effects),
|
|
648
|
-
stdio: ['pipe', 'pipe', 'pipe'],
|
|
649
|
-
shell: needsWindowsShell(command),
|
|
650
|
-
windowsHide: true,
|
|
651
|
-
});
|
|
700
|
+
const spec = this.launchSpec(profile, args, cwd, ['pipe', 'pipe', 'pipe'], effects);
|
|
701
|
+
const child = launchProcess(spec);
|
|
652
702
|
const output = [];
|
|
653
703
|
const errors = [];
|
|
654
704
|
let outputBytes = 0;
|
|
655
705
|
let outputLimitExceeded = false;
|
|
656
|
-
const terminate = () =>
|
|
657
|
-
child.kill('SIGTERM');
|
|
658
|
-
setTimeout(() => child.kill('SIGKILL'), 1_000).unref();
|
|
659
|
-
};
|
|
706
|
+
const terminate = () => terminateProcess(child);
|
|
660
707
|
const relayAbort = () => terminate();
|
|
661
708
|
signal.addEventListener('abort', relayAbort, { once: true });
|
|
662
|
-
child.stdout
|
|
709
|
+
child.stdout?.on('data', (chunk) => {
|
|
663
710
|
outputBytes += chunk.length;
|
|
664
711
|
if (outputBytes > profile.maxOutputBytes) {
|
|
665
712
|
outputLimitExceeded = true;
|
|
@@ -668,11 +715,13 @@ export class RuntimeManager {
|
|
|
668
715
|
}
|
|
669
716
|
output.push(chunk);
|
|
670
717
|
});
|
|
671
|
-
child.stderr
|
|
718
|
+
child.stderr?.on('data', (chunk) => {
|
|
672
719
|
errors.push(chunk);
|
|
673
720
|
if (Buffer.concat(errors).length > 65_536)
|
|
674
721
|
errors.shift();
|
|
675
722
|
});
|
|
723
|
+
if (!child.stdin)
|
|
724
|
+
throw new Error('RUNTIME_STDIN_UNAVAILABLE');
|
|
676
725
|
if (profile.promptTransport === 'stdin')
|
|
677
726
|
child.stdin.end(prompt);
|
|
678
727
|
else
|
|
@@ -704,26 +753,17 @@ export class RuntimeManager {
|
|
|
704
753
|
}
|
|
705
754
|
async runAcp(profile, prompt, signal, effects = [], context, analysis) {
|
|
706
755
|
const cwd = analysis?.cwd ?? context?.workspaceRoot ?? profile.workingDirectory ?? process.cwd();
|
|
707
|
-
const
|
|
708
|
-
const child =
|
|
709
|
-
cwd,
|
|
710
|
-
env: this.acpEnvironment(profile, effects),
|
|
711
|
-
stdio: ['pipe', 'pipe', 'pipe'],
|
|
712
|
-
shell: needsWindowsShell(command),
|
|
713
|
-
windowsHide: true,
|
|
714
|
-
});
|
|
756
|
+
const spec = this.launchSpec(profile, profile.args, cwd, ['pipe', 'pipe', 'pipe'], effects);
|
|
757
|
+
const child = launchProcess(spec);
|
|
715
758
|
let stderr = Buffer.alloc(0);
|
|
716
759
|
let stderrText = '';
|
|
717
|
-
child.stderr
|
|
760
|
+
child.stderr?.on('data', (chunk) => {
|
|
718
761
|
stderr = Buffer.concat([stderr, chunk]);
|
|
719
762
|
if (stderr.length > 65_536)
|
|
720
763
|
stderr = stderr.subarray(stderr.length - 65_536);
|
|
721
764
|
stderrText = stderr.toString('utf8');
|
|
722
765
|
});
|
|
723
|
-
const terminate = () =>
|
|
724
|
-
child.kill('SIGTERM');
|
|
725
|
-
setTimeout(() => child.kill('SIGKILL'), 1_000).unref();
|
|
726
|
-
};
|
|
766
|
+
const terminate = () => terminateProcess(child);
|
|
727
767
|
const relayAbort = () => terminate();
|
|
728
768
|
signal.addEventListener('abort', relayAbort, { once: true });
|
|
729
769
|
const exitPromise = new Promise((resolveExit) => child.once('exit', (code, childSignal) => resolveExit({ code, signal: childSignal })));
|