@duyquangnvx/agent-cli 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +68 -0
- package/dist/agent-cli.d.ts +2 -2
- package/dist/agent-cli.js +1 -1
- package/dist/agent-cli.js.map +1 -1
- package/dist/agent.d.ts +5 -3
- package/dist/agent.js +31 -10
- package/dist/agent.js.map +1 -1
- package/dist/built-ins.d.ts +6 -1
- package/dist/built-ins.js +3 -3
- package/dist/built-ins.js.map +1 -1
- package/dist/command-spec.d.ts +5 -0
- package/dist/command-spec.js +14 -3
- package/dist/command-spec.js.map +1 -1
- package/dist/confirm.js +6 -2
- package/dist/confirm.js.map +1 -1
- package/dist/context.d.ts +102 -0
- package/dist/context.js +2 -0
- package/dist/context.js.map +1 -0
- package/dist/cost.js +2 -2
- package/dist/cost.js.map +1 -1
- package/dist/define.d.ts +42 -75
- package/dist/define.js +6 -1
- package/dist/define.js.map +1 -1
- package/dist/doctor-rows.d.ts +2 -1
- package/dist/doctor-rows.js +18 -10
- package/dist/doctor-rows.js.map +1 -1
- package/dist/doctor.d.ts +2 -1
- package/dist/doctor.js +29 -18
- package/dist/doctor.js.map +1 -1
- package/dist/errno.d.ts +11 -4
- package/dist/errno.js +34 -7
- package/dist/errno.js.map +1 -1
- package/dist/errors.d.ts +2 -1
- package/dist/errors.js +4 -0
- package/dist/errors.js.map +1 -1
- package/dist/execute.d.ts +9 -4
- package/dist/execute.js +10 -3
- package/dist/execute.js.map +1 -1
- package/dist/exit-classes.js +5 -1
- package/dist/exit-classes.js.map +1 -1
- package/dist/files.d.ts +42 -3
- package/dist/files.js +132 -10
- package/dist/files.js.map +1 -1
- package/dist/flags.d.ts +5 -1
- package/dist/flags.js +17 -2
- package/dist/flags.js.map +1 -1
- package/dist/help-json.d.ts +1 -1
- package/dist/help-json.js +4 -1
- package/dist/help-json.js.map +1 -1
- package/dist/help.d.ts +1 -1
- package/dist/help.js +11 -7
- package/dist/help.js.map +1 -1
- package/dist/index.d.ts +8 -2
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/input.d.ts +10 -0
- package/dist/input.js +54 -3
- package/dist/input.js.map +1 -1
- package/dist/interrupts.d.ts +3 -1
- package/dist/interrupts.js +4 -3
- package/dist/interrupts.js.map +1 -1
- package/dist/invocation.d.ts +10 -5
- package/dist/invocation.js +24 -11
- package/dist/invocation.js.map +1 -1
- package/dist/list.js +5 -2
- package/dist/list.js.map +1 -1
- package/dist/npm.d.ts +5 -2
- package/dist/npm.js +23 -31
- package/dist/npm.js.map +1 -1
- package/dist/operator.d.ts +5 -0
- package/dist/operator.js +15 -0
- package/dist/operator.js.map +1 -0
- package/dist/output.d.ts +4 -1
- package/dist/output.js +4 -0
- package/dist/output.js.map +1 -1
- package/dist/outputs.d.ts +24 -1
- package/dist/outputs.js +58 -2
- package/dist/outputs.js.map +1 -1
- package/dist/parse-input.d.ts +11 -2
- package/dist/parse-input.js +92 -19
- package/dist/parse-input.js.map +1 -1
- package/dist/planned.d.ts +6 -0
- package/dist/planned.js +5 -0
- package/dist/planned.js.map +1 -0
- package/dist/project.d.ts +1 -1
- package/dist/route.d.ts +1 -1
- package/dist/route.js +2 -1
- package/dist/route.js.map +1 -1
- package/dist/run-cli.d.ts +16 -2
- package/dist/run-cli.js +116 -58
- package/dist/run-cli.js.map +1 -1
- package/dist/run-process.js +3 -2
- package/dist/run-process.js.map +1 -1
- package/dist/secrets.d.ts +9 -2
- package/dist/secrets.js +7 -5
- package/dist/secrets.js.map +1 -1
- package/dist/skill-source.d.ts +4 -0
- package/dist/skill-source.js +42 -0
- package/dist/skill-source.js.map +1 -0
- package/dist/skills.d.ts +2 -1
- package/dist/skills.js +4 -0
- package/dist/skills.js.map +1 -1
- package/dist/spawn.d.ts +22 -5
- package/dist/spawn.js +126 -29
- package/dist/spawn.js.map +1 -1
- package/dist/spill.d.ts +4 -3
- package/dist/spill.js +1 -2
- package/dist/spill.js.map +1 -1
- package/dist/stdin.d.ts +13 -0
- package/dist/stdin.js +55 -0
- package/dist/stdin.js.map +1 -0
- package/dist/style.d.ts +1 -1
- package/dist/tokenize.d.ts +3 -0
- package/dist/tokenize.js +5 -4
- package/dist/tokenize.js.map +1 -1
- package/dist/tools.d.ts +6 -3
- package/dist/tools.js +18 -11
- package/dist/tools.js.map +1 -1
- package/dist/update.d.ts +2 -1
- package/dist/update.js +3 -3
- package/dist/update.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,74 @@ What changed in each release of `@duyquangnvx/agent-cli` (the Runtime) and `@duy
|
|
|
4
4
|
|
|
5
5
|
## Unreleased
|
|
6
6
|
|
|
7
|
+
## v0.5.0 (2026-10-19)
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- 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`.
|
|
12
|
+
- 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.
|
|
13
|
+
- 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.
|
|
14
|
+
- 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.
|
|
15
|
+
- `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.
|
|
16
|
+
- 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.
|
|
17
|
+
- 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.
|
|
18
|
+
- `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.
|
|
19
|
+
- A run deadline's `resume(input, commandLine)` receives `ctx.commandLine` as its second argument. A `resume` taking only `input` still type-checks.
|
|
20
|
+
- `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.
|
|
21
|
+
- `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.
|
|
22
|
+
- 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`.
|
|
23
|
+
- 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.
|
|
24
|
+
- 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.
|
|
25
|
+
- `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.
|
|
26
|
+
- 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.
|
|
27
|
+
- `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.
|
|
28
|
+
- 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.
|
|
29
|
+
- `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.
|
|
30
|
+
- `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.
|
|
31
|
+
- `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.
|
|
32
|
+
- 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.
|
|
33
|
+
|
|
34
|
+
### Changed
|
|
35
|
+
|
|
36
|
+
- **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`.
|
|
37
|
+
- **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.
|
|
38
|
+
- **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.
|
|
39
|
+
- **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.
|
|
40
|
+
- **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.
|
|
41
|
+
- **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.
|
|
42
|
+
- **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.
|
|
43
|
+
- On Windows, the `PERMISSION_DENIED` hint says a program may hold the path open, and to close it, then run the same command again.
|
|
44
|
+
- `ctx.files.write` through a symlink replaces the link's target and keeps the link.
|
|
45
|
+
- 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`.
|
|
46
|
+
- `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`.
|
|
47
|
+
|
|
48
|
+
### Fixed
|
|
49
|
+
|
|
50
|
+
- 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.
|
|
51
|
+
- `ctx.files.exists` answers false for a path under a file instead of failing.
|
|
52
|
+
|
|
53
|
+
## v0.4.0 (2026-10-19)
|
|
54
|
+
|
|
55
|
+
### Added
|
|
56
|
+
|
|
57
|
+
- 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`.
|
|
58
|
+
- 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.
|
|
59
|
+
- 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.
|
|
60
|
+
- `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.
|
|
61
|
+
- 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`.
|
|
62
|
+
|
|
63
|
+
### Changed
|
|
64
|
+
|
|
65
|
+
- **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`.
|
|
66
|
+
- **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.
|
|
67
|
+
- **Breaking:** `ctx.files.write` creates missing parent folders, so a write into a missing folder no longer fails with `NOT_FOUND`.
|
|
68
|
+
- 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`.
|
|
69
|
+
|
|
70
|
+
### Fixed
|
|
71
|
+
|
|
72
|
+
- 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.
|
|
73
|
+
- 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.
|
|
74
|
+
|
|
7
75
|
## v0.3.0 (2026-10-19)
|
|
8
76
|
|
|
9
77
|
### Added
|
package/dist/agent-cli.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { type Cli, type CommandTreeCli, type DefineCommand, type NoPorts, type SingleCommandCli } from "./define.js";
|
|
2
2
|
type PortsFactory<Ports> = NoPorts extends Ports ? {
|
|
3
|
-
readonly ports?:
|
|
3
|
+
readonly ports?: CommandTreeCli<Ports>["ports"];
|
|
4
4
|
} : {
|
|
5
|
-
readonly ports:
|
|
5
|
+
readonly ports: NonNullable<CommandTreeCli<Ports>["ports"]>;
|
|
6
6
|
};
|
|
7
7
|
type CliDeclaration<Ports, Settings> = (Omit<CommandTreeCli<Ports, Settings>, "ports"> & PortsFactory<Ports>) | (Omit<SingleCommandCli<Ports, Settings>, "ports"> & PortsFactory<Ports>);
|
|
8
8
|
export interface AgentCli<Ports, Settings> {
|
package/dist/agent-cli.js
CHANGED
|
@@ -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
|
}
|
package/dist/agent-cli.js.map
CHANGED
|
@@ -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,
|
|
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,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 "./
|
|
2
|
-
|
|
3
|
-
|
|
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
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
"
|
|
8
|
-
"
|
|
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
|
-
/**
|
|
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
|
|
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,
|
|
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"}
|
package/dist/built-ins.d.ts
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
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
|
+
}
|
|
2
7
|
/** The Commands the Runtime adds to a multi-Command CLI: `update` only when it declares an install. */
|
|
3
|
-
export declare function builtInCommands(cli: CommandTreeCli,
|
|
8
|
+
export declare function builtInCommands(cli: CommandTreeCli, launch: Launch): Commands;
|
package/dist/built-ins.js
CHANGED
|
@@ -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,
|
|
4
|
+
export function builtInCommands(cli, launch) {
|
|
5
5
|
return {
|
|
6
|
-
doctor: doctorCommand(cli,
|
|
7
|
-
...(cli.install === undefined ? {} : { update: updateCommand(cli, cli.install,
|
|
6
|
+
doctor: doctorCommand(cli, launch),
|
|
7
|
+
...(cli.install === undefined ? {} : { update: updateCommand(cli, cli.install, launch) }),
|
|
8
8
|
};
|
|
9
9
|
}
|
|
10
10
|
//# sourceMappingURL=built-ins.js.map
|
package/dist/built-ins.js.map
CHANGED
|
@@ -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;
|
|
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;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"}
|
package/dist/command-spec.d.ts
CHANGED
|
@@ -9,6 +9,9 @@ export interface CommandSpec {
|
|
|
9
9
|
readonly commandLine: string;
|
|
10
10
|
readonly command: Command;
|
|
11
11
|
readonly description: string;
|
|
12
|
+
readonly help: string | undefined;
|
|
13
|
+
readonly hidden: boolean;
|
|
14
|
+
readonly operator: boolean;
|
|
12
15
|
readonly effect: Command["effect"];
|
|
13
16
|
readonly examples: readonly Example[];
|
|
14
17
|
readonly args: readonly InputField[];
|
|
@@ -24,5 +27,7 @@ export interface GroupSpec {
|
|
|
24
27
|
readonly commands: Readonly<Record<string, SpecNode>>;
|
|
25
28
|
}
|
|
26
29
|
export type SpecNode = CommandSpec | GroupSpec;
|
|
30
|
+
/** The group's Commands and groups that help and suggestions may name: hidden Commands left out. */
|
|
31
|
+
export declare function visibleCommands({ commands }: GroupSpec): Readonly<Record<string, SpecNode>>;
|
|
27
32
|
export declare function commandSpec(commandLine: string, command: Command): CommandSpec;
|
|
28
33
|
export declare function groupSpec(commandLine: string, commands: Commands): GroupSpec;
|
package/dist/command-spec.js
CHANGED
|
@@ -2,11 +2,19 @@ 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
|
+
/** The group's Commands and groups that help and suggestions may name: hidden Commands left out. */
|
|
7
|
+
export function visibleCommands({ commands }) {
|
|
8
|
+
return Object.fromEntries(Object.entries(commands).filter(([, node]) => node.kind === "group" || !node.hidden));
|
|
9
|
+
}
|
|
5
10
|
function declaredOf(command) {
|
|
6
|
-
|
|
11
|
+
if (!hasPlan(command)) {
|
|
12
|
+
return { outputs: false, force: undefined, cost: false };
|
|
13
|
+
}
|
|
7
14
|
return {
|
|
8
|
-
outputs:
|
|
9
|
-
|
|
15
|
+
outputs: command.outputs !== undefined,
|
|
16
|
+
force: command.force,
|
|
17
|
+
cost: command.cost !== undefined,
|
|
10
18
|
};
|
|
11
19
|
}
|
|
12
20
|
export function commandSpec(commandLine, command) {
|
|
@@ -16,6 +24,9 @@ export function commandSpec(commandLine, command) {
|
|
|
16
24
|
commandLine,
|
|
17
25
|
command,
|
|
18
26
|
description: command.description,
|
|
27
|
+
help: command.help,
|
|
28
|
+
hidden: command.hidden === true,
|
|
29
|
+
operator: command.operator === true,
|
|
19
30
|
effect: command.effect,
|
|
20
31
|
examples: command.examples,
|
|
21
32
|
args: argFields(command.args),
|
package/dist/command-spec.js.map
CHANGED
|
@@ -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,EAAoC,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAChF,OAAO,EAAE,SAAS,EAAmB,YAAY,EAAE,MAAM,YAAY,CAAC;AACtE,OAAO,EAAiB,QAAQ,EAAE,MAAM,WAAW,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;AA6BvC,oGAAoG;AACpG,MAAM,UAAU,eAAe,CAAC,EAAE,QAAQ,EAAa;IACrD,OAAO,MAAM,CAAC,WAAW,CACvB,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CACrF,CAAC;AACJ,CAAC;AAED,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,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,MAAM,EAAE,OAAO,CAAC,MAAM,KAAK,IAAI;QAC/B,QAAQ,EAAE,OAAO,CAAC,QAAQ,KAAK,IAAI;QACnC,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.js
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import { UsageError } from "./errors.js";
|
|
2
2
|
import { CONFIRM_FLAG } from "./flags.js";
|
|
3
|
-
import {
|
|
3
|
+
import { commandLineOf } from "./invocation.js";
|
|
4
4
|
export const CONFIRMATION_REQUIRED = "CONFIRMATION_REQUIRED";
|
|
5
5
|
export const CONFIRMATION_MISMATCH = "CONFIRMATION_MISMATCH";
|
|
6
6
|
export function checkConfirmation({ invocation, commandLine, given }, expected) {
|
|
7
7
|
if (given === expected) {
|
|
8
8
|
return;
|
|
9
9
|
}
|
|
10
|
-
const
|
|
10
|
+
const confirmed = commandLineOf(invocation, {
|
|
11
|
+
remove: [CONFIRM_FLAG.flag],
|
|
12
|
+
add: [CONFIRM_FLAG.flag, expected],
|
|
13
|
+
});
|
|
14
|
+
const hint = `to confirm, run \`${confirmed}\``;
|
|
11
15
|
if (given === undefined) {
|
|
12
16
|
throw new UsageError({
|
|
13
17
|
code: CONFIRMATION_REQUIRED,
|
package/dist/confirm.js.map
CHANGED
|
@@ -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,
|
|
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,aAAa,EAAmB,MAAM,iBAAiB,CAAC;AAEjE,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,SAAS,GAAG,aAAa,CAAC,UAAU,EAAE;QAC1C,MAAM,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC;QAC3B,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,QAAQ,CAAC;KACnC,CAAC,CAAC;IACH,MAAM,IAAI,GAAG,qBAAqB,SAAS,IAAI,CAAC;IAChD,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"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import type * as z from "zod";
|
|
2
|
+
import type { Clock } from "./clock.js";
|
|
3
|
+
import type { FileAccess } from "./errno.js";
|
|
4
|
+
import type { Files } from "./files.js";
|
|
5
|
+
import type { CommandLineChange } from "./invocation.js";
|
|
6
|
+
import type { Secret } from "./secrets.js";
|
|
7
|
+
import type { ContextSpawn } from "./spawn.js";
|
|
8
|
+
export type Env = Readonly<Record<string, string | undefined>>;
|
|
9
|
+
export interface PollOptions {
|
|
10
|
+
readonly intervalMs: number;
|
|
11
|
+
/** Stops the polling when it aborts, as `ctx.signal` does; pass `ctx.deadline(ms)` for a wait. */
|
|
12
|
+
readonly signal?: AbortSignal;
|
|
13
|
+
}
|
|
14
|
+
/** The commit a build was made from and when, stamped by the bundler. */
|
|
15
|
+
export interface BuildStamp {
|
|
16
|
+
readonly sha: string;
|
|
17
|
+
readonly dirty: boolean;
|
|
18
|
+
readonly builtAt: string;
|
|
19
|
+
}
|
|
20
|
+
export interface Context<Ports = unknown, Settings = unknown> {
|
|
21
|
+
readonly cwd: string;
|
|
22
|
+
readonly env: Env;
|
|
23
|
+
/** The CLI's version, as `--version` prints it. */
|
|
24
|
+
readonly version: string;
|
|
25
|
+
/** The bundler's stamp, as `--version` prints it; absent when the CLI runs unbundled. */
|
|
26
|
+
readonly build: BuildStamp | undefined;
|
|
27
|
+
/**
|
|
28
|
+
* The command line that reruns this CLI, to spawn one of its hidden Commands: Node, its flags and
|
|
29
|
+
* the bin, or the CLI's name, found on PATH, when run without a bin.
|
|
30
|
+
*/
|
|
31
|
+
readonly self: readonly string[];
|
|
32
|
+
/** The folder holding this CLI's `package.json`, for reading files shipped in the package. */
|
|
33
|
+
readonly packageRoot: string;
|
|
34
|
+
/** Writes a plain line to stderr, for long work; it never reaches stdout. */
|
|
35
|
+
progress(message: string): void;
|
|
36
|
+
/**
|
|
37
|
+
* Aborts when the run is interrupted (Ctrl-C) or hits the Command's run deadline; pass it to
|
|
38
|
+
* `fetch` and child processes.
|
|
39
|
+
*/
|
|
40
|
+
readonly signal: AbortSignal;
|
|
41
|
+
/** Returns a signal that also aborts, with `DEADLINE_EXCEEDED`, once `ms` have passed. */
|
|
42
|
+
deadline(ms: number): AbortSignal;
|
|
43
|
+
/**
|
|
44
|
+
* Runs a step that must not stop halfway: the run waits for it even when stopped, and then
|
|
45
|
+
* prints `finishing <name>` on stderr.
|
|
46
|
+
*/
|
|
47
|
+
runToEnd<T>(name: string, work: () => Promise<T>): Promise<T>;
|
|
48
|
+
/**
|
|
49
|
+
* Records the data done so far, in the shape `render` takes; the last call wins. A run that then
|
|
50
|
+
* fails, hits a deadline or is interrupted prints it; a returned value replaces it.
|
|
51
|
+
*/
|
|
52
|
+
deliver(data: unknown): void;
|
|
53
|
+
/** The outside systems the CLI declared with `agentCli<Ports>()`. */
|
|
54
|
+
readonly ports: Ports;
|
|
55
|
+
/**
|
|
56
|
+
* Reads, lists, removes and atomically writes files and folders, paths resolved against `cwd`; a
|
|
57
|
+
* failure fails the run with `PERMISSION_DENIED`, `DISK_FULL`, `NOT_FOUND`, `NOT_A_FILE` or
|
|
58
|
+
* `ALREADY_EXISTS`.
|
|
59
|
+
*/
|
|
60
|
+
readonly files: Files;
|
|
61
|
+
/**
|
|
62
|
+
* Runs a child process, killed when the run is interrupted; `check: true` fails the run with
|
|
63
|
+
* `TOOL_FAILED` and the tail of its stderr when it exits non-zero.
|
|
64
|
+
*/
|
|
65
|
+
readonly spawn: ContextSpawn;
|
|
66
|
+
/** Deadlines, `poll` and the grace period after an interrupt run on it. */
|
|
67
|
+
readonly clock: Clock;
|
|
68
|
+
/**
|
|
69
|
+
* Calls `check` until it returns a value other than `undefined`, sleeping `intervalMs` between
|
|
70
|
+
* calls; it stops when `ctx.signal` or the given `signal` aborts.
|
|
71
|
+
*/
|
|
72
|
+
poll<T>(check: () => T | undefined | Promise<T | undefined>, options: PollOptions): Promise<T>;
|
|
73
|
+
/** The Project file found by walking up from `cwd`, parsed by the CLI's schema. */
|
|
74
|
+
readonly project: Project<Settings> | undefined;
|
|
75
|
+
/** Reads `name` from the env, then from `$XDG_CONFIG_HOME/<cli>/.env`, with where it came from. */
|
|
76
|
+
secret(name: string): Secret | undefined;
|
|
77
|
+
/**
|
|
78
|
+
* Classifies an errno failure of the CLI's own file access, such as a store it opens itself, as
|
|
79
|
+
* `ctx.files` does; any other error comes back unchanged.
|
|
80
|
+
*/
|
|
81
|
+
fileError(error: unknown, at: FileAccess): unknown;
|
|
82
|
+
/** Whether the caller passed `--force`; always false for a Command without it. */
|
|
83
|
+
readonly force: boolean;
|
|
84
|
+
/**
|
|
85
|
+
* The command line as the caller typed it, starting with the CLI's name and shell-quoted, with
|
|
86
|
+
* each flag in `remove` dropped along with its value and the words in `add` placed before any
|
|
87
|
+
* `--`; for the hint that names the command to run next.
|
|
88
|
+
*/
|
|
89
|
+
commandLine(change?: CommandLineChange): string;
|
|
90
|
+
}
|
|
91
|
+
/** The slice of `Context` the ports factory receives, which exists before the ports do. */
|
|
92
|
+
export type PortsBase = Pick<Context, "env" | "cwd" | "packageRoot" | "secret" | "spawn" | "files" | "clock" | "signal" | "progress" | "version" | "build" | "self" | "fileError">;
|
|
93
|
+
export interface Project<Settings = unknown> {
|
|
94
|
+
/** The folder holding the Project file. */
|
|
95
|
+
readonly root: string;
|
|
96
|
+
readonly settings: Settings;
|
|
97
|
+
}
|
|
98
|
+
/** Names the Project file and the schema its JSON must match. */
|
|
99
|
+
export interface ProjectFile<Settings = unknown> {
|
|
100
|
+
readonly file: string;
|
|
101
|
+
readonly schema: z.ZodType<Settings>;
|
|
102
|
+
}
|
package/dist/context.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":""}
|
package/dist/cost.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { CliError } from "./errors.js";
|
|
2
2
|
import { YES_FLAG } from "./flags.js";
|
|
3
|
-
import {
|
|
3
|
+
import { commandLineOf } from "./invocation.js";
|
|
4
4
|
export const NOT_CONFIRMED = "NOT_CONFIRMED";
|
|
5
5
|
/** Refuses a run whose Plan states a cost the caller has not approved with `--yes`. */
|
|
6
6
|
export function checkCost({ invocation, commandLine, yes }, cost) {
|
|
@@ -10,7 +10,7 @@ export function checkCost({ invocation, commandLine, yes }, cost) {
|
|
|
10
10
|
throw new CliError({
|
|
11
11
|
code: NOT_CONFIRMED,
|
|
12
12
|
message: `\`${commandLine}\` needs ${YES_FLAG.flag}: ${cost}`,
|
|
13
|
-
hint: `to approve the cost, run \`${
|
|
13
|
+
hint: `to approve the cost, run \`${commandLineOf(invocation, { add: [YES_FLAG.flag] })}\``,
|
|
14
14
|
});
|
|
15
15
|
}
|
|
16
16
|
//# sourceMappingURL=cost.js.map
|
package/dist/cost.js.map
CHANGED
|
@@ -1 +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,
|
|
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,aAAa,EAAmB,MAAM,iBAAiB,CAAC;AAEjE,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,aAAa,CAAC,UAAU,EAAE,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI;KAC5F,CAAC,CAAC;AACL,CAAC"}
|
package/dist/define.d.ts
CHANGED
|
@@ -1,75 +1,13 @@
|
|
|
1
1
|
import type * as z from "zod";
|
|
2
|
-
import type {
|
|
2
|
+
import type { BuildStamp, Context, PortsBase, ProjectFile } from "./context.js";
|
|
3
3
|
import type { ErrorTable } from "./error-table.js";
|
|
4
|
-
import type { Files } from "./files.js";
|
|
5
4
|
import { type StandardFlagName } from "./flags.js";
|
|
6
5
|
import type { Page, PageInput, RowSchema } from "./list.js";
|
|
7
|
-
import type { Secret } from "./secrets.js";
|
|
8
|
-
import type { ContextSpawn } from "./spawn.js";
|
|
9
6
|
import type { Style } from "./style.js";
|
|
10
|
-
export type Env = Readonly<Record<string, string | undefined>>;
|
|
11
7
|
export interface Example {
|
|
12
8
|
readonly command: string;
|
|
13
9
|
readonly note: string;
|
|
14
10
|
}
|
|
15
|
-
export interface PollOptions {
|
|
16
|
-
readonly intervalMs: number;
|
|
17
|
-
}
|
|
18
|
-
export interface Context<Ports = unknown, Settings = unknown> {
|
|
19
|
-
readonly cwd: string;
|
|
20
|
-
readonly env: Env;
|
|
21
|
-
/** The folder holding this CLI's `package.json`, for reading files shipped in the package. */
|
|
22
|
-
readonly packageRoot: string;
|
|
23
|
-
/** Writes a plain line to stderr, for long work; it never reaches stdout. */
|
|
24
|
-
progress(message: string): void;
|
|
25
|
-
/**
|
|
26
|
-
* Aborts when the run is interrupted (Ctrl-C) or hits the Command's run deadline; pass it to
|
|
27
|
-
* `fetch` and child processes.
|
|
28
|
-
*/
|
|
29
|
-
readonly signal: AbortSignal;
|
|
30
|
-
/** Returns a signal that also aborts, with `DEADLINE_EXCEEDED`, once `ms` have passed. */
|
|
31
|
-
deadline(ms: number): AbortSignal;
|
|
32
|
-
/**
|
|
33
|
-
* Runs a step that must not stop halfway: the run waits for it even when stopped, and then
|
|
34
|
-
* prints `finishing <name>` on stderr.
|
|
35
|
-
*/
|
|
36
|
-
runToEnd<T>(name: string, work: () => Promise<T>): Promise<T>;
|
|
37
|
-
/**
|
|
38
|
-
* Records the data done so far, in the shape `render` takes; the last call wins. A run that then
|
|
39
|
-
* fails, hits a deadline or is interrupted prints it; a returned value replaces it.
|
|
40
|
-
*/
|
|
41
|
-
deliver(data: unknown): void;
|
|
42
|
-
/** The outside systems the CLI declared with `agentCli<Ports>()`. */
|
|
43
|
-
readonly ports: Ports;
|
|
44
|
-
/** Writes files atomically and tells whether one exists; a failure fails the run with `PERMISSION_DENIED`, `DISK_FULL` or `NOT_FOUND`. */
|
|
45
|
-
readonly files: Files;
|
|
46
|
-
/**
|
|
47
|
-
* Runs a child process, killed when the run is interrupted; `check: true` fails the run with
|
|
48
|
-
* `TOOL_FAILED` and the tail of its stderr when it exits non-zero.
|
|
49
|
-
*/
|
|
50
|
-
readonly spawn: ContextSpawn;
|
|
51
|
-
/** Deadlines, `poll` and the grace period after an interrupt run on it. */
|
|
52
|
-
readonly clock: Clock;
|
|
53
|
-
/**
|
|
54
|
-
* Calls `check` until it returns a value other than `undefined`, sleeping `intervalMs` between
|
|
55
|
-
* calls; it stops when `ctx.signal` aborts.
|
|
56
|
-
*/
|
|
57
|
-
poll<T>(check: () => T | undefined | Promise<T | undefined>, options: PollOptions): Promise<T>;
|
|
58
|
-
/** The Project file found by walking up from `cwd`, parsed by the CLI's schema. */
|
|
59
|
-
readonly project: Project<Settings> | undefined;
|
|
60
|
-
/** Reads `name` from the env, then from `$XDG_CONFIG_HOME/<cli>/.env`, with where it came from. */
|
|
61
|
-
secret(name: string): Secret | undefined;
|
|
62
|
-
}
|
|
63
|
-
export interface Project<Settings = unknown> {
|
|
64
|
-
/** The folder holding the Project file. */
|
|
65
|
-
readonly root: string;
|
|
66
|
-
readonly settings: Settings;
|
|
67
|
-
}
|
|
68
|
-
/** Names the Project file and the schema its JSON must match. */
|
|
69
|
-
export interface ProjectFile<Settings = unknown> {
|
|
70
|
-
readonly file: string;
|
|
71
|
-
readonly schema: z.ZodType<Settings>;
|
|
72
|
-
}
|
|
73
11
|
export type InputSchema = z.ZodObject;
|
|
74
12
|
export type NoPorts = Record<never, never>;
|
|
75
13
|
export type NoInput = z.ZodObject<Record<never, never>>;
|
|
@@ -87,13 +25,25 @@ export interface Tool {
|
|
|
87
25
|
/** Bounds a whole run, so a long run stops before the caller's own timeout and can be continued. */
|
|
88
26
|
export interface RunDeadline<In> {
|
|
89
27
|
readonly ms: number;
|
|
90
|
-
/**
|
|
91
|
-
|
|
28
|
+
/**
|
|
29
|
+
* The command line that continues the work, given as the hint of the run's `DEADLINE_EXCEEDED`;
|
|
30
|
+
* `commandLine` is `ctx.commandLine`.
|
|
31
|
+
*/
|
|
32
|
+
resume(input: In, commandLine: Context["commandLine"]): string;
|
|
92
33
|
}
|
|
93
34
|
interface CommandBase<Args extends InputSchema, Options extends InputSchema> {
|
|
94
35
|
readonly name: string;
|
|
95
36
|
readonly description: string;
|
|
37
|
+
/** A paragraph printed after the options in text help, and carried as `help` in help JSON. */
|
|
38
|
+
readonly help?: string;
|
|
96
39
|
readonly examples: readonly Example[];
|
|
40
|
+
/** Left out of help, help JSON, the root examples and suggestions, but still routed and run. */
|
|
41
|
+
readonly hidden?: boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Only a person at a terminal runs it: under a Coding agent the run fails with `NEEDS_OPERATOR`
|
|
44
|
+
* before `plan`, `run` or `start`, naming the line the operator types.
|
|
45
|
+
*/
|
|
46
|
+
readonly operator?: true;
|
|
97
47
|
/** Missing ones fail the run with `TOOL_MISSING` before `plan`, `run` or `start`. */
|
|
98
48
|
readonly tools?: readonly Tool[];
|
|
99
49
|
readonly args?: Args;
|
|
@@ -135,6 +85,11 @@ interface PlannedCommand<Args extends InputSchema, Options extends InputSchema,
|
|
|
135
85
|
* a run refuses with `OUTPUT_EXISTS` when any of them exists.
|
|
136
86
|
*/
|
|
137
87
|
outputs?(plan: Plan): readonly string[];
|
|
88
|
+
/**
|
|
89
|
+
* What `--force` replaces for this Command, shown as the flag's help. Declaring it adds
|
|
90
|
+
* `--force`, which `plan` and `apply` read as `ctx.force`.
|
|
91
|
+
*/
|
|
92
|
+
readonly force?: string;
|
|
138
93
|
}
|
|
139
94
|
export interface WriteCommand<Args extends InputSchema, Options extends InputSchema, Plan, Data, Ports = unknown, Settings = unknown> extends PlannedCommand<Args, Options, Plan, Data, Ports, Settings> {
|
|
140
95
|
readonly effect: "write";
|
|
@@ -159,16 +114,16 @@ interface CliBase<Ports, Settings> {
|
|
|
159
114
|
readonly name: string;
|
|
160
115
|
readonly version: string;
|
|
161
116
|
/** The commit the build was made from and when, stamped by the bundler; `--version` prints it. */
|
|
162
|
-
readonly build?:
|
|
163
|
-
readonly sha: string;
|
|
164
|
-
readonly dirty: boolean;
|
|
165
|
-
readonly builtAt: string;
|
|
166
|
-
};
|
|
117
|
+
readonly build?: BuildStamp;
|
|
167
118
|
/** Every code the CLI throws; a code missing here exits 70, as a bug. */
|
|
168
119
|
readonly errors?: ErrorTable;
|
|
169
|
-
/** Builds the real ports when a
|
|
170
|
-
readonly ports?: () => Ports;
|
|
120
|
+
/** Builds the real ports when a run first reads `ctx.ports`; `runCli`'s `ports` replaces them in a test. */
|
|
121
|
+
readonly ports?: (base: PortsBase) => Ports;
|
|
171
122
|
readonly project?: ProjectFile<Settings>;
|
|
123
|
+
/** Where `npx skills add` installs the CLI's skill from; read from package.json `repository` when absent. */
|
|
124
|
+
readonly skill?: {
|
|
125
|
+
readonly source: string;
|
|
126
|
+
};
|
|
172
127
|
}
|
|
173
128
|
/** Where an Agent CLI is published and how it is installed; `doctor` and `update` read it. */
|
|
174
129
|
export interface GlobalInstall {
|
|
@@ -176,12 +131,22 @@ export interface GlobalInstall {
|
|
|
176
131
|
readonly package: string;
|
|
177
132
|
readonly registry: string;
|
|
178
133
|
}
|
|
179
|
-
|
|
180
|
-
|
|
134
|
+
/** What a `doctor` row found. A skipped row was not checked, and never fails `doctor`. */
|
|
135
|
+
export type DoctorFinding = {
|
|
136
|
+
readonly state: "ok";
|
|
137
|
+
readonly message: string;
|
|
138
|
+
readonly fix?: string;
|
|
139
|
+
} | {
|
|
140
|
+
readonly state: "problem";
|
|
181
141
|
readonly message: string;
|
|
182
142
|
/** The command that fixes the problem. */
|
|
183
143
|
readonly fix?: string;
|
|
184
|
-
|
|
144
|
+
/** A code of the Error table or the Runtime's that `doctor` fails with; `DOCTOR_PROBLEMS` when absent. */
|
|
145
|
+
readonly code?: string;
|
|
146
|
+
} | {
|
|
147
|
+
readonly state: "skipped";
|
|
148
|
+
readonly message: string;
|
|
149
|
+
};
|
|
185
150
|
/** A row the CLI adds to `doctor`, for a system it depends on. */
|
|
186
151
|
export interface DoctorCheck<Ports = unknown, Settings = unknown> {
|
|
187
152
|
readonly name: string;
|
|
@@ -203,6 +168,8 @@ export interface CommandTreeCli<Ports = unknown, Settings = unknown> extends Cli
|
|
|
203
168
|
readonly node?: string;
|
|
204
169
|
};
|
|
205
170
|
readonly doctor?: readonly DoctorCheck<Ports, Settings>[];
|
|
171
|
+
/** Tools `doctor` checks besides the Commands' own; no Command requires them. */
|
|
172
|
+
readonly tools?: readonly Tool[];
|
|
206
173
|
}
|
|
207
174
|
/** An Agent CLI that is one Command, run with no Command name, as in `tool <args>`. */
|
|
208
175
|
export interface SingleCommandCli<Ports = unknown, Settings = unknown> extends CliBase<Ports, Settings> {
|