@procedures/shell 0.34.0 → 0.35.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/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # @procedures/shell
2
2
 
3
+ ## 0.35.0
4
+
5
+ ### Patch Changes
6
+
7
+ - 0b0cb42: One CLI-tool runner in `@procedures/shell` (dedupe review F2, tracker item O60).
8
+
9
+ PATCH: new exports `defineCliTool` and `./testing`, no break. Before 1.0.0, a feature raises the PATCH, and the fixed group shares one version.
10
+
11
+ - The new entry `@procedures/shell/cli` gives `defineCliTool({ name, resolve, error })`. Its runner has `run`, `runJson`, `output`, `json`, `arg` and `shellInput`. Each command goes as argv to `shell.run` through `ctx.client`, never as a shell string.
12
+ - The entry also gives `cliArg()`, `buildArgv()`, `parseJsonDocument()`, `parseJsonOutput()`, the shared result `CliToolOutput` with `cliToolOutputSchema()`, and the program lookup `nodeScript()`, `execPathProgram()` and `findInPath()`. The package root exports them too.
13
+ - The new entry `@procedures/shell/testing` gives `fakeShell(results)`: the shell procedures with their real schemas, effects and root rules, and handlers that record each input. Use `shell.module` in `createRegistry()`, or `shell.client` as `ctx.client`.
14
+ - gh, npm, pnpm, docker and `cli.run` run their program through `defineCliTool()`. Each procedure keeps its path, its schemas, its effects and its behavior. The exported helpers (`resolveNpm`, `resolvePnpm`, the output types and schemas) stay.
15
+ - `PnpmCommandOutput`, `NpmCommandOutput`, `DockerCommandOutput` and `CliRunOutput` extend `CliToolOutput`. Their schemas come from `cliToolOutputSchema()`. The `stderr` description of pnpm and `cli.run` now also names the error message when the program did not start.
16
+ - `@procedures/restic` and `@procedures/tailscale` re-export `buildArgv`, `parseJsonOutput`, `FLAG_NAME` and `ArgValue` from `@procedures/shell/cli`. The two copies of `argv.ts` are gone.
17
+ - `@procedures/vite` and `@procedures/vitest` use `cliArg()` for their argument guard.
18
+ - `SERVER-LAYERS.md` records the one run path of a CLI wrapper, and the reasons.
19
+ - @procedures/client@0.35.0
20
+
3
21
  ## 0.34.0
4
22
 
5
23
  ### Patch Changes
package/README.md CHANGED
@@ -326,22 +326,31 @@ const { path, found } = await client.exec(["shell", "which"], {
326
326
 
327
327
  ### Building CLI Wrappers
328
328
 
329
- The `shell.run` procedure is the foundation for CLI wrapper packages:
329
+ A CLI wrapper package (gh, npm, pnpm, docker, `cli.run`) defines its runner with `defineCliTool()` of `@procedures/shell/cli`. Each command goes as an argument list to `shell.run`, through `ctx.client`, so the host applies its rules to the nested call. `packages/documentation/SERVER-LAYERS.md` ("The run path of a CLI wrapper") gives the reasons.
330
330
 
331
331
  ```typescript
332
- // In client-git/src/procedures/git/status.ts
333
- export async function gitStatus(input: GitStatusInput, ctx: ProcedureContext) {
334
- const args = ["status"];
335
- if (input.short) args.push("--short");
336
-
337
- const result = await ctx.client.call(["shell", "run"], {
338
- command: "git",
339
- args,
340
- cwd: input.cwd,
341
- });
342
-
343
- return parseGitStatus(result.stdout);
344
- }
332
+ import { cliToolOutputSchema, defineCliTool } from "@procedures/shell/cli";
333
+
334
+ const docker = defineCliTool({ name: "docker" });
335
+
336
+ // In a handler: a value that starts with "-" is refused, and no shell runs
337
+ const result = await docker.run(["ps", "--filter", docker.arg("filter", input.filter)], { cwd: input.cwd }, ctx);
338
+ // result: { exitCode, stdout, stderr, success, duration }, the shape of cliToolOutputSchema("docker")
339
+ ```
340
+
341
+ - `run` and `runJson` give a failed result and do not throw. `output` and `json` throw the error of the tool.
342
+ - `resolve` finds the program at each command. `nodeScript()`, `execPathProgram()` and `findInPath()` help to find a script of a `.cmd` file.
343
+ - `buildArgv()`, `parseJsonDocument()` and `parseJsonOutput()` build an argv and read JSON output.
344
+
345
+ The tests of a wrapper use `fakeShell(results)` of `@procedures/shell/testing`:
346
+
347
+ ```typescript
348
+ import { fakeShell } from "@procedures/shell/testing";
349
+
350
+ const shell = fakeShell([{ stdout: "[]" }, { exitCode: 1, stderr: "not found" }]);
351
+ const registry = createRegistry(shell.module, dockerModule); // the first module of a name counts
352
+ // or, for a handler that a test calls directly: { client: shell.client }
353
+ expect(shell.args()).toEqual(["ps"]);
345
354
  ```
346
355
 
347
356
  ### Checking Command Availability