@duyquangnvx/agent-cli 0.2.1 → 0.4.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.
Files changed (130) hide show
  1. package/CHANGELOG.md +71 -0
  2. package/dist/abort.d.ts +2 -0
  3. package/dist/abort.js +11 -0
  4. package/dist/abort.js.map +1 -0
  5. package/dist/agent-cli.d.ts +17 -0
  6. package/dist/agent-cli.js +28 -0
  7. package/dist/agent-cli.js.map +1 -0
  8. package/dist/agent.d.ts +4 -0
  9. package/dist/agent.js +14 -0
  10. package/dist/agent.js.map +1 -0
  11. package/dist/built-ins.d.ts +1 -2
  12. package/dist/built-ins.js +0 -10
  13. package/dist/built-ins.js.map +1 -1
  14. package/dist/clock.d.ts +10 -0
  15. package/dist/clock.js +35 -0
  16. package/dist/clock.js.map +1 -0
  17. package/dist/command-spec.js +12 -1
  18. package/dist/command-spec.js.map +1 -1
  19. package/dist/confirm.d.ts +2 -0
  20. package/dist/confirm.js +4 -2
  21. package/dist/confirm.js.map +1 -1
  22. package/dist/cost.d.ts +9 -0
  23. package/dist/cost.js +16 -0
  24. package/dist/cost.js.map +1 -0
  25. package/dist/define.d.ts +145 -32
  26. package/dist/define.js +9 -2
  27. package/dist/define.js.map +1 -1
  28. package/dist/doctor-rows.d.ts +2 -2
  29. package/dist/doctor-rows.js +45 -5
  30. package/dist/doctor-rows.js.map +1 -1
  31. package/dist/doctor.d.ts +2 -1
  32. package/dist/doctor.js +31 -29
  33. package/dist/doctor.js.map +1 -1
  34. package/dist/errno.d.ts +15 -0
  35. package/dist/errno.js +50 -0
  36. package/dist/errno.js.map +1 -0
  37. package/dist/error-table.d.ts +34 -0
  38. package/dist/error-table.js +10 -0
  39. package/dist/error-table.js.map +1 -0
  40. package/dist/errors.d.ts +17 -12
  41. package/dist/errors.js +59 -38
  42. package/dist/errors.js.map +1 -1
  43. package/dist/execute.d.ts +7 -3
  44. package/dist/execute.js +38 -5
  45. package/dist/execute.js.map +1 -1
  46. package/dist/exit-classes.d.ts +31 -0
  47. package/dist/exit-classes.js +108 -0
  48. package/dist/exit-classes.js.map +1 -0
  49. package/dist/files.d.ts +31 -0
  50. package/dist/files.js +95 -0
  51. package/dist/files.js.map +1 -0
  52. package/dist/flags.d.ts +21 -3
  53. package/dist/flags.js +41 -4
  54. package/dist/flags.js.map +1 -1
  55. package/dist/global-install.d.ts +1 -0
  56. package/dist/global-install.js +2 -2
  57. package/dist/global-install.js.map +1 -1
  58. package/dist/help-json.d.ts +2 -1
  59. package/dist/help-json.js +18 -2
  60. package/dist/help-json.js.map +1 -1
  61. package/dist/help.d.ts +4 -2
  62. package/dist/help.js +62 -6
  63. package/dist/help.js.map +1 -1
  64. package/dist/index.d.ts +11 -4
  65. package/dist/index.js +3 -2
  66. package/dist/index.js.map +1 -1
  67. package/dist/input.d.ts +4 -0
  68. package/dist/input.js +24 -2
  69. package/dist/input.js.map +1 -1
  70. package/dist/interrupts.d.ts +17 -3
  71. package/dist/interrupts.js +43 -25
  72. package/dist/interrupts.js.map +1 -1
  73. package/dist/invocation.d.ts +7 -2
  74. package/dist/invocation.js +11 -3
  75. package/dist/invocation.js.map +1 -1
  76. package/dist/list.d.ts +1 -0
  77. package/dist/list.js +4 -2
  78. package/dist/list.js.map +1 -1
  79. package/dist/npm.d.ts +5 -0
  80. package/dist/npm.js +19 -17
  81. package/dist/npm.js.map +1 -1
  82. package/dist/output.d.ts +18 -4
  83. package/dist/output.js +65 -23
  84. package/dist/output.js.map +1 -1
  85. package/dist/outputs.d.ts +11 -0
  86. package/dist/outputs.js +22 -0
  87. package/dist/outputs.js.map +1 -0
  88. package/dist/package-root.d.ts +6 -0
  89. package/dist/package-root.js +17 -0
  90. package/dist/package-root.js.map +1 -0
  91. package/dist/parse-input.d.ts +2 -0
  92. package/dist/parse-input.js +41 -8
  93. package/dist/parse-input.js.map +1 -1
  94. package/dist/planned.d.ts +6 -0
  95. package/dist/planned.js +5 -0
  96. package/dist/planned.js.map +1 -0
  97. package/dist/project.d.ts +4 -0
  98. package/dist/project.js +48 -0
  99. package/dist/project.js.map +1 -0
  100. package/dist/route.d.ts +2 -0
  101. package/dist/route.js +2 -1
  102. package/dist/route.js.map +1 -1
  103. package/dist/run-cli.d.ts +24 -5
  104. package/dist/run-cli.js +126 -18
  105. package/dist/run-cli.js.map +1 -1
  106. package/dist/run-process.js +6 -3
  107. package/dist/run-process.js.map +1 -1
  108. package/dist/secrets.d.ts +19 -0
  109. package/dist/secrets.js +32 -0
  110. package/dist/secrets.js.map +1 -0
  111. package/dist/spawn.d.ts +29 -0
  112. package/dist/spawn.js +79 -0
  113. package/dist/spawn.js.map +1 -0
  114. package/dist/spill.d.ts +16 -0
  115. package/dist/spill.js +65 -0
  116. package/dist/spill.js.map +1 -0
  117. package/dist/style.js +5 -12
  118. package/dist/style.js.map +1 -1
  119. package/dist/tail.d.ts +2 -0
  120. package/dist/tail.js +5 -0
  121. package/dist/tail.js.map +1 -0
  122. package/dist/tools.d.ts +6 -0
  123. package/dist/tools.js +69 -0
  124. package/dist/tools.js.map +1 -0
  125. package/dist/update.js +7 -7
  126. package/dist/update.js.map +1 -1
  127. package/dist/usage.d.ts +3 -0
  128. package/dist/usage.js +6 -3
  129. package/dist/usage.js.map +1 -1
  130. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -4,6 +4,77 @@ What changed in each release of `@duyquangnvx/agent-cli` (the Runtime) and `@duy
4
4
 
5
5
  ## Unreleased
6
6
 
7
+ ## v0.4.0 (2026-10-19)
8
+
9
+ ### Added
10
+
11
+ - The last field of a Command's `args` may be a `z.array(...)`, optionally wrapped in optional or default, which takes every remaining operand: `tool preview a b c` gives `dirs: ["a", "b", "c"]`. None gives an empty array for the schema to judge, or leaves an optional field out so its default applies. Each operand is coerced like a scalar arg of the element's type, and an issue on one names it and its position, as in `<values...> "x" (argument 3): ...`. Text help shows the field as `<name...>` (`[name...]` when optional), and `--help --json` gives it the array schema. `defineCommand` throws when an array field is not the last of `args`.
12
+ - The ports factory receives `PortsBase`, the run's base context: `env`, `cwd`, `packageRoot`, `secret`, `spawn`, `files`, `clock` and `signal`, the same classified, cwd-resolved helpers a Command gets, so an adapter reads a secret or the package root as a Command does. Under `runCli` it sees the test's `env`, `cwd`, `clock`, `files` and `spawn`, and the `ports` option still replaces its result. It runs when a run first reads `ctx.ports`, at most once, and what it throws exits by its Exit class like a Command error; a run that never reads them, such as `doctor` or `update`, never calls it, and a `doctor` row that reads them reports the error as its problem. A factory written as `() => Ports` still type-checks; the type `PortsBase` is exported.
13
+ - A write or destructive Command may declare `force: "<what it replaces>"`, which gives it the Standard flag `--force` with that sentence as the flag's description in help and help JSON. A Command gets `--force` from `outputs`, `force` or both; with `outputs`, `--force` still lifts `OUTPUT_EXISTS`, and `outputs` alone keeps the generic description. `ctx.force` is true only when the caller passed `--force` to a Command that has it, and `plan` sees it under `--dry-run` too. `defineCommand` throws when a read or serve Command declares `force`, or when the sentence is empty.
14
+ - `ctx.files.read(path)` returns a file's bytes as a `Uint8Array`; `ctx.files.list(folder)` returns the names in a folder, sorted, never the Runtime's temp files; `ctx.files.remove(path)` removes a file or a folder with everything in it, and succeeds when the path does not exist; `ctx.files.mkdir(path, { exclusive? })` creates a folder and its missing parents, and with `exclusive: true` fails when the folder exists. Each resolves its path against `ctx.cwd` and fails as `write` does: `PERMISSION_DENIED` (exit 2, with the sandbox hint under a Coding agent), `DISK_FULL` (exit 2) or `NOT_FOUND` (exit 1), naming the path. The type `MkdirOptions` is exported.
15
+ - The Runtime code `ALREADY_EXISTS` (exit 1), raised for EEXIST, such as an exclusive `mkdir` of an existing folder, naming the path, with a hint to pass another path or remove that one. `ALREADY_EXISTS`, `PERMISSION_DENIED`, `DISK_FULL` and `NOT_FOUND` are exported as constants, so a Command catches one with `error instanceof CliError && error.code === ALREADY_EXISTS`.
16
+
17
+ ### Changed
18
+
19
+ - **Breaking:** `doctor` exits 0 when only its `install` or `registry` row is a problem (not a global install, a newer version on the registry, or the registry unreachable). Those rows still show `problem` with their fix, in text and `--json`, and the fix stays under `next`.
20
+ - **Breaking:** the `Files` interface gains `read`, `list`, `remove` and `mkdir`, so every fake passed as `runCli`'s `files` option must implement them. The scaffolded template's fake and the skill's example implement them.
21
+ - **Breaking:** `ctx.files.write` creates missing parent folders, so a write into a missing folder no longer fails with `NOT_FOUND`.
22
+ - The agent-cli skill teaches every 0.4.0 feature: the ports factory reading `PortsBase`, array positionals, `force` with `ctx.force`, and `ctx.files`' `read`, `list`, `remove` and `mkdir` with a caught `ALREADY_EXISTS`. Its example `links` gains `bundle <folder> <ids...>`, which writes shortcut files into a new folder and replaces an existing one under `--force`, a `web` port that `links check` uses and whose factory reads `LINKS_TOKEN`, and reads `links.json` through `ctx.files`.
23
+
24
+ ### Fixed
25
+
26
+ - Under a Coding agent, a `PERMISSION_DENIED` on a read (`ctx.files.read`, `list` or `exists`, an unreadable `.env`, a tool `ctx.spawn` cannot run) asks the user to allow reading the path in the sandbox, not to add it to the sandbox's write list.
27
+ - A `$XDG_CONFIG_HOME/<cli>/.env` the Runtime cannot read makes `ctx.secret` fail with `PERMISSION_DENIED` (exit 2) naming the file, with the sandbox hint under an agent, instead of exit 70. A missing `.env` still means no secrets.
28
+
29
+ ## v0.3.0 (2026-10-19)
30
+
31
+ ### Added
32
+
33
+ - Data a Command prints over 30,000 characters, returned or delivered before a failure, is written to `$TMPDIR/<cli>/<time>-<command>.txt` (`.json` under `--json`), `<time>` being ISO 8601 with dashes for colons (`2026-10-19T08-00-00.000Z`) so the name is valid on Windows, through `ctx.files`, and stdout carries the file, its size in bytes and its first 2,000 characters: `{ "file", "bytes", "preview" }` under `--json`, else `file:`, `bytes:` and `preview:` lines. Writing one first removes that folder's spill files older than 7 days. A List Command never spills; `--limit` sizes it.
34
+ - A write or destructive Command may declare `outputs(plan)`, the files its Plan writes relative to `ctx.cwd`. It gets the Standard flag `--force`; without it, a run where any output exists refuses with `OUTPUT_EXISTS` (exit 1) after `plan` and before the cost, `--confirm` and `apply`, naming the existing outputs, with the command plus `--force` in the hint. Its `--dry-run` prints `outputs:` and one indented path per line after the Plan, and under `--json` adds `outputs` to the dry run's object (`{ "plan", "outputs" }`, with `cost` too when declared). `Files` gains `exists(path)`, which `ctx.files` resolves under `ctx.cwd`. `force` is a reserved option and arg name.
35
+ - A write or destructive Command may declare `cost(plan)`, a sentence stating the price or `undefined` when the run is cheap. It gets the Standard flag `--yes`; a run whose cost is a sentence and that lacks `--yes` refuses with `NOT_CONFIRMED` (exit 2) before `--confirm` and `apply`, the sentence in the message and the command plus `--yes` in the hint. Its `--dry-run` prints `cost: <sentence>` after the Plan, and under `--json` prints `{ "plan", "cost" }`, `cost` null when cheap. `yes` is a reserved option and arg name.
36
+ - `ctx.deliver(data)` records the data a Command has done so far; the last call wins. When the run then fails, hits a `ctx.deadline` or is interrupted, that data prints on stdout through the Command's `render` (or as JSON under `--json`, with `--fields` applied to a page) and the errors on stderr. A returned value replaces it.
37
+ - The Effect `serve`, for a Command that keeps running, such as a preview server: its `start(input, ctx)` returns data, which prints at once, and the Command runs until `ctx.signal` aborts. Ctrl-C or SIGTERM then ends the run with exit 0, after any `runToEnd` step finishes. It gets `--json` and no other Effect-driven Standard flag. A signal before `start` returns is still `INTERRUPTED`.
38
+ - `agentCli<Ports>()` returns `defineCommand` and `defineCli` typed so that `ctx.ports` is `Ports`; `defineCli` takes `ports: () => Ports`, required when `Ports` has keys, and `runCli`'s `ports` option replaces them in a test. `Ports` defaults to none.
39
+ - `ctx.clock` (`now`, `sleep`), on which `ctx.deadline` and the grace period after an interrupt now run, and `runCli`'s `clock` option, which replaces it so a test runs them instantly.
40
+ - `ctx.poll(check, { intervalMs })` calls `check` until it returns a value other than `undefined`, sleeping on `ctx.clock` between calls, and ends with the abort reason of `ctx.signal`: `INTERRUPTED`, or `DEADLINE_EXCEEDED` at the run deadline.
41
+ - A Command may declare a run deadline, `deadline: { ms, resume(input) }`. At `ms` on `ctx.clock`, `ctx.signal` aborts and the run ends with `DEADLINE_EXCEEDED` (exit 75), whose hint is the command line `resume(input)` returns; the data last passed to `ctx.deliver` prints on stdout, and `runToEnd` steps still finish within the grace period. The type `RunDeadline` is exported.
42
+ - `ctx.packageRoot`: the folder holding the CLI's `package.json`, found from the running bin through any link npm put on `PATH`, or from `cwd` when `runCli` has no `bin`, so a Command can read files its package ships.
43
+ - The Error table: `defineCli({ errors })` declares each error code once with its Exit class (`caller`, `operator`, `source` or `wait`) and an optional Zod `details` schema; `defineErrors` keeps the table's types, and `cliError(errors, code, { message, hint, details, retryAt })` throws a code whose `details` fail type checking when they do not match its schema. `retryAt` (ISO 8601) is accepted only on a wait-class code. Under `--json` each error carries `details` and `retryAt` when present. `defineCli` throws when the table redeclares a Runtime code.
44
+ - Root help ends with `Exit codes:`, listing the classes the CLI can produce, then `Examples:`, one per top-level Command with `doctor` last; `--help --json` at the root has `errors`, the table with each code's class and `details` JSON Schema.
45
+ - `ctx.files.write(path, data)` writes a file under `ctx.cwd` atomically, through a temp file named with the pid and a rename; the first write to a folder in a run removes the temp files of writers no longer running. A failure fails the run naming the path: EACCES or EPERM with `PERMISSION_DENIED` (exit 2), whose hint, when an agent is detected, names `! <command line>` and allowing the path in the sandbox's write list, else the path's permissions; ENOSPC with `DISK_FULL` (exit 2); ENOENT with `NOT_FOUND` (exit 1). `runCli`'s `files` option replaces the file system in a test, and the type `Files` is exported.
46
+ - `ctx.spawn(command, args?, { cwd?, env?, check? })` runs a child process in `ctx.cwd` with `ctx.env` and resolves to `{ stdout, stderr, exitCode }`. Interrupting the run kills the child, and the run ends only once it has exited. With `check: true`, a non-zero exit fails the run with `TOOL_FAILED` (exit 2), its message ending with the last 20 lines of the child's stderr. A program that is not found fails the run with `TOOL_MISSING` (exit 2) naming it; one that cannot start for EACCES or EPERM fails with `PERMISSION_DENIED`, as `ctx.files` does. `runCli`'s `spawn` option replaces the child processes in a test, and the types `Spawn`, `SpawnOptions` and `SpawnResult` are exported.
47
+ - A Command may declare `tools: [{ name, install }]`, the programs it runs. Before `plan`, `run` or `start`, also under `--dry-run`, the Runtime looks each up on `PATH` from `ctx.env`, and any missing fail the run together with `TOOL_MISSING` (exit 2), the hint holding each one's `install`. `doctor` adds one row per distinct tool across all Commands, after the CLI's own rows, with `install` as its fix. The type `Tool` is exported.
48
+ - `ctx.secret(name)` returns `{ value, origin }` from the env (`origin: { kind: "env" }`), else from `$XDG_CONFIG_HOME/<cli>/.env` (default `~/.config`, with `HOME` and `XDG_CONFIG_HOME` read from the run's env; `origin: { kind: "file", path }`); an empty env value counts as unset, and a name in neither gives `undefined`. The agent-cli skill's example has a `doctor` row that reports a secret's origin and never its value.
49
+ - `defineCli({ project: { file, schema } })` declares the Project file: `ctx.project` is `{ root, settings }` for the nearest such file at or above `cwd`, its JSON parsed by `schema`, or `undefined` when there is none. A file that is not JSON or fails its schema fails the run with `PROJECT_INVALID` (exit 2) before the Command runs, naming the path and the issues. The built-ins never read it, so an invalid one never stops `doctor` or `update`: `doctor` gets a `project` row, after `node`, that names the file, says none was found, or reports an invalid one as a problem. `agentCli<Ports, Settings>()` types `ctx.project.settings`.
50
+ - `DoctorCheck.deadlineMs` sets a row's own deadline in place of the default 10 s, and `DoctorCheck.advisory` makes a row whose problem shows, with its fix under `next`, but never fails `doctor`.
51
+ - Under a Coding agent (`CLAUDECODE`, `CODEX_CI`, `CODEX_SANDBOX`, `GEMINI_CLI`, `CURSOR_AGENT` or `CI` set), a usage error's text stderr ends with the full help of the Command or group that was misused, so the agent corrects its call without a second `--help`. A person at a terminal and `--json` output are unchanged.
52
+ - A Command may throw an `AggregateError` of errors to report every problem it found. Text stderr prints each error with its hint, `--json` lists them all in `{ errors: [...] }`, and the run exits with the first of 1, 2, 3, 75 that any of them has, or 70 when any is not a known `CliError`; delivered data still prints on stdout.
53
+ - `FORCE_COLOR`, set and neither empty nor `0`, turns colour on even under a Coding agent or without a TTY. `NO_COLOR` still turns it off.
54
+
55
+ ### Changed
56
+
57
+ - **Breaking:** a `CliError` whose code is missing from the CLI's Error table exits 70, as a bug, no longer 1, and prints as one: `internal error:` with its message, the hint to rerun under `<NAME>_DEBUG=1` in place of its own, and its stack trace under debug. The help of a single-Command CLI shows its examples last, after the exit codes. The Scaffolder's `STEP_FAILED` exits 2.
58
+ - **Breaking:** `CliErrorDetails` is renamed `CliErrorFields` and `UsageErrorDetails` `UsageErrorFields`; `CliError` takes and exposes `details` and `retryAt`.
59
+ - **Breaking:** the skill's example declares an Error table and throws through `cliError`, with `NOT_FOUND` renamed `LINK_NOT_FOUND`; the skill and the scaffolded template's `AGENTS.md` describe the Error table.
60
+ - **Breaking:** `doctor` starts with a `build` row showing the `--version` line, and the CLI's own rows now come right after `node`: the order is `build`, `node`, `project` (when the CLI declares a Project file), the CLI's rows, `install`, `registry`, `skill`.
61
+ - **Breaking:** the Cli field `build` requires `builtAt`, an ISO time, and `--version` of a stamped build prints `X.Y.Z (sha[+dirty]) built <iso>` then `changelog <package root>/CHANGELOG.md`. The scaffolded template's build stamps `builtAt`; a build without a stamp still prints the version alone. The Scaffolder's package ships `CHANGELOG.md`, so the line names a file that exists.
62
+ - **Breaking:** exit codes follow the failure's Exit class, who must act ([ADR 0005](docs/adr/0005-exit-codes-say-who-must-act.md)): 1 the caller, 2 the operator, 3 the source, 75 nobody but time, 70 a bug, 130 or 143 an interrupt. A usage error exits 1, no longer 2. `DEADLINE_EXCEEDED` exits 75. `INTERRUPTED` exits 130 on SIGINT and 143 on SIGTERM, from the bin and from `runCli`, whose `signal` aborted with the reason `"SIGTERM"` gives 143. An error that is not a `CliError` (`INTERNAL`) exits 70. The built-ins' codes exit by class: `DOCTOR_PROBLEMS`, `NOT_GLOBAL_INSTALL`, `REGISTRY_UNREACHABLE`, `REGISTRY_AUTH`, `INSTALL_FAILED` and `NPM_FAILED` exit 2, `NO_LATEST` exits 3.
63
+ - **Breaking:** under `--json`, stderr is `{ "errors": [{ "code", "message", "hint" }] }`, a list even for one error, in place of the single error object.
64
+ - **Breaking:** `ctx.runToEnd(name, work)` takes the step's name first. When the run is interrupted or hits its run deadline during the step, stderr says `finishing <name>`. The built-in `update` names its install step `installing <package>@<version>`.
65
+ - **Breaking:** the scaffolded template declares an Error table and a `greetings` port in `src/ports.ts` through `agentCli<Ports>()`, and adds a `card` Command that writes `<name>.txt` through `ctx.files`, declaring `outputs` and a `cost` for a language other than English; its test fakes the port and the files through `runCli`, and its `AGENTS.md` and skill cover outputs, cost and ports. `examples/notes` gains `summarize`, which sends the notes to a `summarizer` port and writes the summary to a file, with `outputs` and a `cost` above 5 notes.
66
+ - Under `<NAME>_DEBUG=1`, an error's `cause` chain prints after its stack trace, each cause on a `caused by:` line, and in the `stack` field under `--json`.
67
+ - The agent-cli skill teaches every 0.3.0 feature: Exit classes and the Error table, several errors, `ctx.deliver`, spilled output, `outputs` with `--force`, `cost` with `--yes`, run deadlines and named steps, ports, `ctx.files`, `ctx.spawn` with `tools`, `ctx.clock` and `ctx.poll`, secrets, the Project file, `ctx.packageRoot`, the `serve` Effect and doctor's `deadlineMs` and `advisory`. Its example `links` gains `archive` (a port polled on the clock, a cost, a run deadline, delivered data and an `AggregateError`), `export` (an output), `commit` (`git` as a tool), `serve`, a Project file and an advisory `doctor` row, and its tests fake the port, the clock, `files` and `spawn`.
68
+
69
+ ### Fixed
70
+
71
+ - On Windows, the built-in `update` and the `doctor` rows that ask npm (`install`, `registry`) now reach npm; they failed with `NPM_FAILED` because npm was named in quotes, so `npm.cmd` looked for its script in the working directory.
72
+
73
+ ### Removed
74
+
75
+ - **Breaking:** `retryable` is gone from `CliError`, `CliErrorDetails` and the `--json` error; the hint says whether running again helps.
76
+ - **Breaking:** the exports `defineCommand` and `defineCli`: call `agentCli()` (or `agentCli<Ports>()`) and use the pair it returns. The scaffolded template, `examples/notes` and the agent-cli skill do.
77
+
7
78
  ## v0.2.1 (2026-10-19)
8
79
 
9
80
  ### Changed
@@ -0,0 +1,2 @@
1
+ /** Never resolves; rejects with the signal's reason once it aborts. */
2
+ export declare function untilAborted(signal: AbortSignal): Promise<never>;
package/dist/abort.js ADDED
@@ -0,0 +1,11 @@
1
+ /** Never resolves; rejects with the signal's reason once it aborts. */
2
+ export function untilAborted(signal) {
3
+ return new Promise((_resolve, reject) => {
4
+ if (signal.aborted) {
5
+ reject(signal.reason);
6
+ return;
7
+ }
8
+ signal.addEventListener("abort", () => reject(signal.reason), { once: true });
9
+ });
10
+ }
11
+ //# sourceMappingURL=abort.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"abort.js","sourceRoot":"","sources":["../src/abort.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,MAAM,UAAU,YAAY,CAAC,MAAmB;IAC9C,OAAO,IAAI,OAAO,CAAC,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE;QACtC,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;YACnB,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YACtB,OAAO;QACT,CAAC;QACD,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IAChF,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,17 @@
1
+ import { type Cli, type CommandTreeCli, type DefineCommand, type NoPorts, type SingleCommandCli } from "./define.js";
2
+ type PortsFactory<Ports> = NoPorts extends Ports ? {
3
+ readonly ports?: CommandTreeCli<Ports>["ports"];
4
+ } : {
5
+ readonly ports: NonNullable<CommandTreeCli<Ports>["ports"]>;
6
+ };
7
+ type CliDeclaration<Ports, Settings> = (Omit<CommandTreeCli<Ports, Settings>, "ports"> & PortsFactory<Ports>) | (Omit<SingleCommandCli<Ports, Settings>, "ports"> & PortsFactory<Ports>);
8
+ export interface AgentCli<Ports, Settings> {
9
+ readonly defineCommand: DefineCommand<Ports, Settings>;
10
+ defineCli(cli: CliDeclaration<Ports, Settings>): Cli<Ports, Settings>;
11
+ }
12
+ /**
13
+ * Declares the CLI's ports and its Project file's settings once; the `defineCommand` and
14
+ * `defineCli` it returns type `ctx.ports` and `ctx.project`.
15
+ */
16
+ export declare function agentCli<Ports = NoPorts, Settings = unknown>(): AgentCli<Ports, Settings>;
17
+ export {};
@@ -0,0 +1,28 @@
1
+ import { builtInCommands } from "./built-ins.js";
2
+ import { defineCommandFor, } from "./define.js";
3
+ import { runtimeCodesIn } from "./exit-classes.js";
4
+ function checkOwnCodes(cli) {
5
+ const redeclared = runtimeCodesIn(cli.errors ?? {});
6
+ if (redeclared.length > 0) {
7
+ throw new Error(`${cli.name} declares ${redeclared.join(", ")}, an error code the Runtime already declares`);
8
+ }
9
+ }
10
+ function defineCli(cli) {
11
+ checkOwnCodes(cli);
12
+ if (cli.commands === undefined)
13
+ return cli;
14
+ const { commands } = cli;
15
+ const taken = Object.keys(builtInCommands(cli, undefined)).filter((name) => commands[name] !== undefined);
16
+ if (taken.length > 0) {
17
+ throw new Error(`${cli.name} defines ${taken.join(", ")}, a built-in Command it cannot replace`);
18
+ }
19
+ return cli;
20
+ }
21
+ /**
22
+ * Declares the CLI's ports and its Project file's settings once; the `defineCommand` and
23
+ * `defineCli` it returns type `ctx.ports` and `ctx.project`.
24
+ */
25
+ export function agentCli() {
26
+ return { defineCommand: defineCommandFor(), defineCli };
27
+ }
28
+ //# sourceMappingURL=agent-cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-cli.js","sourceRoot":"","sources":["../src/agent-cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAIL,gBAAgB,GAGjB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAgBnD,SAAS,aAAa,CAAkB,GAAyB;IAC/D,MAAM,UAAU,GAAG,cAAc,CAAC,GAAG,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC;IACpD,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CACb,GAAG,GAAG,CAAC,IAAI,aAAa,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,8CAA8C,CAC5F,CAAC;IACJ,CAAC;AACH,CAAC;AAED,SAAS,SAAS,CAAkB,GAAyB;IAC3D,aAAa,CAAC,GAAG,CAAC,CAAC;IACnB,IAAI,GAAG,CAAC,QAAQ,KAAK,SAAS;QAAE,OAAO,GAAG,CAAC;IAC3C,MAAM,EAAE,QAAQ,EAAE,GAAG,GAAG,CAAC;IACzB,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC,CAAC,MAAM,CAC/D,CAAC,IAAI,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,SAAS,CACvC,CAAC;IACF,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACrB,MAAM,IAAI,KAAK,CACb,GAAG,GAAG,CAAC,IAAI,YAAY,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,wCAAwC,CAChF,CAAC;IACJ,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,QAAQ;IACtB,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAmB,EAAE,SAAS,EAAE,CAAC;AAC3E,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { Env } from "./define.js";
2
+ export declare const AGENT_VARIABLES: readonly ["CLAUDECODE", "CODEX_CI", "CODEX_SANDBOX", "GEMINI_CLI", "CURSOR_AGENT", "CI"];
3
+ /** Whether a Coding agent, not a person, is running the Agent CLI. */
4
+ export declare function isAgent(env: Env): boolean;
package/dist/agent.js ADDED
@@ -0,0 +1,14 @@
1
+ // Some Coding agents run commands in a PTY, so a TTY alone doesn't mean a person is watching.
2
+ export const AGENT_VARIABLES = [
3
+ "CLAUDECODE",
4
+ "CODEX_CI",
5
+ "CODEX_SANDBOX",
6
+ "GEMINI_CLI",
7
+ "CURSOR_AGENT",
8
+ "CI",
9
+ ];
10
+ /** Whether a Coding agent, not a person, is running the Agent CLI. */
11
+ export function isAgent(env) {
12
+ return AGENT_VARIABLES.some((name) => env[name] !== undefined);
13
+ }
14
+ //# sourceMappingURL=agent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent.js","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"AAEA,8FAA8F;AAC9F,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,YAAY;IACZ,UAAU;IACV,eAAe;IACf,YAAY;IACZ,cAAc;IACd,IAAI;CACI,CAAC;AAEX,sEAAsE;AACtE,MAAM,UAAU,OAAO,CAAC,GAAQ;IAC9B,OAAO,eAAe,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,SAAS,CAAC,CAAC;AACjE,CAAC"}
@@ -1,4 +1,3 @@
1
- import type { Cli, Commands, CommandTreeCli } from "./define.js";
1
+ import type { Commands, CommandTreeCli } from "./define.js";
2
2
  /** The Commands the Runtime adds to a multi-Command CLI: `update` only when it declares an install. */
3
3
  export declare function builtInCommands(cli: CommandTreeCli, bin: string | undefined): Commands;
4
- export declare function defineCli(cli: Cli): Cli;
package/dist/built-ins.js CHANGED
@@ -7,14 +7,4 @@ export function builtInCommands(cli, bin) {
7
7
  ...(cli.install === undefined ? {} : { update: updateCommand(cli, cli.install, bin) }),
8
8
  };
9
9
  }
10
- export function defineCli(cli) {
11
- if (cli.commands === undefined)
12
- return cli;
13
- const { commands } = cli;
14
- const taken = Object.keys(builtInCommands(cli, undefined)).filter((name) => commands[name] !== undefined);
15
- if (taken.length > 0) {
16
- throw new Error(`${cli.name} defines ${taken.join(", ")}, a built-in Command it cannot replace`);
17
- }
18
- return cli;
19
- }
20
10
  //# sourceMappingURL=built-ins.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"built-ins.js","sourceRoot":"","sources":["../src/built-ins.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,uGAAuG;AACvG,MAAM,UAAU,eAAe,CAAC,GAAmB,EAAE,GAAuB;IAC1E,OAAO;QACL,MAAM,EAAE,aAAa,CAAC,GAAG,EAAE,GAAG,CAAC;QAC/B,GAAG,CAAC,GAAG,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,aAAa,CAAC,GAAG,EAAE,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,EAAE,CAAC;KACvF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,GAAQ;IAChC,IAAI,GAAG,CAAC,QAAQ,KAAK,SAAS;QAAE,OAAO,GAAG,CAAC;IAC3C,MAAM,EAAE,QAAQ,EAAE,GAAG,GAAG,CAAC;IACzB,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC,CAAC,MAAM,CAC/D,CAAC,IAAI,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,SAAS,CACvC,CAAC;IACF,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACrB,MAAM,IAAI,KAAK,CACb,GAAG,GAAG,CAAC,IAAI,YAAY,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,wCAAwC,CAChF,CAAC;IACJ,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
1
+ {"version":3,"file":"built-ins.js","sourceRoot":"","sources":["../src/built-ins.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,uGAAuG;AACvG,MAAM,UAAU,eAAe,CAAC,GAAmB,EAAE,GAAuB;IAC1E,OAAO;QACL,MAAM,EAAE,aAAa,CAAC,GAAG,EAAE,GAAG,CAAC;QAC/B,GAAG,CAAC,GAAG,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,aAAa,CAAC,GAAG,EAAE,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,EAAE,CAAC;KACvF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,10 @@
1
+ /** Time as the Runtime sees it; a test replaces it through `runCli` to run every wait instantly. */
2
+ export interface Clock {
3
+ now(): number;
4
+ /** Resolves after `ms`, or rejects with the signal's reason once it aborts. */
5
+ sleep(ms: number, signal?: AbortSignal): Promise<void>;
6
+ }
7
+ export declare const realClock: Clock;
8
+ /** Runs `then` once `ms` have passed on `clock`; aborting `cancel` drops it. */
9
+ export declare function after(clock: Clock, ms: number, cancel: AbortSignal, then: () => void): void;
10
+ export declare function poll<T>(clock: Clock, check: () => T | undefined | Promise<T | undefined>, intervalMs: number, signal: AbortSignal): Promise<T>;
package/dist/clock.js ADDED
@@ -0,0 +1,35 @@
1
+ export const realClock = {
2
+ now: () => Date.now(),
3
+ sleep: (ms, signal) => new Promise((resolve, reject) => {
4
+ if (signal?.aborted === true) {
5
+ reject(signal.reason);
6
+ return;
7
+ }
8
+ const onAbort = () => {
9
+ clearTimeout(timer);
10
+ reject(signal?.reason);
11
+ };
12
+ const timer = setTimeout(() => {
13
+ signal?.removeEventListener("abort", onAbort);
14
+ resolve();
15
+ }, ms);
16
+ signal?.addEventListener("abort", onAbort, { once: true });
17
+ }),
18
+ };
19
+ /** Runs `then` once `ms` have passed on `clock`; aborting `cancel` drops it. */
20
+ export function after(clock, ms, cancel, then) {
21
+ clock.sleep(ms, cancel).then(then, (error) => {
22
+ if (!cancel.aborted)
23
+ throw error;
24
+ });
25
+ }
26
+ export async function poll(clock, check, intervalMs, signal) {
27
+ for (;;) {
28
+ signal.throwIfAborted();
29
+ const value = await check();
30
+ if (value !== undefined)
31
+ return value;
32
+ await clock.sleep(intervalMs, signal);
33
+ }
34
+ }
35
+ //# sourceMappingURL=clock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clock.js","sourceRoot":"","sources":["../src/clock.ts"],"names":[],"mappings":"AAOA,MAAM,CAAC,MAAM,SAAS,GAAU;IAC9B,GAAG,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE;IACrB,KAAK,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,CACpB,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC9B,IAAI,MAAM,EAAE,OAAO,KAAK,IAAI,EAAE,CAAC;YAC7B,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YACtB,OAAO;QACT,CAAC;QACD,MAAM,OAAO,GAAG,GAAS,EAAE;YACzB,YAAY,CAAC,KAAK,CAAC,CAAC;YACpB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACzB,CAAC,CAAC;QACF,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;YAC5B,MAAM,EAAE,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YAC9C,OAAO,EAAE,CAAC;QACZ,CAAC,EAAE,EAAE,CAAC,CAAC;QACP,MAAM,EAAE,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7D,CAAC,CAAC;CACL,CAAC;AAEF,gFAAgF;AAChF,MAAM,UAAU,KAAK,CAAC,KAAY,EAAE,EAAU,EAAE,MAAmB,EAAE,IAAgB;IACnF,KAAK,CAAC,KAAK,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,KAAc,EAAE,EAAE;QACpD,IAAI,CAAC,MAAM,CAAC,OAAO;YAAE,MAAM,KAAK,CAAC;IACnC,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,IAAI,CACxB,KAAY,EACZ,KAAmD,EACnD,UAAkB,EAClB,MAAmB;IAEnB,SAAS,CAAC;QACR,MAAM,CAAC,cAAc,EAAE,CAAC;QACxB,MAAM,KAAK,GAAG,MAAM,KAAK,EAAE,CAAC;QAC5B,IAAI,KAAK,KAAK,SAAS;YAAE,OAAO,KAAK,CAAC;QACtC,MAAM,KAAK,CAAC,KAAK,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;IACxC,CAAC;AACH,CAAC"}
@@ -2,6 +2,17 @@ import { isCommand } from "./define.js";
2
2
  import { standardFlagsFor } from "./flags.js";
3
3
  import { argFields, optionFields } from "./input.js";
4
4
  import { listSpec } from "./list.js";
5
+ import { hasPlan } from "./planned.js";
6
+ function declaredOf(command) {
7
+ if (!hasPlan(command)) {
8
+ return { outputs: false, force: undefined, cost: false };
9
+ }
10
+ return {
11
+ outputs: command.outputs !== undefined,
12
+ force: command.force,
13
+ cost: command.cost !== undefined,
14
+ };
15
+ }
5
16
  export function commandSpec(commandLine, command) {
6
17
  const list = command.rows === undefined ? undefined : listSpec(command.rows);
7
18
  return {
@@ -13,7 +24,7 @@ export function commandSpec(commandLine, command) {
13
24
  examples: command.examples,
14
25
  args: argFields(command.args),
15
26
  options: optionFields(command.options),
16
- standardFlags: standardFlagsFor(command.effect, list),
27
+ standardFlags: standardFlagsFor(command.effect, declaredOf(command), list),
17
28
  list,
18
29
  output: list?.output ?? command.output,
19
30
  };
@@ -1 +1 @@
1
- {"version":3,"file":"command-spec.js","sourceRoot":"","sources":["../src/command-spec.ts"],"names":[],"mappings":"AACA,OAAO,EAA6C,SAAS,EAAE,MAAM,aAAa,CAAC;AACnF,OAAO,EAAqB,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACjE,OAAO,EAAE,SAAS,EAAmB,YAAY,EAAE,MAAM,YAAY,CAAC;AACtE,OAAO,EAAiB,QAAQ,EAAE,MAAM,WAAW,CAAC;AA0BpD,MAAM,UAAU,WAAW,CAAC,WAAmB,EAAE,OAAgB;IAC/D,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7E,OAAO;QACL,IAAI,EAAE,SAAS;QACf,WAAW;QACX,OAAO;QACP,WAAW,EAAE,OAAO,CAAC,WAAW;QAChC,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,IAAI,EAAE,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC;QAC7B,OAAO,EAAE,YAAY,CAAC,OAAO,CAAC,OAAO,CAAC;QACtC,aAAa,EAAE,gBAAgB,CAAC,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC;QACrD,IAAI;QACJ,MAAM,EAAE,IAAI,EAAE,MAAM,IAAI,OAAO,CAAC,MAAM;KACvC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,WAAmB,EAAE,QAAkB;IAC/D,OAAO;QACL,IAAI,EAAE,OAAO;QACb,WAAW;QACX,QAAQ,EAAE,MAAM,CAAC,WAAW,CAC1B,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,MAAM,CAAC,GAAG,WAAW,IAAI,GAAG,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC,CAC5F;KACF,CAAC;AACJ,CAAC;AAED,SAAS,MAAM,CAAC,WAAmB,EAAE,IAAwB;IAC3D,OAAO,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;AACzF,CAAC"}
1
+ {"version":3,"file":"command-spec.js","sourceRoot":"","sources":["../src/command-spec.ts"],"names":[],"mappings":"AACA,OAAO,EAA6C,SAAS,EAAE,MAAM,aAAa,CAAC;AACnF,OAAO,EAAoC,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAChF,OAAO,EAAE,SAAS,EAAmB,YAAY,EAAE,MAAM,YAAY,CAAC;AACtE,OAAO,EAAiB,QAAQ,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AA0BvC,SAAS,UAAU,CAAC,OAAgB;IAClC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QACtB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;IAC3D,CAAC;IACD,OAAO;QACL,OAAO,EAAE,OAAO,CAAC,OAAO,KAAK,SAAS;QACtC,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,IAAI,EAAE,OAAO,CAAC,IAAI,KAAK,SAAS;KACjC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,WAAmB,EAAE,OAAgB;IAC/D,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7E,OAAO;QACL,IAAI,EAAE,SAAS;QACf,WAAW;QACX,OAAO;QACP,WAAW,EAAE,OAAO,CAAC,WAAW;QAChC,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,IAAI,EAAE,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC;QAC7B,OAAO,EAAE,YAAY,CAAC,OAAO,CAAC,OAAO,CAAC;QACtC,aAAa,EAAE,gBAAgB,CAAC,OAAO,CAAC,MAAM,EAAE,UAAU,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC;QAC1E,IAAI;QACJ,MAAM,EAAE,IAAI,EAAE,MAAM,IAAI,OAAO,CAAC,MAAM;KACvC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,WAAmB,EAAE,QAAkB;IAC/D,OAAO;QACL,IAAI,EAAE,OAAO;QACb,WAAW;QACX,QAAQ,EAAE,MAAM,CAAC,WAAW,CAC1B,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,MAAM,CAAC,GAAG,WAAW,IAAI,GAAG,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC,CAC5F;KACF,CAAC;AACJ,CAAC;AAED,SAAS,MAAM,CAAC,WAAmB,EAAE,IAAwB;IAC3D,OAAO,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;AACzF,CAAC"}
package/dist/confirm.d.ts CHANGED
@@ -1,4 +1,6 @@
1
1
  import { type Invocation } from "./invocation.js";
2
+ export declare const CONFIRMATION_REQUIRED = "CONFIRMATION_REQUIRED";
3
+ export declare const CONFIRMATION_MISMATCH = "CONFIRMATION_MISMATCH";
2
4
  export interface Confirmation {
3
5
  readonly invocation: Invocation;
4
6
  readonly commandLine: string;
package/dist/confirm.js CHANGED
@@ -1,6 +1,8 @@
1
1
  import { UsageError } from "./errors.js";
2
2
  import { CONFIRM_FLAG } from "./flags.js";
3
3
  import { commandLineWith } from "./invocation.js";
4
+ export const CONFIRMATION_REQUIRED = "CONFIRMATION_REQUIRED";
5
+ export const CONFIRMATION_MISMATCH = "CONFIRMATION_MISMATCH";
4
6
  export function checkConfirmation({ invocation, commandLine, given }, expected) {
5
7
  if (given === expected) {
6
8
  return;
@@ -8,13 +10,13 @@ export function checkConfirmation({ invocation, commandLine, given }, expected)
8
10
  const hint = `to confirm, run \`${commandLineWith(invocation, CONFIRM_FLAG.flag, expected)}\``;
9
11
  if (given === undefined) {
10
12
  throw new UsageError({
11
- code: "CONFIRMATION_REQUIRED",
13
+ code: CONFIRMATION_REQUIRED,
12
14
  message: `\`${commandLine}\` is destructive and needs ${CONFIRM_FLAG.flag}`,
13
15
  hint,
14
16
  });
15
17
  }
16
18
  throw new UsageError({
17
- code: "CONFIRMATION_MISMATCH",
19
+ code: CONFIRMATION_MISMATCH,
18
20
  message: `${CONFIRM_FLAG.flag} ${JSON.stringify(given)} does not match the target of \`${commandLine}\``,
19
21
  hint,
20
22
  });
@@ -1 +1 @@
1
- {"version":3,"file":"confirm.js","sourceRoot":"","sources":["../src/confirm.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,eAAe,EAAmB,MAAM,iBAAiB,CAAC;AAQnE,MAAM,UAAU,iBAAiB,CAC/B,EAAE,UAAU,EAAE,WAAW,EAAE,KAAK,EAAgB,EAChD,QAAgB;IAEhB,IAAI,KAAK,KAAK,QAAQ,EAAE,CAAC;QACvB,OAAO;IACT,CAAC;IACD,MAAM,IAAI,GAAG,qBAAqB,eAAe,CAAC,UAAU,EAAE,YAAY,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC;IAC/F,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,MAAM,IAAI,UAAU,CAAC;YACnB,IAAI,EAAE,uBAAuB;YAC7B,OAAO,EAAE,KAAK,WAAW,+BAA+B,YAAY,CAAC,IAAI,EAAE;YAC3E,IAAI;SACL,CAAC,CAAC;IACL,CAAC;IACD,MAAM,IAAI,UAAU,CAAC;QACnB,IAAI,EAAE,uBAAuB;QAC7B,OAAO,EAAE,GAAG,YAAY,CAAC,IAAI,IAAI,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,mCAAmC,WAAW,IAAI;QACxG,IAAI;KACL,CAAC,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"confirm.js","sourceRoot":"","sources":["../src/confirm.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,eAAe,EAAmB,MAAM,iBAAiB,CAAC;AAEnE,MAAM,CAAC,MAAM,qBAAqB,GAAG,uBAAuB,CAAC;AAC7D,MAAM,CAAC,MAAM,qBAAqB,GAAG,uBAAuB,CAAC;AAQ7D,MAAM,UAAU,iBAAiB,CAC/B,EAAE,UAAU,EAAE,WAAW,EAAE,KAAK,EAAgB,EAChD,QAAgB;IAEhB,IAAI,KAAK,KAAK,QAAQ,EAAE,CAAC;QACvB,OAAO;IACT,CAAC;IACD,MAAM,IAAI,GAAG,qBAAqB,eAAe,CAAC,UAAU,EAAE,YAAY,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC;IAC/F,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,MAAM,IAAI,UAAU,CAAC;YACnB,IAAI,EAAE,qBAAqB;YAC3B,OAAO,EAAE,KAAK,WAAW,+BAA+B,YAAY,CAAC,IAAI,EAAE;YAC3E,IAAI;SACL,CAAC,CAAC;IACL,CAAC;IACD,MAAM,IAAI,UAAU,CAAC;QACnB,IAAI,EAAE,qBAAqB;QAC3B,OAAO,EAAE,GAAG,YAAY,CAAC,IAAI,IAAI,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,mCAAmC,WAAW,IAAI;QACxG,IAAI;KACL,CAAC,CAAC;AACL,CAAC"}
package/dist/cost.d.ts ADDED
@@ -0,0 +1,9 @@
1
+ import { type Invocation } from "./invocation.js";
2
+ export declare const NOT_CONFIRMED = "NOT_CONFIRMED";
3
+ export interface Approval {
4
+ readonly invocation: Invocation;
5
+ readonly commandLine: string;
6
+ readonly yes: boolean;
7
+ }
8
+ /** Refuses a run whose Plan states a cost the caller has not approved with `--yes`. */
9
+ export declare function checkCost({ invocation, commandLine, yes }: Approval, cost: string | undefined): void;
package/dist/cost.js ADDED
@@ -0,0 +1,16 @@
1
+ import { CliError } from "./errors.js";
2
+ import { YES_FLAG } from "./flags.js";
3
+ import { commandLineWith } from "./invocation.js";
4
+ export const NOT_CONFIRMED = "NOT_CONFIRMED";
5
+ /** Refuses a run whose Plan states a cost the caller has not approved with `--yes`. */
6
+ export function checkCost({ invocation, commandLine, yes }, cost) {
7
+ if (cost === undefined || yes) {
8
+ return;
9
+ }
10
+ throw new CliError({
11
+ code: NOT_CONFIRMED,
12
+ message: `\`${commandLine}\` needs ${YES_FLAG.flag}: ${cost}`,
13
+ hint: `to approve the cost, run \`${commandLineWith(invocation, YES_FLAG.flag)}\``,
14
+ });
15
+ }
16
+ //# sourceMappingURL=cost.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cost.js","sourceRoot":"","sources":["../src/cost.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,eAAe,EAAmB,MAAM,iBAAiB,CAAC;AAEnE,MAAM,CAAC,MAAM,aAAa,GAAG,eAAe,CAAC;AAQ7C,uFAAuF;AACvF,MAAM,UAAU,SAAS,CACvB,EAAE,UAAU,EAAE,WAAW,EAAE,GAAG,EAAY,EAC1C,IAAwB;IAExB,IAAI,IAAI,KAAK,SAAS,IAAI,GAAG,EAAE,CAAC;QAC9B,OAAO;IACT,CAAC;IACD,MAAM,IAAI,QAAQ,CAAC;QACjB,IAAI,EAAE,aAAa;QACnB,OAAO,EAAE,KAAK,WAAW,YAAY,QAAQ,CAAC,IAAI,KAAK,IAAI,EAAE;QAC7D,IAAI,EAAE,8BAA8B,eAAe,CAAC,UAAU,EAAE,QAAQ,CAAC,IAAI,CAAC,IAAI;KACnF,CAAC,CAAC;AACL,CAAC"}