@aragon-agent/cli 0.4.3 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +131 -0
- package/README.md +227 -3
- package/dist/agent/agent-mode.d.ts +53 -0
- package/dist/agent/agent-mode.js +69 -0
- package/dist/agent/controller.d.ts +69 -0
- package/dist/agent/controller.js +154 -1
- package/dist/agent/plan-prompt.d.ts +18 -0
- package/dist/agent/plan-prompt.js +93 -0
- package/dist/agent/reducer.d.ts +14 -1
- package/dist/agent/reducer.js +9 -0
- package/dist/agent/system-prompt.d.ts +15 -0
- package/dist/agent/system-prompt.js +8 -0
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +183 -20
- package/dist/commands/builtins.js +60 -0
- package/dist/commands/registry.d.ts +17 -0
- package/dist/config/app-paths.d.ts +71 -4
- package/dist/config/app-paths.js +139 -8
- package/dist/config/cli-commands.d.ts +43 -0
- package/dist/config/cli-commands.js +196 -0
- package/dist/config/env.d.ts +7 -1
- package/dist/config/env.js +45 -1
- package/dist/config/load.d.ts +8 -0
- package/dist/config/load.js +59 -2
- package/dist/config/migrate-home.d.ts +63 -0
- package/dist/config/migrate-home.js +165 -0
- package/dist/config/migrate-legacy-state.d.ts +10 -0
- package/dist/config/migrate-legacy-state.js +15 -6
- package/dist/config/schema.d.ts +61 -0
- package/dist/config/schema.js +83 -0
- package/dist/config/store.d.ts +30 -12
- package/dist/config/store.js +47 -35
- package/dist/logging/cli-commands.d.ts +25 -0
- package/dist/logging/cli-commands.js +221 -0
- package/dist/logging/file-sink.d.ts +114 -0
- package/dist/logging/file-sink.js +326 -0
- package/dist/logging/install.d.ts +163 -0
- package/dist/logging/install.js +302 -0
- package/dist/logging/levels.d.ts +40 -0
- package/dist/logging/levels.js +59 -0
- package/dist/logging/logger.d.ts +110 -0
- package/dist/logging/logger.js +237 -0
- package/dist/logging/redact.d.ts +28 -0
- package/dist/logging/redact.js +90 -0
- package/dist/logging/secret-registry.d.ts +30 -0
- package/dist/logging/secret-registry.js +55 -0
- package/dist/skills/paths.d.ts +2 -4
- package/dist/skills/paths.js +7 -9
- package/dist/tools/human-input.d.ts +179 -0
- package/dist/tools/human-input.js +227 -0
- package/dist/tools/index.d.ts +35 -3
- package/dist/tools/index.js +96 -9
- package/dist/tools/plan-tools.d.ts +64 -0
- package/dist/tools/plan-tools.js +198 -0
- package/dist/ui/App.d.ts +4 -1
- package/dist/ui/App.js +182 -11
- package/dist/ui/Composer.d.ts +4 -1
- package/dist/ui/Composer.js +26 -7
- package/dist/ui/ModeChip.d.ts +29 -0
- package/dist/ui/ModeChip.js +15 -0
- package/dist/ui/PromptInput.d.ts +8 -1
- package/dist/ui/PromptInput.js +12 -2
- package/dist/ui/StatusBar.d.ts +15 -0
- package/dist/ui/StatusBar.js +10 -2
- package/dist/ui/entries/ToolPreview.d.ts +2 -0
- package/dist/ui/entries/ToolPreview.js +64 -0
- package/dist/ui/glyphs.d.ts +9 -0
- package/dist/ui/glyphs.js +8 -0
- package/dist/ui/layout/wrap-rows.d.ts +24 -0
- package/dist/ui/layout/wrap-rows.js +74 -0
- package/dist/ui/overlays/HelpOverlay.js +13 -0
- package/dist/ui/overlays/PlanReviewOverlay.d.ts +50 -0
- package/dist/ui/overlays/PlanReviewOverlay.js +117 -0
- package/dist/ui/overlays/QuestionOverlay.d.ts +30 -0
- package/dist/ui/overlays/QuestionOverlay.js +193 -0
- package/dist/ui/overlays/SettingsScreen.d.ts +7 -0
- package/dist/ui/overlays/SettingsScreen.js +8 -1
- package/dist/ui/use-startup-notices.d.ts +15 -0
- package/dist/ui/use-startup-notices.js +38 -0
- package/package.json +3 -2
- package/runtime/insecure-tls-warning.cjs +62 -0
- package/runtime/insecure-tls-warning.d.cts +5 -0
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,137 @@ All notable changes to `@aragon-agent/cli` are documented here. Entries at
|
|
|
5
5
|
— those releases really were published under that name, so they are left as they
|
|
6
6
|
were written.
|
|
7
7
|
|
|
8
|
+
## Unreleased
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
|
|
12
|
+
- **Your files moved to `~/.aragon-agent/`.** Config, sessions, installed skills
|
|
13
|
+
and the usage counters now live in one directory in your home — on Windows
|
|
14
|
+
`C:\Users\<you>\.aragon-agent\`, and the same path on macOS and Linux. They
|
|
15
|
+
used to be split across `%APPDATA%\aragon-agent-nodejs\Config` and
|
|
16
|
+
`%LOCALAPPDATA%\aragon-agent-nodejs\Data` (or the XDG equivalents), which are
|
|
17
|
+
correct locations and terrible answers to "where do I change the model?".
|
|
18
|
+
|
|
19
|
+
**The move happens once, automatically, on first launch, and prints a line on
|
|
20
|
+
stderr when it does.** Nothing is deleted: `config.json` is COPIED rather than
|
|
21
|
+
moved, and the old directories are left where they are, so reinstalling 0.5.0
|
|
22
|
+
remains lossless. `aragon config home` prints the new location and names the
|
|
23
|
+
old ones. Once you are satisfied, you can delete them yourself.
|
|
24
|
+
|
|
25
|
+
`ARAGON_HOME` relocates the whole tree. It has to be a real environment
|
|
26
|
+
variable — the path is resolved before any `.env` is read, so putting it in a
|
|
27
|
+
`.env` will not work. `aragon config home` always prints what is actually in
|
|
28
|
+
use.
|
|
29
|
+
|
|
30
|
+
### Added
|
|
31
|
+
|
|
32
|
+
- **Logging.** Records go to `~/.aragon-agent/logs/aragon-<date>.log` as JSON
|
|
33
|
+
Lines: startup and exit, config writes, turn boundaries with token counts,
|
|
34
|
+
tool names with durations, skill loads, and every uncaught error. Files rotate
|
|
35
|
+
by day and by size (`log.maxFileBytes`, default 5 MiB) and the oldest beyond
|
|
36
|
+
`log.maxFiles` (default 10) are deleted.
|
|
37
|
+
|
|
38
|
+
**`info`, the default, records no conversation content**, so attaching a log
|
|
39
|
+
to a bug report is safe. `--log-level debug` (or `--verbose`) adds prompts,
|
|
40
|
+
replies and tool arguments truncated to `log.previewChars`; `trace` adds them
|
|
41
|
+
in full. Those two write what you typed — check before sharing one.
|
|
42
|
+
|
|
43
|
+
API keys are removed at every level by two independent passes: fields whose
|
|
44
|
+
name looks like a credential are blanked whatever they hold, and every string
|
|
45
|
+
is scanned both for known key formats and for the literal keys this process is
|
|
46
|
+
holding — which is what covers a custom endpoint whose key looks like nothing
|
|
47
|
+
in particular. `log.redactSecrets false` turns both off and warns you on
|
|
48
|
+
stdout when you set it.
|
|
49
|
+
|
|
50
|
+
Nothing is ever uploaded. There is no network path out of this subsystem.
|
|
51
|
+
|
|
52
|
+
New commands: `aragon logs path | list | tail [-n N] [--follow] [--level lv]
|
|
53
|
+
[--json] | clear --yes | open`, and `/logs` inside the TUI. New flags:
|
|
54
|
+
`--log-level`, `--verbose`, `--log-file` / `--no-log-file`, `--log-dir`. New
|
|
55
|
+
environment variables: `ARAGON_LOG_LEVEL`, `ARAGON_LOG_FILE`, `ARAGON_LOG_DIR`
|
|
56
|
+
— these three, unlike `ARAGON_HOME`, can come from a `.env`.
|
|
57
|
+
|
|
58
|
+
- **`aragon config get <key>` / `list [--json]` / `edit` / `home`.** `get` and
|
|
59
|
+
`list` mask every secret, `--json` included. `edit` opens `config.json` in
|
|
60
|
+
`$VISUAL` / `$EDITOR` (`notepad` on Windows), takes a `config.json.bak` first,
|
|
61
|
+
and re-parses on exit — an invalid edit is reported immediately, and the
|
|
62
|
+
backup is named in the message.
|
|
63
|
+
|
|
64
|
+
- **`/reload`** re-reads `config.json` into the running session, for when you
|
|
65
|
+
have edited it in another window. Refused while a run is in progress: swapping
|
|
66
|
+
the model mid-turn would let the second half of an answer come from different
|
|
67
|
+
settings than the first, with nothing afterwards able to explain the result.
|
|
68
|
+
|
|
69
|
+
- **Log level in the settings screen**, alongside provider / model / thinking.
|
|
70
|
+
The rest of the log settings — and `redactSecrets` above all — stay
|
|
71
|
+
command-line-only, so the one switch that can put credentials on disk cannot
|
|
72
|
+
be flipped with an arrow key.
|
|
73
|
+
|
|
74
|
+
### Fixed
|
|
75
|
+
|
|
76
|
+
- **A malformed `config.json` no longer resets everything in silence.** A stray
|
|
77
|
+
comma used to send the model, theme, timeouts, skills and (as far as you could
|
|
78
|
+
tell) your API key back to defaults, with nothing anywhere explaining it. The
|
|
79
|
+
fallback is unchanged — a bad config still never stops the CLI from starting —
|
|
80
|
+
but it now says so, and records why.
|
|
81
|
+
|
|
82
|
+
- **Ctrl+C now flushes pending log records in every mode.** The signal handlers
|
|
83
|
+
only existed in the full-screen branch, so `-p`, the inline renderer and every
|
|
84
|
+
subcommand took Node's default termination, which does not run exit handlers.
|
|
85
|
+
|
|
86
|
+
### Added
|
|
87
|
+
|
|
88
|
+
- **Plan mode.** `Shift+Tab` toggles between `BUILD` (everything as before) and
|
|
89
|
+
`PLAN`, a read-only research-and-design posture. `/plan [on|off|status]` is a
|
|
90
|
+
first-class equivalent for terminals that swallow `CSI Z`, and `--plan` /
|
|
91
|
+
`--no-plan` / `ARAGON_PLAN=1` / `planModeDefault` cover the startup case.
|
|
92
|
+
|
|
93
|
+
In `PLAN`, `write_file`, `edit_file`, `bash`, `skill_install` and
|
|
94
|
+
`skill_create` are refused **at the tool boundary**, so read-only is a
|
|
95
|
+
property of the wiring rather than a promise in a prompt. `bash` is refused in
|
|
96
|
+
full, `git status` included: a shell string cannot be classified reliably, and
|
|
97
|
+
a gate that is right most of the time is worse than one that is always right,
|
|
98
|
+
because you stop trusting the badge. The refusal names `read_file` / `glob` /
|
|
99
|
+
`grep` as the alternatives.
|
|
100
|
+
|
|
101
|
+
Two tools exist only while a human is attached. `ask_user` renders a
|
|
102
|
+
keyboard-driven wizard - 1-5 questions, 2-4 options each, exactly one marked
|
|
103
|
+
`RECOMMENDED`, plus an `Other...` free-text option - where pressing `Enter`
|
|
104
|
+
through the wizard accepts every recommendation. `submit_plan` renders the
|
|
105
|
+
plan as a scrollable card: `a` approves, `r` sends written feedback (`<-`
|
|
106
|
+
returns to the card), `Esc` dismisses. **Approving flips the session to
|
|
107
|
+
`BUILD` immediately and the same run continues into implementation.**
|
|
108
|
+
|
|
109
|
+
Dismissing a plan asks for a better one rather than stopping - the agent is
|
|
110
|
+
told to refine and resubmit - so the way out of a run is `Esc` twice: the
|
|
111
|
+
first closes the card, the second aborts the run.
|
|
112
|
+
|
|
113
|
+
Toggling mid-run is asymmetric on purpose: `build -> plan` applies at once,
|
|
114
|
+
`plan -> build` is deferred to the end of the run (the status bar shows
|
|
115
|
+
`PLAN -> BUILD` meanwhile) so a run launched under a read-only guarantee
|
|
116
|
+
cannot start writing files because of one stray keypress.
|
|
117
|
+
|
|
118
|
+
`aragon -p --plan "..."` registers no question or plan tool - there is nobody
|
|
119
|
+
to ask - but the read-only gate still applies, so it means "tell me how you
|
|
120
|
+
would do this, and do not touch my repository".
|
|
121
|
+
|
|
122
|
+
- Three flat config keys: `planModeDefault` (default `false`),
|
|
123
|
+
`planModeMaxAskRounds` (default `4`, clamped `[1, 10]`) and
|
|
124
|
+
`planModeHumanTimeoutMs` (default `1800000`, clamped `[60000, 7200000]`). All
|
|
125
|
+
three are settable with `aragon config set`. Additive, as always: a config
|
|
126
|
+
file written by an earlier version loads unchanged.
|
|
127
|
+
|
|
128
|
+
### Fixed
|
|
129
|
+
|
|
130
|
+
- A `--confirm` prompt no longer races the idle watchdog. Taking longer than
|
|
131
|
+
`idleTimeoutMs` over `Proceed? (y/N)` used to abort the run with no
|
|
132
|
+
explanation; every human wait now suspends the watchdog and restarts it in a
|
|
133
|
+
`finally`.
|
|
134
|
+
|
|
135
|
+
- Honor an explicit `NODE_TLS_REJECT_UNAUTHORIZED=0` setting in the CLI and the
|
|
136
|
+
official npm release workflow while hiding only Node's standard insecure-TLS
|
|
137
|
+
warning. Other process warnings remain visible.
|
|
138
|
+
|
|
8
139
|
## 0.5.0
|
|
9
140
|
|
|
10
141
|
### Breaking
|
package/README.md
CHANGED
|
@@ -71,6 +71,7 @@ aragon --help | -h Print help
|
|
|
71
71
|
| `--fullscreen` | Force the full-screen TUI, overriding the automatic downgrades |
|
|
72
72
|
| `--no-fullscreen` | Force the inline renderer (the 0.2.0 behavior) |
|
|
73
73
|
| `--no-exit-transcript` | Do not replay the session summary after exiting |
|
|
74
|
+
| `--plan` / `--no-plan` | Start the session in PLAN mode (read-only research + review) or force BUILD |
|
|
74
75
|
| `--no-skills` | Disable the skill system entirely (no catalog, no skill tools) |
|
|
75
76
|
| `--skill <name>` | Force-load a skill's full body for this run (repeatable) |
|
|
76
77
|
| `--skills-yes` | Approve skill installs for this run (CI / headless) |
|
|
@@ -94,9 +95,12 @@ Exit codes: `0` success · `1` agent/runtime error · `2` config/usage error ·
|
|
|
94
95
|
| `/cwd [dir]` | Show / change the tool working directory |
|
|
95
96
|
| `/save [file]` | Save the session to JSON |
|
|
96
97
|
| `/resume [file]` | Load a saved session |
|
|
98
|
+
| `/plan [on\|off\|status]` | Toggle plan mode - the keyboard-free equivalent of `Shift+Tab` |
|
|
97
99
|
| `/theme <auto\|warm\|cool\|light>` | Switch the color theme live (persisted) |
|
|
98
100
|
| `/expand [n]` | Expand / collapse the n-th-from-last (default last) tool card |
|
|
99
101
|
| `/copy` | Copy the last answer to the clipboard |
|
|
102
|
+
| `/logs` | Show where this session is being logged, and at what level |
|
|
103
|
+
| `/reload` | Re-read `config.json` after editing it in another window (refused mid-run) |
|
|
100
104
|
| `/skills [sub]` | List and manage skills (see below) |
|
|
101
105
|
| `/<skill-name> [args]` | Run an installed skill directly |
|
|
102
106
|
| `/exit` (`/quit`) | Exit |
|
|
@@ -111,6 +115,7 @@ completes, `Up` / `Down` moves the selection, `Esc` closes it.
|
|
|
111
115
|
| --- | --- |
|
|
112
116
|
| `Enter` | Submit (idle) / queue a steering message (running) |
|
|
113
117
|
| `Alt+Enter` / `Shift+Enter` | Insert a newline |
|
|
118
|
+
| `Shift+Tab` | Toggle **plan mode** (`BUILD` <-> `PLAN`). Equivalent: `/plan` |
|
|
114
119
|
| `Esc` | Abort the run / close an overlay / close a popup |
|
|
115
120
|
| `Ctrl+C` ×2 | Exit (first press warns) |
|
|
116
121
|
| `Ctrl+L` | Redraw the frame (clear the screen in inline mode) |
|
|
@@ -184,6 +189,90 @@ this mode, and mouse tracking is deliberately left off because enabling it costs
|
|
|
184
189
|
text selection and copy in most terminals. If a crash ever strands your terminal
|
|
185
190
|
on the alternate screen, `reset` restores it.
|
|
186
191
|
|
|
192
|
+
## Plan mode
|
|
193
|
+
|
|
194
|
+
`aragon` has two postures, and `Shift+Tab` switches between them. `/plan` does
|
|
195
|
+
the same thing for terminals that swallow the key (see below).
|
|
196
|
+
|
|
197
|
+
| Mode | What it means |
|
|
198
|
+
| --- | --- |
|
|
199
|
+
| `BUILD` | The default, and unchanged from earlier versions: you ask, the agent does it. |
|
|
200
|
+
| `PLAN` | Research and design only. The agent reads, asks you the decisions it cannot settle by reading, and submits a plan for approval before anything is written. |
|
|
201
|
+
|
|
202
|
+
`BUILD` is right for "rename this symbol". `PLAN` is right for "add multi-tenant
|
|
203
|
+
support" — anything where you want to see and steer the *approach* before a
|
|
204
|
+
single byte changes.
|
|
205
|
+
|
|
206
|
+
### What plan mode actually stops
|
|
207
|
+
|
|
208
|
+
In `PLAN`, five tools are refused at the tool boundary: `write_file`,
|
|
209
|
+
`edit_file`, `bash`, `skill_install` and `skill_create`. That is a property of
|
|
210
|
+
the wiring, not a promise in a prompt — the refusal happens before the tool runs,
|
|
211
|
+
so the badge is telling you something that is structurally true.
|
|
212
|
+
|
|
213
|
+
**`bash` is refused in full, `git status` included.** This is the most likely
|
|
214
|
+
question this feature generates, so: there is no reliable way to classify a shell
|
|
215
|
+
string as read-only, and a gate that is right 95 % of the time is worse than one
|
|
216
|
+
that is always right, because you stop trusting the badge. Use `read_file`,
|
|
217
|
+
`list_dir`, `glob` and `grep`, which stay available; the refusal message names
|
|
218
|
+
them so the agent has somewhere to go. There is no allowlist and there will not
|
|
219
|
+
be one built out of substring matching.
|
|
220
|
+
|
|
221
|
+
Everything else still works: reading, searching, loading skills, and asking you
|
|
222
|
+
questions.
|
|
223
|
+
|
|
224
|
+
### The two plan-mode tools
|
|
225
|
+
|
|
226
|
+
- **`ask_user`** renders a keyboard-driven wizard: 1–5 questions, 2–4 options
|
|
227
|
+
each, exactly one marked `RECOMMENDED`, plus an `Other…` free-text option.
|
|
228
|
+
`↑`/`↓` choose, `Enter` confirms and advances, `←` goes back, `Esc` cancels.
|
|
229
|
+
Pressing `Enter` through the whole wizard accepts every recommendation, which
|
|
230
|
+
is a deliberate "use your judgement" path rather than an accident. A last
|
|
231
|
+
screen lets you review before submitting.
|
|
232
|
+
- **`submit_plan`** renders the plan as a scrollable card: `a` approves, `r`
|
|
233
|
+
opens a one-line feedback field (`Enter` sends it, `←` goes back to the card),
|
|
234
|
+
`Esc` dismisses. **Approving flips the session to `BUILD` immediately and the
|
|
235
|
+
same run continues straight into implementation** — you do not have to re-ask.
|
|
236
|
+
|
|
237
|
+
Cancelling either one is not an error. The agent is told to proceed on stated
|
|
238
|
+
assumptions rather than to retry.
|
|
239
|
+
|
|
240
|
+
**Dismissing a plan is not how you stop.** `Esc` on a plan card asks for a
|
|
241
|
+
*better* plan — the agent is told to refine it and submit again — so a model that
|
|
242
|
+
keeps submitting keeps getting cards. To stop the run itself, **press `Esc`
|
|
243
|
+
twice**: the first closes the card, the second aborts the run. `Ctrl+C` twice
|
|
244
|
+
still exits the session outright.
|
|
245
|
+
|
|
246
|
+
### Where the mode is shown
|
|
247
|
+
|
|
248
|
+
The status bar always names a non-default mode (`PLAN`, or `PLAN → BUILD` while
|
|
249
|
+
a switch is pending), including on short terminals, with `--no-hints`, and in
|
|
250
|
+
inline mode. The composer additionally shows a `PLAN` chip on its hint row and
|
|
251
|
+
tints its border, where there is room for it.
|
|
252
|
+
|
|
253
|
+
### Switching mid-run
|
|
254
|
+
|
|
255
|
+
Tightening applies at once; loosening waits. Pressing `Shift+Tab` toward `PLAN`
|
|
256
|
+
during a run takes effect immediately — you pressed it *because* the agent is
|
|
257
|
+
about to do something. Pressing it toward `BUILD` during a run is **deferred to
|
|
258
|
+
the end of the run**, so a session you launched under a read-only guarantee
|
|
259
|
+
cannot start writing files because of one stray keypress. The status bar shows
|
|
260
|
+
`PLAN → BUILD` while that is pending. Approving a plan is the one exception, and
|
|
261
|
+
it is an informed act rather than a stray keypress.
|
|
262
|
+
|
|
263
|
+
### If `Shift+Tab` does nothing
|
|
264
|
+
|
|
265
|
+
Some multiplexers and remote-desktop stacks never send `CSI Z`. `/plan`,
|
|
266
|
+
`/plan on`, `/plan off` and `/plan status` are first-class equivalents, and
|
|
267
|
+
`--plan` / `ARAGON_PLAN=1` / `planModeDefault` cover the startup case.
|
|
268
|
+
|
|
269
|
+
### Headless
|
|
270
|
+
|
|
271
|
+
`aragon -p --plan "add SSO"` is a useful combination: the read-only gate still
|
|
272
|
+
applies, so it means *"tell me how you would do this, and do not touch my
|
|
273
|
+
repository"*. No question or plan tool is registered there — there is nobody to
|
|
274
|
+
ask — and the agent writes the finished plan as its final message in markdown.
|
|
275
|
+
|
|
187
276
|
## Built-in tools
|
|
188
277
|
|
|
189
278
|
`read_file`, `write_file`, `edit_file`, `list_dir`, `glob`, `grep`, `bash` — all
|
|
@@ -484,17 +573,26 @@ env / `.env` → CLI flags**.
|
|
|
484
573
|
- **Env / `.env`**: `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`,
|
|
485
574
|
`GOOGLE_API_KEY` / `GEMINI_API_KEY`, plus `ARAGON_PROVIDER`, `ARAGON_MODEL`,
|
|
486
575
|
`ARAGON_BASE_URL`, `ARAGON_THINKING`, `ARAGON_MAX_TOKENS`, `ARAGON_THEME`,
|
|
487
|
-
`ARAGON_FULLSCREEN`, `
|
|
488
|
-
`
|
|
576
|
+
`ARAGON_FULLSCREEN`, `ARAGON_PLAN` (`1` starts in plan mode),
|
|
577
|
+
`ARAGON_SKILLS` (`0` disables), `ARAGON_SKILLS_PATH`,
|
|
578
|
+
`ARAGON_SKILLS_DISABLED` (comma-separated names), `ARAGON_LOG_LEVEL`,
|
|
579
|
+
`ARAGON_LOG_FILE` (`0` disables), `ARAGON_LOG_DIR`.
|
|
580
|
+
`ARAGON_HOME` is the exception that **cannot** come from `.env`: it is read
|
|
581
|
+
before any `.env` is loaded. See [Files & logs](#files--logs).
|
|
489
582
|
- **User config file** (`aragon config path`): JSON, written `0600` on POSIX.
|
|
490
583
|
Holds provider/model/keys and MRU lists. Keys are masked in the UI and never
|
|
491
|
-
logged.
|
|
584
|
+
logged. It lives in your home directory — see [Files & logs](#files--logs) —
|
|
585
|
+
and editing it by hand is supported: `aragon config edit` opens it, and an
|
|
586
|
+
invalid edit is reported rather than silently resetting every setting.
|
|
492
587
|
|
|
493
588
|
| Config key | Default | Meaning |
|
|
494
589
|
| --- | --- | --- |
|
|
495
590
|
| `fullscreen` | `true` | Use the full-screen TUI (still subject to the automatic downgrades). Setting it to `false` opts out permanently; leaving it `true` is *not* a force — only `--fullscreen` / `ARAGON_FULLSCREEN=1` override the heuristics. |
|
|
496
591
|
| `exitTranscript` | `true` | Replay a plain-text session summary after exiting (full-screen only). |
|
|
497
592
|
| `transcriptWindow` | `300` | How many trailing entries the full-screen viewport renders, clamped to `[50, 2000]`. The full history stays in memory and in `/save`. |
|
|
593
|
+
| `planModeDefault` | `false` | Start every session in plan mode. `--no-plan` still overrides it for a single run. |
|
|
594
|
+
| `planModeMaxAskRounds` | `4` | `ask_user` rounds allowed per user message, clamped to `[1, 10]`. The counter resets on your next message; steering does **not** reset it. |
|
|
595
|
+
| `planModeHumanTimeoutMs` | `1800000` | Ceiling on a single question / plan wait, clamped to `[60000, 7200000]`. Thirty minutes is far outside "went to get coffee", but a ceiling has to exist so an unattended terminal cannot wedge a CI job forever. |
|
|
498
596
|
| `skills.enabled` | `true` | Master switch for the skill system. |
|
|
499
597
|
| `skills.requireApproval` | `true` | Require a human to approve `skill_install` / `skill_create`. |
|
|
500
598
|
| `skills.catalogMaxBytes` | `6000` | Level 1 catalog ceiling, in UTF-8 **bytes**, clamped to `[500, 40000]`. |
|
|
@@ -505,6 +603,13 @@ env / `.env` → CLI flags**.
|
|
|
505
603
|
| `skills.integrity` | `warn` | What to do when `SKILL.md` no longer matches the copy you approved. `off` skips the check; `warn` flags it in `/skills list` and once per session; `strict` removes it from the catalog and makes `skill()` refuse it. Defaults to `warn` because editing an installed skill is a legitimate thing to do — `strict` suits CI and managed environments. |
|
|
506
604
|
| `skills.usageTracking` | `true` | Keep local per-skill use counters to rank the catalog. Name, count and timestamp only; never transmitted. Inspect with `aragon skills usage`, erase with `--reset --yes`. |
|
|
507
605
|
| `skills.toolPolicy` | `enforce` | How hard a skill's `allowed-tools` bites, for the turn it is loaded in. `off` disables it and says nothing about it to the model; `warn` runs the tool and reports it; `enforce` refuses. Unlike `skills.integrity`, a false positive here means a skill AUTHOR under-declared their own skill — which `aragon skills doctor` reports before it can bite. |
|
|
606
|
+
| `log.level` | `info` | `silent` · `error` · `warn` · `info` · `debug` · `trace`. See [Files & logs](#files--logs) for what each level records. |
|
|
607
|
+
| `log.toFile` | `true` | Write records to a file at all. `false` here is respected; `--log-file` overrides it for one run. |
|
|
608
|
+
| `log.dir` | `""` | Log directory. Empty means `<home>/logs`. Only **absolute** paths are accepted — a relative one would mean a different directory for every working directory you launch from. |
|
|
609
|
+
| `log.maxFileBytes` | `5242880` | Rotate once a file would exceed this, clamped to `[65536, 268435456]`. |
|
|
610
|
+
| `log.maxFiles` | `10` | Files kept in the log directory, clamped to `[1, 200]`. The oldest beyond this are deleted — on rotation **and** on the first write of each day. |
|
|
611
|
+
| `log.redactSecrets` | `true` | Run every record through redaction. Setting it to `false` is the one way to get credentials onto disk, so it prints a warning and has no settings-screen entry. |
|
|
612
|
+
| `log.previewChars` | `512` | How much user content `debug` keeps per field, clamped to `[0, 8192]`. `trace` is never truncated. |
|
|
508
613
|
|
|
509
614
|
Byte, not character: `ToolExecutor` truncates at 100 000 **bytes**, so a
|
|
510
615
|
character-based budget would be roughly triple its nominal size for CJK text
|
|
@@ -513,6 +618,108 @@ and would get cut mid-tag.
|
|
|
513
618
|
These are additive: a config file written by an earlier version loads
|
|
514
619
|
unchanged, with no migration and no version bump.
|
|
515
620
|
|
|
621
|
+
## Files & logs
|
|
622
|
+
|
|
623
|
+
Everything AragonAgent keeps for you lives under one directory in your home:
|
|
624
|
+
|
|
625
|
+
```
|
|
626
|
+
~/.aragon-agent/ (Windows: C:\Users\<you>\.aragon-agent\)
|
|
627
|
+
├── config.json settings + API keys (0600 on POSIX)
|
|
628
|
+
├── config.json.bak written by `aragon config edit` before it opens
|
|
629
|
+
├── logs/
|
|
630
|
+
│ ├── aragon-2026-07-27.log today, JSON Lines
|
|
631
|
+
│ └── aragon-2026-07-27.1.log rotated at log.maxFileBytes
|
|
632
|
+
├── sessions/ /save and /resume
|
|
633
|
+
├── skills/ aragon skills install
|
|
634
|
+
└── skill-usage.json
|
|
635
|
+
```
|
|
636
|
+
|
|
637
|
+
`ARAGON_HOME` moves the whole tree. **It cannot come from a `.env` file** — the
|
|
638
|
+
path is resolved when the process starts, long before a `.env` is read — so set
|
|
639
|
+
it as a real environment variable. `aragon config home` always prints the
|
|
640
|
+
directory actually in use.
|
|
641
|
+
|
|
642
|
+
Upgrading from 0.5.0 or earlier moves your config, sessions and skills here
|
|
643
|
+
automatically, once, and prints a line on stderr when it does. The old
|
|
644
|
+
`%APPDATA%\aragon-agent-nodejs` / `%LOCALAPPDATA%\aragon-agent-nodejs`
|
|
645
|
+
directories are **left in place** so that reinstalling an older build stays
|
|
646
|
+
lossless; `aragon config home` names them, and you can delete them once you are
|
|
647
|
+
satisfied.
|
|
648
|
+
|
|
649
|
+
### What gets logged
|
|
650
|
+
|
|
651
|
+
Logs are local files. Nothing is uploaded, ever — there is no network path out
|
|
652
|
+
of this subsystem at all.
|
|
653
|
+
|
|
654
|
+
| Level | Records | Contains your content? |
|
|
655
|
+
| --- | --- | --- |
|
|
656
|
+
| `error` | crashes, failed requests, config write/parse failures | no |
|
|
657
|
+
| `warn` | degraded migrations, clamped values, dropped records | no |
|
|
658
|
+
| `info` *(default)* | start/exit, config writes, turn boundaries with token counts, tool names and durations | **no** |
|
|
659
|
+
| `debug` | the above, plus prompts, replies and tool arguments truncated to `log.previewChars` | yes, truncated |
|
|
660
|
+
| `trace` | full message bodies and full tool output | yes, in full |
|
|
661
|
+
|
|
662
|
+
The default is `info` specifically so that attaching a log to a bug report is
|
|
663
|
+
safe. **`debug` and `trace` write what you typed and what the model replied** —
|
|
664
|
+
check before sharing one.
|
|
665
|
+
|
|
666
|
+
API keys are removed at every level, by two independent passes: any field whose
|
|
667
|
+
name looks like a credential is blanked whatever it holds, and every string is
|
|
668
|
+
scanned for known key formats *and* for the literal keys this process is
|
|
669
|
+
holding. The second half is what covers a custom endpoint whose key looks like
|
|
670
|
+
nothing in particular. Setting `log.redactSecrets false` disables both, and says
|
|
671
|
+
so on stdout when you do.
|
|
672
|
+
|
|
673
|
+
### Commands
|
|
674
|
+
|
|
675
|
+
```bash
|
|
676
|
+
aragon logs path # where records are going right now, and at what level
|
|
677
|
+
aragon logs list # files, sizes, timestamps
|
|
678
|
+
aragon logs tail -n 50 # render the last 50 records
|
|
679
|
+
aragon logs tail --follow # keep printing new ones
|
|
680
|
+
aragon logs tail --json # raw JSON Lines, for jq
|
|
681
|
+
aragon logs tail --level warn # only warn and above
|
|
682
|
+
aragon logs clear --yes # delete every log file
|
|
683
|
+
aragon logs open # open the directory in your file manager
|
|
684
|
+
|
|
685
|
+
aragon config home # the user-state root (and whether ARAGON_HOME set it)
|
|
686
|
+
aragon config get log.level # one value; secrets always masked
|
|
687
|
+
aragon config list --json # everything; secrets always masked here too
|
|
688
|
+
aragon config edit # open config.json in $VISUAL / $EDITOR
|
|
689
|
+
```
|
|
690
|
+
|
|
691
|
+
Per-run overrides, none of which are persisted:
|
|
692
|
+
|
|
693
|
+
```bash
|
|
694
|
+
aragon --log-level debug "…" # or --verbose, which means the same thing
|
|
695
|
+
aragon --no-log-file "…" # nothing reaches a file this run
|
|
696
|
+
aragon --log-dir D:\logs "…"
|
|
697
|
+
```
|
|
698
|
+
|
|
699
|
+
`ARAGON_LOG_LEVEL`, `ARAGON_LOG_FILE=0` and `ARAGON_LOG_DIR` do the same from the
|
|
700
|
+
environment, and unlike `ARAGON_HOME` these three *can* come from a `.env`.
|
|
701
|
+
|
|
702
|
+
### Insecure TLS opt-in
|
|
703
|
+
|
|
704
|
+
When `NODE_TLS_REJECT_UNAUTHORIZED` is the exact string `0`, the installed or
|
|
705
|
+
locally built `aragon` process honors that setting and suppresses only Node's
|
|
706
|
+
standard insecure-TLS warning. Every unrelated process warning remains visible,
|
|
707
|
+
and any other value leaves warning behavior unchanged. The check happens when a
|
|
708
|
+
warning is emitted, so a `0` loaded from the project `.env` is covered too; the
|
|
709
|
+
CLI never creates, normalizes, or persists this variable.
|
|
710
|
+
|
|
711
|
+
> **Security warning:** `0` genuinely disables certificate verification. It does
|
|
712
|
+
> not make an insecure connection safe and can expose credentials or request
|
|
713
|
+
> contents to interception. Use it only in a controlled environment where you
|
|
714
|
+
> accept that risk.
|
|
715
|
+
|
|
716
|
+
The automatic filter starts with the `aragon` process. An earlier `npm install`
|
|
717
|
+
or `npx` bootstrap belongs to npm and is outside the installed package's process
|
|
718
|
+
boundary, so that parent may still print Node's warning. The official repository
|
|
719
|
+
release flow covers its npm children through `publish-latest.ps1`; callers that
|
|
720
|
+
own another npm/npx parent must preload the filter in that parent themselves if
|
|
721
|
+
quiet output is required.
|
|
722
|
+
|
|
516
723
|
### Theming & color
|
|
517
724
|
|
|
518
725
|
`--theme` / `config.theme` / `/theme` pick a palette: `warm`, `cool`, `light`, or
|
|
@@ -552,6 +759,23 @@ node packages/cli/dist/cli.js --version
|
|
|
552
759
|
- `echo "list files" | node dist/cli.js -p` prints an answer and exits `0`.
|
|
553
760
|
- A missing/invalid key produces a visible, actionable message (never a blank
|
|
554
761
|
screen), both in the TUI and headless.
|
|
762
|
+
- `Shift+Tab` at 40, 80 and 120 columns - the chip, the hint and the status bar
|
|
763
|
+
are all legible and nothing wraps onto a second row.
|
|
764
|
+
- The question wizard at 24 rows with 5 questions x 4 options - no clipping, and
|
|
765
|
+
the `n/N` counter matches what is on screen.
|
|
766
|
+
- Approve a plan and watch the SAME run start writing files, with no second
|
|
767
|
+
prompt.
|
|
768
|
+
- `--no-color` on a legacy `cmd.exe` - the chip renders `[PLAN]`, radios render
|
|
769
|
+
`*`/`o`, checkboxes render `[x]`/`[ ]`, no mojibake anywhere.
|
|
770
|
+
- A plan with a 600-character summary and a 400-character step detail - the text
|
|
771
|
+
wraps and scrolls, the footer count matches the real number of rows, and
|
|
772
|
+
nothing is truncated to a single line.
|
|
773
|
+
- `--no-hints` on a 20-row terminal in plan mode - the status bar still says
|
|
774
|
+
`PLAN` with no chip on screen.
|
|
775
|
+
- Dismiss a plan card with `Esc`, let the agent resubmit, then press `Esc` twice:
|
|
776
|
+
the run aborts and the session returns to an idle prompt. Do this one BY HAND
|
|
777
|
+
as well as in a test - the point of the check is whether the exit is findable,
|
|
778
|
+
which no assertion can tell you.
|
|
555
779
|
|
|
556
780
|
## License
|
|
557
781
|
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent mode vocabulary (plan-mode §5.1).
|
|
3
|
+
*
|
|
4
|
+
* Pure: no React, no I/O, no `node:*`. Imported by the controller, the tool
|
|
5
|
+
* gate, the prompt builder, the slash command and four UI components, which is
|
|
6
|
+
* exactly why it must stay free of every one of their dependencies.
|
|
7
|
+
*
|
|
8
|
+
* `PLAN_MODE_BLOCKED_TOOLS` is deliberately NOT here. It lives in
|
|
9
|
+
* `tools/index.ts` beside `SKILL_TOOL_FLOOR`, because the invariant worth having
|
|
10
|
+
* is that the two sets PARTITION `HOST_TOOL_NAMES` — and a partition test is
|
|
11
|
+
* only as trustworthy as the distance between the two definitions. This file
|
|
12
|
+
* owns the mode vocabulary; that file owns which tools the modes act on.
|
|
13
|
+
*
|
|
14
|
+
* ASCII ONLY in every string literal below. `agent/` is inside the glyph
|
|
15
|
+
* scanner's scope (`glyphs.test.ts`), so a stray ellipsis here fails the build —
|
|
16
|
+
* which is why `OTHER_OPTION_LABEL` is a bare word and the ellipsis is appended
|
|
17
|
+
* at render time from `glyphs.ellipsis`.
|
|
18
|
+
*/
|
|
19
|
+
export type AgentMode = 'build' | 'plan';
|
|
20
|
+
export declare const AGENT_MODES: readonly AgentMode[];
|
|
21
|
+
/** The user-visible word for each mode. English, per the repo convention. */
|
|
22
|
+
export declare const MODE_LABEL: Record<AgentMode, string>;
|
|
23
|
+
/**
|
|
24
|
+
* The next mode in the cycle.
|
|
25
|
+
*
|
|
26
|
+
* Written as a cycle rather than a boolean flip so that adding Claude Code's
|
|
27
|
+
* "auto-accept edits" as a third posture is a one-line change to `AGENT_MODES`
|
|
28
|
+
* and nothing else. Two ship today (§1 non-goals).
|
|
29
|
+
*/
|
|
30
|
+
export declare function nextMode(current: AgentMode): AgentMode;
|
|
31
|
+
/** The two tools that only exist because a human is attached. */
|
|
32
|
+
export declare const PLAN_TOOL_NAMES: readonly ["ask_user", "submit_plan"];
|
|
33
|
+
/**
|
|
34
|
+
* The synthetic free-text option appended to every question.
|
|
35
|
+
*
|
|
36
|
+
* Plain `Other`, with no ellipsis: this module is inside the glyph scanner's
|
|
37
|
+
* scope, and the overlay appends `glyphs.ellipsis` itself so the label degrades
|
|
38
|
+
* to `Other...` on a terminal without Unicode.
|
|
39
|
+
*/
|
|
40
|
+
export declare const OTHER_OPTION_LABEL = "Other";
|
|
41
|
+
/**
|
|
42
|
+
* Why a mutating tool was refused in plan mode.
|
|
43
|
+
*
|
|
44
|
+
* The wording carries weight beyond politeness (§3.9). A run that flips
|
|
45
|
+
* `build -> plan` mid-flight keeps its original system prompt to the end — the
|
|
46
|
+
* loop reads `ctx.systemPrompt`, which was copied by value when the run
|
|
47
|
+
* started — so for the rest of that run this refusal is the ONLY place the
|
|
48
|
+
* model learns that plan mode is on. A bare "not permitted" reads as a tool
|
|
49
|
+
* malfunction and gets retried.
|
|
50
|
+
*/
|
|
51
|
+
export declare function planRefusal(tool: string): string;
|
|
52
|
+
/** Why `submit_plan` was refused outside plan mode. */
|
|
53
|
+
export declare function submitPlanRefusal(): string;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent mode vocabulary (plan-mode §5.1).
|
|
3
|
+
*
|
|
4
|
+
* Pure: no React, no I/O, no `node:*`. Imported by the controller, the tool
|
|
5
|
+
* gate, the prompt builder, the slash command and four UI components, which is
|
|
6
|
+
* exactly why it must stay free of every one of their dependencies.
|
|
7
|
+
*
|
|
8
|
+
* `PLAN_MODE_BLOCKED_TOOLS` is deliberately NOT here. It lives in
|
|
9
|
+
* `tools/index.ts` beside `SKILL_TOOL_FLOOR`, because the invariant worth having
|
|
10
|
+
* is that the two sets PARTITION `HOST_TOOL_NAMES` — and a partition test is
|
|
11
|
+
* only as trustworthy as the distance between the two definitions. This file
|
|
12
|
+
* owns the mode vocabulary; that file owns which tools the modes act on.
|
|
13
|
+
*
|
|
14
|
+
* ASCII ONLY in every string literal below. `agent/` is inside the glyph
|
|
15
|
+
* scanner's scope (`glyphs.test.ts`), so a stray ellipsis here fails the build —
|
|
16
|
+
* which is why `OTHER_OPTION_LABEL` is a bare word and the ellipsis is appended
|
|
17
|
+
* at render time from `glyphs.ellipsis`.
|
|
18
|
+
*/
|
|
19
|
+
export const AGENT_MODES = ['build', 'plan'];
|
|
20
|
+
/** The user-visible word for each mode. English, per the repo convention. */
|
|
21
|
+
export const MODE_LABEL = { build: 'BUILD', plan: 'PLAN' };
|
|
22
|
+
/**
|
|
23
|
+
* The next mode in the cycle.
|
|
24
|
+
*
|
|
25
|
+
* Written as a cycle rather than a boolean flip so that adding Claude Code's
|
|
26
|
+
* "auto-accept edits" as a third posture is a one-line change to `AGENT_MODES`
|
|
27
|
+
* and nothing else. Two ship today (§1 non-goals).
|
|
28
|
+
*/
|
|
29
|
+
export function nextMode(current) {
|
|
30
|
+
const index = AGENT_MODES.indexOf(current);
|
|
31
|
+
return AGENT_MODES[(index + 1) % AGENT_MODES.length];
|
|
32
|
+
}
|
|
33
|
+
/** The two tools that only exist because a human is attached. */
|
|
34
|
+
export const PLAN_TOOL_NAMES = ['ask_user', 'submit_plan'];
|
|
35
|
+
/**
|
|
36
|
+
* The synthetic free-text option appended to every question.
|
|
37
|
+
*
|
|
38
|
+
* Plain `Other`, with no ellipsis: this module is inside the glyph scanner's
|
|
39
|
+
* scope, and the overlay appends `glyphs.ellipsis` itself so the label degrades
|
|
40
|
+
* to `Other...` on a terminal without Unicode.
|
|
41
|
+
*/
|
|
42
|
+
export const OTHER_OPTION_LABEL = 'Other';
|
|
43
|
+
/** Read-only alternatives named in every refusal, so the model has somewhere to go. */
|
|
44
|
+
const READ_ONLY_ALTERNATIVES = 'read_file / list_dir / glob / grep';
|
|
45
|
+
/**
|
|
46
|
+
* Why a mutating tool was refused in plan mode.
|
|
47
|
+
*
|
|
48
|
+
* The wording carries weight beyond politeness (§3.9). A run that flips
|
|
49
|
+
* `build -> plan` mid-flight keeps its original system prompt to the end — the
|
|
50
|
+
* loop reads `ctx.systemPrompt`, which was copied by value when the run
|
|
51
|
+
* started — so for the rest of that run this refusal is the ONLY place the
|
|
52
|
+
* model learns that plan mode is on. A bare "not permitted" reads as a tool
|
|
53
|
+
* malfunction and gets retried.
|
|
54
|
+
*/
|
|
55
|
+
export function planRefusal(tool) {
|
|
56
|
+
const extra = tool === 'bash'
|
|
57
|
+
? ' bash is refused in full, including read-only commands like "git status":' +
|
|
58
|
+
' a shell string cannot be classified reliably, and a gate that is right' +
|
|
59
|
+
' most of the time is worse than one that is always right.'
|
|
60
|
+
: '';
|
|
61
|
+
return (`Plan mode is active, so ${tool} is refused.${extra}` +
|
|
62
|
+
` Use ${READ_ONLY_ALTERNATIVES} to research, then call submit_plan.` +
|
|
63
|
+
' Do not try to work around this; finish the plan instead.');
|
|
64
|
+
}
|
|
65
|
+
/** Why `submit_plan` was refused outside plan mode. */
|
|
66
|
+
export function submitPlanRefusal() {
|
|
67
|
+
return ('submit_plan is only available in Plan mode. You are in Build mode - ' +
|
|
68
|
+
'just do the work and summarize when you are done.');
|
|
69
|
+
}
|
|
@@ -11,7 +11,9 @@
|
|
|
11
11
|
import { ModelRegistry, type AgentEvent, type AgentTool, type Message, type ModelInfo, type ProviderRegistry, type ThinkingLevel } from '@aragon-agent/core';
|
|
12
12
|
import type { CliConfig, ThemeName } from '../config/schema.js';
|
|
13
13
|
import { type ConfirmRequest } from '../tools/index.js';
|
|
14
|
+
import { type HumanInputGate } from '../tools/human-input.js';
|
|
14
15
|
import { SkillService, type ApprovalGate } from '../skills/service.js';
|
|
16
|
+
import type { AgentMode } from './agent-mode.js';
|
|
15
17
|
import type { NoticeLevel } from './reducer.js';
|
|
16
18
|
/** Approval gate used whenever there is provably no human to ask (headless). */
|
|
17
19
|
export declare const DENY_ALL_APPROVAL: ApprovalGate;
|
|
@@ -37,6 +39,24 @@ export interface ControllerDeps {
|
|
|
37
39
|
onSkillsChanged?: () => void;
|
|
38
40
|
/** Transcript notices from the skill subsystem. */
|
|
39
41
|
notify?: (level: NoticeLevel, text: string) => void;
|
|
42
|
+
/**
|
|
43
|
+
* The plan-mode human channel (§3.5). Defaults to `DENY_ALL_HUMAN_INPUT`, so
|
|
44
|
+
* forgetting to pass one registers NO plan tools rather than registering tools
|
|
45
|
+
* that would hang. A THIRD approval channel on purpose: `confirm` auto-approves
|
|
46
|
+
* when unattached and `approval` denies, but neither can render a question
|
|
47
|
+
* wizard or a plan card.
|
|
48
|
+
*/
|
|
49
|
+
humanInput?: HumanInputGate;
|
|
50
|
+
}
|
|
51
|
+
/** What `setAgentMode` actually adopted — see `AgentController.setAgentMode`. */
|
|
52
|
+
export interface AgentModeState {
|
|
53
|
+
effective: AgentMode;
|
|
54
|
+
/** Non-null only while a `plan -> build` switch is waiting for `agent_end`. */
|
|
55
|
+
pending: AgentMode | null;
|
|
56
|
+
}
|
|
57
|
+
export interface PlanStatus extends AgentModeState {
|
|
58
|
+
askRoundsUsed: number;
|
|
59
|
+
maxAskRounds: number;
|
|
40
60
|
}
|
|
41
61
|
export interface PreflightResult {
|
|
42
62
|
ok: boolean;
|
|
@@ -55,6 +75,11 @@ export declare class AgentController {
|
|
|
55
75
|
private onSkillsChanged?;
|
|
56
76
|
/** Mutable session cwd — tools resolve relative paths against this. */
|
|
57
77
|
private cwd;
|
|
78
|
+
private effectiveMode;
|
|
79
|
+
private pendingMode;
|
|
80
|
+
private askRounds;
|
|
81
|
+
/** Static: whether this session could ever render a question overlay. */
|
|
82
|
+
private readonly planInteractive;
|
|
58
83
|
constructor(config: CliConfig, deps?: ControllerDeps);
|
|
59
84
|
private resolveKey;
|
|
60
85
|
/**
|
|
@@ -110,6 +135,50 @@ export declare class AgentController {
|
|
|
110
135
|
steer(text: string): void;
|
|
111
136
|
followUp(text: string): void;
|
|
112
137
|
isRunning(): boolean;
|
|
138
|
+
getAgentMode(): AgentMode;
|
|
139
|
+
/**
|
|
140
|
+
* Request a mode change and return what was ACTUALLY ADOPTED.
|
|
141
|
+
*
|
|
142
|
+
* Returning the adopted state rather than `void` is the whole point of this
|
|
143
|
+
* signature. The caller dispatches THIS value into the view, never the value
|
|
144
|
+
* it asked for — dispatching the request is the one way to make the badge lie
|
|
145
|
+
* about what the gate will do, and the API shape forecloses it (R-P7).
|
|
146
|
+
*
|
|
147
|
+
* The two directions are deliberately asymmetric:
|
|
148
|
+
*
|
|
149
|
+
* - `build -> plan` applies IMMEDIATELY. Tightening a permission mid-run is
|
|
150
|
+
* always safe; the user pressed the key *because* the agent is about to do
|
|
151
|
+
* something they want to stop.
|
|
152
|
+
* - `plan -> build` is DEFERRED to `agent_end`. Applying it live would mean a
|
|
153
|
+
* run the user launched under a read-only guarantee could start writing
|
|
154
|
+
* files because of one stray keypress.
|
|
155
|
+
* - `{ force: true }` is the single exception, used only by `submit_plan`'s
|
|
156
|
+
* approval path: the user has just read the plan and authorized exactly
|
|
157
|
+
* that work. That is an informed act; a stray Shift+Tab is not. If this
|
|
158
|
+
* code is ever refactored, that distinction is the thing to preserve.
|
|
159
|
+
*/
|
|
160
|
+
setAgentMode(next: AgentMode, opts?: {
|
|
161
|
+
force?: boolean;
|
|
162
|
+
}): AgentModeState;
|
|
163
|
+
/**
|
|
164
|
+
* Adopt a deferred `plan -> build` switch. Call from the App's `agent_end`
|
|
165
|
+
* handling. Returns `null` when nothing was pending, so the caller can skip
|
|
166
|
+
* both the dispatch and the toast.
|
|
167
|
+
*/
|
|
168
|
+
applyPendingMode(): AgentModeState | null;
|
|
169
|
+
/** Named read surface for `/plan status`, so no command reaches into internals. */
|
|
170
|
+
getPlanStatus(): PlanStatus;
|
|
171
|
+
/** Spend one `ask_user` round. Called from the tool, never from the UI. */
|
|
172
|
+
private takeAskRound;
|
|
173
|
+
/**
|
|
174
|
+
* Run `fn` with the idle watchdog paused.
|
|
175
|
+
*
|
|
176
|
+
* `try/finally` rather than two sequential calls: a throw inside the overlay
|
|
177
|
+
* path must not leave the watchdog disarmed for the rest of the run. Also used
|
|
178
|
+
* by the `--confirm` gate, which had exactly this bug — a user who took four
|
|
179
|
+
* minutes over `Proceed? (y/N)` had their run killed by the watchdog.
|
|
180
|
+
*/
|
|
181
|
+
withHumanWait<T>(fn: () => Promise<T>): Promise<T>;
|
|
113
182
|
setModel(provider: string, model: string, baseUrl?: string): void;
|
|
114
183
|
setThinkingLevel(level: ThinkingLevel): void;
|
|
115
184
|
setMaxTokens(value: number | undefined): void;
|