@procedures/shell 0.34.0 → 0.35.1
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/CHANGELOG.md +31 -0
- package/README.md +23 -14
- package/dist/.tsbuildinfo +1 -1
- package/dist/cli/argv.d.ts +29 -0
- package/dist/cli/argv.d.ts.map +1 -0
- package/dist/cli/argv.js +71 -0
- package/dist/cli/argv.js.map +1 -0
- package/dist/cli/index.d.ts +17 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +17 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/output.d.ts +38 -0
- package/dist/cli/output.d.ts.map +1 -0
- package/dist/cli/output.js +27 -0
- package/dist/cli/output.js.map +1 -0
- package/dist/cli/program.d.ts +29 -0
- package/dist/cli/program.d.ts.map +1 -0
- package/dist/cli/program.js +41 -0
- package/dist/cli/program.js.map +1 -0
- package/dist/cli/tool.d.ts +75 -0
- package/dist/cli/tool.d.ts.map +1 -0
- package/dist/cli/tool.js +104 -0
- package/dist/cli/tool.js.map +1 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/module.d.ts +2 -2
- package/dist/module.d.ts.map +1 -1
- package/dist/module.js +8 -9
- package/dist/module.js.map +1 -1
- package/dist/testing.d.ts +67 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +114 -0
- package/dist/testing.js.map +1 -0
- package/package.json +11 -3
- package/src/cli/argv.ts +71 -0
- package/src/cli/index.ts +32 -0
- package/src/cli/output.ts +59 -0
- package/src/cli/program.ts +47 -0
- package/src/cli/tool.ts +164 -0
- package/src/index.ts +6 -1
- package/src/module.ts +9 -9
- package/src/testing.ts +163 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The argument helpers of a CLI tool (dedupe review F2). A wrapper starts its program with argv,
|
|
3
|
+
* never through a shell, so these helpers only keep a value from becoming an option.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* This function gives a value that the program reads as an argument (a package, a branch, a
|
|
7
|
+
* path). It throws when the value starts with "-", because the program then reads it as an option.
|
|
8
|
+
*/
|
|
9
|
+
export declare function cliArg(name: string, value: string): string;
|
|
10
|
+
/** The value of a named argument of `buildArgv()`. */
|
|
11
|
+
export type ArgValue = string | number | boolean | readonly string[];
|
|
12
|
+
/** A flag name: lowercase letters, digits and hyphens. */
|
|
13
|
+
export declare const FLAG_NAME: RegExp;
|
|
14
|
+
/**
|
|
15
|
+
* This function gives the argv: the path, then each named argument, then `--` and the positional
|
|
16
|
+
* arguments. `true` gives `--key`, `false` gives nothing, a list gives `--key=value` for each
|
|
17
|
+
* value, and another value gives `--key=value`.
|
|
18
|
+
*/
|
|
19
|
+
export declare function buildArgv(input: {
|
|
20
|
+
readonly path: readonly string[];
|
|
21
|
+
readonly args?: Readonly<Record<string, ArgValue>> | undefined;
|
|
22
|
+
readonly positional?: readonly string[] | undefined;
|
|
23
|
+
readonly flags?: readonly string[] | undefined;
|
|
24
|
+
}): string[];
|
|
25
|
+
/** This function reads one JSON document from a standard output. Output that is not JSON gives undefined. */
|
|
26
|
+
export declare function parseJsonDocument(stdout: string): unknown;
|
|
27
|
+
/** This function reads JSON output: one document, or one document on each line (NDJSON). */
|
|
28
|
+
export declare function parseJsonOutput(stdout: string): unknown;
|
|
29
|
+
//# sourceMappingURL=argv.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"argv.d.ts","sourceRoot":"","sources":["../../src/cli/argv.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;GAGG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAK1D;AAED,sDAAsD;AACtD,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,MAAM,EAAE,CAAC;AAErE,0DAA0D;AAC1D,eAAO,MAAM,SAAS,EAAE,MAA4B,CAAC;AAErD;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE;IAC/B,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,QAAQ,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,GAAG,SAAS,CAAC;IAC/D,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;IACpD,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;CAChD,GAAG,MAAM,EAAE,CAWX;AAED,6GAA6G;AAC7G,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAQzD;AAED,4FAA4F;AAC5F,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAavD"}
|
package/dist/cli/argv.js
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The argument helpers of a CLI tool (dedupe review F2). A wrapper starts its program with argv,
|
|
3
|
+
* never through a shell, so these helpers only keep a value from becoming an option.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* This function gives a value that the program reads as an argument (a package, a branch, a
|
|
7
|
+
* path). It throws when the value starts with "-", because the program then reads it as an option.
|
|
8
|
+
*/
|
|
9
|
+
export function cliArg(name, value) {
|
|
10
|
+
if (value.startsWith("-")) {
|
|
11
|
+
throw new Error(`Invalid ${name} (starts with "-"): ${value}`);
|
|
12
|
+
}
|
|
13
|
+
return value;
|
|
14
|
+
}
|
|
15
|
+
/** A flag name: lowercase letters, digits and hyphens. */
|
|
16
|
+
export const FLAG_NAME = /^[a-z][a-z0-9-]*$/;
|
|
17
|
+
/**
|
|
18
|
+
* This function gives the argv: the path, then each named argument, then `--` and the positional
|
|
19
|
+
* arguments. `true` gives `--key`, `false` gives nothing, a list gives `--key=value` for each
|
|
20
|
+
* value, and another value gives `--key=value`.
|
|
21
|
+
*/
|
|
22
|
+
export function buildArgv(input) {
|
|
23
|
+
const argv = [...input.path, ...(input.flags ?? [])];
|
|
24
|
+
for (const [key, value] of Object.entries(input.args ?? {})) {
|
|
25
|
+
if (!FLAG_NAME.test(key))
|
|
26
|
+
throw new Error(`The argument name "${key}" is not a flag name (lowercase letters, digits, hyphens)`);
|
|
27
|
+
if (value === false)
|
|
28
|
+
continue;
|
|
29
|
+
if (value === true)
|
|
30
|
+
argv.push(`--${key}`);
|
|
31
|
+
else if (Array.isArray(value))
|
|
32
|
+
for (const item of value)
|
|
33
|
+
argv.push(`--${key}=${item}`);
|
|
34
|
+
else
|
|
35
|
+
argv.push(`--${key}=${String(value)}`);
|
|
36
|
+
}
|
|
37
|
+
if (input.positional && input.positional.length > 0)
|
|
38
|
+
argv.push("--", ...input.positional);
|
|
39
|
+
return argv;
|
|
40
|
+
}
|
|
41
|
+
/** This function reads one JSON document from a standard output. Output that is not JSON gives undefined. */
|
|
42
|
+
export function parseJsonDocument(stdout) {
|
|
43
|
+
const text = stdout.trim();
|
|
44
|
+
if (text === "")
|
|
45
|
+
return undefined;
|
|
46
|
+
try {
|
|
47
|
+
return JSON.parse(text);
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return undefined;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/** This function reads JSON output: one document, or one document on each line (NDJSON). */
|
|
54
|
+
export function parseJsonOutput(stdout) {
|
|
55
|
+
const text = stdout.trim();
|
|
56
|
+
if (text.length === 0)
|
|
57
|
+
return undefined;
|
|
58
|
+
try {
|
|
59
|
+
return JSON.parse(text);
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
const lines = text.split(/\r?\n/).filter((line) => line.trim().length > 0);
|
|
63
|
+
try {
|
|
64
|
+
return lines.map((line) => JSON.parse(line));
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
return undefined;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=argv.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"argv.js","sourceRoot":"","sources":["../../src/cli/argv.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;GAGG;AACH,MAAM,UAAU,MAAM,CAAC,IAAY,EAAE,KAAa;IAChD,IAAI,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,WAAW,IAAI,uBAAuB,KAAK,EAAE,CAAC,CAAC;IACjE,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAKD,0DAA0D;AAC1D,MAAM,CAAC,MAAM,SAAS,GAAW,mBAAmB,CAAC;AAErD;;;;GAIG;AACH,MAAM,UAAU,SAAS,CAAC,KAKzB;IACC,MAAM,IAAI,GAAG,CAAC,GAAG,KAAK,CAAC,IAAI,EAAE,GAAG,CAAC,KAAK,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC;IACrD,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,IAAI,EAAE,CAAC,EAAE,CAAC;QAC5D,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,sBAAsB,GAAG,2DAA2D,CAAC,CAAC;QAChI,IAAI,KAAK,KAAK,KAAK;YAAE,SAAS;QAC9B,IAAI,KAAK,KAAK,IAAI;YAAE,IAAI,CAAC,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC,CAAC;aACrC,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;YAAE,KAAK,MAAM,IAAI,IAAI,KAAK;gBAAE,IAAI,CAAC,IAAI,CAAC,KAAK,GAAG,IAAI,IAAI,EAAE,CAAC,CAAC;;YAClF,IAAI,CAAC,IAAI,CAAC,KAAK,GAAG,IAAI,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAC9C,CAAC;IACD,IAAI,KAAK,CAAC,UAAU,IAAI,KAAK,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC;QAAE,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,KAAK,CAAC,UAAU,CAAC,CAAC;IAC1F,OAAO,IAAI,CAAC;AACd,CAAC;AAED,6GAA6G;AAC7G,MAAM,UAAU,iBAAiB,CAAC,MAAc;IAC9C,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC;IAC3B,IAAI,IAAI,KAAK,EAAE;QAAE,OAAO,SAAS,CAAC;IAClC,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED,4FAA4F;AAC5F,MAAM,UAAU,eAAe,CAAC,MAAc;IAC5C,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC;IAC3B,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IACxC,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAC3E,IAAI,CAAC;YACH,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAY,CAAC,CAAC;QAC1D,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,SAAS,CAAC;QACnB,CAAC;IACH,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@procedures/shell/cli`: the shared parts of the CLI wrapper packages (dedupe review F2).
|
|
3
|
+
*
|
|
4
|
+
* - `defineCliTool()` gives the runner of a program: `run`, `runJson`, `output`, `json` and the
|
|
5
|
+
* argument guard. Each command goes as argv to the `shell.run` procedure, never as a shell string.
|
|
6
|
+
* - `cliArg()`, `buildArgv()`, `parseJsonDocument()` and `parseJsonOutput()` build the argv and
|
|
7
|
+
* read the output.
|
|
8
|
+
* - `CliToolOutput` and `cliToolOutputSchema()` are the shared result and its schema.
|
|
9
|
+
* - `nodeScript()`, `execPathProgram()` and `findInPath()` find the program without a shell.
|
|
10
|
+
*
|
|
11
|
+
* This entry point has no side effects: it registers no procedures.
|
|
12
|
+
*/
|
|
13
|
+
export { cliArg, buildArgv, parseJsonDocument, parseJsonOutput, FLAG_NAME, type ArgValue } from "./argv.js";
|
|
14
|
+
export { cliToolOutputFields, cliToolOutputSchema, cliToolJsonOutputSchema, type CliToolOutput, type CliToolJsonOutput, type CliToolOutputFields, } from "./output.js";
|
|
15
|
+
export { nodeScript, execPathProgram, findInPath, type CliProgram } from "./program.js";
|
|
16
|
+
export { defineCliTool, CliToolError, type CliTool, type CliToolOptions, type CliToolContext, type CliRunOptions, type CliShellInput, } from "./tool.js";
|
|
17
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,iBAAiB,EAAE,eAAe,EAAE,SAAS,EAAE,KAAK,QAAQ,EAAE,MAAM,WAAW,CAAC;AAC5G,OAAO,EACL,mBAAmB,EACnB,mBAAmB,EACnB,uBAAuB,EACvB,KAAK,aAAa,EAClB,KAAK,iBAAiB,EACtB,KAAK,mBAAmB,GACzB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,UAAU,EAAE,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AACxF,OAAO,EACL,aAAa,EACb,YAAY,EACZ,KAAK,OAAO,EACZ,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,aAAa,GACnB,MAAM,WAAW,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@procedures/shell/cli`: the shared parts of the CLI wrapper packages (dedupe review F2).
|
|
3
|
+
*
|
|
4
|
+
* - `defineCliTool()` gives the runner of a program: `run`, `runJson`, `output`, `json` and the
|
|
5
|
+
* argument guard. Each command goes as argv to the `shell.run` procedure, never as a shell string.
|
|
6
|
+
* - `cliArg()`, `buildArgv()`, `parseJsonDocument()` and `parseJsonOutput()` build the argv and
|
|
7
|
+
* read the output.
|
|
8
|
+
* - `CliToolOutput` and `cliToolOutputSchema()` are the shared result and its schema.
|
|
9
|
+
* - `nodeScript()`, `execPathProgram()` and `findInPath()` find the program without a shell.
|
|
10
|
+
*
|
|
11
|
+
* This entry point has no side effects: it registers no procedures.
|
|
12
|
+
*/
|
|
13
|
+
export { cliArg, buildArgv, parseJsonDocument, parseJsonOutput, FLAG_NAME } from "./argv.js";
|
|
14
|
+
export { cliToolOutputFields, cliToolOutputSchema, cliToolJsonOutputSchema, } from "./output.js";
|
|
15
|
+
export { nodeScript, execPathProgram, findInPath } from "./program.js";
|
|
16
|
+
export { defineCliTool, CliToolError, } from "./tool.js";
|
|
17
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,iBAAiB,EAAE,eAAe,EAAE,SAAS,EAAiB,MAAM,WAAW,CAAC;AAC5G,OAAO,EACL,mBAAmB,EACnB,mBAAmB,EACnB,uBAAuB,GAIxB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,UAAU,EAAmB,MAAM,cAAc,CAAC;AACxF,OAAO,EACL,aAAa,EACb,YAAY,GAMb,MAAM,WAAW,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The shared output of a CLI tool procedure: the result of `shell.run` with `success` and the
|
|
3
|
+
* time of the call. The schemas are loose, so a field that a schema does not name stays.
|
|
4
|
+
*/
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
/** The result of one command of a CLI tool. */
|
|
7
|
+
export interface CliToolOutput {
|
|
8
|
+
/** The exit code of the program (0 is success) */
|
|
9
|
+
exitCode: number;
|
|
10
|
+
/** The standard output */
|
|
11
|
+
stdout: string;
|
|
12
|
+
/** The standard error, or the error message when the program did not start */
|
|
13
|
+
stderr: string;
|
|
14
|
+
/** True when the exit code is 0 */
|
|
15
|
+
success: boolean;
|
|
16
|
+
/** The time of the command, in milliseconds */
|
|
17
|
+
duration: number;
|
|
18
|
+
}
|
|
19
|
+
/** The result of a command that writes JSON: `data` is its parsed standard output. */
|
|
20
|
+
export interface CliToolJsonOutput extends CliToolOutput {
|
|
21
|
+
/** The parsed JSON of the standard output. It is absent when the output is not JSON. */
|
|
22
|
+
data?: unknown;
|
|
23
|
+
}
|
|
24
|
+
/** The fields of the output schema of a tool, as a shape for `z.looseObject()`. */
|
|
25
|
+
export interface CliToolOutputFields {
|
|
26
|
+
exitCode: z.ZodNumber;
|
|
27
|
+
stdout: z.ZodString;
|
|
28
|
+
stderr: z.ZodString;
|
|
29
|
+
success: z.ZodBoolean;
|
|
30
|
+
duration: z.ZodNumber;
|
|
31
|
+
}
|
|
32
|
+
/** This function gives the fields of the output schema, with descriptions that name the program. */
|
|
33
|
+
export declare function cliToolOutputFields(program: string): CliToolOutputFields;
|
|
34
|
+
/** This function gives the loose output schema of a command of the program. */
|
|
35
|
+
export declare function cliToolOutputSchema(program: string): z.ZodType<CliToolOutput>;
|
|
36
|
+
/** This function gives the loose output schema of a command of the program that writes JSON. */
|
|
37
|
+
export declare function cliToolJsonOutputSchema(program: string): z.ZodType<CliToolJsonOutput>;
|
|
38
|
+
//# sourceMappingURL=output.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../../src/cli/output.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,+CAA+C;AAC/C,MAAM,WAAW,aAAa;IAC5B,kDAAkD;IAClD,QAAQ,EAAE,MAAM,CAAC;IACjB,0BAA0B;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,8EAA8E;IAC9E,MAAM,EAAE,MAAM,CAAC;IACf,mCAAmC;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,+CAA+C;IAC/C,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,sFAAsF;AACtF,MAAM,WAAW,iBAAkB,SAAQ,aAAa;IACtD,wFAAwF;IACxF,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,mFAAmF;AACnF,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,CAAC,CAAC,SAAS,CAAC;IACtB,MAAM,EAAE,CAAC,CAAC,SAAS,CAAC;IACpB,MAAM,EAAE,CAAC,CAAC,SAAS,CAAC;IACpB,OAAO,EAAE,CAAC,CAAC,UAAU,CAAC;IACtB,QAAQ,EAAE,CAAC,CAAC,SAAS,CAAC;CACvB;AAED,oGAAoG;AACpG,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,mBAAmB,CAQxE;AAED,+EAA+E;AAC/E,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,CAE7E;AAED,gGAAgG;AAChG,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,CAAC,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAKrF"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The shared output of a CLI tool procedure: the result of `shell.run` with `success` and the
|
|
3
|
+
* time of the call. The schemas are loose, so a field that a schema does not name stays.
|
|
4
|
+
*/
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
/** This function gives the fields of the output schema, with descriptions that name the program. */
|
|
7
|
+
export function cliToolOutputFields(program) {
|
|
8
|
+
return {
|
|
9
|
+
exitCode: z.number().describe(`The exit code of ${program} (0 is success)`),
|
|
10
|
+
stdout: z.string().describe(`The standard output of ${program}`),
|
|
11
|
+
stderr: z.string().describe(`The standard error of ${program}, or the error message when ${program} did not start`),
|
|
12
|
+
success: z.boolean().describe("True when the exit code is 0"),
|
|
13
|
+
duration: z.number().describe("The time of the command, in milliseconds"),
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
/** This function gives the loose output schema of a command of the program. */
|
|
17
|
+
export function cliToolOutputSchema(program) {
|
|
18
|
+
return z.looseObject(cliToolOutputFields(program));
|
|
19
|
+
}
|
|
20
|
+
/** This function gives the loose output schema of a command of the program that writes JSON. */
|
|
21
|
+
export function cliToolJsonOutputSchema(program) {
|
|
22
|
+
return z.looseObject({
|
|
23
|
+
...cliToolOutputFields(program),
|
|
24
|
+
data: z.unknown().optional().describe("The parsed JSON of the standard output, when it is JSON"),
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=output.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"output.js","sourceRoot":"","sources":["../../src/cli/output.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AA+BxB,oGAAoG;AACpG,MAAM,UAAU,mBAAmB,CAAC,OAAe;IACjD,OAAO;QACL,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,oBAAoB,OAAO,iBAAiB,CAAC;QAC3E,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,0BAA0B,OAAO,EAAE,CAAC;QAChE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,yBAAyB,OAAO,+BAA+B,OAAO,gBAAgB,CAAC;QACnH,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,CAAC,8BAA8B,CAAC;QAC7D,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,0CAA0C,CAAC;KAC1E,CAAC;AACJ,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,mBAAmB,CAAC,OAAe;IACjD,OAAO,CAAC,CAAC,WAAW,CAAC,mBAAmB,CAAC,OAAO,CAAC,CAAC,CAAC;AACrD,CAAC;AAED,gGAAgG;AAChG,MAAM,UAAU,uBAAuB,CAAC,OAAe;IACrD,OAAO,CAAC,CAAC,WAAW,CAAC;QACnB,GAAG,mBAAmB,CAAC,OAAO,CAAC;QAC/B,IAAI,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,yDAAyD,CAAC;KACjG,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The lookup of the program of a CLI tool. On Windows, a package manager is often a `.cmd` file,
|
|
3
|
+
* and Node runs a `.cmd` file only through a shell. So a tool finds the real program: an
|
|
4
|
+
* executable, or the script that the `.cmd` file starts, run with Node.
|
|
5
|
+
*/
|
|
6
|
+
/** The program and the first arguments that start a CLI tool without a shell. */
|
|
7
|
+
export interface CliProgram {
|
|
8
|
+
/** The program that `shell.run` starts */
|
|
9
|
+
command: string;
|
|
10
|
+
/** The arguments before the arguments of the command (for example the script of the tool) */
|
|
11
|
+
prefix: string[];
|
|
12
|
+
}
|
|
13
|
+
/** This function gives the program that runs a JavaScript script with the Node of this process. */
|
|
14
|
+
export declare function nodeScript(script: string): CliProgram;
|
|
15
|
+
/**
|
|
16
|
+
* This function gives the program of `npm_execpath`, when the package manager that runs this
|
|
17
|
+
* process matches. A `script` match runs with Node, and an `executable` match runs directly.
|
|
18
|
+
* The file must exist.
|
|
19
|
+
*/
|
|
20
|
+
export declare function execPathProgram(match: {
|
|
21
|
+
script?: RegExp | undefined;
|
|
22
|
+
executable?: RegExp | undefined;
|
|
23
|
+
}): CliProgram | undefined;
|
|
24
|
+
/**
|
|
25
|
+
* This function gives the first program that `find` gives for a folder of PATH, in the order of
|
|
26
|
+
* PATH. It skips empty entries, and it gives undefined when no folder has the program.
|
|
27
|
+
*/
|
|
28
|
+
export declare function findInPath(find: (dir: string) => CliProgram | undefined, path?: string): CliProgram | undefined;
|
|
29
|
+
//# sourceMappingURL=program.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"program.d.ts","sourceRoot":"","sources":["../../src/cli/program.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,iFAAiF;AACjF,MAAM,WAAW,UAAU;IACzB,0CAA0C;IAC1C,OAAO,EAAE,MAAM,CAAC;IAChB,6FAA6F;IAC7F,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,mGAAmG;AACnG,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,CAErD;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,GAAG,UAAU,GAAG,SAAS,CAM/H;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,UAAU,GAAG,SAAS,EAAE,IAAI,GAAE,MAAkC,GAAG,UAAU,GAAG,SAAS,CAO1I"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The lookup of the program of a CLI tool. On Windows, a package manager is often a `.cmd` file,
|
|
3
|
+
* and Node runs a `.cmd` file only through a shell. So a tool finds the real program: an
|
|
4
|
+
* executable, or the script that the `.cmd` file starts, run with Node.
|
|
5
|
+
*/
|
|
6
|
+
import { existsSync } from "node:fs";
|
|
7
|
+
import { delimiter } from "node:path";
|
|
8
|
+
/** This function gives the program that runs a JavaScript script with the Node of this process. */
|
|
9
|
+
export function nodeScript(script) {
|
|
10
|
+
return { command: process.execPath, prefix: [script] };
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* This function gives the program of `npm_execpath`, when the package manager that runs this
|
|
14
|
+
* process matches. A `script` match runs with Node, and an `executable` match runs directly.
|
|
15
|
+
* The file must exist.
|
|
16
|
+
*/
|
|
17
|
+
export function execPathProgram(match) {
|
|
18
|
+
const execPath = process.env["npm_execpath"];
|
|
19
|
+
if (!execPath || !existsSync(execPath))
|
|
20
|
+
return undefined;
|
|
21
|
+
if (match.script?.test(execPath))
|
|
22
|
+
return nodeScript(execPath);
|
|
23
|
+
if (match.executable?.test(execPath))
|
|
24
|
+
return { command: execPath, prefix: [] };
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* This function gives the first program that `find` gives for a folder of PATH, in the order of
|
|
29
|
+
* PATH. It skips empty entries, and it gives undefined when no folder has the program.
|
|
30
|
+
*/
|
|
31
|
+
export function findInPath(find, path = process.env["PATH"] ?? "") {
|
|
32
|
+
for (const dir of path.split(delimiter)) {
|
|
33
|
+
if (!dir)
|
|
34
|
+
continue;
|
|
35
|
+
const program = find(dir);
|
|
36
|
+
if (program !== undefined)
|
|
37
|
+
return program;
|
|
38
|
+
}
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=program.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"program.js","sourceRoot":"","sources":["../../src/cli/program.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAUtC,mGAAmG;AACnG,MAAM,UAAU,UAAU,CAAC,MAAc;IACvC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC;AACzD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,KAAuE;IACrG,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAC7C,IAAI,CAAC,QAAQ,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;QAAE,OAAO,SAAS,CAAC;IACzD,IAAI,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC;QAAE,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC;IAC9D,IAAI,KAAK,CAAC,UAAU,EAAE,IAAI,CAAC,QAAQ,CAAC;QAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;IAC/E,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,IAA6C,EAAE,IAAI,GAAW,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE;IAChH,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC;QACxC,IAAI,CAAC,GAAG;YAAE,SAAS;QACnB,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC;QAC1B,IAAI,OAAO,KAAK,SAAS;YAAE,OAAO,OAAO,CAAC;IAC5C,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `defineCliTool()`: the one runner of the CLI wrapper packages (dedupe review F2).
|
|
3
|
+
*
|
|
4
|
+
* Each command goes as an argument list to the `shell.run` procedure, through `ctx.client`. No
|
|
5
|
+
* shell runs, so a value cannot start a second command. The nested call keeps the rules of the
|
|
6
|
+
* host: the declared calls, the effects, the root of the files and the signal of the call.
|
|
7
|
+
* `packages/documentation/SERVER-LAYERS.md` gives the reason for this run path.
|
|
8
|
+
*/
|
|
9
|
+
import type { ProcedureContext } from "@procedures/client";
|
|
10
|
+
import type { CliToolJsonOutput, CliToolOutput } from "./output.js";
|
|
11
|
+
import type { CliProgram } from "./program.js";
|
|
12
|
+
/** The part of the procedure context that a CLI tool uses: the client of the nested call. */
|
|
13
|
+
export type CliToolContext = Pick<ProcedureContext, "client">;
|
|
14
|
+
/** The options of one command of a CLI tool. */
|
|
15
|
+
export interface CliRunOptions {
|
|
16
|
+
/** The working folder of the program */
|
|
17
|
+
cwd?: string | undefined;
|
|
18
|
+
/** The time limit, in milliseconds. At the limit, `shell.run` kills the process tree. */
|
|
19
|
+
timeout?: number | undefined;
|
|
20
|
+
/** The environment variables that the program gets in addition to the environment of the host */
|
|
21
|
+
env?: Record<string, string> | undefined;
|
|
22
|
+
}
|
|
23
|
+
/** The input of a `shell.run` call that a CLI tool makes. */
|
|
24
|
+
export interface CliShellInput {
|
|
25
|
+
command: string;
|
|
26
|
+
args: string[];
|
|
27
|
+
cwd?: string;
|
|
28
|
+
timeout?: number;
|
|
29
|
+
env?: Record<string, string>;
|
|
30
|
+
}
|
|
31
|
+
/** A failed command of a CLI tool: its exit code and its standard error. */
|
|
32
|
+
export declare class CliToolError extends Error {
|
|
33
|
+
readonly exitCode: number;
|
|
34
|
+
readonly stderr: string;
|
|
35
|
+
readonly name: string;
|
|
36
|
+
constructor(message: string, exitCode: number, stderr: string);
|
|
37
|
+
}
|
|
38
|
+
/** The definition of a CLI tool. */
|
|
39
|
+
export interface CliToolOptions {
|
|
40
|
+
/** The name of the program in the error messages. Without `resolve`, it is also the program. */
|
|
41
|
+
readonly name: string;
|
|
42
|
+
/**
|
|
43
|
+
* This function gives the program at each command: a command name, or a program with the first
|
|
44
|
+
* arguments. A throw is the error of the command (the program was not found).
|
|
45
|
+
*/
|
|
46
|
+
readonly resolve?: (() => CliProgram | string) | undefined;
|
|
47
|
+
/** This function makes the error of a failed command for `output()` and `json()` (default: `CliToolError`). */
|
|
48
|
+
readonly error?: ((message: string, exitCode: number, stderr: string) => Error) | undefined;
|
|
49
|
+
}
|
|
50
|
+
/** The runner of a CLI tool that `defineCliTool()` gives. */
|
|
51
|
+
export interface CliTool {
|
|
52
|
+
/** The name of the program */
|
|
53
|
+
readonly name: string;
|
|
54
|
+
/** This function gives a value that the program reads as an argument. It throws for a value that starts with "-". */
|
|
55
|
+
arg(name: string, value: string): string;
|
|
56
|
+
/** This function gives the `shell.run` input of a command. It throws when the program is not found. */
|
|
57
|
+
shellInput(args: readonly string[], options?: CliRunOptions): CliShellInput;
|
|
58
|
+
/** This function runs a command and gives its result. It throws when the program is not found or `shell.run` fails. */
|
|
59
|
+
call(args: readonly string[], options: CliRunOptions, ctx: CliToolContext): Promise<CliToolOutput>;
|
|
60
|
+
/** This function runs a command and gives its result. It does not throw: an error gives exit code 1 and its message as `stderr`. */
|
|
61
|
+
run(args: readonly string[], options: CliRunOptions, ctx: CliToolContext): Promise<CliToolOutput>;
|
|
62
|
+
/** This function runs a command that writes JSON, and gives `data` when `parse` reads the output. It does not throw. */
|
|
63
|
+
runJson(args: readonly string[], options: CliRunOptions, ctx: CliToolContext, parse?: (stdout: string) => unknown): Promise<CliToolJsonOutput>;
|
|
64
|
+
/** This function runs a command and gives its standard output. It throws the tool error for an exit code other than 0. */
|
|
65
|
+
output(args: readonly string[], options: CliRunOptions, ctx: CliToolContext): Promise<string>;
|
|
66
|
+
/** This function runs a command that writes JSON and gives the parsed value. It throws the tool error for a failure or for output that is not JSON. */
|
|
67
|
+
json<T>(args: readonly string[], options: CliRunOptions, ctx: CliToolContext): Promise<T>;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* This function defines the runner of a CLI tool. The wrapper package keeps its procedures, its
|
|
71
|
+
* schemas and its own argument rules. The runner gives the run, the JSON, the argument guard
|
|
72
|
+
* and the shared result.
|
|
73
|
+
*/
|
|
74
|
+
export declare function defineCliTool(options: CliToolOptions): CliTool;
|
|
75
|
+
//# sourceMappingURL=tool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool.d.ts","sourceRoot":"","sources":["../../src/cli/tool.ts"],"names":[],"mappings":"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"}
|
package/dist/cli/tool.js
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `defineCliTool()`: the one runner of the CLI wrapper packages (dedupe review F2).
|
|
3
|
+
*
|
|
4
|
+
* Each command goes as an argument list to the `shell.run` procedure, through `ctx.client`. No
|
|
5
|
+
* shell runs, so a value cannot start a second command. The nested call keeps the rules of the
|
|
6
|
+
* host: the declared calls, the effects, the root of the files and the signal of the call.
|
|
7
|
+
* `packages/documentation/SERVER-LAYERS.md` gives the reason for this run path.
|
|
8
|
+
*/
|
|
9
|
+
import { cliArg, parseJsonDocument } from "./argv.js";
|
|
10
|
+
/** A failed command of a CLI tool: its exit code and its standard error. */
|
|
11
|
+
export class CliToolError extends Error {
|
|
12
|
+
exitCode;
|
|
13
|
+
stderr;
|
|
14
|
+
name = "CliToolError";
|
|
15
|
+
constructor(message, exitCode, stderr) {
|
|
16
|
+
super(message);
|
|
17
|
+
this.exitCode = exitCode;
|
|
18
|
+
this.stderr = stderr;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
/** The first two words of a command, for an error message. */
|
|
22
|
+
function commandWords(name, args) {
|
|
23
|
+
return `${name} ${args[0] ?? ""} ${args[1] ?? ""}`;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* This function defines the runner of a CLI tool. The wrapper package keeps its procedures, its
|
|
27
|
+
* schemas and its own argument rules. The runner gives the run, the JSON, the argument guard
|
|
28
|
+
* and the shared result.
|
|
29
|
+
*/
|
|
30
|
+
export function defineCliTool(options) {
|
|
31
|
+
const { name } = options;
|
|
32
|
+
const makeError = options.error ?? ((message, exitCode, stderr) => new CliToolError(message, exitCode, stderr));
|
|
33
|
+
const shellInput = (args, run = {}) => {
|
|
34
|
+
const resolved = options.resolve?.() ?? name;
|
|
35
|
+
const program = typeof resolved === "string" ? { command: resolved, prefix: [] } : resolved;
|
|
36
|
+
const input = { command: program.command, args: [...program.prefix, ...args] };
|
|
37
|
+
if (run.cwd !== undefined)
|
|
38
|
+
input.cwd = run.cwd;
|
|
39
|
+
if (run.timeout !== undefined)
|
|
40
|
+
input.timeout = run.timeout;
|
|
41
|
+
if (run.env !== undefined)
|
|
42
|
+
input.env = run.env;
|
|
43
|
+
return input;
|
|
44
|
+
};
|
|
45
|
+
const call = async (args, run, ctx) => {
|
|
46
|
+
const startTime = Date.now();
|
|
47
|
+
const result = await ctx.client.call(["shell", "run"], shellInput(args, run));
|
|
48
|
+
return {
|
|
49
|
+
exitCode: result.exitCode,
|
|
50
|
+
stdout: result.stdout,
|
|
51
|
+
stderr: result.stderr,
|
|
52
|
+
success: result.exitCode === 0,
|
|
53
|
+
duration: Date.now() - startTime,
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
const runCommand = async (args, run, ctx) => {
|
|
57
|
+
const startTime = Date.now();
|
|
58
|
+
try {
|
|
59
|
+
return await call(args, run, ctx);
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
return {
|
|
63
|
+
exitCode: 1,
|
|
64
|
+
stdout: "",
|
|
65
|
+
stderr: error instanceof Error ? error.message : String(error),
|
|
66
|
+
success: false,
|
|
67
|
+
duration: Date.now() - startTime,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
const output = async (args, run, ctx) => {
|
|
72
|
+
const result = await call(args, run, ctx);
|
|
73
|
+
if (result.exitCode !== 0) {
|
|
74
|
+
const text = result.stderr.trim() || result.stdout.trim();
|
|
75
|
+
throw makeError(`${commandWords(name, args)} failed (exit ${result.exitCode}): ${text}`.trim(), result.exitCode, result.stderr);
|
|
76
|
+
}
|
|
77
|
+
return result.stdout;
|
|
78
|
+
};
|
|
79
|
+
return {
|
|
80
|
+
name,
|
|
81
|
+
arg: cliArg,
|
|
82
|
+
shellInput,
|
|
83
|
+
call,
|
|
84
|
+
run: runCommand,
|
|
85
|
+
async runJson(args, run, ctx, parse = parseJsonDocument) {
|
|
86
|
+
const result = await runCommand(args, run, ctx);
|
|
87
|
+
const data = parse(result.stdout);
|
|
88
|
+
if (data !== undefined)
|
|
89
|
+
result.data = data;
|
|
90
|
+
return result;
|
|
91
|
+
},
|
|
92
|
+
output,
|
|
93
|
+
async json(args, run, ctx) {
|
|
94
|
+
const stdout = await output(args, run, ctx);
|
|
95
|
+
try {
|
|
96
|
+
return JSON.parse(stdout);
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
throw makeError(`${commandWords(name, args)} gave no JSON: ${stdout.slice(0, 200)}`, 0, "");
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=tool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool.js","sourceRoot":"","sources":["../../src/cli/tool.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -10,7 +10,9 @@
|
|
|
10
10
|
* - shell.stream - Run command with args and stream each output line
|
|
11
11
|
*
|
|
12
12
|
* The command helpers (`runCommand`, `streamCommand`, `processes`) are also available without
|
|
13
|
-
* the registration of the procedures, from `@procedures/shell/command`.
|
|
13
|
+
* the registration of the procedures, from `@procedures/shell/command`. The runner of the CLI
|
|
14
|
+
* wrapper packages (`defineCliTool`) is in `@procedures/shell/cli`, and the fake shell of their
|
|
15
|
+
* tests (`fakeShell`) is in `@procedures/shell/testing`.
|
|
14
16
|
*
|
|
15
17
|
* @example
|
|
16
18
|
* ```typescript
|
|
@@ -27,5 +29,6 @@ export type { ShellRunInput, ShellRunOutput, ShellExecInput, ShellExecOutput, Sh
|
|
|
27
29
|
export { ShellRunInputSchema, ShellExecInputSchema, ShellWhichInputSchema, ShellStreamInputSchema, } from "./types.js";
|
|
28
30
|
export { shellRun, shellExec, shellWhich, shellStream } from "./procedures/shell/index.js";
|
|
29
31
|
export * from "./command/index.js";
|
|
32
|
+
export * from "./cli/index.js";
|
|
30
33
|
export { registerShellProcedures } from "./module.js";
|
|
31
34
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAGH,YAAY,EACV,aAAa,EACb,cAAc,EACd,cAAc,EACd,eAAe,EACf,eAAe,EACf,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,GAChB,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,mBAAmB,EACnB,oBAAoB,EACpB,qBAAqB,EACrB,sBAAsB,GACvB,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAG3F,cAAc,oBAAoB,CAAC;AAGnC,cAAc,gBAAgB,CAAC;AAG/B,OAAO,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -10,7 +10,9 @@
|
|
|
10
10
|
* - shell.stream - Run command with args and stream each output line
|
|
11
11
|
*
|
|
12
12
|
* The command helpers (`runCommand`, `streamCommand`, `processes`) are also available without
|
|
13
|
-
* the registration of the procedures, from `@procedures/shell/command`.
|
|
13
|
+
* the registration of the procedures, from `@procedures/shell/command`. The runner of the CLI
|
|
14
|
+
* wrapper packages (`defineCliTool`) is in `@procedures/shell/cli`, and the fake shell of their
|
|
15
|
+
* tests (`fakeShell`) is in `@procedures/shell/testing`.
|
|
14
16
|
*
|
|
15
17
|
* @example
|
|
16
18
|
* ```typescript
|
|
@@ -28,6 +30,8 @@ export { ShellRunInputSchema, ShellExecInputSchema, ShellWhichInputSchema, Shell
|
|
|
28
30
|
export { shellRun, shellExec, shellWhich, shellStream } from "./procedures/shell/index.js";
|
|
29
31
|
// Command helpers
|
|
30
32
|
export * from "./command/index.js";
|
|
33
|
+
// The runner of the CLI wrapper packages (also from `@procedures/shell/cli`)
|
|
34
|
+
export * from "./cli/index.js";
|
|
31
35
|
// Registration
|
|
32
36
|
export { registerShellProcedures } from "./module.js";
|
|
33
37
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAcH,OAAO,EACL,mBAAmB,EACnB,oBAAoB,EACpB,qBAAqB,EACrB,sBAAsB,GACvB,MAAM,YAAY,CAAC;AAEpB,aAAa;AACb,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAE3F,kBAAkB;AAClB,cAAc,oBAAoB,CAAC;AAEnC,6EAA6E;AAC7E,cAAc,gBAAgB,CAAC;AAE/B,eAAe;AACf,OAAO,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC"}
|
package/dist/module.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Procedure Registration for shell operations
|
|
5
5
|
*/
|
|
6
|
-
import { type ProcedureModule, type
|
|
6
|
+
import { type ProcedureModule, type PackageDefinition } from "@procedures/client";
|
|
7
7
|
/**
|
|
8
8
|
* The module of this package, for `createRegistry()`: its procedures as data. Importing this
|
|
9
9
|
* file registers nothing. (`register.ts` registers the same procedures in the global registry.)
|
|
@@ -15,5 +15,5 @@ export default shellModule;
|
|
|
15
15
|
* a registry. The default is the global registry. Importing this file registers nothing: the
|
|
16
16
|
* `./register` entry starts this function (ARCHITECTURE-PROPOSALS-2026-10, P9).
|
|
17
17
|
*/
|
|
18
|
-
export declare
|
|
18
|
+
export declare const registerShellProcedures: PackageDefinition["register"];
|
|
19
19
|
//# sourceMappingURL=module.d.ts.map
|
package/dist/module.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../src/module.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,
|
|
1
|
+
{"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../src/module.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAgD,KAAK,eAAe,EAAE,KAAK,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AA4GhI;;;GAGG;AACH,eAAO,MAAM,WAAW,EAAE,eAAqC,CAAC;eAEjD,WAAW;AAE1B;;;;GAIG;AACH,eAAO,MAAM,uBAAuB,EAAE,iBAAiB,CAAC,UAAU,CAAyB,CAAC"}
|
package/dist/module.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Procedure Registration for shell operations
|
|
5
5
|
*/
|
|
6
|
-
import {
|
|
6
|
+
import { definePackage, createProcedure } from "@procedures/client";
|
|
7
7
|
import { shellRun } from "./procedures/shell/run.js";
|
|
8
8
|
import { shellExec } from "./procedures/shell/exec.js";
|
|
9
9
|
import { shellWhich } from "./procedures/shell/which.js";
|
|
@@ -83,23 +83,22 @@ const shellStreamProcedure = createProcedure()
|
|
|
83
83
|
})
|
|
84
84
|
.handler(shellStream)
|
|
85
85
|
.build();
|
|
86
|
-
|
|
87
|
-
* The module of this package, for `createRegistry()`: its procedures as data. Importing this
|
|
88
|
-
* file registers nothing. (`register.ts` registers the same procedures in the global registry.)
|
|
89
|
-
*/
|
|
90
|
-
export const shellModule = defineModule("@procedures/shell", [
|
|
86
|
+
const shellPackage = definePackage("@procedures/shell", [
|
|
91
87
|
shellRunProcedure,
|
|
92
88
|
shellExecProcedure,
|
|
93
89
|
shellWhichProcedure,
|
|
94
90
|
shellStreamProcedure,
|
|
95
91
|
]);
|
|
92
|
+
/**
|
|
93
|
+
* The module of this package, for `createRegistry()`: its procedures as data. Importing this
|
|
94
|
+
* file registers nothing. (`register.ts` registers the same procedures in the global registry.)
|
|
95
|
+
*/
|
|
96
|
+
export const shellModule = shellPackage.module;
|
|
96
97
|
export default shellModule;
|
|
97
98
|
/**
|
|
98
99
|
* This function registers the procedures of @procedures/shell, and of the modules that it requires, in
|
|
99
100
|
* a registry. The default is the global registry. Importing this file registers nothing: the
|
|
100
101
|
* `./register` entry starts this function (ARCHITECTURE-PROPOSALS-2026-10, P9).
|
|
101
102
|
*/
|
|
102
|
-
export
|
|
103
|
-
registerModules(registry, [shellModule]);
|
|
104
|
-
}
|
|
103
|
+
export const registerShellProcedures = shellPackage.register;
|
|
105
104
|
//# sourceMappingURL=module.js.map
|