@swiftuijs/twill-shell 0.0.0-stage → 0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Saiya and twill contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,4 +1,38 @@
1
- # Temporary Holding Version
1
+ # <img src="https://twill.evecalm.com/logo.png" alt="Twill hummingbird" align="right" width="40" height="40" /> Twill shell
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
4
- If no other versions are published within 30 days, this package and version will be deleted.
3
+ Swift-inspired subprocess tools for Twill and ordinary Node JS/TS scripts, available in 0.2.0.
4
+
5
+ ```sh
6
+ npm install @swiftuijs/twill-shell
7
+ # For .twill source scripts:
8
+ npm install --save-dev @swiftuijs/twill
9
+ ```
10
+
11
+ Commands execute through one Rust process engine with literal argv, without shell interpretation or command compilation (`shell: false`). The prebuilt implementation dependency installs automatically; users need no Rust toolchain and do not choose a backend. Native JS/TS needs no Twill compiler. One async reactor per Node environment coordinates already-started children and pipes independently of libuv's worker pool.
12
+
13
+ Supported prebuilds: Linux glibc x64/ARM64 (glibc 2.28+), Linux musl x64/ARM64 (musl 1.2.5+), macOS x64/ARM64 and Windows x64/ARM64. Missing/incompatible binaries and unsupported platforms reject before launch, without fallback, install-time builds or downloads. See [performance](https://twill.evecalm.com/performance#rust-shell-backend) for measured warm gains and cold/polling limits.
14
+
15
+ ```twill
16
+ #!/usr/bin/env twill
17
+ import { Command, Output, Subprocess } from '@swiftuijs/twill-shell';
18
+
19
+ const result = await Subprocess.run(Command.name('git', ['status', '--short']), {
20
+ output: Output.text({ limit: 64 * 1024 }),
21
+ timeoutMs: 5000,
22
+ });
23
+ console.log(result.standardOutput);
24
+ ```
25
+
26
+ The compiler runner supplies the `twill` binary. Save this as `status.twill`, then use `twill status.twill` or `twill run status.twill`. On Linux/macOS, `chmod +x status.twill` enables `./status.twill` when `twill` is on PATH; `pnpm exec ./status.twill` uses a project-local binary. Windows uses the explicit CLI. Arguments after the script path pass through unchanged. Application dependencies resolve from the script's location. Use the compiler and SDK from 0.2.0 or newer.
27
+
28
+ Use `Command.path(absolutePath, args)` for a trusted executable; `Command.name(name, args)` uses native PATH search. Arguments are immutable snapshots and remain literal strings, including spaces, quotes, newlines and shell metacharacters. Tool-specific options still matter: use `--` before user-supplied filenames when the executable supports it.
29
+
30
+ Stdin defaults to EOF; stdout/stderr inherit without capture. `Input.inherit()` inherits stdin; a string or `Uint8Array` writes input with native backpressure. Byte input is copied at submission; cwd and environment are snapshotted then. `Output.text({limit})` and `Output.bytes({limit})` require positive byte limits; `Output.discard()` retains nothing. Output-limit failure rejects after teardown, never returns silent truncation. Capture limits bound retained stream bytes, not total process memory or the final UTF-8 string/buffer allocation.
31
+
32
+ Named Unix signals use Node names; unnamed signals retain their numeric OS value. A successful result contains `processIdentifier`, `terminationStatus`, `standardOutput` and `standardError`. Nonzero/signal exits reject with `ProcessExitError`; `check: false` returns that status. Launch/I/O failures, abort, timeout and output overflow always reject. Use ordinary `try/catch` and exported error classes. Errors can carry bounded output and native causes; the SDK never logs them automatically.
33
+
34
+ `cwd` and `Environment.inherit(updates)` / `.replace(values)` apply only to the child. Pass an `AbortSignal` or `timeoutMs` for cancellation. The default grace period is 250 ms before forced termination, followed by at most 1000 ms joining time. Settlement normally waits for child close and owned I/O. Failed teardown reports `unresolvedProcessIdentifier` and `cleanupErrors`, preserving the first failure. Ownership covers the direct child; descendants and arbitrary process trees are outside this contract. Windows uses its native process handle for termination, without POSIX graceful-signal guarantees.
35
+
36
+ This first stage does not implement scoped streaming, pipelines, shell templates or shell-text execution. Node ESM is required (`^20.19.0 || >=22.12.0`). Twill source execution uses its existing loader; exported/native JS only needs this SDK. See the [scripting guide](https://twill.evecalm.com/scripting), [RFC 0034](https://github.com/swiftuijs/twill/blob/main/docs/rfcs/0034-shell-scripting-toolkit.md) and [official AI skill](https://twill.evecalm.com/ai). Twill's sibling UI project is [SwiftUI.js](https://swiftuijs.evecalm.com/).
37
+
38
+ Worker termination cancels that environment's children. Explicit `process.exit()` and environment teardown use a native cleanup barrier bounded to 1.1 seconds; JS callbacks do not run during exit. OS creation/uninterruptible kernel waits are not hard real-time guarantees, and SIGKILL/native faults cannot run cleanup handlers.
package/dist/cwd.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export declare function cwdSnapshot(cwd: string | undefined, platform?: NodeJS.Platform, parent?: string): string;
2
+ //# sourceMappingURL=cwd.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cwd.d.ts","sourceRoot":"","sources":["../src/cwd.ts"],"names":[],"mappings":"AACA,wBAAgB,WAAW,CACzB,GAAG,EAAE,MAAM,GAAG,SAAS,EACvB,QAAQ,kBAAmB,EAC3B,MAAM,SAAgB,GACrB,MAAM,CAQR"}
package/dist/cwd.js ADDED
@@ -0,0 +1,11 @@
1
+ import { isAbsolute, win32 } from 'node:path';
2
+ export function cwdSnapshot(cwd, platform = process.platform, parent = process.cwd()) {
3
+ return cwd === undefined
4
+ ? parent
5
+ : platform === 'win32'
6
+ ? win32.resolve(parent, cwd)
7
+ : isAbsolute(cwd)
8
+ ? cwd
9
+ : `${parent}/${cwd}`;
10
+ }
11
+ //# sourceMappingURL=cwd.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cwd.js","sourceRoot":"","sources":["../src/cwd.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,WAAW,CAAC;AAC9C,MAAM,UAAU,WAAW,CACzB,GAAuB,EACvB,QAAQ,GAAG,OAAO,CAAC,QAAQ,EAC3B,MAAM,GAAG,OAAO,CAAC,GAAG,EAAE;IAEtB,OAAO,GAAG,KAAK,SAAS;QACtB,CAAC,CAAC,MAAM;QACR,CAAC,CAAC,QAAQ,KAAK,OAAO;YACpB,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC;YAC5B,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC;gBACf,CAAC,CAAC,GAAG;gBACL,CAAC,CAAC,GAAG,MAAM,IAAI,GAAG,EAAE,CAAC;AAC7B,CAAC"}
@@ -0,0 +1,5 @@
1
+ import type { Environment } from './values.js';
2
+ export declare function environmentSnapshot(policy: Environment | undefined, platform?: NodeJS.Platform, parent?: NodeJS.ProcessEnv): {
3
+ [key: string]: string | undefined;
4
+ };
5
+ //# sourceMappingURL=environment.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"environment.d.ts","sourceRoot":"","sources":["../src/environment.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAiB/C,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,WAAW,GAAG,SAAS,EAC/B,QAAQ,kBAAmB,EAC3B,MAAM,oBAAc;;EAgBrB"}
@@ -0,0 +1,32 @@
1
+ import { childEnvironment } from './values.js';
2
+ // Match Node/libuv's mandatory Windows spawn environment additions (including
3
+ // replacement/removal policies). Explicit empty values still override defaults.
4
+ const windowsRequired = [
5
+ 'HOMEDRIVE',
6
+ 'HOMEPATH',
7
+ 'LOGONSERVER',
8
+ 'PATH',
9
+ 'SYSTEMDRIVE',
10
+ 'SYSTEMROOT',
11
+ 'TEMP',
12
+ 'USERDOMAIN',
13
+ 'USERNAME',
14
+ 'USERPROFILE',
15
+ 'WINDIR',
16
+ ];
17
+ export function environmentSnapshot(policy, platform = process.platform, parent = process.env) {
18
+ const environment = { ...(childEnvironment(policy, platform) ?? parent) };
19
+ if (parent.NODE_V8_COVERAGE && !Object.hasOwn(environment, 'NODE_V8_COVERAGE'))
20
+ environment.NODE_V8_COVERAGE = parent.NODE_V8_COVERAGE;
21
+ if (platform === 'win32') {
22
+ const selected = new Set(Object.keys(environment).map((key) => key.toUpperCase()));
23
+ const inherited = new Map(Object.entries(parent).map(([key, value]) => [key.toUpperCase(), value]));
24
+ for (const key of windowsRequired) {
25
+ const value = inherited.get(key);
26
+ if (!selected.has(key) && value !== undefined)
27
+ environment[key] = value;
28
+ }
29
+ }
30
+ return environment;
31
+ }
32
+ //# sourceMappingURL=environment.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"environment.js","sourceRoot":"","sources":["../src/environment.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAG/C,8EAA8E;AAC9E,gFAAgF;AAChF,MAAM,eAAe,GAAG;IACtB,WAAW;IACX,UAAU;IACV,aAAa;IACb,MAAM;IACN,aAAa;IACb,YAAY;IACZ,MAAM;IACN,YAAY;IACZ,UAAU;IACV,aAAa;IACb,QAAQ;CACT,CAAC;AACF,MAAM,UAAU,mBAAmB,CACjC,MAA+B,EAC/B,QAAQ,GAAG,OAAO,CAAC,QAAQ,EAC3B,MAAM,GAAG,OAAO,CAAC,GAAG;IAEpB,MAAM,WAAW,GAAG,EAAE,GAAG,CAAC,gBAAgB,CAAC,MAAM,EAAE,QAAQ,CAAC,IAAI,MAAM,CAAC,EAAE,CAAC;IAC1E,IAAI,MAAM,CAAC,gBAAgB,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,WAAW,EAAE,kBAAkB,CAAC;QAC5E,WAAW,CAAC,gBAAgB,GAAG,MAAM,CAAC,gBAAgB,CAAC;IACzD,IAAI,QAAQ,KAAK,OAAO,EAAE,CAAC;QACzB,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;QACnF,MAAM,SAAS,GAAG,IAAI,GAAG,CACvB,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,WAAW,EAAE,EAAE,KAAK,CAAC,CAAC,CACzE,CAAC;QACF,KAAK,MAAM,GAAG,IAAI,eAAe,EAAE,CAAC;YAClC,MAAM,KAAK,GAAG,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YACjC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,KAAK,KAAK,SAAS;gBAAE,WAAW,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;QAC1E,CAAC;IACH,CAAC;IACD,OAAO,WAAW,CAAC;AACrB,CAAC"}
@@ -0,0 +1,37 @@
1
+ import type { ExecutionResult, TerminationStatus } from './index.js';
2
+ export declare class ProcessError extends Error {
3
+ readonly processIdentifier?: number;
4
+ readonly terminationStatus?: TerminationStatus;
5
+ readonly standardOutput?: string | Buffer;
6
+ readonly standardError?: string | Buffer;
7
+ readonly unresolvedProcessIdentifier?: number;
8
+ readonly cleanupErrors: readonly Error[];
9
+ constructor(message: string, processIdentifier?: number, options?: ErrorOptions);
10
+ }
11
+ export declare class ProcessLaunchError extends ProcessError {
12
+ constructor(cause: unknown);
13
+ }
14
+ export declare class ProcessIOError extends ProcessError {
15
+ readonly stream: 'stdin' | 'stdout' | 'stderr';
16
+ constructor(stream: 'stdin' | 'stdout' | 'stderr', processIdentifier: number | undefined, cause: unknown);
17
+ }
18
+ export declare class ProcessAbortError extends ProcessError {
19
+ constructor(processIdentifier: number | undefined, reason: unknown);
20
+ }
21
+ export declare class ProcessTimeoutError extends ProcessError {
22
+ readonly timeoutMs: number;
23
+ constructor(timeoutMs: number, processIdentifier: number | undefined);
24
+ }
25
+ export declare class OutputLimitError extends ProcessError {
26
+ readonly stream: 'stdout' | 'stderr';
27
+ readonly limit: number;
28
+ constructor(stream: 'stdout' | 'stderr', limit: number, processIdentifier: number | undefined);
29
+ }
30
+ export declare class ProcessTeardownError extends ProcessError {
31
+ constructor(processIdentifier: number, cause?: unknown);
32
+ }
33
+ export declare class ProcessExitError extends ProcessError {
34
+ readonly result: ExecutionResult;
35
+ constructor(result: ExecutionResult);
36
+ }
37
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAErE,qBAAa,YAAa,SAAQ,KAAK;IACrC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IACpC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;IAC/C,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC1C,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACzC,QAAQ,CAAC,2BAA2B,CAAC,EAAE,MAAM,CAAC;IAC9C,QAAQ,CAAC,aAAa,EAAE,SAAS,KAAK,EAAE,CAAM;gBAClC,OAAO,EAAE,MAAM,EAAE,iBAAiB,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY;CAKhF;AACD,qBAAa,kBAAmB,SAAQ,YAAY;gBACtC,KAAK,EAAE,OAAO;CAG3B;AACD,qBAAa,cAAe,SAAQ,YAAY;IAE5C,QAAQ,CAAC,MAAM,EAAE,OAAO,GAAG,QAAQ,GAAG,QAAQ;gBAArC,MAAM,EAAE,OAAO,GAAG,QAAQ,GAAG,QAAQ,EAC9C,iBAAiB,EAAE,MAAM,GAAG,SAAS,EACrC,KAAK,EAAE,OAAO;CAIjB;AACD,qBAAa,iBAAkB,SAAQ,YAAY;gBACrC,iBAAiB,EAAE,MAAM,GAAG,SAAS,EAAE,MAAM,EAAE,OAAO;CAGnE;AACD,qBAAa,mBAAoB,SAAQ,YAAY;IAEjD,QAAQ,CAAC,SAAS,EAAE,MAAM;gBAAjB,SAAS,EAAE,MAAM,EAC1B,iBAAiB,EAAE,MAAM,GAAG,SAAS;CAIxC;AACD,qBAAa,gBAAiB,SAAQ,YAAY;IAE9C,QAAQ,CAAC,MAAM,EAAE,QAAQ,GAAG,QAAQ;IACpC,QAAQ,CAAC,KAAK,EAAE,MAAM;gBADb,MAAM,EAAE,QAAQ,GAAG,QAAQ,EAC3B,KAAK,EAAE,MAAM,EACtB,iBAAiB,EAAE,MAAM,GAAG,SAAS;CAIxC;AACD,qBAAa,oBAAqB,SAAQ,YAAY;gBACxC,iBAAiB,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO;CAIvD;AACD,qBAAa,gBAAiB,SAAQ,YAAY;IACpC,QAAQ,CAAC,MAAM,EAAE,eAAe;gBAAvB,MAAM,EAAE,eAAe;CAI7C"}
package/dist/errors.js ADDED
@@ -0,0 +1,61 @@
1
+ export class ProcessError extends Error {
2
+ processIdentifier;
3
+ terminationStatus;
4
+ standardOutput;
5
+ standardError;
6
+ unresolvedProcessIdentifier;
7
+ cleanupErrors = [];
8
+ constructor(message, processIdentifier, options) {
9
+ super(message, options);
10
+ this.name = new.target.name;
11
+ this.processIdentifier = processIdentifier;
12
+ }
13
+ }
14
+ export class ProcessLaunchError extends ProcessError {
15
+ constructor(cause) {
16
+ super('Subprocess could not start', undefined, { cause });
17
+ }
18
+ }
19
+ export class ProcessIOError extends ProcessError {
20
+ stream;
21
+ constructor(stream, processIdentifier, cause) {
22
+ super(`Subprocess ${stream} failed`, processIdentifier, { cause });
23
+ this.stream = stream;
24
+ }
25
+ }
26
+ export class ProcessAbortError extends ProcessError {
27
+ constructor(processIdentifier, reason) {
28
+ super('Subprocess aborted', processIdentifier, { cause: reason });
29
+ }
30
+ }
31
+ export class ProcessTimeoutError extends ProcessError {
32
+ timeoutMs;
33
+ constructor(timeoutMs, processIdentifier) {
34
+ super('Subprocess timed out', processIdentifier);
35
+ this.timeoutMs = timeoutMs;
36
+ }
37
+ }
38
+ export class OutputLimitError extends ProcessError {
39
+ stream;
40
+ limit;
41
+ constructor(stream, limit, processIdentifier) {
42
+ super(`Subprocess ${stream} exceeded its byte limit`, processIdentifier);
43
+ this.stream = stream;
44
+ this.limit = limit;
45
+ }
46
+ }
47
+ export class ProcessTeardownError extends ProcessError {
48
+ constructor(processIdentifier, cause) {
49
+ super('Owned subprocess could not be terminated', processIdentifier, { cause });
50
+ Object.assign(this, { unresolvedProcessIdentifier: processIdentifier });
51
+ }
52
+ }
53
+ export class ProcessExitError extends ProcessError {
54
+ result;
55
+ constructor(result) {
56
+ super('Subprocess exited unsuccessfully', result.processIdentifier);
57
+ this.result = result;
58
+ Object.assign(this, result);
59
+ }
60
+ }
61
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,YAAa,SAAQ,KAAK;IAC5B,iBAAiB,CAAU;IAC3B,iBAAiB,CAAqB;IACtC,cAAc,CAAmB;IACjC,aAAa,CAAmB;IAChC,2BAA2B,CAAU;IACrC,aAAa,GAAqB,EAAE,CAAC;IAC9C,YAAY,OAAe,EAAE,iBAA0B,EAAE,OAAsB;QAC7E,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxB,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC;QAC5B,IAAI,CAAC,iBAAiB,GAAG,iBAAiB,CAAC;IAC7C,CAAC;CACF;AACD,MAAM,OAAO,kBAAmB,SAAQ,YAAY;IAClD,YAAY,KAAc;QACxB,KAAK,CAAC,4BAA4B,EAAE,SAAS,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;IAC5D,CAAC;CACF;AACD,MAAM,OAAO,cAAe,SAAQ,YAAY;IAEnC;IADX,YACW,MAAqC,EAC9C,iBAAqC,EACrC,KAAc;QAEd,KAAK,CAAC,cAAc,MAAM,SAAS,EAAE,iBAAiB,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;QAJ1D,WAAM,GAAN,MAAM,CAA+B;IAKhD,CAAC;CACF;AACD,MAAM,OAAO,iBAAkB,SAAQ,YAAY;IACjD,YAAY,iBAAqC,EAAE,MAAe;QAChE,KAAK,CAAC,oBAAoB,EAAE,iBAAiB,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;IACpE,CAAC;CACF;AACD,MAAM,OAAO,mBAAoB,SAAQ,YAAY;IAExC;IADX,YACW,SAAiB,EAC1B,iBAAqC;QAErC,KAAK,CAAC,sBAAsB,EAAE,iBAAiB,CAAC,CAAC;QAHxC,cAAS,GAAT,SAAS,CAAQ;IAI5B,CAAC;CACF;AACD,MAAM,OAAO,gBAAiB,SAAQ,YAAY;IAErC;IACA;IAFX,YACW,MAA2B,EAC3B,KAAa,EACtB,iBAAqC;QAErC,KAAK,CAAC,cAAc,MAAM,0BAA0B,EAAE,iBAAiB,CAAC,CAAC;QAJhE,WAAM,GAAN,MAAM,CAAqB;QAC3B,UAAK,GAAL,KAAK,CAAQ;IAIxB,CAAC;CACF;AACD,MAAM,OAAO,oBAAqB,SAAQ,YAAY;IACpD,YAAY,iBAAyB,EAAE,KAAe;QACpD,KAAK,CAAC,0CAA0C,EAAE,iBAAiB,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;QAChF,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,2BAA2B,EAAE,iBAAiB,EAAE,CAAC,CAAC;IAC1E,CAAC;CACF;AACD,MAAM,OAAO,gBAAiB,SAAQ,YAAY;IAC3B;IAArB,YAAqB,MAAuB;QAC1C,KAAK,CAAC,kCAAkC,EAAE,MAAM,CAAC,iBAAiB,CAAC,CAAC;QADjD,WAAM,GAAN,MAAM,CAAiB;QAE1C,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAC9B,CAAC;CACF"}
@@ -0,0 +1,24 @@
1
+ import { type Command, type RunOptions, type OutputPolicy, type OutputValue, type InheritedOutput } from './values.js';
2
+ export { Command, Environment, Input, Output } from './values.js';
3
+ export type { OutputPolicy, OutputValue, RunOptions, ProcessInput, InputPolicy, InheritedOutput, DiscardedOutput, TextOutput, ByteOutput, } from './values.js';
4
+ export { ProcessError, ProcessLaunchError, ProcessAbortError, ProcessTimeoutError, ProcessExitError, ProcessIOError, OutputLimitError, ProcessTeardownError, } from './errors.js';
5
+ export type TerminationStatus = {
6
+ readonly kind: 'exited';
7
+ readonly code: number;
8
+ } | {
9
+ readonly kind: 'signaled';
10
+ readonly signal: NodeJS.Signals | number;
11
+ };
12
+ export interface ExecutionResult<O extends OutputPolicy = OutputPolicy, E extends OutputPolicy = OutputPolicy> {
13
+ readonly processIdentifier: number;
14
+ readonly terminationStatus: TerminationStatus;
15
+ readonly standardOutput: OutputValue<O>;
16
+ readonly standardError: OutputValue<E>;
17
+ }
18
+ type ExactOptions<O> = O & Record<Exclude<keyof O, keyof RunOptions>, never>;
19
+ type SelectedOutput<P> = Extract<P, OutputPolicy> | (undefined extends P ? InheritedOutput : never);
20
+ declare function run<Options extends RunOptions = RunOptions<InheritedOutput, InheritedOutput>>(command: Command, options?: ExactOptions<Options>): Promise<ExecutionResult<SelectedOutput<Options['output']>, SelectedOutput<Options['error']>>>;
21
+ export declare const Subprocess: Readonly<{
22
+ run: typeof run;
23
+ }>;
24
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAEL,KAAK,OAAO,EACZ,KAAK,UAAU,EACf,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,eAAe,EACrB,MAAM,aAAa,CAAC;AAYrB,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAClE,YAAY,EACV,YAAY,EACZ,WAAW,EACX,UAAU,EACV,YAAY,EACZ,WAAW,EACX,eAAe,EACf,eAAe,EACf,UAAU,EACV,UAAU,GACX,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,YAAY,EACZ,kBAAkB,EAClB,iBAAiB,EACjB,mBAAmB,EACnB,gBAAgB,EAChB,cAAc,EACd,gBAAgB,EAChB,oBAAoB,GACrB,MAAM,aAAa,CAAC;AAErB,MAAM,MAAM,iBAAiB,GACzB;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAClD;IAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,GAAG,MAAM,CAAA;CAAE,CAAC;AAC5E,MAAM,WAAW,eAAe,CAC9B,CAAC,SAAS,YAAY,GAAG,YAAY,EACrC,CAAC,SAAS,YAAY,GAAG,YAAY;IAErC,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,iBAAiB,EAAE,iBAAiB,CAAC;IAC9C,QAAQ,CAAC,cAAc,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC;IACxC,QAAQ,CAAC,aAAa,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC;CACxC;AAED,KAAK,YAAY,CAAC,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,UAAU,CAAC,EAAE,KAAK,CAAC,CAAC;AAC7E,KAAK,cAAc,CAAC,CAAC,IAAI,OAAO,CAAC,CAAC,EAAE,YAAY,CAAC,GAAG,CAAC,SAAS,SAAS,CAAC,GAAG,eAAe,GAAG,KAAK,CAAC,CAAC;AASpG,iBAAS,GAAG,CAAC,OAAO,SAAS,UAAU,GAAG,UAAU,CAAC,eAAe,EAAE,eAAe,CAAC,EACpF,OAAO,EAAE,OAAO,EAChB,OAAO,GAAE,YAAY,CAAC,OAAO,CAAyC,GACrE,OAAO,CAAC,eAAe,CAAC,cAAc,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,EAAE,cAAc,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAyJ/F;AACD,eAAO,MAAM,UAAU;;EAAyB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,168 @@
1
+ import { addAbortListener } from 'node:events';
2
+ import { constants } from 'node:os';
3
+ import { cwdSnapshot } from './cwd.js';
4
+ import { environmentSnapshot } from './environment.js';
5
+ import { settings, } from './values.js';
6
+ import { ProcessError, ProcessLaunchError, ProcessAbortError, ProcessTimeoutError, ProcessExitError, ProcessIOError, OutputLimitError, ProcessTeardownError, } from './errors.js';
7
+ import { loadBackend } from '@swiftuijs/twill-shell-native';
8
+ export { Command, Environment, Input, Output } from './values.js';
9
+ export { ProcessError, ProcessLaunchError, ProcessAbortError, ProcessTimeoutError, ProcessExitError, ProcessIOError, OutputLimitError, ProcessTeardownError, } from './errors.js';
10
+ const emptyOptions = Object.freeze({});
11
+ function cause(failure) {
12
+ return Object.assign(new Error(failure.message), {
13
+ code: failure.code,
14
+ errno: failure.osCode,
15
+ });
16
+ }
17
+ function run(command, options = emptyOptions) {
18
+ return new Promise((resolve, reject) => {
19
+ const config = settings(command, options);
20
+ const { signal } = config;
21
+ if (signal?.aborted) {
22
+ reject(new ProcessAbortError(undefined, signal.reason));
23
+ return;
24
+ }
25
+ const input = typeof config.input === 'string'
26
+ ? Buffer.from(config.input)
27
+ : config.input instanceof Uint8Array
28
+ ? Buffer.from(config.input.buffer, config.input.byteOffset, config.input.byteLength)
29
+ : undefined;
30
+ const inputPolicy = typeof config.input === 'object' && !(config.input instanceof Uint8Array)
31
+ ? config.input
32
+ : undefined;
33
+ let backend, job;
34
+ try {
35
+ backend = loadBackend();
36
+ job = backend.start({
37
+ executable: command.executable,
38
+ arguments: command.arguments,
39
+ cwd: cwdSnapshot(config.cwd),
40
+ environment: environmentSnapshot(config.environment),
41
+ input,
42
+ inheritInput: inputPolicy?.kind === 'inherit',
43
+ outputLimit: 'limit' in config.output ? config.output.limit : undefined,
44
+ errorLimit: 'limit' in config.error ? config.error.limit : undefined,
45
+ discardOutput: config.output.kind === 'discard',
46
+ discardError: config.error.kind === 'discard',
47
+ timeoutMs: config.timeoutMs,
48
+ gracePeriodMs: config.gracePeriodMs,
49
+ killTimeoutMs: config.killTimeoutMs,
50
+ });
51
+ }
52
+ catch (error) {
53
+ reject(new ProcessLaunchError(error));
54
+ return;
55
+ }
56
+ let abortReason, setupFailure;
57
+ let listener;
58
+ const abort = () => {
59
+ abortReason = signal.reason;
60
+ backend.cancel(job.id, false);
61
+ };
62
+ if (signal) {
63
+ if (signal.aborted)
64
+ abort();
65
+ else {
66
+ try {
67
+ listener = addAbortListener(signal, abort);
68
+ }
69
+ catch (error) {
70
+ setupFailure = error;
71
+ backend.cancel(job.id, true);
72
+ }
73
+ }
74
+ }
75
+ const failure = (value, pid) => {
76
+ switch (value.kind) {
77
+ case 'launch':
78
+ return new ProcessLaunchError(cause(value));
79
+ case 'abort':
80
+ return new ProcessAbortError(pid, abortReason);
81
+ case 'timeout':
82
+ return new ProcessTimeoutError(config.timeoutMs, pid);
83
+ case 'io':
84
+ return new ProcessIOError(value.stream, pid, cause(value));
85
+ case 'limit': {
86
+ const policy = value.stream === 'stdout' ? config.output : config.error;
87
+ return new OutputLimitError(value.stream, policy.limit, pid);
88
+ }
89
+ case 'teardown':
90
+ return new ProcessTeardownError(pid, cause(value));
91
+ case 'setup':
92
+ return new ProcessError('Subprocess cancellation setup failed', pid, {
93
+ cause: setupFailure,
94
+ });
95
+ default:
96
+ return new ProcessError(value.message, pid, { cause: cause(value) });
97
+ }
98
+ };
99
+ const complete = (outcome) => {
100
+ listener?.[Symbol.dispose]();
101
+ const pid = outcome.processIdentifier;
102
+ const terminationStatus = outcome.windowsSignal !== undefined
103
+ ? Object.freeze({ kind: 'signaled', signal: outcome.windowsSignal })
104
+ : outcome.signal !== undefined
105
+ ? Object.freeze({
106
+ kind: 'signaled',
107
+ signal: Object.keys(constants.signals).find((key) => constants.signals[key] === outcome.signal) ?? outcome.signal,
108
+ })
109
+ : outcome.code !== undefined
110
+ ? Object.freeze({ kind: 'exited', code: outcome.code })
111
+ : undefined;
112
+ let primary = outcome.failure ? failure(outcome.failure, pid) : undefined;
113
+ const secondary = outcome.cleanupErrors.map((value) => failure(value, pid));
114
+ if (setupFailure !== undefined && outcome.failure?.kind !== 'setup') {
115
+ const error = new ProcessError('Subprocess cancellation setup failed', pid, {
116
+ cause: setupFailure,
117
+ });
118
+ if (primary)
119
+ secondary.push(error);
120
+ else
121
+ primary = error;
122
+ }
123
+ const capture = (bytes, policy, stream) => {
124
+ try {
125
+ return policy.kind === 'text' ? bytes?.toString('utf8') : bytes;
126
+ }
127
+ catch (error) {
128
+ const value = new ProcessIOError(stream, pid, error);
129
+ if (primary)
130
+ secondary.push(value);
131
+ else
132
+ primary = value;
133
+ return undefined;
134
+ }
135
+ };
136
+ const standardOutput = capture(outcome.standardOutput, config.output, 'stdout');
137
+ const standardError = capture(outcome.standardError, config.error, 'stderr');
138
+ if (primary) {
139
+ primary.cleanupErrors.push(...secondary);
140
+ Object.assign(primary, {
141
+ terminationStatus,
142
+ standardOutput,
143
+ standardError,
144
+ unresolvedProcessIdentifier: outcome.unresolvedProcessIdentifier,
145
+ });
146
+ reject(primary);
147
+ }
148
+ else {
149
+ const result = Object.freeze({
150
+ processIdentifier: pid,
151
+ terminationStatus: terminationStatus,
152
+ standardOutput,
153
+ standardError,
154
+ });
155
+ if (config.check && (terminationStatus.kind !== 'exited' || terminationStatus.code !== 0))
156
+ reject(new ProcessExitError(result));
157
+ else
158
+ resolve(result);
159
+ }
160
+ };
161
+ job.promise.then(complete).catch((error) => {
162
+ listener?.[Symbol.dispose]();
163
+ reject(new ProcessError('Native subprocess operation failed', undefined, { cause: error }));
164
+ });
165
+ });
166
+ }
167
+ export const Subprocess = Object.freeze({ run });
168
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,90 @@
1
+ declare const commandBrand: unique symbol;
2
+ declare const environmentBrand: unique symbol;
3
+ declare const outputBrand: unique symbol;
4
+ declare const inputBrand: unique symbol;
5
+ export interface Command {
6
+ readonly [commandBrand]: true;
7
+ readonly executable: string;
8
+ readonly arguments: readonly string[];
9
+ }
10
+ export declare const Command: Readonly<{
11
+ name(executable: string, args?: readonly string[]): Command;
12
+ path(executable: string, args?: readonly string[]): Command;
13
+ }>;
14
+ export interface Environment {
15
+ readonly [environmentBrand]: true;
16
+ readonly kind: 'inherit' | 'replace';
17
+ readonly values: Readonly<Record<string, string | undefined>>;
18
+ }
19
+ export declare const Environment: Readonly<{
20
+ inherit(updates?: Record<string, string | undefined>): Environment;
21
+ replace(values: Record<string, string | undefined>): Environment;
22
+ }>;
23
+ interface OutputBrand {
24
+ readonly [outputBrand]: true;
25
+ }
26
+ export interface InheritedOutput extends OutputBrand {
27
+ readonly kind: 'inherit';
28
+ }
29
+ export interface DiscardedOutput extends OutputBrand {
30
+ readonly kind: 'discard';
31
+ }
32
+ export interface TextOutput extends OutputBrand {
33
+ readonly kind: 'text';
34
+ readonly limit: number;
35
+ }
36
+ export interface ByteOutput extends OutputBrand {
37
+ readonly kind: 'bytes';
38
+ readonly limit: number;
39
+ }
40
+ export type OutputPolicy = InheritedOutput | DiscardedOutput | TextOutput | ByteOutput;
41
+ export type OutputValue<P extends OutputPolicy> = P extends TextOutput ? string : P extends ByteOutput ? Buffer : undefined;
42
+ export declare const Output: Readonly<{
43
+ inherit(): InheritedOutput;
44
+ discard(): DiscardedOutput;
45
+ text(options: {
46
+ limit: number;
47
+ }): TextOutput;
48
+ bytes(options: {
49
+ limit: number;
50
+ }): ByteOutput;
51
+ }>;
52
+ export interface InputPolicy {
53
+ readonly [inputBrand]: true;
54
+ readonly kind: 'none' | 'inherit';
55
+ }
56
+ export declare const Input: Readonly<{
57
+ none(): InputPolicy;
58
+ inherit(): InputPolicy;
59
+ }>;
60
+ export type ProcessInput = string | Uint8Array | InputPolicy;
61
+ export interface RunOptions<O extends OutputPolicy = OutputPolicy, E extends OutputPolicy = OutputPolicy> {
62
+ readonly cwd?: string;
63
+ readonly environment?: Environment;
64
+ readonly input?: ProcessInput;
65
+ readonly output?: O;
66
+ readonly error?: E;
67
+ readonly check?: boolean;
68
+ readonly signal?: AbortSignal;
69
+ readonly timeoutMs?: number;
70
+ /** Time allowed after SIGTERM, before SIGKILL. Defaults to 250 ms. */
71
+ readonly gracePeriodMs?: number;
72
+ /** Maximum join time after forced termination. Defaults to 1000 ms. */
73
+ readonly killTimeoutMs?: number;
74
+ }
75
+ export declare function settings(cmd: Command, options: RunOptions): {
76
+ cwd: string | undefined;
77
+ environment: Environment | undefined;
78
+ input: ProcessInput;
79
+ output: OutputPolicy;
80
+ error: OutputPolicy;
81
+ check: boolean;
82
+ signal: AbortSignal | undefined;
83
+ timeoutMs: number | undefined;
84
+ gracePeriodMs: number;
85
+ killTimeoutMs: number;
86
+ };
87
+ /** Internal helper; parameter permits testing Windows key behavior on other hosts. */
88
+ export declare function childEnvironment(policy: Environment | undefined, platform?: NodeJS.Platform): NodeJS.ProcessEnv | undefined;
89
+ export {};
90
+ //# sourceMappingURL=values.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"values.d.ts","sourceRoot":"","sources":["../src/values.ts"],"names":[],"mappings":"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"}
package/dist/values.js ADDED
@@ -0,0 +1,200 @@
1
+ import { isAbsolute } from 'node:path';
2
+ import { constants } from 'node:buffer';
3
+ const commandBrand = Symbol.for('@swiftuijs/twill-shell/command/v1');
4
+ const environmentBrand = Symbol.for('@swiftuijs/twill-shell/environment/v1');
5
+ const outputBrand = Symbol.for('@swiftuijs/twill-shell/output/v1');
6
+ const inputBrand = Symbol.for('@swiftuijs/twill-shell/input/v1');
7
+ function string(value, label, empty = false) {
8
+ if (typeof value !== 'string' || (!empty && value.length === 0) || value.includes('\0'))
9
+ throw new TypeError(`${label} must be a ${empty ? '' : 'nonempty '}string without NUL`);
10
+ }
11
+ function command(executable, args) {
12
+ if (!Array.isArray(args))
13
+ throw new TypeError('arguments must be an array of strings');
14
+ const snapshot = Array.from(args);
15
+ for (const arg of snapshot)
16
+ string(arg, 'argument', true);
17
+ return Object.freeze({
18
+ [commandBrand]: true,
19
+ executable,
20
+ arguments: Object.freeze(snapshot),
21
+ });
22
+ }
23
+ export const Command = Object.freeze({
24
+ name(executable, args = []) {
25
+ string(executable, 'executable');
26
+ if (/[\\/:]/.test(executable))
27
+ throw new TypeError('Command.name requires a name without path separators');
28
+ return command(executable, args);
29
+ },
30
+ path(executable, args = []) {
31
+ string(executable, 'executable');
32
+ if (!isAbsolute(executable))
33
+ throw new TypeError('Command.path requires an absolute path');
34
+ return command(executable, args);
35
+ },
36
+ });
37
+ function environment(kind, values) {
38
+ if (!values || typeof values !== 'object' || Array.isArray(values))
39
+ throw new TypeError('environment values must be an object');
40
+ const snapshot = Object.create(null);
41
+ for (const [key, value] of Object.entries(values)) {
42
+ string(key, 'environment key');
43
+ if (key.includes('='))
44
+ throw new TypeError('environment key cannot contain =');
45
+ if (value !== undefined)
46
+ string(value, 'environment value', true);
47
+ snapshot[key] = value;
48
+ }
49
+ return Object.freeze({
50
+ [environmentBrand]: true,
51
+ kind,
52
+ values: Object.freeze(snapshot),
53
+ });
54
+ }
55
+ export const Environment = Object.freeze({
56
+ inherit(updates = {}) {
57
+ return environment('inherit', updates);
58
+ },
59
+ replace(values) {
60
+ return environment('replace', values);
61
+ },
62
+ });
63
+ const inheritedOutput = Object.freeze({
64
+ [outputBrand]: true,
65
+ kind: 'inherit',
66
+ });
67
+ const discardedOutput = Object.freeze({
68
+ [outputBrand]: true,
69
+ kind: 'discard',
70
+ });
71
+ function captureLimit(limit) {
72
+ if (!Number.isSafeInteger(limit) || limit <= 0 || limit > constants.MAX_LENGTH)
73
+ throw new TypeError('output limit must be a positive safe byte count within Buffer.MAX_LENGTH');
74
+ }
75
+ function capture(kind, options) {
76
+ const limit = options?.limit;
77
+ captureLimit(limit);
78
+ return Object.freeze({ [outputBrand]: true, kind, limit });
79
+ }
80
+ export const Output = Object.freeze({
81
+ inherit() {
82
+ return inheritedOutput;
83
+ },
84
+ discard() {
85
+ return discardedOutput;
86
+ },
87
+ text(options) {
88
+ return capture('text', options);
89
+ },
90
+ bytes(options) {
91
+ return capture('bytes', options);
92
+ },
93
+ });
94
+ const noInput = Object.freeze({ [inputBrand]: true, kind: 'none' });
95
+ const inheritedInput = Object.freeze({ [inputBrand]: true, kind: 'inherit' });
96
+ export const Input = Object.freeze({
97
+ none() {
98
+ return noInput;
99
+ },
100
+ inherit() {
101
+ return inheritedInput;
102
+ },
103
+ });
104
+ const optionKeys = new Set([
105
+ 'cwd',
106
+ 'environment',
107
+ 'input',
108
+ 'output',
109
+ 'error',
110
+ 'check',
111
+ 'signal',
112
+ 'timeoutMs',
113
+ 'gracePeriodMs',
114
+ 'killTimeoutMs',
115
+ ]);
116
+ function duration(value, label, minimum) {
117
+ if (!Number.isInteger(value) || value < minimum || value > 2147483647)
118
+ throw new TypeError(`${label} must be an integer between ${minimum} and 2147483647`);
119
+ }
120
+ export function settings(cmd, options) {
121
+ if (!cmd || cmd[commandBrand] !== true)
122
+ throw new TypeError('Use Command.name or Command.path');
123
+ if (!options || typeof options !== 'object' || Array.isArray(options))
124
+ throw new TypeError('run options must be an object');
125
+ for (const key of Object.keys(options))
126
+ if (!optionKeys.has(key))
127
+ throw new TypeError(`Unknown run option: ${key}`);
128
+ const { cwd, environment: env, input = noInput, output = inheritedOutput, error = inheritedOutput, check = true, signal, timeoutMs, gracePeriodMs = 250, killTimeoutMs = 1000, } = options;
129
+ if (cwd !== undefined)
130
+ string(cwd, 'cwd');
131
+ if (env !== undefined && (!env || env[environmentBrand] !== true))
132
+ throw new TypeError('Use Environment.inherit or Environment.replace');
133
+ if (!output || output[outputBrand] !== true || !error || error[outputBrand] !== true)
134
+ throw new TypeError('Use Output policies');
135
+ for (const policy of [output, error]) {
136
+ if (policy.kind === 'text' || policy.kind === 'bytes')
137
+ captureLimit(policy.limit);
138
+ else if (policy.kind !== 'inherit' && policy.kind !== 'discard')
139
+ throw new TypeError('Unknown output policy');
140
+ }
141
+ if (typeof input !== 'string' &&
142
+ !(input instanceof Uint8Array) &&
143
+ (!input || input[inputBrand] !== true))
144
+ throw new TypeError('input must be a string, Uint8Array or Input policy');
145
+ if (typeof check !== 'boolean')
146
+ throw new TypeError('check must be a boolean');
147
+ if (signal !== undefined && !(signal instanceof AbortSignal))
148
+ throw new TypeError('signal must be an AbortSignal');
149
+ if (timeoutMs !== undefined)
150
+ duration(timeoutMs, 'timeoutMs', 1);
151
+ duration(gracePeriodMs, 'gracePeriodMs', 0);
152
+ duration(killTimeoutMs, 'killTimeoutMs', 1);
153
+ return {
154
+ cwd,
155
+ environment: env,
156
+ input,
157
+ output,
158
+ error,
159
+ check,
160
+ signal,
161
+ timeoutMs,
162
+ gracePeriodMs,
163
+ killTimeoutMs,
164
+ };
165
+ }
166
+ /** Internal helper; parameter permits testing Windows key behavior on other hosts. */
167
+ export function childEnvironment(policy, platform = process.platform) {
168
+ if (policy === undefined)
169
+ return undefined;
170
+ const env = Object.assign(Object.create(null), policy.kind === 'inherit' ? process.env : undefined);
171
+ if (platform === 'win32') {
172
+ const keys = new Map();
173
+ for (const key of Object.keys(env)) {
174
+ const normalized = key.toUpperCase();
175
+ const previous = keys.get(normalized);
176
+ if (previous !== undefined)
177
+ delete env[previous];
178
+ keys.set(normalized, key);
179
+ }
180
+ for (const [key, value] of Object.entries(policy.values)) {
181
+ const normalized = key.toUpperCase();
182
+ const previous = keys.get(normalized);
183
+ if (previous !== undefined)
184
+ delete env[previous];
185
+ keys.set(normalized, key);
186
+ if (value !== undefined)
187
+ env[key] = value;
188
+ }
189
+ }
190
+ else {
191
+ for (const [key, value] of Object.entries(policy.values)) {
192
+ if (value === undefined)
193
+ delete env[key];
194
+ else
195
+ env[key] = value;
196
+ }
197
+ }
198
+ return env;
199
+ }
200
+ //# sourceMappingURL=values.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"values.js","sourceRoot":"","sources":["../src/values.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,76 @@
1
1
  {
2
2
  "name": "@swiftuijs/twill-shell",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "0.2.0",
4
+ "description": "Swift-inspired subprocess toolkit for Twill and native Node scripts: explicit arguments, bounded output and owned teardown.",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/swiftuijs/twill.git",
10
+ "directory": "packages/shell"
11
+ },
12
+ "homepage": "https://twill.evecalm.com/",
13
+ "bugs": {
14
+ "url": "https://github.com/swiftuijs/twill/issues"
15
+ },
16
+ "sideEffects": false,
17
+ "files": [
18
+ "dist",
19
+ "README.md",
20
+ "LICENSE"
21
+ ],
22
+ "exports": {
23
+ ".": {
24
+ "types": "./dist/index.d.ts",
25
+ "import": "./dist/index.js"
26
+ }
27
+ },
28
+ "engines": {
29
+ "node": "^20.19.0 || >=22.12.0"
30
+ },
31
+ "publishConfig": {
32
+ "access": "public"
33
+ },
34
+ "devDependencies": {
35
+ "typescript": "5.9.3",
36
+ "@types/node": "^26.6.4",
37
+ "vitest": "^5.0.3",
38
+ "@vitest/coverage-v8": "^5.0.3",
39
+ "prettier": "^3.9.9",
40
+ "@swiftuijs/twill": "0.2.0",
41
+ "@swiftuijs/twill-formatter": "0.2.0",
42
+ "@swiftuijs/twill-export": "0.2.0"
43
+ },
44
+ "author": {
45
+ "name": "forth.ink",
46
+ "url": "https://forth.ink"
47
+ },
48
+ "keywords": [
49
+ "twill",
50
+ "shell",
51
+ "subprocess",
52
+ "scripting",
53
+ "swift",
54
+ "typescript",
55
+ "node"
56
+ ],
57
+ "peerDependencies": {
58
+ "@types/node": "^20.0.0 || ^22.0.0 || ^24.0.0 || ^26.0.0"
59
+ },
60
+ "peerDependenciesMeta": {
61
+ "@types/node": {
62
+ "optional": true
63
+ }
64
+ },
65
+ "dependencies": {
66
+ "@swiftuijs/twill-shell-native": "0.2.0"
67
+ },
68
+ "scripts": {
69
+ "build": "node -e \"require('node:fs').rmSync('dist', {recursive: true, force: true})\" && tsc -p tsconfig.build.json",
70
+ "typecheck": "tsc --noEmit -p tsconfig.json",
71
+ "test:unit": "vitest run",
72
+ "test:coverage": "vitest run --coverage",
73
+ "test:package": "node tests/consumer.mjs",
74
+ "benchmark": "node benchmarks/run.mjs"
75
+ }
6
76
  }