@swiftuijs/twill-shell 0.0.0-stage → 0.3.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 +21 -0
- package/README.md +72 -3
- package/dist/cwd.d.ts +2 -0
- package/dist/cwd.d.ts.map +1 -0
- package/dist/cwd.js +9 -0
- package/dist/cwd.js.map +1 -0
- package/dist/environment.d.ts +5 -0
- package/dist/environment.d.ts.map +1 -0
- package/dist/environment.js +32 -0
- package/dist/environment.js.map +1 -0
- package/dist/errors.d.ts +37 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +65 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +224 -0
- package/dist/index.js.map +1 -0
- package/dist/values.d.ts +90 -0
- package/dist/values.d.ts.map +1 -0
- package/dist/values.js +176 -0
- package/dist/values.js.map +1 -0
- package/package.json +72 -3
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,73 @@
|
|
|
1
|
-
#
|
|
1
|
+
# <img src="https://twill.evecalm.com/logo.png" alt="Twill hummingbird" align="right" width="40" height="40" /> Twill shell
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
Swift-inspired subprocess tools for Twill and ordinary Node JS/TS scripts, Node-based in 0.3.0.
|
|
4
|
+
|
|
5
|
+
## Install in your project
|
|
6
|
+
|
|
7
|
+
Use Node 24 LTS for a new setup (supported range: `^20.19.0 || >=22.12.0`). Run from the directory containing your `package.json`; for a new project, run `npm init -y` first. Install the SDK as a production dependency:
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
npm install @swiftuijs/twill-shell@0.3.0
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
With pnpm, use `pnpm add @swiftuijs/twill-shell@0.3.0`. This package supplies the process API; `@swiftuijs/twill` supplies the optional Twill source runner. A global compiler does not make this SDK available to project imports. Keep Twill packages on the same version.
|
|
14
|
+
|
|
15
|
+
## Run ordinary JavaScript
|
|
16
|
+
|
|
17
|
+
The SDK uses Node spawn/streams with literal argv (`shell: false`), bounded capture and owned cancellation/timeout teardown. It has zero production dependencies; native JS/TS needs no Twill compiler or Rust toolchain.
|
|
18
|
+
|
|
19
|
+
Changed in 0.3.0: the SDK no longer depends on `@swiftuijs/twill-shell-native`. Older npm 0.2.0 still requires the retired Rust addon; its versions remain downloadable for compatibility. The public command/policy/error API remains; abrupt worker/process-exit cleanup and unnamed Unix signal reporting change to Node's boundaries. See the [scripting guide](https://twill.evecalm.com/scripting#execution-and-version-boundary).
|
|
20
|
+
|
|
21
|
+
Save this as `command.mjs`:
|
|
22
|
+
|
|
23
|
+
```js
|
|
24
|
+
import { Command, Output, Subprocess } from '@swiftuijs/twill-shell';
|
|
25
|
+
|
|
26
|
+
const result = await Subprocess.run(
|
|
27
|
+
Command.path(process.execPath, ['-e', 'console.log("Hello from a child process")']),
|
|
28
|
+
{ output: Output.text({ limit: 64 * 1024 }), timeoutMs: 5000 },
|
|
29
|
+
);
|
|
30
|
+
console.log(result.standardOutput.trim());
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Run `node command.mjs`. Expected output is `Hello from a child process`. This works without Git, a Twill compiler or a global installation. Native TypeScript uses your existing TS runner/build.
|
|
34
|
+
|
|
35
|
+
## Run Twill source
|
|
36
|
+
|
|
37
|
+
Install the compiler as well:
|
|
38
|
+
|
|
39
|
+
```sh
|
|
40
|
+
npm install --save-dev @swiftuijs/twill@0.3.0
|
|
41
|
+
# pnpm add -D @swiftuijs/twill@0.3.0
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Copy the JavaScript example to `command.twill` and add `#!/usr/bin/env twill` as its first line. Use the local command:
|
|
45
|
+
|
|
46
|
+
```sh
|
|
47
|
+
npm exec -- twill command.twill
|
|
48
|
+
# pnpm exec twill command.twill
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
On Linux/macOS, `chmod +x command.twill` enables `npm exec --call './command.twill'` or `pnpm exec ./command.twill`. To run `./command.twill` directly, install the compiler globally with `npm install --global @swiftuijs/twill@0.3.0` and keep its executable directory on PATH. Windows uses the explicit CLI. Arguments after the script path pass through unchanged. Application dependencies resolve from the script's location. Use compiler and SDK 0.3.0 or newer.
|
|
52
|
+
|
|
53
|
+
For package scripts, Node type declarations, error handling and troubleshooting, follow the [complete shell scripting guide](https://twill.evecalm.com/scripting). [Getting started](https://twill.evecalm.com/getting-started) covers application modules and build integration.
|
|
54
|
+
|
|
55
|
+
## Process contracts
|
|
56
|
+
|
|
57
|
+
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.
|
|
58
|
+
|
|
59
|
+
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.
|
|
60
|
+
|
|
61
|
+
From 0.3.0, statuses follow Node reports, including its unnamed-signal limitations. Released 0.2.0 preserves numeric unnamed Unix signals. 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.
|
|
62
|
+
|
|
63
|
+
`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.
|
|
64
|
+
|
|
65
|
+
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/).
|
|
66
|
+
|
|
67
|
+
Cancel and await outstanding work before a worker shuts down. Set `process.exitCode` after awaited work; forced `Worker.terminate()` and `process.exit()` cannot perform an asynchronous join. Version 0.3.0 removes the old native cleanup barrier. OS creation and event-loop scheduling are not hard real-time deadlines.
|
|
68
|
+
|
|
69
|
+
Bounded capture and lifecycle checks add overhead. The reviewed Linux/Node 24 report measured about 17% median overhead for native dual 1 MiB capture and 11% for full duplex, accepted for 0.3.0. See the [recorded costs](https://twill.evecalm.com/performance#node-shell-sdk); this is not a universal native-parity guarantee.
|
|
70
|
+
|
|
71
|
+
## Development
|
|
72
|
+
|
|
73
|
+
This package's implementation uses Twill and emits ordinary JavaScript. Build and check a checkout with the workspace tools; see [developing tooling in Twill](https://github.com/swiftuijs/twill/blob/main/docs/contributing/dogfooding.md) for bootstrap and contribution instructions.
|
package/dist/cwd.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cwd.d.ts","mappings":"AACA,wBAAgB,WAAW,CACzB,GAAG,EAAE,MAAM,GAAG,SAAS,EACvB,QAAQ,kBAAmB,EAC3B,MAAM,SAAgB,GACrB,MAAM","names":[],"ignoreList":[],"sources":["../src/cwd.twill"]}
|
package/dist/cwd.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { isAbsolute, win32 } from "node:path";
|
|
2
|
+
//#region src/cwd.twill
|
|
3
|
+
function cwdSnapshot(cwd, platform = process.platform, parent = process.cwd()) {
|
|
4
|
+
return cwd === void 0 ? parent : platform === "win32" ? win32.resolve(parent, cwd) : isAbsolute(cwd) ? cwd : `${parent}/${cwd}`;
|
|
5
|
+
}
|
|
6
|
+
//#endregion
|
|
7
|
+
export { cwdSnapshot };
|
|
8
|
+
|
|
9
|
+
//# sourceMappingURL=cwd.js.map
|
package/dist/cwd.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cwd.js","names":[],"sources":["../src/cwd.twill"],"mappings":";;AACA,SAAgB,YACd,KACA,WAAW,QAAQ,UACnB,SAAS,QAAQ,IAAG,GAAE;CAEtB,OAAO,QAAQ,KAAA,IACX,SACA,aAAa,UACX,MAAM,QAAQ,QAAQ,GAAG,IACzB,WAAW,GAAG,IACZ,MACA,GAAG,OAAM,GAAI;AACvB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"environment.d.ts","mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAgB;AAiBjD,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,WAAW,GAAG,SAAS,EAC/B,QAAQ,kBAAmB,EAC3B,MAAM,oBAAc","names":[],"ignoreList":[],"sources":["../src/environment.twill"]}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { childEnvironment } from "./values.js";
|
|
2
|
+
//#region src/environment.twill
|
|
3
|
+
var windowsRequired = [
|
|
4
|
+
"HOMEDRIVE",
|
|
5
|
+
"HOMEPATH",
|
|
6
|
+
"LOGONSERVER",
|
|
7
|
+
"PATH",
|
|
8
|
+
"SYSTEMDRIVE",
|
|
9
|
+
"SYSTEMROOT",
|
|
10
|
+
"TEMP",
|
|
11
|
+
"USERDOMAIN",
|
|
12
|
+
"USERNAME",
|
|
13
|
+
"USERPROFILE",
|
|
14
|
+
"WINDIR"
|
|
15
|
+
];
|
|
16
|
+
function environmentSnapshot(policy, platform = process.platform, parent = process.env) {
|
|
17
|
+
const environment = { ...childEnvironment(policy, platform) ?? parent };
|
|
18
|
+
if (parent.NODE_V8_COVERAGE && !Object.hasOwn(environment, "NODE_V8_COVERAGE")) environment.NODE_V8_COVERAGE = parent.NODE_V8_COVERAGE;
|
|
19
|
+
if (platform === "win32") {
|
|
20
|
+
const selected = new Set(Object.keys(environment).map((key) => key.toUpperCase()));
|
|
21
|
+
const inherited = new Map(Object.entries(parent).map(([key, value]) => [key.toUpperCase(), value]));
|
|
22
|
+
for (const key of windowsRequired) {
|
|
23
|
+
const value = inherited.get(key);
|
|
24
|
+
if (!selected.has(key) && value !== void 0) environment[key] = value;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return environment;
|
|
28
|
+
}
|
|
29
|
+
//#endregion
|
|
30
|
+
export { environmentSnapshot };
|
|
31
|
+
|
|
32
|
+
//# sourceMappingURL=environment.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"environment.js","names":[],"sources":["../src/environment.twill"],"mappings":";;AAKA,IAAM,kBAAkB;CACtB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACD;AACD,SAAgB,oBACd,QACA,WAAW,QAAQ,UACnB,SAAS,QAAQ,KAAG;CAEpB,MAAM,cAAc,EAAE,GAAI,iBAAiB,QAAQ,QAAQ,KAAK,OAAO;CACvE,IAAI,OAAO,oBAAoB,CAAC,OAAO,OAAO,aAAa,kBAAkB,GAC3E,YAAY,mBAAmB,OAAO;CACxC,IAAI,aAAa,SAAS;EACxB,MAAM,WAAW,IAAI,IAAI,OAAO,KAAK,WAAW,CAAC,CAAC,KAAK,QAAQ,IAAI,YAAW,CAAE,CAAC;EACjF,MAAM,YAAY,IAAI,IACpB,OAAO,QAAQ,MAAM,CAAC,CAAC,KAAK,CAAC,KAAK,WAAW,CAAC,IAAI,YAAW,GAAI,KAAK,CAAC,CAAC;EAE1E,KAAK,MAAM,OAAO,iBAAiB;GACjC,MAAM,QAAQ,UAAU,IAAI,GAAG;GAC/B,IAAI,CAAC,SAAS,IAAI,GAAG,KAAK,UAAU,KAAA,GAAW,YAAY,OAAO;EACpE;CACF;CACA,OAAO;AACT"}
|
package/dist/errors.d.ts
ADDED
|
@@ -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","mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,YAAe;AAEvE,qBAAa,YAAa,SAAQ,KAAK;IACrC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM;IACnC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,iBAAiB;IAC9C,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,MAAM;IACzC,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM;IACxC,QAAQ,CAAC,2BAA2B,CAAC,EAAE,MAAM;IAC7C,QAAQ,CAAC,aAAa,EAAE,SAAS,KAAK,EAAE;gBAC5B,OAAO,EAAE,MAAM,EAAE,iBAAiB,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY;;AAMjF,qBAAa,kBAAmB,SAAQ,YAAY;gBACtC,KAAK,EAAE,OAAO;;AAI5B,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;;AAKlB,qBAAa,iBAAkB,SAAQ,YAAY;gBACrC,iBAAiB,EAAE,MAAM,GAAG,SAAS,EAAE,MAAM,EAAE,OAAO;;AAIpE,qBAAa,mBAAoB,SAAQ,YAAY;IAEjD,QAAQ,CAAC,SAAS,EAAE,MAAM;gBAAjB,SAAS,EAAE,MAAM,EAC1B,iBAAiB,EAAE,MAAM,GAAG,SAAS;;AAKzC,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;;AAKzC,qBAAa,oBAAqB,SAAQ,YAAY;gBACxC,iBAAiB,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO;;AAKxD,qBAAa,gBAAiB,SAAQ,YAAY;IACpC,QAAQ,CAAC,MAAM,EAAE,eAAe;gBAAvB,MAAM,EAAE,eAAe","names":[],"ignoreList":[],"sources":["../src/errors.twill"]}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
//#region src/errors.twill
|
|
2
|
+
var ProcessError = class extends Error {
|
|
3
|
+
processIdentifier;
|
|
4
|
+
terminationStatus;
|
|
5
|
+
standardOutput;
|
|
6
|
+
standardError;
|
|
7
|
+
unresolvedProcessIdentifier;
|
|
8
|
+
cleanupErrors = [];
|
|
9
|
+
constructor(message, processIdentifier, options) {
|
|
10
|
+
super(message, options);
|
|
11
|
+
this.name = new.target.name;
|
|
12
|
+
this.processIdentifier = processIdentifier;
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
var ProcessLaunchError = class extends ProcessError {
|
|
16
|
+
constructor(cause) {
|
|
17
|
+
super("Subprocess could not start", void 0, { cause });
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
var ProcessIOError = class extends ProcessError {
|
|
21
|
+
stream;
|
|
22
|
+
constructor(stream, processIdentifier, cause) {
|
|
23
|
+
super(`Subprocess ${stream} failed`, processIdentifier, { cause });
|
|
24
|
+
this.stream = stream;
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
var ProcessAbortError = class extends ProcessError {
|
|
28
|
+
constructor(processIdentifier, reason) {
|
|
29
|
+
super("Subprocess aborted", processIdentifier, { cause: reason });
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
var ProcessTimeoutError = class extends ProcessError {
|
|
33
|
+
timeoutMs;
|
|
34
|
+
constructor(timeoutMs, processIdentifier) {
|
|
35
|
+
super("Subprocess timed out", processIdentifier);
|
|
36
|
+
this.timeoutMs = timeoutMs;
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
var OutputLimitError = class extends ProcessError {
|
|
40
|
+
stream;
|
|
41
|
+
limit;
|
|
42
|
+
constructor(stream, limit, processIdentifier) {
|
|
43
|
+
super(`Subprocess ${stream} exceeded its byte limit`, processIdentifier);
|
|
44
|
+
this.stream = stream;
|
|
45
|
+
this.limit = limit;
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
var ProcessTeardownError = class extends ProcessError {
|
|
49
|
+
constructor(processIdentifier, cause) {
|
|
50
|
+
super("Owned subprocess could not be terminated", processIdentifier, { cause });
|
|
51
|
+
Object.assign(this, { unresolvedProcessIdentifier: processIdentifier });
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
var ProcessExitError = class extends ProcessError {
|
|
55
|
+
result;
|
|
56
|
+
constructor(result) {
|
|
57
|
+
super("Subprocess exited unsuccessfully", result.processIdentifier);
|
|
58
|
+
this.result = result;
|
|
59
|
+
Object.assign(this, result);
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
//#endregion
|
|
63
|
+
export { OutputLimitError, ProcessAbortError, ProcessError, ProcessExitError, ProcessIOError, ProcessLaunchError, ProcessTeardownError, ProcessTimeoutError };
|
|
64
|
+
|
|
65
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","names":[],"sources":["../src/errors.twill"],"mappings":";AAEA,IAAa,eAAb,cAAkC,MAAK;CAC5B;CACA;CACA;CACA;CACA;CACA,gBAAkC,CAAA;CAC3C,YAAY,SAAiB,mBAA4B,SAAsB;EAC7E,MAAM,SAAS,OAAO;EACtB,KAAK,OAAO,WAAW;EACvB,KAAK,oBAAoB;CAC3B;AACF;AACA,IAAa,qBAAb,cAAwC,aAAY;CAClD,YAAY,OAAc;EACxB,MAAM,8BAA8B,KAAA,GAAW,EAAE,MAAK,CAAE;CAC1D;AACF;AACA,IAAa,iBAAb,cAAoC,aAAY;CAEnC;CADX,YACW,QACT,mBACA,OAAc;EAEd,MAAM,cAAc,OAAM,UAAW,mBAAmB,EAAE,MAAK,CAAE;EAJxD,KAAA,SAAA;CAKX;AACF;AACA,IAAa,oBAAb,cAAuC,aAAY;CACjD,YAAY,mBAAuC,QAAe;EAChE,MAAM,sBAAsB,mBAAmB,EAAE,OAAO,OAAM,CAAE;CAClE;AACF;AACA,IAAa,sBAAb,cAAyC,aAAY;CAExC;CADX,YACW,WACT,mBAAqC;EAErC,MAAM,wBAAwB,iBAAiB;EAHtC,KAAA,YAAA;CAIX;AACF;AACA,IAAa,mBAAb,cAAsC,aAAY;CAErC;CACA;CAFX,YACW,QACA,OACT,mBAAqC;EAErC,MAAM,cAAc,OAAM,2BAA4B,iBAAiB;EAJ9D,KAAA,SAAA;EACA,KAAA,QAAA;CAIX;AACF;AACA,IAAa,uBAAb,cAA0C,aAAY;CACpD,YAAY,mBAA2B,OAAe;EACpD,MAAM,4CAA4C,mBAAmB,EAAE,MAAK,CAAE;EAC9E,OAAO,OAAO,MAAM,EAAE,6BAA6B,kBAAiB,CAAE;CACxE;AACF;AACA,IAAa,mBAAb,cAAsC,aAAY;CAC3B;CAArB,YAAqB,QAAuB;EAC1C,MAAM,oCAAoC,OAAO,iBAAiB;EAD/C,KAAA,SAAA;EAEnB,OAAO,OAAO,MAAM,MAAM;CAC5B;AACF"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Command, type OutputPolicy, type OutputValue, type RunOptions, 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>>(cmd: 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","mappings":"AAMA,OAAO,EACL,OAAO,EAEP,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,eAAe,EACrB,MAAM,aAAgB;AAWvB,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,aAAgB;AACpE,YAAY,EACV,YAAY,EACZ,WAAW,EACX,UAAU,EACV,YAAY,EACZ,WAAW,EACX,eAAe,EACf,eAAe,EACf,UAAU,EACV,UAAU,GACX,MAAM,aAAgB;AACvB,OAAO,EACL,YAAY,EACZ,kBAAkB,EAClB,iBAAiB,EACjB,mBAAmB,EACnB,gBAAgB,EAChB,cAAc,EACd,gBAAgB,EAChB,oBAAoB,GACrB,MAAM,aAAgB;AAEvB,MAAM,MAAM,iBAAiB,GACzB;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM;CAAC,GACjD;IAAE,QAAQ,CAAC,IAAI,EAAE,UAAU;IAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,GAAG,MAAM;CAAE;AAC3E,MAAM,WAAW,eAAe,CAC9B,CAAC,SAAS,YAAY,GAAG,YAAY,EACrC,CAAC,SAAS,YAAY,GAAG,YAAY;IAErC,QAAQ,CAAC,iBAAiB,EAAE,MAAM;IAClC,QAAQ,CAAC,iBAAiB,EAAE,iBAAiB;IAC7C,QAAQ,CAAC,cAAc,EAAE,WAAW,CAAC,CAAC,CAAC;IACvC,QAAQ,CAAC,aAAa,EAAE,WAAW,CAAC,CAAC,CAAC;;AA4CxC,KAAK,YAAY,CAAC,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,UAAU,CAAC,EAAE,KAAK,CAAC;AAC5E,KAAK,cAAc,CAAC,CAAC,IAAI,OAAO,CAAC,CAAC,EAAE,YAAY,CAAC,GAAG,CAAC,SAAS,SAAS,CAAC,GAAG,eAAe,GAAG,KAAK,CAAC;AACnG,iBAAS,GAAG,CAAC,OAAO,SAAS,UAAU,GAAG,UAAU,CAAC,eAAe,EAAE,eAAe,CAAC,EACpF,GAAG,EAAE,OAAO,EACZ,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;AAuOhG,eAAO,MAAM,UAAU;;EAAyB","names":[],"ignoreList":[],"sources":["../src/index.twill"]}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import { cwdSnapshot } from "./cwd.js";
|
|
2
|
+
import { Command, Environment, Input, Output, settings } from "./values.js";
|
|
3
|
+
import { environmentSnapshot } from "./environment.js";
|
|
4
|
+
import { OutputLimitError, ProcessAbortError, ProcessError, ProcessExitError, ProcessIOError, ProcessLaunchError, ProcessTeardownError, ProcessTimeoutError } from "./errors.js";
|
|
5
|
+
import childProcess from "node:child_process";
|
|
6
|
+
import { performance } from "node:perf_hooks";
|
|
7
|
+
import { addAbortListener } from "node:events";
|
|
8
|
+
//#region src/index.twill
|
|
9
|
+
var Capture = class {
|
|
10
|
+
reader;
|
|
11
|
+
policy;
|
|
12
|
+
chunks = [];
|
|
13
|
+
size = 0;
|
|
14
|
+
constructor(reader, policy, channel, pid, fail, failed) {
|
|
15
|
+
this.reader = reader;
|
|
16
|
+
this.policy = policy;
|
|
17
|
+
this.onData = (chunk) => {
|
|
18
|
+
if (failed()) return;
|
|
19
|
+
if (this.size + chunk.length > policy.limit) {
|
|
20
|
+
fail(new OutputLimitError(channel, policy.limit, pid));
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
this.size += chunk.length;
|
|
24
|
+
this.chunks.push(chunk);
|
|
25
|
+
};
|
|
26
|
+
this.onError = (cause) => fail(pid === void 0 ? new ProcessLaunchError(cause) : new ProcessIOError(channel, pid, cause));
|
|
27
|
+
reader.on("data", this.onData).on("error", this.onError);
|
|
28
|
+
}
|
|
29
|
+
onData;
|
|
30
|
+
onError;
|
|
31
|
+
value() {
|
|
32
|
+
const bytes = this.chunks.length === 1 ? this.chunks[0] : Buffer.concat(this.chunks, this.size);
|
|
33
|
+
return this.policy.kind === "text" ? bytes.toString("utf8") : bytes;
|
|
34
|
+
}
|
|
35
|
+
detach() {
|
|
36
|
+
this.reader.off("data", this.onData).off("error", this.onError);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
var stdio = (policy) => policy.kind === "inherit" ? "inherit" : policy.kind === "discard" ? "ignore" : "pipe";
|
|
40
|
+
var emptyOptions = Object.freeze({});
|
|
41
|
+
function run(cmd, options = emptyOptions) {
|
|
42
|
+
return new Promise((resolve, reject) => {
|
|
43
|
+
const config = settings(cmd, options);
|
|
44
|
+
const { signal } = config;
|
|
45
|
+
const submitted = config.timeoutMs === void 0 ? void 0 : performance.now();
|
|
46
|
+
if (signal?.aborted) {
|
|
47
|
+
reject(new ProcessAbortError(void 0, signal.reason));
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
let child;
|
|
51
|
+
const input = typeof config.input === "string" ? config.input : config.input instanceof Uint8Array ? Buffer.from(Buffer.from(config.input.buffer, config.input.byteOffset, config.input.byteLength)) : void 0;
|
|
52
|
+
try {
|
|
53
|
+
child = childProcess.spawn(cmd.executable, cmd.arguments, {
|
|
54
|
+
shell: false,
|
|
55
|
+
cwd: config.cwd === void 0 ? void 0 : cwdSnapshot(config.cwd),
|
|
56
|
+
env: config.environment === void 0 ? void 0 : environmentSnapshot(config.environment),
|
|
57
|
+
stdio: [
|
|
58
|
+
typeof config.input === "object" && !(config.input instanceof Uint8Array) ? config.input.kind === "inherit" ? "inherit" : "ignore" : "pipe",
|
|
59
|
+
stdio(config.output),
|
|
60
|
+
stdio(config.error)
|
|
61
|
+
]
|
|
62
|
+
});
|
|
63
|
+
} catch (cause) {
|
|
64
|
+
reject(new ProcessLaunchError(cause));
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
let primary;
|
|
68
|
+
let closed = false, settled = false, inputClosed = child.stdin === null;
|
|
69
|
+
let status;
|
|
70
|
+
let timeout;
|
|
71
|
+
let grace;
|
|
72
|
+
let forced;
|
|
73
|
+
let stdout, stderr;
|
|
74
|
+
let abortListener;
|
|
75
|
+
const failed = () => primary !== void 0;
|
|
76
|
+
const clearTimers = () => {
|
|
77
|
+
clearTimeout(timeout);
|
|
78
|
+
clearTimeout(grace);
|
|
79
|
+
clearTimeout(forced);
|
|
80
|
+
};
|
|
81
|
+
const destroyIO = () => {
|
|
82
|
+
child.stdin?.destroy();
|
|
83
|
+
child.stdout?.destroy();
|
|
84
|
+
child.stderr?.destroy();
|
|
85
|
+
};
|
|
86
|
+
const cleanup = () => {
|
|
87
|
+
clearTimers();
|
|
88
|
+
abortListener?.[Symbol.dispose]();
|
|
89
|
+
child.off("error", onError).off("exit", onExit).off("close", onClose);
|
|
90
|
+
child.stdin?.off("error", onInputError).off("close", onInputClose);
|
|
91
|
+
stdout?.detach();
|
|
92
|
+
stderr?.detach();
|
|
93
|
+
};
|
|
94
|
+
const captured = (capture, stream) => {
|
|
95
|
+
try {
|
|
96
|
+
return capture?.value();
|
|
97
|
+
} catch (cause) {
|
|
98
|
+
const error = new ProcessIOError(stream, child.pid, cause);
|
|
99
|
+
if (primary) primary.cleanupErrors.push(error);
|
|
100
|
+
else primary = error;
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
const finish = () => {
|
|
105
|
+
if (settled || !closed || !inputClosed) return;
|
|
106
|
+
settled = true;
|
|
107
|
+
cleanup();
|
|
108
|
+
const standardOutput = captured(stdout, "stdout"), standardError = captured(stderr, "stderr");
|
|
109
|
+
if (primary) {
|
|
110
|
+
Object.assign(primary, {
|
|
111
|
+
terminationStatus: status,
|
|
112
|
+
standardOutput,
|
|
113
|
+
standardError
|
|
114
|
+
});
|
|
115
|
+
reject(primary);
|
|
116
|
+
} else {
|
|
117
|
+
const result = Object.freeze({
|
|
118
|
+
processIdentifier: child.pid,
|
|
119
|
+
terminationStatus: status,
|
|
120
|
+
standardOutput,
|
|
121
|
+
standardError
|
|
122
|
+
});
|
|
123
|
+
if (config.check && (status.kind !== "exited" || status.code !== 0)) reject(new ProcessExitError(result));
|
|
124
|
+
else resolve(result);
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
const secondary = (error) => primary.cleanupErrors.push(error);
|
|
128
|
+
const kill = (signal) => {
|
|
129
|
+
const errors = primary.cleanupErrors.length;
|
|
130
|
+
try {
|
|
131
|
+
if (!child.kill(signal) && child.exitCode === null && child.signalCode === null && child.pid !== void 0 && primary.cleanupErrors.length === errors) secondary(new ProcessError("Subprocess termination signal failed", child.pid));
|
|
132
|
+
} catch (cause) {
|
|
133
|
+
secondary(new ProcessError("Subprocess termination signal failed", child.pid, { cause }));
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
const fail = (error) => {
|
|
137
|
+
if (settled) return;
|
|
138
|
+
if (primary) {
|
|
139
|
+
secondary(error);
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
primary = error;
|
|
143
|
+
clearTimeout(timeout);
|
|
144
|
+
if (child.pid === void 0 || child.exitCode !== null || child.signalCode !== null) {
|
|
145
|
+
destroyIO();
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
kill("SIGTERM");
|
|
149
|
+
grace = setTimeout(() => {
|
|
150
|
+
if (closed) return;
|
|
151
|
+
kill("SIGKILL");
|
|
152
|
+
destroyIO();
|
|
153
|
+
forced = setTimeout(() => {
|
|
154
|
+
if (closed) return;
|
|
155
|
+
const alive = child.exitCode === null && child.signalCode === null;
|
|
156
|
+
secondary(alive ? new ProcessTeardownError(child.pid) : new ProcessError("Subprocess I/O did not close", child.pid));
|
|
157
|
+
Object.assign(primary, {
|
|
158
|
+
unresolvedProcessIdentifier: alive ? child.pid : void 0,
|
|
159
|
+
standardOutput: captured(stdout, "stdout"),
|
|
160
|
+
standardError: captured(stderr, "stderr")
|
|
161
|
+
});
|
|
162
|
+
settled = true;
|
|
163
|
+
cleanup();
|
|
164
|
+
child.unref();
|
|
165
|
+
reject(primary);
|
|
166
|
+
}, config.killTimeoutMs);
|
|
167
|
+
forced.unref();
|
|
168
|
+
}, config.gracePeriodMs);
|
|
169
|
+
grace.unref();
|
|
170
|
+
};
|
|
171
|
+
const onAbort = () => {
|
|
172
|
+
if (!closed) fail(new ProcessAbortError(child.pid, signal.reason));
|
|
173
|
+
};
|
|
174
|
+
const onError = (cause) => fail(child.pid === void 0 ? new ProcessLaunchError(cause) : new ProcessError("Subprocess process control failed", child.pid, { cause }));
|
|
175
|
+
const onExit = () => {
|
|
176
|
+
if (primary) destroyIO();
|
|
177
|
+
};
|
|
178
|
+
const onClose = (code, signal) => {
|
|
179
|
+
closed = true;
|
|
180
|
+
clearTimers();
|
|
181
|
+
if (child.pid !== void 0) status = Object.freeze(signal !== null ? {
|
|
182
|
+
kind: "signaled",
|
|
183
|
+
signal
|
|
184
|
+
} : {
|
|
185
|
+
kind: "exited",
|
|
186
|
+
code
|
|
187
|
+
});
|
|
188
|
+
finish();
|
|
189
|
+
};
|
|
190
|
+
const onInputError = (cause) => fail(child.pid === void 0 ? new ProcessLaunchError(cause) : new ProcessIOError("stdin", child.pid, cause));
|
|
191
|
+
const onInputClose = () => {
|
|
192
|
+
inputClosed = true;
|
|
193
|
+
finish();
|
|
194
|
+
};
|
|
195
|
+
child.on("error", onError).once("exit", onExit).once("close", onClose);
|
|
196
|
+
if (child.stdout) stdout = new Capture(child.stdout, config.output, "stdout", child.pid, fail, failed);
|
|
197
|
+
if (child.stderr) stderr = new Capture(child.stderr, config.error, "stderr", child.pid, fail, failed);
|
|
198
|
+
if (child.stdin) {
|
|
199
|
+
child.stdin.on("error", onInputError).once("close", onInputClose);
|
|
200
|
+
try {
|
|
201
|
+
child.stdin.end(input);
|
|
202
|
+
} catch (cause) {
|
|
203
|
+
fail(new ProcessIOError("stdin", child.pid, cause));
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
if (signal) {
|
|
207
|
+
if (signal.aborted) onAbort();
|
|
208
|
+
else try {
|
|
209
|
+
abortListener = addAbortListener(signal, onAbort);
|
|
210
|
+
} catch (cause) {
|
|
211
|
+
fail(new ProcessError("Subprocess cancellation setup failed", child.pid, { cause }));
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
if (config.timeoutMs !== void 0 && !primary) {
|
|
215
|
+
timeout = setTimeout(() => fail(new ProcessTimeoutError(config.timeoutMs, child.pid)), Math.max(0, config.timeoutMs - (performance.now() - submitted)));
|
|
216
|
+
timeout.unref();
|
|
217
|
+
}
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
var Subprocess = Object.freeze({ run });
|
|
221
|
+
//#endregion
|
|
222
|
+
export { Command, Environment, Input, Output, OutputLimitError, ProcessAbortError, ProcessError, ProcessExitError, ProcessIOError, ProcessLaunchError, ProcessTeardownError, ProcessTimeoutError, Subprocess };
|
|
223
|
+
|
|
224
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/index.twill"],"mappings":"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"}
|
package/dist/values.d.ts
ADDED
|
@@ -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","mappings":"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","names":[],"ignoreList":[],"sources":["../src/values.twill"]}
|
package/dist/values.js
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { isAbsolute } from "node:path";
|
|
2
|
+
import { constants } from "node:buffer";
|
|
3
|
+
//#region src/values.twill
|
|
4
|
+
var commandBrand = Symbol.for("@swiftuijs/twill-shell/command/v1");
|
|
5
|
+
var environmentBrand = Symbol.for("@swiftuijs/twill-shell/environment/v1");
|
|
6
|
+
var outputBrand = Symbol.for("@swiftuijs/twill-shell/output/v1");
|
|
7
|
+
var inputBrand = Symbol.for("@swiftuijs/twill-shell/input/v1");
|
|
8
|
+
function string(value, label, empty = false) {
|
|
9
|
+
if (typeof value !== "string" || !empty && value.length === 0 || value.includes("\0")) throw new TypeError(`${label} must be a ${empty ? "" : "nonempty "}string without NUL`);
|
|
10
|
+
}
|
|
11
|
+
function command(executable, args) {
|
|
12
|
+
if (!Array.isArray(args)) throw new TypeError("arguments must be an array of strings");
|
|
13
|
+
const snapshot = Array.from(args);
|
|
14
|
+
for (const arg of snapshot) string(arg, "argument", true);
|
|
15
|
+
return Object.freeze({
|
|
16
|
+
[commandBrand]: true,
|
|
17
|
+
executable,
|
|
18
|
+
arguments: Object.freeze(snapshot)
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
var Command = Object.freeze({
|
|
22
|
+
name(executable, args = []) {
|
|
23
|
+
string(executable, "executable");
|
|
24
|
+
if (/[\\/:]/.test(executable)) throw new TypeError("Command.name requires a name without path separators");
|
|
25
|
+
return command(executable, args);
|
|
26
|
+
},
|
|
27
|
+
path(executable, args = []) {
|
|
28
|
+
string(executable, "executable");
|
|
29
|
+
if (!isAbsolute(executable)) throw new TypeError("Command.path requires an absolute path");
|
|
30
|
+
return command(executable, args);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
function environment(kind, values) {
|
|
34
|
+
if (!values || typeof values !== "object" || Array.isArray(values)) throw new TypeError("environment values must be an object");
|
|
35
|
+
const snapshot = Object.create(null);
|
|
36
|
+
for (const [key, value] of Object.entries(values)) {
|
|
37
|
+
string(key, "environment key");
|
|
38
|
+
if (key.includes("=")) throw new TypeError("environment key cannot contain =");
|
|
39
|
+
if (value !== void 0) string(value, "environment value", true);
|
|
40
|
+
snapshot[key] = value;
|
|
41
|
+
}
|
|
42
|
+
return Object.freeze({
|
|
43
|
+
[environmentBrand]: true,
|
|
44
|
+
kind,
|
|
45
|
+
values: Object.freeze(snapshot)
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
var Environment = Object.freeze({
|
|
49
|
+
inherit(updates = {}) {
|
|
50
|
+
return environment("inherit", updates);
|
|
51
|
+
},
|
|
52
|
+
replace(values) {
|
|
53
|
+
return environment("replace", values);
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
var inheritedOutput = Object.freeze({
|
|
57
|
+
[outputBrand]: true,
|
|
58
|
+
kind: "inherit"
|
|
59
|
+
});
|
|
60
|
+
var discardedOutput = Object.freeze({
|
|
61
|
+
[outputBrand]: true,
|
|
62
|
+
kind: "discard"
|
|
63
|
+
});
|
|
64
|
+
function captureLimit(limit) {
|
|
65
|
+
if (!Number.isSafeInteger(limit) || limit <= 0 || limit > constants.MAX_LENGTH) throw new TypeError("output limit must be a positive safe byte count within Buffer.MAX_LENGTH");
|
|
66
|
+
}
|
|
67
|
+
function capture(kind, options) {
|
|
68
|
+
const limit = options?.limit;
|
|
69
|
+
captureLimit(limit);
|
|
70
|
+
return Object.freeze({
|
|
71
|
+
[outputBrand]: true,
|
|
72
|
+
kind,
|
|
73
|
+
limit
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
var Output = Object.freeze({
|
|
77
|
+
inherit() {
|
|
78
|
+
return inheritedOutput;
|
|
79
|
+
},
|
|
80
|
+
discard() {
|
|
81
|
+
return discardedOutput;
|
|
82
|
+
},
|
|
83
|
+
text(options) {
|
|
84
|
+
return capture("text", options);
|
|
85
|
+
},
|
|
86
|
+
bytes(options) {
|
|
87
|
+
return capture("bytes", options);
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
var noInput = Object.freeze({
|
|
91
|
+
[inputBrand]: true,
|
|
92
|
+
kind: "none"
|
|
93
|
+
});
|
|
94
|
+
var inheritedInput = Object.freeze({
|
|
95
|
+
[inputBrand]: true,
|
|
96
|
+
kind: "inherit"
|
|
97
|
+
});
|
|
98
|
+
var Input = Object.freeze({
|
|
99
|
+
none() {
|
|
100
|
+
return noInput;
|
|
101
|
+
},
|
|
102
|
+
inherit() {
|
|
103
|
+
return inheritedInput;
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
var optionKeys = /* @__PURE__ */ new Set([
|
|
107
|
+
"cwd",
|
|
108
|
+
"environment",
|
|
109
|
+
"input",
|
|
110
|
+
"output",
|
|
111
|
+
"error",
|
|
112
|
+
"check",
|
|
113
|
+
"signal",
|
|
114
|
+
"timeoutMs",
|
|
115
|
+
"gracePeriodMs",
|
|
116
|
+
"killTimeoutMs"
|
|
117
|
+
]);
|
|
118
|
+
function duration(value, label, minimum) {
|
|
119
|
+
if (!Number.isInteger(value) || value < minimum || value > 2147483647) throw new TypeError(`${label} must be an integer between ${minimum} and 2147483647`);
|
|
120
|
+
}
|
|
121
|
+
function settings(cmd, options) {
|
|
122
|
+
if (!cmd || cmd[commandBrand] !== true) throw new TypeError("Use Command.name or Command.path");
|
|
123
|
+
if (!options || typeof options !== "object" || Array.isArray(options)) throw new TypeError("run options must be an object");
|
|
124
|
+
for (const key of Object.keys(options)) if (!optionKeys.has(key)) throw new TypeError(`Unknown run option: ${key}`);
|
|
125
|
+
const { cwd, environment: env, input = noInput, output = inheritedOutput, error = inheritedOutput, check = true, signal, timeoutMs, gracePeriodMs = 250, killTimeoutMs = 1e3 } = options;
|
|
126
|
+
if (cwd !== void 0) string(cwd, "cwd");
|
|
127
|
+
if (env !== void 0 && (!env || env[environmentBrand] !== true)) throw new TypeError("Use Environment.inherit or Environment.replace");
|
|
128
|
+
if (!output || output[outputBrand] !== true || !error || error[outputBrand] !== true) throw new TypeError("Use Output policies");
|
|
129
|
+
for (const policy of [output, error]) if (policy.kind === "text" || policy.kind === "bytes") captureLimit(policy.limit);
|
|
130
|
+
else if (policy.kind !== "inherit" && policy.kind !== "discard") throw new TypeError("Unknown output policy");
|
|
131
|
+
if (typeof input !== "string" && !(input instanceof Uint8Array) && (!input || input[inputBrand] !== true)) throw new TypeError("input must be a string, Uint8Array or Input policy");
|
|
132
|
+
if (typeof check !== "boolean") throw new TypeError("check must be a boolean");
|
|
133
|
+
if (signal !== void 0 && !(signal instanceof AbortSignal)) throw new TypeError("signal must be an AbortSignal");
|
|
134
|
+
if (timeoutMs !== void 0) duration(timeoutMs, "timeoutMs", 1);
|
|
135
|
+
duration(gracePeriodMs, "gracePeriodMs", 0);
|
|
136
|
+
duration(killTimeoutMs, "killTimeoutMs", 1);
|
|
137
|
+
return {
|
|
138
|
+
cwd,
|
|
139
|
+
environment: env,
|
|
140
|
+
input,
|
|
141
|
+
output,
|
|
142
|
+
error,
|
|
143
|
+
check,
|
|
144
|
+
signal,
|
|
145
|
+
timeoutMs,
|
|
146
|
+
gracePeriodMs,
|
|
147
|
+
killTimeoutMs
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
/** Internal helper; parameter permits testing Windows key behavior on other hosts. */
|
|
151
|
+
function childEnvironment(policy, platform = process.platform) {
|
|
152
|
+
if (policy === void 0) return void 0;
|
|
153
|
+
const env = Object.assign(Object.create(null), policy.kind === "inherit" ? process.env : void 0);
|
|
154
|
+
if (platform === "win32") {
|
|
155
|
+
const keys = /* @__PURE__ */ new Map();
|
|
156
|
+
for (const key of Object.keys(env)) {
|
|
157
|
+
const normalized = key.toUpperCase();
|
|
158
|
+
const previous = keys.get(normalized);
|
|
159
|
+
if (previous !== void 0) delete env[previous];
|
|
160
|
+
keys.set(normalized, key);
|
|
161
|
+
}
|
|
162
|
+
for (const [key, value] of Object.entries(policy.values)) {
|
|
163
|
+
const normalized = key.toUpperCase();
|
|
164
|
+
const previous = keys.get(normalized);
|
|
165
|
+
if (previous !== void 0) delete env[previous];
|
|
166
|
+
keys.set(normalized, key);
|
|
167
|
+
if (value !== void 0) env[key] = value;
|
|
168
|
+
}
|
|
169
|
+
} else for (const [key, value] of Object.entries(policy.values)) if (value === void 0) delete env[key];
|
|
170
|
+
else env[key] = value;
|
|
171
|
+
return env;
|
|
172
|
+
}
|
|
173
|
+
//#endregion
|
|
174
|
+
export { Command, Environment, Input, Output, childEnvironment, settings };
|
|
175
|
+
|
|
176
|
+
//# sourceMappingURL=values.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"values.js","names":[],"sources":["../src/values.twill"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,75 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@swiftuijs/twill-shell",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.3.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
|
+
"vite": "^8.3.2",
|
|
41
|
+
"@swiftuijs/twill": "0.3.0",
|
|
42
|
+
"@swiftuijs/twill-export": "0.3.0",
|
|
43
|
+
"@swiftuijs/twill-formatter": "0.3.0"
|
|
44
|
+
},
|
|
45
|
+
"author": {
|
|
46
|
+
"name": "forth.ink",
|
|
47
|
+
"url": "https://forth.ink"
|
|
48
|
+
},
|
|
49
|
+
"keywords": [
|
|
50
|
+
"twill",
|
|
51
|
+
"shell",
|
|
52
|
+
"subprocess",
|
|
53
|
+
"scripting",
|
|
54
|
+
"swift",
|
|
55
|
+
"typescript",
|
|
56
|
+
"node"
|
|
57
|
+
],
|
|
58
|
+
"peerDependencies": {
|
|
59
|
+
"@types/node": "^20.0.0 || ^22.0.0 || ^24.0.0 || ^26.0.0"
|
|
60
|
+
},
|
|
61
|
+
"peerDependenciesMeta": {
|
|
62
|
+
"@types/node": {
|
|
63
|
+
"optional": true
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
"scripts": {
|
|
67
|
+
"build": "vite build && twill declarations -p tsconfig.build.json -o dist && node scripts/compact-maps.mjs",
|
|
68
|
+
"typecheck": "twill check -p tsconfig.json",
|
|
69
|
+
"test:unit": "vitest run",
|
|
70
|
+
"test:coverage": "vitest run --coverage",
|
|
71
|
+
"test:package": "node tests/consumer.mjs",
|
|
72
|
+
"benchmark": "node benchmarks/run.mjs",
|
|
73
|
+
"benchmark:complete": "node benchmarks/complete.mjs"
|
|
74
|
+
}
|
|
6
75
|
}
|