@duyquangnvx/agent-cli 0.4.0 → 0.6.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 (161) hide show
  1. package/CHANGELOG.md +80 -0
  2. package/dist/agent-cli.js +2 -2
  3. package/dist/agent-cli.js.map +1 -1
  4. package/dist/agent.d.ts +5 -3
  5. package/dist/agent.js +31 -10
  6. package/dist/agent.js.map +1 -1
  7. package/dist/built-ins/commands.d.ts +8 -0
  8. package/dist/{built-ins.js → built-ins/commands.js} +4 -4
  9. package/dist/built-ins/commands.js.map +1 -0
  10. package/dist/built-ins/doctor-rows.d.ts +4 -0
  11. package/dist/{doctor-rows.js → built-ins/doctor-rows.js} +18 -26
  12. package/dist/built-ins/doctor-rows.js.map +1 -0
  13. package/dist/built-ins/doctor.d.ts +5 -0
  14. package/dist/{doctor.js → built-ins/doctor.js} +27 -20
  15. package/dist/built-ins/doctor.js.map +1 -0
  16. package/dist/{global-install.js → built-ins/global-install.js} +1 -1
  17. package/dist/built-ins/global-install.js.map +1 -0
  18. package/dist/{npm.d.ts → built-ins/npm.d.ts} +5 -2
  19. package/dist/{npm.js → built-ins/npm.js} +25 -33
  20. package/dist/built-ins/npm.js.map +1 -0
  21. package/dist/built-ins/semver.js.map +1 -0
  22. package/dist/built-ins/skills.d.ts +18 -0
  23. package/dist/built-ins/skills.js +97 -0
  24. package/dist/built-ins/skills.js.map +1 -0
  25. package/dist/{update.d.ts → built-ins/update.d.ts} +3 -2
  26. package/dist/{update.js → built-ins/update.js} +28 -18
  27. package/dist/built-ins/update.js.map +1 -0
  28. package/dist/{upgrade-notes.js → built-ins/upgrade-notes.js} +1 -1
  29. package/dist/built-ins/upgrade-notes.js.map +1 -0
  30. package/dist/clock.d.ts +1 -0
  31. package/dist/clock.js.map +1 -1
  32. package/dist/command-spec.d.ts +17 -2
  33. package/dist/command-spec.js +30 -9
  34. package/dist/command-spec.js.map +1 -1
  35. package/dist/confirm.js +6 -2
  36. package/dist/confirm.js.map +1 -1
  37. package/dist/context.d.ts +139 -0
  38. package/dist/context.js +2 -0
  39. package/dist/context.js.map +1 -0
  40. package/dist/cost.js +2 -2
  41. package/dist/cost.js.map +1 -1
  42. package/dist/define.d.ts +100 -87
  43. package/dist/define.js +3 -1
  44. package/dist/define.js.map +1 -1
  45. package/dist/errno.d.ts +8 -4
  46. package/dist/errno.js +21 -4
  47. package/dist/errno.js.map +1 -1
  48. package/dist/error-table.d.ts +6 -1
  49. package/dist/error-table.js +5 -1
  50. package/dist/error-table.js.map +1 -1
  51. package/dist/errors.d.ts +11 -2
  52. package/dist/errors.js +21 -8
  53. package/dist/errors.js.map +1 -1
  54. package/dist/execute.d.ts +9 -2
  55. package/dist/execute.js +10 -3
  56. package/dist/execute.js.map +1 -1
  57. package/dist/exit-classes.js +38 -38
  58. package/dist/exit-classes.js.map +1 -1
  59. package/dist/files.d.ts +30 -8
  60. package/dist/files.js +104 -17
  61. package/dist/files.js.map +1 -1
  62. package/dist/help-json.d.ts +2 -2
  63. package/dist/help-json.js +6 -2
  64. package/dist/help-json.js.map +1 -1
  65. package/dist/help.d.ts +1 -1
  66. package/dist/help.js +14 -9
  67. package/dist/help.js.map +1 -1
  68. package/dist/index.d.ts +12 -5
  69. package/dist/index.js +6 -2
  70. package/dist/index.js.map +1 -1
  71. package/dist/input.d.ts +7 -1
  72. package/dist/input.js +33 -4
  73. package/dist/input.js.map +1 -1
  74. package/dist/interrupts.d.ts +7 -2
  75. package/dist/interrupts.js +29 -15
  76. package/dist/interrupts.js.map +1 -1
  77. package/dist/invocation.d.ts +10 -5
  78. package/dist/invocation.js +24 -11
  79. package/dist/invocation.js.map +1 -1
  80. package/dist/list.d.ts +12 -3
  81. package/dist/list.js +38 -6
  82. package/dist/list.js.map +1 -1
  83. package/dist/manifest.d.ts +17 -0
  84. package/dist/manifest.js +24 -0
  85. package/dist/manifest.js.map +1 -0
  86. package/dist/operator.d.ts +5 -0
  87. package/dist/operator.js +15 -0
  88. package/dist/operator.js.map +1 -0
  89. package/dist/output.d.ts +6 -4
  90. package/dist/output.js +5 -6
  91. package/dist/output.js.map +1 -1
  92. package/dist/outputs.d.ts +24 -1
  93. package/dist/outputs.js +58 -2
  94. package/dist/outputs.js.map +1 -1
  95. package/dist/parse-input.d.ts +11 -2
  96. package/dist/parse-input.js +78 -27
  97. package/dist/parse-input.js.map +1 -1
  98. package/dist/project.d.ts +3 -2
  99. package/dist/project.js +11 -10
  100. package/dist/project.js.map +1 -1
  101. package/dist/route.d.ts +1 -1
  102. package/dist/route.js +2 -1
  103. package/dist/route.js.map +1 -1
  104. package/dist/run-cli.d.ts +8 -33
  105. package/dist/run-cli.js +50 -157
  106. package/dist/run-cli.js.map +1 -1
  107. package/dist/run-command.d.ts +11 -0
  108. package/dist/run-command.js +234 -0
  109. package/dist/run-command.js.map +1 -0
  110. package/dist/run-options.d.ts +48 -0
  111. package/dist/run-options.js +2 -0
  112. package/dist/run-options.js.map +1 -0
  113. package/dist/run-process.js +7 -4
  114. package/dist/run-process.js.map +1 -1
  115. package/dist/secrets.d.ts +10 -6
  116. package/dist/secrets.js +8 -9
  117. package/dist/secrets.js.map +1 -1
  118. package/dist/side-task.d.ts +27 -0
  119. package/dist/side-task.js +31 -0
  120. package/dist/side-task.js.map +1 -0
  121. package/dist/spawn.d.ts +29 -6
  122. package/dist/spawn.js +126 -29
  123. package/dist/spawn.js.map +1 -1
  124. package/dist/spill.d.ts +4 -3
  125. package/dist/spill.js +1 -7
  126. package/dist/spill.js.map +1 -1
  127. package/dist/stdin.d.ts +33 -0
  128. package/dist/stdin.js +92 -0
  129. package/dist/stdin.js.map +1 -0
  130. package/dist/style.d.ts +1 -1
  131. package/dist/tokenize.d.ts +3 -0
  132. package/dist/tokenize.js +5 -4
  133. package/dist/tokenize.js.map +1 -1
  134. package/dist/tools.d.ts +6 -3
  135. package/dist/tools.js +18 -11
  136. package/dist/tools.js.map +1 -1
  137. package/dist/usage.d.ts +2 -0
  138. package/dist/usage.js +12 -1
  139. package/dist/usage.js.map +1 -1
  140. package/dist/version.d.ts +3 -0
  141. package/dist/version.js +7 -0
  142. package/dist/version.js.map +1 -0
  143. package/package.json +1 -1
  144. package/dist/built-ins.d.ts +0 -3
  145. package/dist/built-ins.js.map +0 -1
  146. package/dist/doctor-rows.d.ts +0 -3
  147. package/dist/doctor-rows.js.map +0 -1
  148. package/dist/doctor.d.ts +0 -4
  149. package/dist/doctor.js.map +0 -1
  150. package/dist/global-install.js.map +0 -1
  151. package/dist/npm.js.map +0 -1
  152. package/dist/semver.js.map +0 -1
  153. package/dist/skills.d.ts +0 -11
  154. package/dist/skills.js +0 -58
  155. package/dist/skills.js.map +0 -1
  156. package/dist/update.js.map +0 -1
  157. package/dist/upgrade-notes.js.map +0 -1
  158. /package/dist/{global-install.d.ts → built-ins/global-install.d.ts} +0 -0
  159. /package/dist/{semver.d.ts → built-ins/semver.d.ts} +0 -0
  160. /package/dist/{semver.js → built-ins/semver.js} +0 -0
  161. /package/dist/{upgrade-notes.d.ts → built-ins/upgrade-notes.d.ts} +0 -0
package/CHANGELOG.md CHANGED
@@ -4,6 +4,86 @@ What changed in each release of `@duyquangnvx/agent-cli` (the Runtime) and `@duy
4
4
 
5
5
  ## Unreleased
6
6
 
7
+ ## v0.6.0 (2026-10-20)
8
+
9
+ ### Changed
10
+
11
+ - **Breaking:** `defineCli` requires `description`, one line that root help and root `--help --json` print; for a single-Command CLI it replaces the Command's own line at the root. The scaffolded template passes its package.json `description`, which `--description` sets.
12
+ - **Breaking:** `Context` requires `timeout` and `PortsBase` requires `envFile` (see Added), so a `ctx` or `PortsBase` built by hand, such as a test's fake, stops type-checking until it has them.
13
+ - **Breaking:** an `orStdin` arg read from a pipe that sends nothing for 30 s fails the run with the new code `STDIN_STALLED` (exit 1) instead of waiting forever; a terminal is never bounded. See the exports `STDIN_STALLED` and `STDIN_IDLE_MS`.
14
+ - **Breaking:** text that opens with `-` and holds whitespace, such as `"- a red apple"`, given to a Command whose `orStdin` arg is left out, fails with `UNKNOWN_OPTION` instead of `INVALID_INPUT` (still exit 1), its hint naming the command line that sends the text through a heredoc.
15
+ - **Breaking:** `--cursor` is an opaque string, and a List Command's `run` receives `cursor` as a string. `paginate` still pages a list held in memory and refuses a cursor it never gave as a usage error.
16
+ - The agent-cli skill keeps in `SKILL.md` what every Command needs, ending on the list a finished Command meets, and moves long runs, ports, `doctor` rows and testing into `references/`. Its description now triggers on starting any CLI.
17
+ - The agent-cli skill points at the Runtime's types for its API reference: the JSDoc on its exports, shipped in `dist/index.d.ts`, now carries the contracts the skill used to list (exit codes, defaults, what `--dry-run` shows), and the skill keeps only what a type cannot show.
18
+
19
+ ### Added
20
+
21
+ - A new CLI's skill installs its CLI: the Scaffolder writes `references/setup.md` beside the skill, which walks the agent through installing, checking and updating the CLI, and the README gives the skill's install line, then the CLI's. The new CLI's test fails when those lines differ from what `doctor` gives. `--repository <url>` sets package.json `repository`, where the skill is installed from.
22
+ - `ctx.timeout(ms)` bounds a call that Ctrl-C must not cut short, such as a billed call inside `ctx.runToEnd`; see `Context.timeout`. The agent-cli skill's remote-services reference uses it.
23
+ - `defineCli({ sideTask })` runs a Side task, such as a usage count, beside each Command run, without changing its output or exit code; see `Cli.sideTask`, `SideTaskRun` and `SIDE_TASK_WAIT_MS`. The agent-cli skill's example counts its runs with one.
24
+ - `PortsBase.envFile`, and so `ctx.envFile`: the `.env` path `ctx.secret` reads, for a missing-key hint or a `doctor` row to name.
25
+ - `ctx.files.mkdir(path, { mode })` sets the mode of each folder it creates; see `MkdirOptions.mode`.
26
+ - The hint of an `INTERNAL` error (exit 70) names package.json `bugs`, a URL or `{ url }`, as where to report it.
27
+ - `page(items, next)` returns a page whose source pages itself, such as a remote API: `next` is the source's own cursor, which the Runtime puts in the page's `next` command line.
28
+ - The agent-cli skill covers what the Runtime leaves to a CLI: remote services (classifying failures, polite retries, requests that start a job or bill, paid calls, SDK and LLM calls), shipping (install lines, release, the CLI's own skill, an `AGENTS.md` block), a daemon or store that outlives a run, and queues and progress in long runs.
29
+ - The agent-cli skill teaches the agent-first rules the Runtime leaves to a CLI: data carries names beside ids and absolute paths, reads and changes sit under distinct leading words for permission rules, a write Command is safe to run again, long jobs split into a start and a `--wait` check, and a CLI is evaluated on real agent transcripts. Its example's `export` and `bundle` return absolute paths.
30
+
31
+ ### Fixed
32
+
33
+ - `doctor`'s `skill` row installs a GitHub `owner/repo` shorthand `repository` from its `release` branch (`owner/repo#release`), as it does every other source, instead of from the default branch, which may describe what is still unreleased. It also reads npm's `github:owner/repo` and `gitlab:group/repo` shorthands, which gave no fix before.
34
+ - **Breaking:** an `AggregateError` held inside another exits by the first Exit class among its leaves, each printed with its hint, instead of exit 70. An empty one is still reported as itself.
35
+ - **Breaking:** a Project file that cannot be read fails with `PERMISSION_DENIED` (exit 2), and a folder in its place with `NOT_A_FILE` (exit 1), instead of exit 70; `doctor` reports either in its `project` row.
36
+ - **Breaking:** once `ctx.deadline` fires, only an error that is not a `CliError` and holds the deadline's abort in its `cause` chain becomes `DEADLINE_EXCEEDED`, instead of every error that is not a `CliError`: a wrapper that drops the abort now exits 70, not 75, and a `CliError` keeps its own code. See `Context.deadline`. The agent-cli skill teaches keeping the abort as `cause`.
37
+ - `doctor`'s `skill` row fixes a copy with no `metadata.version` with `npx -y skills add <source> --skill <name> -g` when the source is known, since `skills update` skips copies it did not install, and with `skills update` then that line when another copy is older than the CLI. Without a source it still suggests `skills update`.
38
+ - `update`'s `next` gives the fix `doctor`'s `skill` row would, against the version it installed, instead of always `npx -y skills update <name>`: `skills add <source>` for a missing copy or one with no `metadata.version`, nothing for a copy already newer. With nothing to install, `next` fixes copies older than the latest release instead of staying empty, and the text output prints it.
39
+ - `doctor`'s `skill` row gives no fix for a copy newer than the build, instead of `<cli> update`, which a CLI without `install` lacks; the `registry` row still says when the build is older than the latest release.
40
+
41
+ ## v0.5.0 (2026-10-19)
42
+
43
+ ### Added
44
+
45
+ - A command-tree CLI may declare `defineCli({ tools })`, the tools `doctor` checks besides its Commands' own. `doctor` reports one row per tool from the CLI's `tools` and every Command's, once per name, a missing one as a problem with its `install` as the fix. A Command still requires only its own `tools`, so the CLI's list never makes a Command refuse with `TOOL_MISSING`.
46
+ - A Command may declare `hidden: true`. It routes and runs when named, and its own `--help` works, but it is left out of text help, `--help --json`, the root examples and "did you mean" suggestions for a misspelt Command.
47
+ - A Command may declare `operator: true`, an Operator Command only a person at a terminal runs. When a Coding agent is detected, the run fails before its input is read, stdin included, with the new Runtime code `NEEDS_OPERATOR` (exit 2, exported as a constant), whose hint is `ask the operator to type: ! <command line as typed>`; `--json` alone does not refuse. Text help marks it `(operator only)` in a listing and with an `Operator Command:` line in its own help, and `--help --json` carries `operator` on every Command, `true` on an Operator Command and `false` on the rest.
48
+ - A Command may declare `help`, a paragraph printed as written after the options in text help. `--help --json` carries it as `help`, which is `null` on a Command without one.
49
+ - `ctx.spawn(command, args, { progress: true })` passes each line of the child's stdout and stderr through `ctx.progress` as it arrives, and still resolves to the whole output, which `check: true` uses for `TOOL_FAILED`. A `Spawn` passed as `runCli`'s `spawn` option receives an `onLine` callback when the caller asked for progress, to emit the child's lines.
50
+ - On Windows, `ctx.spawn` runs a `.cmd` or `.bat` tool, such as one npm installed, found on `PATH` through `PATHEXT` or given by its path. Each argument reaches the tool as given: it is quoted, then escaped for `cmd.exe`, which otherwise expands `%VAR%` and acts on `&`, `|`, `<`, `>`, `^`, `(`, `)` and `!` even inside quotes, twice for a `.cmd` shim that hands its arguments to a second `cmd.exe` parse, as cross-spawn does.
51
+ - A field of a Command's `options` may be a `z.array(...)`, optionally wrapped in optional or default, which collects every occurrence of its flag in order: `--ref a --ref=b --ref c` gives `ref: ["a", "b", "c"]`. Each value is coerced like a scalar option of the element's type, and an issue on one names it, as in `--row "x": ...`. None gives an empty array for the schema to judge, or leaves an optional field out so its default applies. Text help shows the flag as `--ref <value>...`, and `--help --json` gives it the array schema. `defineCommand` throws for an array of booleans. A repeated scalar flag still keeps its last value.
52
+ - `ctx.commandLine({ add?, remove? })` returns the command line as the caller typed it, starting with the CLI's name and shell-quoted, with each flag in `remove` dropped along with its value (`--from 3`, `--from=3`, every time it was given) and the words in `add` placed before any `--`, for a hint naming the exact command to run next. It is the helper the Runtime's own hints (`--confirm`, `--yes`, `--force`, a page's `next`) are built with.
53
+ - A run deadline's `resume(input, commandLine)` receives `ctx.commandLine` as its second argument. A `resume` taking only `input` still type-checks.
54
+ - `ctx.poll(check, { intervalMs, signal })` also stops when `signal` aborts, ending with its reason, so `signal: ctx.deadline(ms)` stops polling at a `--wait` deadline rather than one interval after it.
55
+ - `INTERRUPTED` and `DEADLINE_EXCEEDED` are exported as constants, so a Command tells `ctx.signal.reason` apart and throws its own `INTERRUPTED` with a hint it computes, which wins over the Runtime's. The skill teaches it.
56
+ - A `doctor` row may return `{ state: "skipped", message }` for a check it did not run, such as "not checked: the bridge is down". It shows in text and `--json` and never fails `doctor`.
57
+ - On Ctrl-C or SIGTERM, `doctor` prints the rows finished so far, in text or `--json`, before the run ends with 130 or 143. Rows cut short are left out.
58
+ - With no copy of the skill installed, `doctor`'s `skill` row gives the fix `npx -y skills add <source> --skill <cli name> -g`, which installs only this CLI's skill from a repo holding several, and stays ok. The source is `defineCli({ skill: { source } })` as given, else the package.json `repository` URL with `git+` dropped, `.git` added if missing and `#release` appended, for an `https`, `http`, `ssh` or `git` URL or an scp-style `git@host:group/repo`; a GitHub `owner/repo` shorthand is kept as it is. With no `repository`, one that is neither, or a package.json that cannot be read or parsed, the row gives no fix.
59
+ - `orStdin(schema)` marks one string field of a Command's `args` as also reading stdin: when its operand is exactly `-`, the Runtime reads stdin to its end as UTF-8, before `plan`, `run` or `start`, and the field's schema judges the text, so an empty or invalid text fails with `INVALID_INPUT` like typed text, the issue naming the field `from stdin` instead of quoting the text. Ctrl-C and the run deadline stop a read that never ends; a deadline hit there hints to pipe the text in. When stdin is a terminal, a progress line first says what is read and how to end it (Ctrl-D, or Ctrl-Z then Enter on Windows). Text help shows the field as `<name|->` (`[name|-]` when optional), and `--help --json` marks it `"stdin": true`. `defineCommand` throws for two such args, or for the marker on an option. `runCli` takes `stdin`, a string or a readable stream, read by a `-`; absent, a `-` reads an empty text. The type `StdinSource` is exported.
60
+ - The ports factory's `PortsBase` adds `progress`, `fileError`, `version`, `build` and `self`, which `Context` carries too: a bridge or store writes progress lines (JSON Lines under `--json`) and classifies a failure of its own file as a Command does. `version` and `build` are the CLI's version and bundler stamp as `--version` prints them, `build` absent when unbundled. `self` is the command line that reruns the CLI, `[process.execPath, ...process.execArgv, bin]` from `runCli`'s `bin`, or `[name]`, found on `PATH`, without one, for spawning a hidden Command. The type `BuildStamp` is exported.
61
+ - `ctx.fileError(error, { path, access })` turns an errno failure of a Command's own file access, such as a SQLite store or a log it opens itself, into the Runtime's classified error, with the same codes and hints as `ctx.files`; any other error comes back unchanged. The type `FileAccess` is exported.
62
+ - The Runtime code `NOT_A_FILE` (exit 1), raised for EISDIR, such as `ctx.files.read` of a folder, naming the path. It is exported as a constant.
63
+ - `runCli` takes a `platform` option, which replaces `process.platform` in picking the wording of hints, the `PERMISSION_DENIED` hint and how to end stdin, so a test checks the Windows wording on any OS.
64
+ - `ctx.files.write(path, data, { exclusive, mode })`: `exclusive: true` fails with `ALREADY_EXISTS` when anything is at the path, never leaving half a file there, and `mode` sets the file's permission bits whatever mode an older file had. The type `WriteOptions` is exported.
65
+ - `ctx.files.stat(path)` returns `{ size, id }`, where `id` is the same for every link to one file (device and inode), or `undefined` when nothing is at the path or a part of it is a file. The type `FileStat` is exported.
66
+ - The agent-cli skill's example `links` has `import <text|->`, which saves every link found in a text, read from stdin when given `-`, tags each with every repeated `--tag`, and explains its stdin form in a `help` paragraph. The scaffolded template's `card` takes an optional message to write under the greeting, read from stdin when given `-`, signs the card from every repeated `--from`, and states its cost in a `help` paragraph; its tests cover each.
67
+
68
+ ### Changed
69
+
70
+ - **Breaking:** `DoctorFinding` is a union over `state`: `ok` (`message`, `fix?`), `problem` (`message`, `fix?`, `code?`) and `skipped` (`message`). A row that throws a `CliError` keeps its code, and `doctor --json` rows carry `code`.
71
+ - **Breaking:** `doctor` fails with one error per non-advisory problem row, with the row's code or `DOCTOR_PROBLEMS` without one, so it exits by the first of 1, 2, 3 and 75 that any of them has, not always 2: an expired session exits 3, a network failure 75. Each error's message is `<cli> doctor found a problem in <row>: <message>`. The report still prints on stdout.
72
+ - **Breaking:** the `Files` interface gains `stat`, and its `write` receives the write options, so every fake passed as `runCli`'s `files` option must implement `stat`. The scaffolded template's fake and the skill's example implement it.
73
+ - **Breaking:** more errno are classified, naming the path: EROFS and EBUSY fail with `PERMISSION_DENIED` (exit 2, with the sandbox hint under a Coding agent), EDQUOT with `DISK_FULL` (exit 2), and ENOTDIR and ENAMETOOLONG with `NOT_FOUND` (exit 1). Each was exit 70 before, so a write Claude Code's Linux sandbox denies with EROFS no longer reads as a bug.
74
+ - **Breaking:** for a Command with `outputs`, after every guard passes and before `apply`, the Runtime creates each output's folder and a temp file in it, so a denied folder fails with `PERMISSION_DENIED` naming the folder before `apply` runs; `--dry-run` and a refused guard create nothing. Without `--force`, the first write to each output during `apply`, through `ctx.files` or a port's `files`, is exclusive: it fails with `ALREADY_EXISTS`, whose hint names the command line with `--force`, if the file appeared meanwhile. A later write to an output the run already wrote replaces it; with `--force` every write replaces.
75
+ - **Breaking:** agent detection follows gh's marker list: `AI_AGENT` (an agent name), `AGENT=amp`, `CODEX_SANDBOX`, `CODEX_CI`, `CODEX_THREAD_ID`, `GEMINI_CLI`, `COPILOT_CLI`, `OPENCODE`, `ANTIGRAVITY_AGENT`, `AUGMENT_AGENT`, `REPL_ID`, `CLAUDE_CODE_IS_COWORK`, `CLAUDECODE`, `CLAUDE_CODE`, `CURSOR_TRACE_ID`, `CURSOR_AGENT`, `CURSOR_EXTENSION_HOST_ROLE=agent-exec`, `TERM_PROGRAM=kiro`, a `.pi/agent` folder on `PATH`, or `GOOSE_PROVIDER`. A marker set to an empty string no longer counts, and `CI` alone no longer counts as an agent, so a usage error in a CI job prints the error and hint without the full help, and a CI job on a TTY gets colour.
76
+ - **Breaking:** under `--json`, stderr is JSON Lines (ADR 0006): each `ctx.progress(message)` writes `{"progress":"<message>"}` as it happens, the Runtime's own progress lines (`finishing <name>`, the `stopping… (Ctrl-C again to quit now)` notice, the stdin announcement) and a spawned child's lines under `progress: true` are written the same way, and a failure's `{"errors":[…]}` stays the last line, so every stderr line parses as JSON. Without `--json`, progress stays plain text. The agent-cli skill and the scaffolded skill say so.
77
+ - On Windows, the `PERMISSION_DENIED` hint says a program may hold the path open, and to close it, then run the same command again.
78
+ - `ctx.files.write` through a symlink replaces the link's target and keeps the link.
79
+ - On Windows, a replacing `ctx.files.write` retries a transient EPERM or EBUSY, such as an antivirus scan holding the file, for about half a second before failing with `PERMISSION_DENIED`.
80
+ - `doctor` and `update` run the npm beside the Node running the CLI (`npm`, or `npm.cmd` on Windows), with that Node first on its `PATH`, so under nvm they install into that Node; with no npm beside it, they run the npm on `PATH` as before. `runCli` gains the option `node`, the path `runProcess` passes as `process.execPath`; absent, npm comes from `PATH`.
81
+
82
+ ### Fixed
83
+
84
+ - On Windows, an interrupt kills the child `ctx.spawn` started, or the npm `doctor` and `update` run, together with every process it started (`taskkill /T /F`), so Ctrl-C leaves no orphaned processes.
85
+ - `ctx.files.exists` answers false for a path under a file instead of failing.
86
+
7
87
  ## v0.4.0 (2026-10-19)
8
88
 
9
89
  ### Added
package/dist/agent-cli.js CHANGED
@@ -1,4 +1,4 @@
1
- import { builtInCommands } from "./built-ins.js";
1
+ import { builtInCommands } from "./built-ins/commands.js";
2
2
  import { defineCommandFor, } from "./define.js";
3
3
  import { runtimeCodesIn } from "./exit-classes.js";
4
4
  function checkOwnCodes(cli) {
@@ -12,7 +12,7 @@ function defineCli(cli) {
12
12
  if (cli.commands === undefined)
13
13
  return cli;
14
14
  const { commands } = cli;
15
- const taken = Object.keys(builtInCommands(cli, undefined)).filter((name) => commands[name] !== undefined);
15
+ const taken = Object.keys(builtInCommands(cli, { bin: undefined, node: undefined })).filter((name) => commands[name] !== undefined);
16
16
  if (taken.length > 0) {
17
17
  throw new Error(`${cli.name} defines ${taken.join(", ")}, a built-in Command it cannot replace`);
18
18
  }
@@ -1 +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"}
1
+ {"version":3,"file":"agent-cli.js","sourceRoot":"","sources":["../src/agent-cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,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,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,MAAM,CACzF,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"}
package/dist/agent.d.ts CHANGED
@@ -1,4 +1,6 @@
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. */
1
+ import type { Env } from "./context.js";
2
+ /**
3
+ * Whether a Coding agent, not a person, is running the Agent CLI. Some Coding agents run commands
4
+ * in a PTY, so a TTY alone doesn't mean a person is watching.
5
+ */
4
6
  export declare function isAgent(env: Env): boolean;
package/dist/agent.js CHANGED
@@ -1,14 +1,35 @@
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",
1
+ const AGENT_NAME = /^[a-zA-Z0-9_-]+$/u;
2
+ const isSet = (name) => (env) => (env[name] ?? "") !== "";
3
+ const equals = (name, value) => (env) => env[name] === value;
4
+ // Copied in order from gh, which keeps it current as agents appear:
5
+ // https://github.com/cli/cli/blob/17142e08db2e300b37e6da1ddcfb651eb6d9c587/internal/agents/detect.go
6
+ const MARKERS = [
7
+ (env) => AGENT_NAME.test(env.AI_AGENT ?? ""),
8
+ equals("AGENT", "amp"),
9
+ isSet("CODEX_SANDBOX"),
10
+ isSet("CODEX_CI"),
11
+ isSet("CODEX_THREAD_ID"),
12
+ isSet("GEMINI_CLI"),
13
+ isSet("COPILOT_CLI"),
14
+ isSet("OPENCODE"),
15
+ isSet("ANTIGRAVITY_AGENT"),
16
+ isSet("AUGMENT_AGENT"),
17
+ isSet("REPL_ID"),
18
+ isSet("CLAUDE_CODE_IS_COWORK"),
19
+ isSet("CLAUDECODE"),
20
+ isSet("CLAUDE_CODE"),
21
+ isSet("CURSOR_TRACE_ID"),
22
+ isSet("CURSOR_AGENT"),
23
+ equals("CURSOR_EXTENSION_HOST_ROLE", "agent-exec"),
24
+ equals("TERM_PROGRAM", "kiro"),
25
+ (env) => ["/.pi/agent", "\\.pi\\agent"].some((dir) => (env.PATH ?? "").includes(dir)),
26
+ isSet("GOOSE_PROVIDER"),
9
27
  ];
10
- /** Whether a Coding agent, not a person, is running the Agent CLI. */
28
+ /**
29
+ * Whether a Coding agent, not a person, is running the Agent CLI. Some Coding agents run commands
30
+ * in a PTY, so a TTY alone doesn't mean a person is watching.
31
+ */
11
32
  export function isAgent(env) {
12
- return AGENT_VARIABLES.some((name) => env[name] !== undefined);
33
+ return MARKERS.some((marker) => marker(env));
13
34
  }
14
35
  //# sourceMappingURL=agent.js.map
package/dist/agent.js.map CHANGED
@@ -1 +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
+ {"version":3,"file":"agent.js","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,GAAG,mBAAmB,CAAC;AAEvC,MAAM,KAAK,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,CAAC,GAAQ,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,EAAE,CAAC;AACvE,MAAM,MAAM,GAAG,CAAC,IAAY,EAAE,KAAa,EAAE,EAAE,CAAC,CAAC,GAAQ,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,KAAK,CAAC;AAElF,oEAAoE;AACpE,qGAAqG;AACrG,MAAM,OAAO,GAAuC;IAClD,CAAC,GAAG,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,IAAI,EAAE,CAAC;IAC5C,MAAM,CAAC,OAAO,EAAE,KAAK,CAAC;IACtB,KAAK,CAAC,eAAe,CAAC;IACtB,KAAK,CAAC,UAAU,CAAC;IACjB,KAAK,CAAC,iBAAiB,CAAC;IACxB,KAAK,CAAC,YAAY,CAAC;IACnB,KAAK,CAAC,aAAa,CAAC;IACpB,KAAK,CAAC,UAAU,CAAC;IACjB,KAAK,CAAC,mBAAmB,CAAC;IAC1B,KAAK,CAAC,eAAe,CAAC;IACtB,KAAK,CAAC,SAAS,CAAC;IAChB,KAAK,CAAC,uBAAuB,CAAC;IAC9B,KAAK,CAAC,YAAY,CAAC;IACnB,KAAK,CAAC,aAAa,CAAC;IACpB,KAAK,CAAC,iBAAiB,CAAC;IACxB,KAAK,CAAC,cAAc,CAAC;IACrB,MAAM,CAAC,4BAA4B,EAAE,YAAY,CAAC;IAClD,MAAM,CAAC,cAAc,EAAE,MAAM,CAAC;IAC9B,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,YAAY,EAAE,cAAc,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;IACrF,KAAK,CAAC,gBAAgB,CAAC;CACxB,CAAC;AAEF;;;GAGG;AACH,MAAM,UAAU,OAAO,CAAC,GAAQ;IAC9B,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;AAC/C,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { Commands, CommandTreeCli } from "../define.js";
2
+ /** How the CLI was started: the script, and the Node running it. */
3
+ export interface Launch {
4
+ readonly bin: string | undefined;
5
+ readonly node: string | undefined;
6
+ }
7
+ /** The Commands the Runtime adds to a multi-Command CLI: `update` only when it declares an install. */
8
+ export declare function builtInCommands(cli: CommandTreeCli, launch: Launch): Commands;
@@ -1,10 +1,10 @@
1
1
  import { doctorCommand } from "./doctor.js";
2
2
  import { updateCommand } from "./update.js";
3
3
  /** The Commands the Runtime adds to a multi-Command CLI: `update` only when it declares an install. */
4
- export function builtInCommands(cli, bin) {
4
+ export function builtInCommands(cli, launch) {
5
5
  return {
6
- doctor: doctorCommand(cli, bin),
7
- ...(cli.install === undefined ? {} : { update: updateCommand(cli, cli.install, bin) }),
6
+ doctor: doctorCommand(cli, launch),
7
+ ...(cli.install === undefined ? {} : { update: updateCommand(cli, cli.install, launch) }),
8
8
  };
9
9
  }
10
- //# sourceMappingURL=built-ins.js.map
10
+ //# sourceMappingURL=commands.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commands.js","sourceRoot":"","sources":["../../src/built-ins/commands.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAQ5C,uGAAuG;AACvG,MAAM,UAAU,eAAe,CAAC,GAAmB,EAAE,MAAc;IACjE,OAAO;QACL,MAAM,EAAE,aAAa,CAAC,GAAG,EAAE,MAAM,CAAC;QAClC,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,MAAM,CAAC,EAAE,CAAC;KAC1F,CAAC;AACJ,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { CommandTreeCli, DoctorCheck } from "../define.js";
2
+ import type { Launch } from "./commands.js";
3
+ /** Every row `doctor` reports, in order: the fixed rows around the CLI's own and its tools'. */
4
+ export declare function doctorChecks(cli: CommandTreeCli, launch: Launch): DoctorCheck[];
@@ -1,12 +1,12 @@
1
1
  import { join } from "node:path";
2
- import { CliError } from "./errors.js";
2
+ import { CliError } from "../errors.js";
3
+ import { PROJECT_INVALID, projectOf } from "../project.js";
4
+ import { toolRows } from "../tools.js";
5
+ import { versionLine } from "../version.js";
3
6
  import { globalInstallOf, NOT_GLOBAL_INSTALL } from "./global-install.js";
4
7
  import { installCommandLine, latestVersion, npmContext } from "./npm.js";
5
- import { versionLine } from "./output.js";
6
- import { PROJECT_INVALID, projectOf } from "./project.js";
7
8
  import { engineMinimum, meetsMinimum, standingOf } from "./semver.js";
8
- import { skillCopies, skillUpdateCommand } from "./skills.js";
9
- import { toolRows } from "./tools.js";
9
+ import { skillReport } from "./skills.js";
10
10
  function ok(message) {
11
11
  return { state: "ok", message };
12
12
  }
@@ -48,7 +48,7 @@ function projectRow(projectFile) {
48
48
  run: (ctx) => {
49
49
  let project;
50
50
  try {
51
- project = projectOf(projectFile, ctx.cwd);
51
+ project = projectOf(projectFile, ctx.cwd, ctx.fileError);
52
52
  }
53
53
  catch (error) {
54
54
  if (error instanceof CliError && error.code === PROJECT_INVALID) {
@@ -63,7 +63,7 @@ function projectRow(projectFile) {
63
63
  };
64
64
  }
65
65
  // A source run or an unreachable registry never stops a Command working, so these two rows are advisory.
66
- function installRow(cli, bin) {
66
+ function installRow(cli, { bin, node }) {
67
67
  return {
68
68
  name: "install",
69
69
  advisory: true,
@@ -73,7 +73,7 @@ function installRow(cli, bin) {
73
73
  return ok(`${cli.name} declares no install, so it has no \`update\``);
74
74
  }
75
75
  try {
76
- const copy = await globalInstallOf(bin, npmContext(cli, install, ctx));
76
+ const copy = await globalInstallOf(bin, npmContext(cli, install, ctx, node));
77
77
  return ok(`a global npm install under ${copy.prefix}`);
78
78
  }
79
79
  catch (error) {
@@ -85,7 +85,7 @@ function installRow(cli, bin) {
85
85
  },
86
86
  };
87
87
  }
88
- function registryRow(cli) {
88
+ function registryRow(cli, node) {
89
89
  return {
90
90
  name: "registry",
91
91
  advisory: true,
@@ -94,7 +94,7 @@ function registryRow(cli) {
94
94
  if (install === undefined) {
95
95
  return ok(`${cli.name} declares no registry to compare this build with`);
96
96
  }
97
- const latest = await latestVersion(npmContext(cli, install, ctx));
97
+ const latest = await latestVersion(npmContext(cli, install, ctx, node));
98
98
  const standing = standingOf(cli.version, latest);
99
99
  const head = `${install.registry} has ${latest} as latest: this build`;
100
100
  if (standing === "behind") {
@@ -118,37 +118,29 @@ const SKILL_STATE_NOTES = {
118
118
  function describeCopy({ path, version, state }) {
119
119
  return `${path}${version === undefined ? "" : ` ${version}`} (${SKILL_STATE_NOTES[state]})`;
120
120
  }
121
- function skillFix(cli, copies) {
122
- if (copies.some(({ state }) => state === "behind" || state === "unversioned")) {
123
- return skillUpdateCommand(cli.name);
124
- }
125
- return copies.some(({ state }) => state === "ahead") ? `${cli.name} update` : undefined;
126
- }
127
121
  // A skill describes the CLI but never stops it working, so this row is always ok.
128
122
  function skillRow(cli) {
129
123
  return {
130
124
  name: "skill",
131
125
  run: async (ctx) => {
132
- const copies = await skillCopies(cli.name, cli.version, ctx.cwd, ctx.env);
133
- if (copies.length === 0) {
134
- return ok(`no copy of the ${cli.name} skill is installed`);
135
- }
136
- const fix = skillFix(cli, copies);
137
- const message = copies.map(describeCopy).join("; ");
126
+ const { copies, fix } = await skillReport(cli, cli.version, ctx);
127
+ const message = copies.length === 0
128
+ ? `no copy of the ${cli.name} skill is installed`
129
+ : copies.map(describeCopy).join("; ");
138
130
  return fix === undefined ? ok(message) : { state: "ok", message, fix };
139
131
  },
140
132
  };
141
133
  }
142
134
  /** Every row `doctor` reports, in order: the fixed rows around the CLI's own and its tools'. */
143
- export function doctorChecks(cli, bin) {
135
+ export function doctorChecks(cli, launch) {
144
136
  return [
145
137
  buildRow(cli),
146
138
  nodeRow(cli),
147
139
  ...(cli.project === undefined ? [] : [projectRow(cli.project)]),
148
140
  ...(cli.doctor ?? []),
149
- ...toolRows(cli.commands),
150
- installRow(cli, bin),
151
- registryRow(cli),
141
+ ...toolRows(cli.tools ?? [], cli.commands),
142
+ installRow(cli, launch),
143
+ registryRow(cli, launch.node),
152
144
  skillRow(cli),
153
145
  ];
154
146
  }
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor-rows.js","sourceRoot":"","sources":["../../src/built-ins/doctor-rows.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import { type Command, type CommandTreeCli } from "../define.js";
2
+ import type { Launch } from "./commands.js";
3
+ export declare const DOCTOR_PROBLEMS = "DOCTOR_PROBLEMS";
4
+ /** The built-in `doctor`: the fixed rows around the CLI's own, each under its own deadline. */
5
+ export declare function doctorCommand(cli: CommandTreeCli, launch: Launch): Command;
@@ -1,17 +1,18 @@
1
1
  import * as z from "zod";
2
- import { untilAborted } from "./abort.js";
3
- import { defineCommand, } from "./define.js";
2
+ import { untilAborted } from "../abort.js";
3
+ import { defineCommand, } from "../define.js";
4
+ import { CliError, messageOf } from "../errors.js";
4
5
  import { doctorChecks } from "./doctor-rows.js";
5
- import { CliError, messageOf } from "./errors.js";
6
6
  export const DOCTOR_PROBLEMS = "DOCTOR_PROBLEMS";
7
7
  const DEFAULT_DEADLINE_MS = 10_000;
8
8
  const MS_PER_SECOND = 1000;
9
9
  const MIN_LABEL_WIDTH = 8;
10
10
  const rowSchema = z.object({
11
11
  check: z.string(),
12
- state: z.enum(["ok", "problem"]),
12
+ state: z.enum(["ok", "problem", "skipped"]),
13
13
  message: z.string(),
14
14
  fix: z.string().optional(),
15
+ code: z.string().optional(),
15
16
  });
16
17
  const reportSchema = z.object({
17
18
  rows: z.array(rowSchema),
@@ -25,7 +26,7 @@ function problemOf(check, error, { signal, deadline, ms }) {
25
26
  };
26
27
  }
27
28
  if (error instanceof CliError) {
28
- return { state: "problem", message: `${error.message}; ${error.hint}` };
29
+ return { state: "problem", message: `${error.message}; ${error.hint}`, code: error.code };
29
30
  }
30
31
  return { state: "problem", message: `the ${check.name} row hit a bug: ${messageOf(error)}` };
31
32
  }
@@ -33,7 +34,8 @@ function problemOf(check, error, { signal, deadline, ms }) {
33
34
  function withSignal(ctx, signal) {
34
35
  return Object.create(ctx, { signal: { value: signal } });
35
36
  }
36
- // Racing the deadline ends a row whose check ignores its signal.
37
+ // Racing the deadline ends a row whose check ignores its signal. A row cut short by an interrupt
38
+ // has no finding, since the interrupt is no problem of the row's.
37
39
  async function rowOf(check, ctx) {
38
40
  const ms = check.deadlineMs ?? DEFAULT_DEADLINE_MS;
39
41
  const signal = ctx.deadline(ms);
@@ -45,6 +47,8 @@ async function rowOf(check, ctx) {
45
47
  ]);
46
48
  }
47
49
  catch (error) {
50
+ if (ctx.signal.aborted)
51
+ return undefined;
48
52
  finding = problemOf(check, error, { signal: ctx.signal, deadline: signal, ms });
49
53
  }
50
54
  return { row: { check: check.name, ...finding }, advisory: check.advisory === true };
@@ -61,17 +65,17 @@ function render({ rows, next }, style) {
61
65
  });
62
66
  return [...lines, ...next.map((fix) => `${"next".padEnd(width)}${fix}`)].join("\n");
63
67
  }
64
- function failure(cliName, problems, report) {
65
- return new CliError({
66
- code: DOCTOR_PROBLEMS,
67
- message: `${cliName} doctor found ${problems.length === 1 ? "a problem" : `${problems.length} problems`}: ${problems.join(", ")}`,
68
- hint: report.next.length === 0
69
- ? "each problem row says what is wrong"
70
- : "run the commands under next, then run doctor again",
71
- });
68
+ // One error per problem row, so the exit follows the class that must act first (ADR 0005).
69
+ function failure(cliName, problems) {
70
+ const errors = problems.map(({ check, message, fix, code }) => new CliError({
71
+ code: code ?? DOCTOR_PROBLEMS,
72
+ message: `${cliName} doctor found a problem in ${check}: ${message}`,
73
+ hint: fix === undefined ? "the row says what is wrong" : `run ${fix}, then run doctor again`,
74
+ }));
75
+ return new AggregateError(errors);
72
76
  }
73
77
  /** The built-in `doctor`: the fixed rows around the CLI's own, each under its own deadline. */
74
- export function doctorCommand(cli, bin) {
78
+ export function doctorCommand(cli, launch) {
75
79
  return defineCommand({
76
80
  name: "doctor",
77
81
  description: "check the setup and say what fixes each problem",
@@ -82,17 +86,20 @@ export function doctorCommand(cli, bin) {
82
86
  effect: "read",
83
87
  output: reportSchema,
84
88
  run: async (_input, ctx) => {
85
- const checked = await Promise.all(doctorChecks(cli, bin).map((check) => rowOf(check, ctx)));
86
- // Rows cut short by an interrupt report it as their problem, which no row has.
87
- ctx.signal.throwIfAborted();
89
+ const settled = await Promise.all(doctorChecks(cli, launch).map((check) => rowOf(check, ctx)));
90
+ const checked = settled.filter((row) => row !== undefined);
88
91
  const rows = checked.map(({ row }) => row);
89
92
  const report = { rows, next: nextOf(rows) };
93
+ if (ctx.signal.aborted) {
94
+ ctx.deliver(report);
95
+ ctx.signal.throwIfAborted();
96
+ }
90
97
  const problems = checked
91
98
  .filter(({ row, advisory }) => row.state === "problem" && !advisory)
92
- .map(({ row }) => row.check);
99
+ .map(({ row }) => row);
93
100
  if (problems.length > 0) {
94
101
  ctx.deliver(report);
95
- throw failure(cli.name, problems, report);
102
+ throw failure(cli.name, problems);
96
103
  }
97
104
  return report;
98
105
  },
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/built-ins/doctor.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { lstat, realpath } from "node:fs/promises";
2
2
  import { isAbsolute, join, relative } from "node:path";
3
- import { CliError, isMissingFile } from "./errors.js";
3
+ import { CliError, isMissingFile } from "../errors.js";
4
4
  import { globalPrefix, installCommandLine } from "./npm.js";
5
5
  export const NOT_GLOBAL_INSTALL = "NOT_GLOBAL_INSTALL";
6
6
  /** Where npm puts global packages under its global prefix. */
@@ -0,0 +1 @@
1
+ {"version":3,"file":"global-install.js","sourceRoot":"","sources":["../../src/built-ins/global-install.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAmB,MAAM,UAAU,CAAC;AAE7E,MAAM,CAAC,MAAM,kBAAkB,GAAG,oBAAoB,CAAC;AAQvD,8DAA8D;AAC9D,MAAM,UAAU,gBAAgB,CAAC,MAAc;IAC7C,OAAO,OAAO,CAAC,QAAQ,KAAK,OAAO;QACjC,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,cAAc,CAAC;QAC9B,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,cAAc,CAAC,CAAC;AAC1C,CAAC;AAED,SAAS,SAAS,CAAC,GAAe,EAAE,OAAe;IACjD,OAAO,IAAI,QAAQ,CAAC;QAClB,IAAI,EAAE,kBAAkB;QACxB,OAAO;QACP,IAAI,EAAE,6BAA6B,GAAG,CAAC,OAAO,6BAA6B,kBAAkB,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE;KAC7G,CAAC,CAAC;AACL,CAAC;AAED,KAAK,UAAU,mBAAmB,CAAC,IAAY;IAC7C,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;QAC7C,IAAI,aAAa,CAAC,KAAK,CAAC;YAAE,OAAO,SAAS,CAAC;QAC3C,MAAM,KAAK,CAAC;IACd,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,QAAQ,CAAC,GAAW,EAAE,IAAY;IACzC,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IAClC,OAAO,KAAK,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;AACvE,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,GAAuB,EACvB,GAAe;IAEf,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;QACtB,MAAM,SAAS,CAAC,GAAG,EAAE,GAAG,GAAG,CAAC,OAAO,4CAA4C,CAAC,CAAC;IACnF,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,GAAG,CAAC,CAAC;IACvC,MAAM,UAAU,GAAG,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IACvE,MAAM,SAAS,GAAG,MAAM,mBAAmB,CAAC,UAAU,CAAC,CAAC;IACxD,MAAM,IAAI,GAAG,CAAC,MAAM,mBAAmB,CAAC,GAAG,CAAC,CAAC,IAAI,GAAG,CAAC;IACrD,IAAI,SAAS,KAAK,SAAS,IAAI,CAAC,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC,EAAE,CAAC;QAC1D,MAAM,SAAS,CACb,GAAG,EACH,GAAG,GAAG,CAAC,OAAO,cAAc,IAAI,sCAAsC,UAAU,EAAE,CACnF,CAAC;IACJ,CAAC;IACD,6EAA6E;IAC7E,IAAI,CAAC,MAAM,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,cAAc,EAAE,EAAE,CAAC;QAC/C,MAAM,SAAS,CACb,GAAG,EACH,GAAG,GAAG,CAAC,OAAO,wBAAwB,SAAS,sCAAsC,CACtF,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;AAChC,CAAC"}
@@ -1,4 +1,5 @@
1
- import type { CommandTreeCli, Context, Env, GlobalInstall } from "./define.js";
1
+ import type { Context, Env } from "../context.js";
2
+ import type { CommandTreeCli, GlobalInstall } from "../define.js";
2
3
  export declare const REGISTRY_UNREACHABLE = "REGISTRY_UNREACHABLE";
3
4
  export declare const REGISTRY_AUTH = "REGISTRY_AUTH";
4
5
  export declare const INSTALL_FAILED = "INSTALL_FAILED";
@@ -10,10 +11,12 @@ export interface NpmContext {
10
11
  readonly install: GlobalInstall;
11
12
  readonly env: Env;
12
13
  readonly signal: AbortSignal;
14
+ /** The Node running the CLI, whose npm installs into it. */
15
+ readonly node: string | undefined;
13
16
  }
14
17
  /** Which kind of npm call failed, since the same npm code means different things for each. */
15
18
  export type NpmCall = "prefix" | "view" | "install";
16
- export declare function npmContext(cli: CommandTreeCli, install: GlobalInstall, ctx: Context): NpmContext;
19
+ export declare function npmContext(cli: CommandTreeCli, install: GlobalInstall, ctx: Context, node: string | undefined): NpmContext;
17
20
  /** The flag that points npm at the CLI's registry; none for npmjs, npm's default. */
18
21
  export declare function registryFlags({ package: name, registry }: GlobalInstall): string[];
19
22
  /** The command a person runs to install the CLI globally from its registry. */
@@ -1,17 +1,18 @@
1
- import { spawn } from "node:child_process";
1
+ import { existsSync } from "node:fs";
2
2
  import { mkdtemp, rm } from "node:fs/promises";
3
3
  import { tmpdir } from "node:os";
4
- import { join } from "node:path";
5
- import { CliError, messageOf } from "./errors.js";
4
+ import { delimiter, dirname, join } from "node:path";
5
+ import { CliError, messageOf } from "../errors.js";
6
+ import { spawnChild } from "../spawn.js";
7
+ import { lastLines } from "../tail.js";
6
8
  import { isVersion } from "./semver.js";
7
- import { lastLines } from "./tail.js";
8
9
  export const REGISTRY_UNREACHABLE = "REGISTRY_UNREACHABLE";
9
10
  export const REGISTRY_AUTH = "REGISTRY_AUTH";
10
11
  export const INSTALL_FAILED = "INSTALL_FAILED";
11
12
  export const NPM_FAILED = "NPM_FAILED";
12
13
  export const NO_LATEST = "NO_LATEST";
13
- export function npmContext(cli, install, ctx) {
14
- return { cliName: cli.name, install, env: ctx.env, signal: ctx.signal };
14
+ export function npmContext(cli, install, ctx, node) {
15
+ return { cliName: cli.name, install, env: ctx.env, signal: ctx.signal, node };
15
16
  }
16
17
  const NPMJS = "https://registry.npmjs.org/";
17
18
  const STDERR_TAIL_LINES = 10;
@@ -45,34 +46,25 @@ export function installCommandLine(install, version = "latest") {
45
46
  ...registryFlags(install),
46
47
  ].join(" ");
47
48
  }
48
- // npm.cmd needs cmd.exe on Windows, so there the arguments go through a shell, quoted; npm itself
49
- // stays unquoted, because cmd.exe resolves %~dp0 against the working directory for a quoted batch
50
- // name found on PATH. A step without a signal must finish, so on POSIX it leaves the terminal's
51
- // process group and its Ctrl-C.
49
+ // Under nvm the first npm on PATH may belong to another Node, and install there.
50
+ function npmOf(ctx, windows) {
51
+ const beside = ctx.node === undefined ? undefined : join(dirname(ctx.node), windows ? "npm.cmd" : "npm");
52
+ if (beside === undefined || !existsSync(beside))
53
+ return { path: "npm", env: ctx.env };
54
+ if (windows)
55
+ return { path: beside, env: ctx.env };
56
+ // npm starts with `#!/usr/bin/env node`, so its own Node must come first on PATH.
57
+ const PATH = [dirname(beside), ctx.env.PATH].filter(Boolean).join(delimiter);
58
+ return { path: beside, env: { ...ctx.env, PATH } };
59
+ }
60
+ // A step without a signal must finish, so it leaves the terminal's process group and its Ctrl-C.
52
61
  function spawnNpm(args, ctx, signal) {
53
- const windows = process.platform === "win32";
54
- const command = windows
55
- ? ["npm", ...args.map((arg) => `"${arg.replaceAll('"', '""')}"`)].join(" ")
56
- : "npm";
57
- return new Promise((resolve, reject) => {
58
- const child = spawn(command, windows ? [] : args, {
59
- env: ctx.env,
60
- shell: windows,
61
- windowsHide: true,
62
- stdio: ["ignore", "pipe", "pipe"],
63
- detached: signal === null && !windows,
64
- signal: signal ?? undefined,
65
- });
66
- let stdout = "";
67
- let stderr = "";
68
- child.stdout.setEncoding("utf8").on("data", (chunk) => {
69
- stdout += chunk;
70
- });
71
- child.stderr.setEncoding("utf8").on("data", (chunk) => {
72
- stderr += chunk;
73
- });
74
- child.on("error", reject);
75
- child.on("close", (exitCode) => resolve({ exitCode, stdout, stderr }));
62
+ const npm = npmOf(ctx, process.platform === "win32");
63
+ return spawnChild(npm.path, args, {
64
+ cwd: process.cwd(),
65
+ env: npm.env,
66
+ signal: signal ?? new AbortController().signal,
67
+ detached: signal === null,
76
68
  });
77
69
  }
78
70
  function tail(stderr) {
@@ -0,0 +1 @@
1
+ {"version":3,"file":"npm.js","sourceRoot":"","sources":["../../src/built-ins/npm.ts"],"names":[],"mappings":"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"}