@aragon-agent/cli 0.6.3 → 0.6.7
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 +142 -0
- package/README.md +203 -13
- package/dist/agent/controller.d.ts +158 -2
- package/dist/agent/controller.js +400 -1
- package/dist/agent/reducer.d.ts +102 -19
- package/dist/agent/reducer.js +162 -71
- package/dist/agent/system-prompt.d.ts +14 -0
- package/dist/agent/system-prompt.js +2 -0
- package/dist/agent/usage.d.ts +34 -0
- package/dist/agent/usage.js +43 -0
- package/dist/cli.js +132 -23
- package/dist/commands/builtins.js +101 -1
- package/dist/compaction/child.js +5 -0
- package/dist/compaction/command.js +14 -1
- package/dist/compaction/compactor.d.ts +94 -24
- package/dist/compaction/compactor.js +247 -98
- package/dist/compaction/context-command.d.ts +33 -0
- package/dist/compaction/context-command.js +166 -0
- package/dist/compaction/meter.d.ts +251 -0
- package/dist/compaction/meter.js +428 -0
- package/dist/compaction/pressure.d.ts +6 -0
- package/dist/compaction/pressure.js +4 -0
- package/dist/compaction/types.d.ts +77 -0
- package/dist/compaction/wiring.d.ts +56 -0
- package/dist/compaction/wiring.js +107 -25
- package/dist/config/cli-commands.js +5 -0
- package/dist/config/env.d.ts +1 -1
- package/dist/config/env.js +63 -2
- package/dist/config/load.d.ts +28 -0
- package/dist/config/load.js +83 -1
- package/dist/config/schema.d.ts +129 -0
- package/dist/config/schema.js +69 -0
- package/dist/config/store.js +47 -1
- package/dist/exec/events.d.ts +138 -1
- package/dist/exec/events.js +42 -0
- package/dist/exec/index.js +43 -6
- package/dist/exec/progress-reporter.d.ts +23 -0
- package/dist/exec/progress-reporter.js +88 -0
- package/dist/exec/runner.d.ts +34 -0
- package/dist/exec/runner.js +137 -25
- package/dist/fast/reviewer.d.ts +19 -1
- package/dist/fast/reviewer.js +22 -0
- package/dist/fast/types.d.ts +15 -0
- package/dist/fast/wiring.d.ts +10 -1
- package/dist/fast/wiring.js +18 -1
- package/dist/input/limits.d.ts +72 -0
- package/dist/input/limits.js +63 -0
- package/dist/input/paste-parse.d.ts +71 -0
- package/dist/input/paste-parse.js +95 -0
- package/dist/input/stdin-filter.d.ts +81 -0
- package/dist/input/stdin-filter.js +379 -0
- package/dist/logging/install.d.ts +2 -0
- package/dist/logging/install.js +53 -1
- package/dist/proc/classify.d.ts +52 -0
- package/dist/proc/classify.js +143 -0
- package/dist/proc/kill-tree.d.ts +42 -0
- package/dist/proc/kill-tree.js +119 -0
- package/dist/proc/limits.d.ts +84 -0
- package/dist/proc/limits.js +84 -0
- package/dist/proc/log-ring.d.ts +68 -0
- package/dist/proc/log-ring.js +102 -0
- package/dist/proc/prompt.d.ts +24 -0
- package/dist/proc/prompt.js +49 -0
- package/dist/proc/readiness.d.ts +102 -0
- package/dist/proc/readiness.js +219 -0
- package/dist/proc/supervisor.d.ts +103 -0
- package/dist/proc/supervisor.js +465 -0
- package/dist/proc/types.d.ts +175 -0
- package/dist/proc/types.js +15 -0
- package/dist/session/persist.js +36 -1
- package/dist/todo/limits.d.ts +4 -17
- package/dist/todo/limits.js +4 -17
- package/dist/todo/panel-rows.d.ts +8 -6
- package/dist/todo/panel-rows.js +19 -6
- package/dist/tools/bash-tool.d.ts +51 -2
- package/dist/tools/bash-tool.js +321 -51
- package/dist/tools/fs-tools.d.ts +17 -0
- package/dist/tools/index.d.ts +55 -2
- package/dist/tools/index.js +39 -1
- package/dist/tools/proc-tools.d.ts +25 -0
- package/dist/tools/proc-tools.js +102 -0
- package/dist/ui/App.d.ts +15 -2
- package/dist/ui/App.js +330 -69
- package/dist/ui/AutocompletePopup.d.ts +3 -1
- package/dist/ui/AutocompletePopup.js +9 -11
- package/dist/ui/BottomStatusRow.d.ts +1 -1
- package/dist/ui/Composer.d.ts +56 -1
- package/dist/ui/Composer.js +50 -6
- package/dist/ui/PromptInput.d.ts +52 -3
- package/dist/ui/PromptInput.js +201 -55
- package/dist/ui/StatusBar.d.ts +40 -15
- package/dist/ui/StatusBar.js +51 -9
- package/dist/ui/TeamPanel.d.ts +3 -1
- package/dist/ui/TeamPanel.js +13 -9
- package/dist/ui/TodoPanel.d.ts +5 -5
- package/dist/ui/TodoPanel.js +56 -24
- package/dist/ui/Transcript.js +29 -1
- package/dist/ui/UpdateLine.d.ts +1 -1
- package/dist/ui/capabilities.js +5 -5
- package/dist/ui/composer-limits.d.ts +31 -0
- package/dist/ui/composer-limits.js +50 -0
- package/dist/ui/composer-rows.d.ts +73 -0
- package/dist/ui/composer-rows.js +201 -0
- package/dist/ui/editor-reducer.d.ts +37 -0
- package/dist/ui/editor-reducer.js +88 -12
- package/dist/ui/entries/ServiceCard.d.ts +66 -0
- package/dist/ui/entries/ServiceCard.js +116 -0
- package/dist/ui/entries/UserEntry.d.ts +17 -3
- package/dist/ui/entries/UserEntry.js +34 -5
- package/dist/ui/exit-snapshot.d.ts +9 -0
- package/dist/ui/layout/ScrollViewport.d.ts +1 -1
- package/dist/ui/layout/autocomplete.d.ts +18 -0
- package/dist/ui/layout/autocomplete.js +26 -0
- package/dist/ui/layout/budget.d.ts +34 -6
- package/dist/ui/layout/budget.js +32 -7
- package/dist/ui/layout/rail.d.ts +4 -53
- package/dist/ui/layout/rail.js +10 -62
- package/dist/ui/layout/team-panel.d.ts +18 -0
- package/dist/ui/layout/team-panel.js +22 -0
- package/dist/ui/layout/todo-layout.d.ts +24 -0
- package/dist/ui/layout/todo-layout.js +27 -0
- package/dist/ui/layout/virtual-window.js +51 -1
- package/dist/ui/overlays/HelpOverlay.js +3 -0
- package/dist/ui/overlays/PlanReviewOverlay.js +10 -2
- package/dist/ui/overlays/QuestionOverlay.js +5 -1
- package/dist/ui/overlays/SettingsScreen.js +14 -1
- package/dist/ui/paste-frames.d.ts +87 -0
- package/dist/ui/paste-frames.js +112 -0
- package/dist/ui/paste-tokens.d.ts +90 -0
- package/dist/ui/paste-tokens.js +147 -0
- package/dist/ui/screen.d.ts +16 -0
- package/dist/ui/screen.js +45 -2
- package/dist/ui/selection/selection-controller.d.ts +1 -1
- package/dist/ui/transcript-text.js +55 -2
- package/dist/ui/use-wheel-routing.d.ts +1 -1
- package/package.json +2 -2
- package/dist/input/stdin-mouse-filter.d.ts +0 -47
- package/dist/input/stdin-mouse-filter.js +0 -153
package/CHANGELOG.md
CHANGED
|
@@ -9,6 +9,148 @@ were written.
|
|
|
9
9
|
|
|
10
10
|
### Added
|
|
11
11
|
|
|
12
|
+
- **`system/init` now lists what this build can do.** A new optional
|
|
13
|
+
`capabilities: string[]` field, carrying `["interrupt"]` for this release.
|
|
14
|
+
|
|
15
|
+
A wrapper cannot tell by observation whether an interrupt will settle
|
|
16
|
+
gracefully or kill the process outright, and guessing wrong costs the user
|
|
17
|
+
their conversation. Rather than have callers compare version numbers — which
|
|
18
|
+
breaks on forks, prereleases, and version shapes nobody anticipated — the
|
|
19
|
+
build now says so itself, in an event that already arrives on every start.
|
|
20
|
+
Absent on older builds, and absence should be read as "no", never as
|
|
21
|
+
"probably".
|
|
22
|
+
|
|
23
|
+
Additive, so `schemaVersion` does not move. Consumers that do not know the
|
|
24
|
+
field ignore it, exactly as the schema contract asks.
|
|
25
|
+
|
|
26
|
+
- **The composer understands pasting.** Until now it did not have the concept at
|
|
27
|
+
all: every byte the terminal delivered on stdin was a keystroke, and a
|
|
28
|
+
clipboard block is thousands of bytes arriving in an unpredictable number of
|
|
29
|
+
chunks. Three separate failures fell out of that one omission, and on Windows
|
|
30
|
+
you hit all three at once.
|
|
31
|
+
|
|
32
|
+
A carriage return that landed alone in a chunk **sent the half-finished
|
|
33
|
+
message** — a fifteen-line paste could arrive as a dozen separate messages,
|
|
34
|
+
interleaved with the agent's replies. A carriage return in the middle of a
|
|
35
|
+
chunk was inserted into the draft as a literal `\r`, which the terminal obeyed
|
|
36
|
+
by **overwriting the row it was drawn on**. And a paste that survived both grew
|
|
37
|
+
the composer to the height of the pasted text, pushing the transcript out of a
|
|
38
|
+
frame whose row accounting still believed the composer was three rows tall.
|
|
39
|
+
|
|
40
|
+
Pasting now works the way it reads:
|
|
41
|
+
|
|
42
|
+
- **A paste never submits.** Line breaks become buffer newlines, exactly one
|
|
43
|
+
per source line break, `CRLF` and lone `CR` alike.
|
|
44
|
+
- **A short paste appears verbatim.** At or below 6 lines and 400 characters it
|
|
45
|
+
is inserted as-is, indentation intact, and renders exactly like typed text.
|
|
46
|
+
- **A large paste collapses to a placeholder** — `[Pasted text #1 +218 lines]`
|
|
47
|
+
— which occupies one line, carries its own size in its label, deletes as a
|
|
48
|
+
single unit (one `Backspace`, and `Ctrl+W` / `Ctrl+U` / `Ctrl+K` cannot leave
|
|
49
|
+
half of one behind), and expands back to the full text the moment you send.
|
|
50
|
+
The model receives every byte; the composer never has to draw them.
|
|
51
|
+
- **No pasted byte is executed as a terminal control.** `\r`, `\x1b`, NUL, DEL
|
|
52
|
+
and the C1 range are stripped from the payload — never from your keystrokes,
|
|
53
|
+
so `Ctrl+A` and Escape are untouched.
|
|
54
|
+
- **The composer has a ceiling.** A draft of any length occupies at most 3 / 6 /
|
|
55
|
+
10 rows depending on terminal height, scrolls internally to keep the caret
|
|
56
|
+
visible, shows how many rows are hidden above and below, and reports its true
|
|
57
|
+
height to the layout budget. Four hundred presses of `Shift+Enter` were
|
|
58
|
+
already able to destroy the frame; they no longer are.
|
|
59
|
+
- **A submitted message cannot make the transcript unresponsive.** A user entry
|
|
60
|
+
renders at most 40 rows plus a `... +N more lines` tail. The full text is kept
|
|
61
|
+
and the exit transcript is uncapped.
|
|
62
|
+
|
|
63
|
+
On terminals that support it, detection is **exact**: aragon asks for bracketed
|
|
64
|
+
paste (`DECSET 2004`) in full-screen mode and reads the markers the terminal
|
|
65
|
+
wraps your paste in. Where that is unavailable — inline mode, an old Windows
|
|
66
|
+
console — a heuristic on chunk shape catches the same cases, and it needs no
|
|
67
|
+
cooperation from the terminal at all. Both feed one code path.
|
|
68
|
+
|
|
69
|
+
Turn it off with `--no-paste`, `ARAGON_PASTE=0`, or
|
|
70
|
+
`aragon config set paste false`; the input path is then byte-for-byte what
|
|
71
|
+
0.6.2 did.
|
|
72
|
+
|
|
73
|
+
### Fixed
|
|
74
|
+
|
|
75
|
+
- **`{"type":"interrupt"}` now really does settle the run — on every platform.**
|
|
76
|
+
The stdin interrupt frame used to raise a SIGINT at our own process. On POSIX
|
|
77
|
+
that reaches the runner's terminator and the run winds down properly: it
|
|
78
|
+
breaks out of the loop, persists the session, and emits `result` with the
|
|
79
|
+
usage and cost. On Windows, Node does not deliver a self-directed SIGINT to
|
|
80
|
+
its own handlers — the process simply terminated with exit code 1, having run
|
|
81
|
+
none of it.
|
|
82
|
+
|
|
83
|
+
For anyone using `aragon exec` interactively that difference was invisible,
|
|
84
|
+
because an interrupt there is usually the last thing that happens. It is not
|
|
85
|
+
invisible to a **wrapper** that interrupts a turn and then respawns on the same
|
|
86
|
+
`--session-id` to keep the conversation going: on Windows it silently got back
|
|
87
|
+
a session missing everything since the previous save. `exec/index.ts` has
|
|
88
|
+
carried a comment about that caller for some time ("PERSIST FIRST, ANNOUNCE
|
|
89
|
+
SECOND … a caller that reads `result` and immediately respawns with the same
|
|
90
|
+
`--session-id` must not race the writer"), so the intent was there; the path
|
|
91
|
+
just could not be reached on Windows.
|
|
92
|
+
|
|
93
|
+
The frame now calls the runner directly instead of going through a signal.
|
|
94
|
+
POSIX behaviour is byte-for-byte unchanged — the same code runs, with the same
|
|
95
|
+
`stopReason`, the same exit code 130, and the same two-second window in which a
|
|
96
|
+
second signal still forces an immediate exit.
|
|
97
|
+
|
|
98
|
+
- **A pasted API key is stored correctly again.** Ink broadcasts each stdin chunk
|
|
99
|
+
to every mounted input handler, so the settings screen, the question overlay
|
|
100
|
+
and the plan-review feedback field all see what the composer sees. Without
|
|
101
|
+
this, a ~100-character key pasted into Settings would have been stored wrapped
|
|
102
|
+
in invisible framing bytes, masked on screen by the password dots, and would
|
|
103
|
+
have failed to authenticate on every request afterwards with nothing anywhere
|
|
104
|
+
explaining why.
|
|
105
|
+
|
|
106
|
+
- **`--no-mouse` still writes no mouse sequence.** Paste support installs a
|
|
107
|
+
stdin filter, and `paste` defaults to on, so the filter now exists in sessions
|
|
108
|
+
that disabled the mouse. Whether the mouse is on is a separate question from
|
|
109
|
+
whether the stream is wrapped, and the four places that used to conflate them
|
|
110
|
+
now ask the right one: `aragon --no-mouse` writes no `?1000h`, no `?1006h` and
|
|
111
|
+
no `?1002h`, leaves your terminal's own click-drag selection alone, and reports
|
|
112
|
+
`/mouse` as off — while pasting still works.
|
|
113
|
+
|
|
114
|
+
### Changed
|
|
115
|
+
|
|
116
|
+
- **Auto-compaction no longer reports compactions that did not happen.** A long
|
|
117
|
+
unattended run used to print a red `context not compacted #2: nothing_to_drop`
|
|
118
|
+
card into the transcript. The card was accurate; nobody had asked for it.
|
|
119
|
+
Auto-compaction evaluates itself at every turn boundary, and a checkpoint that
|
|
120
|
+
looks at the history and finds nothing worth dropping has changed nothing,
|
|
121
|
+
called nothing and spent nothing — a smoke alarm announcing "no fire" twice an
|
|
122
|
+
hour, in error colours, with a machine reason attached.
|
|
123
|
+
|
|
124
|
+
A compaction now announces itself **if and only if it commits to doing work**.
|
|
125
|
+
That is a position in the control flow, not a list of reason strings: everything
|
|
126
|
+
decided before the first spend is silent, and everything decided after it —
|
|
127
|
+
including every failure, the truncation fallback, an Esc, and a host fault — is
|
|
128
|
+
as loud as it ever was. A declined `pressure` checkpoint is now
|
|
129
|
+
indistinguishable from a turn on which the threshold was never crossed.
|
|
130
|
+
|
|
131
|
+
**`/compact` and overflow recovery are unchanged.** A compaction you asked for
|
|
132
|
+
is owed an answer, and a reactive compaction running after the provider has
|
|
133
|
+
already refused your request is the one moment the diagnosis matters most. Both
|
|
134
|
+
still report on every outcome.
|
|
135
|
+
|
|
136
|
+
**Quiet, not unrecorded.** Every attempt is still written to the diagnostic log
|
|
137
|
+
(its `compaction` line gains an `announced` field, so `announced: false` is one
|
|
138
|
+
grep), still charged to the anti-loop guards, and still counted by
|
|
139
|
+
`/compact status` — which now reads
|
|
140
|
+
`This session: 1 compaction (2 checkpoints declined), 94.2k tokens reclaimed`
|
|
141
|
+
when checkpoints declined, and is byte-identical to before when none did. If
|
|
142
|
+
declines keep happening, the self-disable notice still says so out loud, once,
|
|
143
|
+
naming the cause and the remedies. Card numbers are also contiguous again: `#N`
|
|
144
|
+
counts compactions that ran, not checkpoints that fired.
|
|
145
|
+
|
|
146
|
+
**Behaviour change for wrapper scripts.** A declined `pressure` compaction no
|
|
147
|
+
longer emits a `{ type: 'compaction', subtype: 'start' | 'end' }` pair on the
|
|
148
|
+
`--output-format json` stream, and no longer prints `[compaction] skipped:` on
|
|
149
|
+
`-p` stderr. The pairs stay balanced, so only consumers counting *attempts* are
|
|
150
|
+
affected; the diagnostic log reports those more accurately.
|
|
151
|
+
|
|
152
|
+
### Added
|
|
153
|
+
|
|
12
154
|
- **Context compaction, hardened — the trigger now counts the whole history, the
|
|
13
155
|
recent turns can no longer wedge a run, sub-agents get the same protection, and
|
|
14
156
|
a compaction is no longer irreversible.**
|
package/README.md
CHANGED
|
@@ -413,6 +413,8 @@ signal ends the run (`130` SIGINT, `143` SIGTERM, `129` SIGHUP).
|
|
|
413
413
|
| `/retry [show\|on\|off\|max <n>]` | API retry: the effective ladder, the on/off switch, the retry count. Takes effect **in the running session**, children included |
|
|
414
414
|
| `/fast [on\|off\|model <id>\|provider <id>\|same\|review <n\|off>\|delegate on\|off]` | Fast model tier: status and this session's totals, the on/off switch, which model, the review cadence |
|
|
415
415
|
| `/compact [status\|on\|off\|threshold <n>\|keep <n>\|history\|show <n>\|<instructions>]` | Context compaction: occupancy and this session's totals, the on/off switch, when it fires, how much it keeps. With free text, compacts now and tells the summarizer what to pay attention to |
|
|
416
|
+
| `/context` | What the context gauge is showing: occupancy split into measured and estimated, the window and **where it came from**, how stale the measurement is, compaction's actual state, and what the session-spend readout includes |
|
|
417
|
+
| `/bg [list\|logs <id> [n]\|stop <id\|all>\|status]` | Background services: what is running, its log tail, and how to stop it. `list` is the default |
|
|
416
418
|
| `/update [status\|now\|skip\|off]` | Auto-update: what is running, what is available, where it came from, when it looks again. `now` forces a check past the throttle; `skip` declines the offered version until a newer one appears |
|
|
417
419
|
| `/theme <auto\|warm\|cool\|light>` | Switch the color theme live (persisted) |
|
|
418
420
|
| `/expand [n]` | Expand / collapse the n-th-from-last (default last) tool card |
|
|
@@ -437,10 +439,12 @@ completes, `Up` / `Down` moves the selection, `Esc` closes it.
|
|
|
437
439
|
| `Shift+Tab` | Toggle **plan mode** (`BUILD` <-> `PLAN`). Equivalent: `/plan`. On Windows this needs a console flag Node < 22.17 does not set; aragon sets it at startup — see [Requirements](#requirements) |
|
|
438
440
|
| `Ctrl+P` | The same toggle, over a channel no Windows console can swallow. Use it if `Shift+Tab` does nothing |
|
|
439
441
|
| `Esc` | Abort the run / close an overlay / close a popup |
|
|
440
|
-
| `
|
|
442
|
+
| `Esc` ×2 | **Force-stop** a run that did not abort: kills the shell command it is blocked on and returns the view to `idle`. The second press only does anything while the run is *still* running, so in a healthy run it is a no-op |
|
|
443
|
+
| `Ctrl+C` | Stop the background **services** the agent started, when there are any. It does not arm exit |
|
|
444
|
+
| `Ctrl+C` ×2 | Exit (first press warns), once no services are running |
|
|
441
445
|
| `Ctrl+L` | Redraw the frame (clear the screen in inline mode) |
|
|
442
446
|
| `Ctrl+T` | Show / hide thinking (**off by default**). In inline mode it applies to the live entry and everything drawn after it — settled entries are already in your terminal's scrollback and cannot be repainted |
|
|
443
|
-
| `Ctrl+O` | Expand / collapse the most recent tool card — including
|
|
447
|
+
| `Ctrl+O` | Expand / collapse the most recent tool, team, compaction or **service** card — including a diff or a service's log tail |
|
|
444
448
|
| `PgUp` / `PgDn` | Scroll the transcript a page (full-screen mode) |
|
|
445
449
|
| `Shift+↑` / `Shift+↓` | Scroll the transcript a line (full-screen mode) |
|
|
446
450
|
| Mouse wheel | Scroll the transcript (or the open overlay). On Windows needs Node ≥ 22.17 — see [Requirements](#requirements) |
|
|
@@ -450,6 +454,7 @@ completes, `Up` / `Down` moves the selection, `Esc` closes it.
|
|
|
450
454
|
| `Ctrl+W`, `Alt+Backspace` | Delete the previous word |
|
|
451
455
|
| `Ctrl+U` / `Ctrl+K` | Kill to line start / end |
|
|
452
456
|
| `Up` / `Down` | Move between draft lines; recall prompt history at the edges |
|
|
457
|
+
| Paste | Inserted as-is up to 6 lines / 400 chars; larger collapses to `[Pasted text #1 +15 lines]`, which deletes as one unit and expands in full when you send. `--no-paste` restores the pre-0.6.3 behaviour |
|
|
453
458
|
| `?` | Open help (empty input) |
|
|
454
459
|
|
|
455
460
|
In **full-screen mode** the transcript is scrolled by the app itself: `PgUp` /
|
|
@@ -795,7 +800,8 @@ ask — and the agent writes the finished plan as its final message in markdown.
|
|
|
795
800
|
For work with three or more distinct steps the agent keeps a **visible plan**:
|
|
796
801
|
it writes a checklist with the `todo_write` tool, marks exactly one item as in
|
|
797
802
|
progress, and ticks it off before starting the next. In full-screen mode that
|
|
798
|
-
list is rendered as a right-hand rail,
|
|
803
|
+
list is rendered as a right-hand rail, targeting 15% of the terminal width
|
|
804
|
+
(14–36 columns, including its separator and padding).
|
|
799
805
|
|
|
800
806
|
```
|
|
801
807
|
transcript ... | TODO 2/7
|
|
@@ -803,8 +809,7 @@ list is rendered as a right-hand rail, about a fifth of the terminal wide.
|
|
|
803
809
|
|
|
|
804
810
|
| v 1 Read the reducer
|
|
805
811
|
| v 2 Design the store
|
|
806
|
-
| > 3 Wiring the rail
|
|
807
|
-
| AppShell
|
|
812
|
+
| > 3 Wiring the rail...
|
|
808
813
|
| o 4 Add the panel-rows test
|
|
809
814
|
| o 5 Update the README
|
|
810
815
|
| +2 more
|
|
@@ -828,7 +833,7 @@ not also tell the model may change it — except you, saying so:
|
|
|
828
833
|
conversation has just been replaced.
|
|
829
834
|
- A finished plan is dropped at the START of your next message, so you still get
|
|
830
835
|
to see `7/7 done`. An unfinished one survives "continue" / "now do the rest",
|
|
831
|
-
and is dropped after three unrelated turns rather than holding
|
|
836
|
+
and is dropped after three unrelated turns rather than holding part of the
|
|
832
837
|
screen for the rest of the session.
|
|
833
838
|
|
|
834
839
|
### When a run ends with steps left
|
|
@@ -884,11 +889,19 @@ planning discipline and hides the column — which is what you want with a scree
|
|
|
884
889
|
reader, and what `--no-todo-panel` does for a whole session. Under `-p` the plan
|
|
885
890
|
is written to stderr as `[todo] 3/7 <step>` lines, suppressed by `--quiet`.
|
|
886
891
|
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
+
右栏从 76 列开始显示,正文至少保留 62 列;100 列终端使用 15 列右栏。
|
|
893
|
+
已有任务时,团队面板按实际行数占用空间,补全菜单的边框和提示也计入预算。
|
|
894
|
+
例如 100×20、团队占 8 行时,TODO 仍以 4 行紧凑视图显示。
|
|
895
|
+
|
|
896
|
+
剩余 3–5 行时保留标题、完成计数、当前任务与合并提示 `-A +B`:
|
|
897
|
+
`-9 +10` 表示上方隐藏 9 项、下方隐藏 10 项。6 行起使用常规视图;
|
|
898
|
+
所有任务各占一行,全文仍可在正文任务卡片中查看。进度条需要至少 20 列、8 行。
|
|
899
|
+
输入增长导致空间不足时团队先折叠为摘要;菜单不足 3 行时隐藏,其候选不会拦截输入。
|
|
900
|
+
|
|
901
|
+
低于 76 列、共享区域不足 3 行、打开 overlay、显式关闭面板、没有任务或
|
|
902
|
+
inline 模式时不显示右栏。低于 12 行使用原有小终端提示;扩大窗口后自动恢复。
|
|
903
|
+
inline 仍使用上文的单行任务条。`/todo status` 中的 `Panel: on` 仅表示配置开启,
|
|
904
|
+
实际可见性还取决于数据和窗口空间;可以通过该命令区分未生成计划与暂时隐藏。
|
|
892
905
|
|
|
893
906
|
## Built-in tools
|
|
894
907
|
|
|
@@ -908,6 +921,94 @@ delegation tool (see below). `--no-team` removes it again.
|
|
|
908
921
|
With todo planning on — also the default — one more is added: `todo_write`, the
|
|
909
922
|
planning tool (see above). `--no-todo` removes it again.
|
|
910
923
|
|
|
924
|
+
With background services on — also the default — two more are added:
|
|
925
|
+
`bash_output` and `bash_kill` (see below), and `bash` itself gains a `background`
|
|
926
|
+
parameter. `bash.background: false` removes all three again.
|
|
927
|
+
|
|
928
|
+
## Background services
|
|
929
|
+
|
|
930
|
+
The agent can write a web app; it also has to be able to **run** one. A command
|
|
931
|
+
that never exits on its own — `npm run dev`, `uvicorn main:app`, `vite`,
|
|
932
|
+
`docker compose up`, `tsc --watch` — is not a hung tool, it is a server, and
|
|
933
|
+
running it in the foreground stalls the turn until the tool timeout kills it
|
|
934
|
+
three minutes later.
|
|
935
|
+
|
|
936
|
+
So those commands are **supervised** instead. `bash` gains one optional
|
|
937
|
+
parameter:
|
|
938
|
+
|
|
939
|
+
```jsonc
|
|
940
|
+
{ "command": "npm run dev", "background": true }
|
|
941
|
+
```
|
|
942
|
+
|
|
943
|
+
`true` supervises it, `false` never does, and **omitting it lets the runtime
|
|
944
|
+
decide** from the command itself — a closed allowlist over the leading token and
|
|
945
|
+
the script name (`npm|pnpm|yarn|bun run dev|start|serve|watch|preview`,
|
|
946
|
+
`next dev`, `vite`, `nuxt dev`, `ng serve`, `nodemon`, `tsc --watch`, `uvicorn`,
|
|
947
|
+
`gunicorn`, `flask run`, `manage.py runserver`, `rails server`, `php -S`,
|
|
948
|
+
`cargo watch`, `docker compose up` without `-d`, `tail -f`, `watch `). It never
|
|
949
|
+
fires on a chained command, because a chain's tail is what you actually wanted
|
|
950
|
+
the result of, and `npm run build` and `npm test` are deliberately not on it.
|
|
951
|
+
|
|
952
|
+
A supervised launch returns as soon as there is something true to say — the
|
|
953
|
+
**first** of ready, exited, or four seconds — so a server that crashes on boot is
|
|
954
|
+
reported in 400 ms with the stack in the result rather than after a three-minute
|
|
955
|
+
stall:
|
|
956
|
+
|
|
957
|
+
```
|
|
958
|
+
$ npm run dev
|
|
959
|
+
[background] service s1 started (pid 24188)
|
|
960
|
+
[ready] http://localhost:3000 (detected from output after 1.4s)
|
|
961
|
+
[log tail]
|
|
962
|
+
> next dev
|
|
963
|
+
- Local: http://localhost:3000
|
|
964
|
+
Read more with bash_output({ service: "s1" }); stop it with bash_kill({ service: "s1" }).
|
|
965
|
+
```
|
|
966
|
+
|
|
967
|
+
Readiness is a URL the server printed, or one TCP connect to a port the command
|
|
968
|
+
named — and if that port was **already answering before the launch**, the probe
|
|
969
|
+
is switched off and the card says so, rather than calling somebody else's server
|
|
970
|
+
yours. A process that stays up without listening on anything (`tsc --watch`) is
|
|
971
|
+
reported as `running`, which is the honest third answer.
|
|
972
|
+
|
|
973
|
+
Each service gets a transcript card and a `svc N` chip in the status bar. Two
|
|
974
|
+
tools read and stop them:
|
|
975
|
+
|
|
976
|
+
- `bash_output({ service, since? })` — the log tail and the current status.
|
|
977
|
+
`since` is the cursor the previous call returned, so a watcher can be read
|
|
978
|
+
incrementally. The tail is a bounded in-memory ring of 200 rows; there are no
|
|
979
|
+
log files on disk.
|
|
980
|
+
- `bash_kill({ service })` — stop one, or `"all"`.
|
|
981
|
+
|
|
982
|
+
**Services do not survive the CLI.** Quitting, `Ctrl+C`, `SIGTERM` and a crash
|
|
983
|
+
all reap the tree on a best-effort basis; there is no daemon, no PID file and no
|
|
984
|
+
reattach across launches. A `SIGKILL` of aragon itself is unrecoverable by
|
|
985
|
+
construction, and if a stop cannot confirm the process is gone it says
|
|
986
|
+
`may have left a detached child` rather than claiming success.
|
|
987
|
+
|
|
988
|
+
From your side there are two keys and one command: `Ctrl+C` stops every live
|
|
989
|
+
service (and does *not* arm exit), `/bg` lists them, and `/bg logs s1` prints a
|
|
990
|
+
tail without going through the model.
|
|
991
|
+
|
|
992
|
+
### Turning it off
|
|
993
|
+
|
|
994
|
+
```jsonc
|
|
995
|
+
// ~/.aragon/config.json
|
|
996
|
+
{ "bash": { "background": false } }
|
|
997
|
+
```
|
|
998
|
+
|
|
999
|
+
`ARAGON_BASH_BACKGROUND=0` does the same for one run;
|
|
1000
|
+
`ARAGON_BASH_AUTO_BACKGROUND=0` keeps the tools but stops the classifier firing
|
|
1001
|
+
on a command that did not ask. With `background: false` the build behaves exactly
|
|
1002
|
+
as it did before this feature existed — no `background` parameter, no extra
|
|
1003
|
+
tools, no prompt block, no chip.
|
|
1004
|
+
|
|
1005
|
+
Two things are **not** governed by that switch, because they are fixes rather
|
|
1006
|
+
than features. `bash` now always settles: it returns when the process exits
|
|
1007
|
+
rather than when its output stream closes, so a command that detaches a
|
|
1008
|
+
grandchild can no longer leave the turn pending forever, and it is handed a
|
|
1009
|
+
closed stdin so a command that prompts fails instead of blocking on a read
|
|
1010
|
+
nobody will answer. And `Esc` twice always force-stops, whatever the flag says.
|
|
1011
|
+
|
|
911
1012
|
## Team subagents
|
|
912
1013
|
|
|
913
1014
|
The agent can hand parts of a job to short-lived **subagents** that run in
|
|
@@ -1119,6 +1220,84 @@ it for a background advisory is how an unrequested call ends up competing with
|
|
|
1119
1220
|
you for a rate-limited provider's quota. The review's own wall-clock bound is
|
|
1120
1221
|
20 s.
|
|
1121
1222
|
|
|
1223
|
+
## The context gauge
|
|
1224
|
+
|
|
1225
|
+
The right end of the status bar answers one question: **how full is the context,
|
|
1226
|
+
out of how much.**
|
|
1227
|
+
|
|
1228
|
+
```
|
|
1229
|
+
[####----] 43% 86.0k/200.0k total 1.2M^ 48.0k v $3.21 12 tok/s 1m02s
|
|
1230
|
+
^ ^ ^
|
|
1231
|
+
| | +-- session spend, prompt side / output side
|
|
1232
|
+
| +-- occupied / window
|
|
1233
|
+
+-- the two together, as a percentage
|
|
1234
|
+
```
|
|
1235
|
+
|
|
1236
|
+
The readouts drop as the terminal narrows, in that order of priority:
|
|
1237
|
+
|
|
1238
|
+
| Columns | Right cluster |
|
|
1239
|
+
|---|---|
|
|
1240
|
+
| >= 96 | `[####----] 43% 86.0k/200.0k total 1.2M^ 48.0k v $3.21` |
|
|
1241
|
+
| 72-95 | `[####----] 43% 86.0k/200.0k $3.21` |
|
|
1242
|
+
| 60-71 | `[####----] 43% $3.21` |
|
|
1243
|
+
| < 60 | `43% $3.21` |
|
|
1244
|
+
|
|
1245
|
+
**Two different markers, because there are two different things to doubt.**
|
|
1246
|
+
|
|
1247
|
+
- `~` sits on the **percentage** and means the *numerator* is partly a guess:
|
|
1248
|
+
either no completed turn has reported usage yet (right after `/resume`, or
|
|
1249
|
+
right after a compaction), or tool results have been appended since the last
|
|
1250
|
+
measurement and their size is estimated.
|
|
1251
|
+
- `?` sits on the **window** and means the *denominator* is a guess: the model is
|
|
1252
|
+
not in the built-in table, so a flat 128 000 was substituted. See
|
|
1253
|
+
`contextWindow` below.
|
|
1254
|
+
|
|
1255
|
+
**The percentage keeps moving during a turn.** Every tool result nudges it,
|
|
1256
|
+
whether or not compaction is enabled — it is not a compaction feature, and a
|
|
1257
|
+
session started with `--no-compaction` gets the same live reading. After
|
|
1258
|
+
`/resume` the gauge shows the restored session's real occupancy immediately,
|
|
1259
|
+
without sending anything.
|
|
1260
|
+
|
|
1261
|
+
### `/context`
|
|
1262
|
+
|
|
1263
|
+
The gauge is a bar and a rounded percentage; `/context` is the full answer, at
|
|
1264
|
+
any width, in any mode:
|
|
1265
|
+
|
|
1266
|
+
```
|
|
1267
|
+
Context
|
|
1268
|
+
Occupancy 43% 86.2k of 200.0k [measured 85.1k + 1.1k estimated]
|
|
1269
|
+
Window 200000 from the model table
|
|
1270
|
+
Since measured 1.1k estimated tokens appended since the last provider-reported usage
|
|
1271
|
+
Compaction on - triggers at 90% (amber at 75%), 2 this session, 118.0k reclaimed
|
|
1272
|
+
Session spend 1.2M in (incl. 940.0k cache read, 12.0k cache write) / 48.2k out, $3.21
|
|
1273
|
+
includes subagent, fast-tier and compaction spend,
|
|
1274
|
+
not just this conversation
|
|
1275
|
+
```
|
|
1276
|
+
|
|
1277
|
+
Two lines are worth reading closely. **`Window`** always names where the number
|
|
1278
|
+
came from — the model table, your own `contextWindow`, or the invented
|
|
1279
|
+
placeholder — because those are indistinguishable everywhere else. And
|
|
1280
|
+
**`Compaction`** reports what is actually true of this session, including
|
|
1281
|
+
`off - not registered for this session (started with --no-compaction)`; it never
|
|
1282
|
+
promises a threshold that nothing will act on.
|
|
1283
|
+
|
|
1284
|
+
### `contextWindow`
|
|
1285
|
+
|
|
1286
|
+
When the model is not in the built-in table — a custom `baseUrl`, a self-hosted
|
|
1287
|
+
id, something released last week — the denominator is a **fabricated** 128 000
|
|
1288
|
+
and the percentage is meaningless. Correct it:
|
|
1289
|
+
|
|
1290
|
+
```bash
|
|
1291
|
+
aragon config set contextWindow 1000000 # persisted; prints "Set contextWindow = 1000000"
|
|
1292
|
+
aragon config set contextWindow auto # back to the model table / placeholder
|
|
1293
|
+
ARAGON_CONTEXT_WINDOW=1000000 aragon # one session
|
|
1294
|
+
```
|
|
1295
|
+
|
|
1296
|
+
Values are clamped to `[8000, 5000000]`; `auto` (the default) is stored as
|
|
1297
|
+
`null`. Setting it removes the `?` marker, because you have asserted the number —
|
|
1298
|
+
and `/context` still shows that it came from you, which is what makes a wrong
|
|
1299
|
+
value findable.
|
|
1300
|
+
|
|
1122
1301
|
## Context compaction
|
|
1123
1302
|
|
|
1124
1303
|
A long agentic run fills the model's context window. Before this existed, the
|
|
@@ -1215,7 +1394,10 @@ Three surfaces, each answering something the others cannot:
|
|
|
1215
1394
|
- **As state** — a `compacting` chip in the status bar, and the context gauge's
|
|
1216
1395
|
colours aligned to your own thresholds. The gauge **falls immediately** after a
|
|
1217
1396
|
compaction rather than waiting for the next turn, with a `~` while the value is
|
|
1218
|
-
derived rather than measured.
|
|
1397
|
+
derived rather than measured. The colours follow your configured thresholds
|
|
1398
|
+
whenever compaction is **enabled**, even if no summarizer model currently
|
|
1399
|
+
resolves; after `/compact off` they fall back to the generic 60 / 85, because
|
|
1400
|
+
colouring by a rescue that is not coming is worse than not colouring at all.
|
|
1219
1401
|
- **As a record** — a transcript card with the before/after message and token
|
|
1220
1402
|
counts, the summarizer, the duration, and the summary itself. `Ctrl+O` expands
|
|
1221
1403
|
it.
|
|
@@ -1228,7 +1410,9 @@ self-disabled, or the ladder ran out.
|
|
|
1228
1410
|
|
|
1229
1411
|
`/compact status` is the guaranteed surface: the chip drops on a narrow terminal
|
|
1230
1412
|
and the card scrolls away, but the command answers at any width, in any mode,
|
|
1231
|
-
after the fact.
|
|
1413
|
+
after the fact. For the gauge specifically, [`/context`](#the-context-gauge) is
|
|
1414
|
+
the equivalent — and it works in a session that never registered compaction at
|
|
1415
|
+
all.
|
|
1232
1416
|
|
|
1233
1417
|
### When the RECENT turns are what does not fit
|
|
1234
1418
|
|
|
@@ -1609,6 +1793,8 @@ env / `.env` → CLI flags**.
|
|
|
1609
1793
|
reasoning blocks), `ARAGON_LIVE_TOOL_OUTPUT` (`0` keeps a running tool card to
|
|
1610
1794
|
one line),
|
|
1611
1795
|
`ARAGON_MAX_TOKENS` (a number, or `auto` / `0` for the per-model ceiling),
|
|
1796
|
+
`ARAGON_CONTEXT_WINDOW` (a number, or `auto`; the denominator the context
|
|
1797
|
+
gauge measures against),
|
|
1612
1798
|
`ARAGON_THEME`,
|
|
1613
1799
|
`ARAGON_FULLSCREEN`, `ARAGON_PLAN` (`1` starts in plan mode),
|
|
1614
1800
|
`ARAGON_TEAM` (`0` disables team subagents), `ARAGON_TEAM_MAX` (fan-out width),
|
|
@@ -1636,6 +1822,7 @@ env / `.env` → CLI flags**.
|
|
|
1636
1822
|
| Config key | Default | Meaning |
|
|
1637
1823
|
| --- | --- | --- |
|
|
1638
1824
|
| `maxTokens` | `64000` | Output token cap, clamped to `[256, 200000]`. `null` means **auto** — use each model's own ceiling, never above 64000. Absent means the default. See [Output token limits](#output-token-limits). |
|
|
1825
|
+
| `contextWindow` | `null` | The window the context gauge measures against, clamped to `[8000, 5000000]`. `null` means **auto** — the built-in model table, or a fabricated 128000 for a model it has never seen. Set it when the gauge shows `?` on the denominator. See [The context gauge](#the-context-gauge). |
|
|
1639
1826
|
| `showThinking` | `false` | Draw the reasoning the model returns. `thinkingLevel` is the effort the provider is asked to **spend**; this is whether the terminal **shows** it. Off by default: a settled turn that thought leaves one muted `thought for 12s` row in its place, so nothing is hidden silently. |
|
|
1640
1827
|
| `liveToolOutput` | `true` | Draw up to eight sanitised rows of a **running** tool's output on its card, plus a `no output for Ns` row when the child goes quiet. On by default, unlike `showThinking`: this ADDS the information a long `bash` call otherwise hides, and its cost is bounded by construction — eight rows per call, sixteen calls, whatever the command emits. Turn it off and the card is a single `running` row again, with no store allocated and no recorder attached. |
|
|
1641
1828
|
| `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. |
|
|
@@ -1647,6 +1834,7 @@ env / `.env` → CLI flags**.
|
|
|
1647
1834
|
| `planModeDefault` | `false` | Start every session in plan mode. `--no-plan` still overrides it for a single run. |
|
|
1648
1835
|
| `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. |
|
|
1649
1836
|
| `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. |
|
|
1837
|
+
| `paste` | `true` | Recognise pasted text before Ink's key parser sees it: line breaks become buffer newlines instead of fifteen separate messages, control bytes are stripped instead of overwriting the row they land on, and a paste above 6 lines or 400 characters collapses to a one-line placeholder that expands when you send. `false` treats pasted bytes as keystrokes, which is what 0.6.2 did. |
|
|
1650
1838
|
| `historyEnabled` | `true` | Record submitted prompts to `prompt-history.jsonl` for `↑` recall. Setting it to `false` stops new writes; it does not delete what is already stored (that is `aragon history clear --yes`) and does not stop reading. See [Prompt history](#prompt-history). |
|
|
1651
1839
|
| `team.enabled` | `true` | Master switch for team subagents. `false` means the `task` tool is never registered — `/team on` in such a session saves the setting for next launch and says so, rather than advertising a tool that is not there. |
|
|
1652
1840
|
| `team.maxSubagents` | `5` | Subagents per dispatch, clamped to `[1, 10]`. The 10 is the hard ceiling and is enforced twice — on the config value and again on what the model asks for — so hand-editing this file cannot raise it. |
|
|
@@ -1712,6 +1900,8 @@ ARAGON_MAX_TOKENS=32000 aragon # env layer, between the flag and the file
|
|
|
1712
1900
|
aragon config set maxTokens 32000 # persisted; prints "Set maxTokens = 32000"
|
|
1713
1901
|
aragon config set maxTokens auto # persisted as null
|
|
1714
1902
|
aragon config set maxTokens default # back to 64000
|
|
1903
|
+
aragon config set contextWindow 1000000 # the gauge's denominator
|
|
1904
|
+
aragon config set contextWindow auto # back to the model table
|
|
1715
1905
|
aragon config get maxTokens # "64000" | "auto"
|
|
1716
1906
|
```
|
|
1717
1907
|
|
|
@@ -15,9 +15,12 @@ import type { ToolPermission } from '../exec/permission.js';
|
|
|
15
15
|
import { type ToolOutputListener } from '../tools/tool-output-store.js';
|
|
16
16
|
import type { FilePatch } from '../tools/patch.js';
|
|
17
17
|
import type { TeamEvent, TeamSnapshot } from '../team/types.js';
|
|
18
|
+
import { ProcSupervisor } from '../proc/supervisor.js';
|
|
19
|
+
import type { ProcEventListener, ServiceSnapshot } from '../proc/types.js';
|
|
18
20
|
import { type FastStatus } from '../fast/wiring.js';
|
|
19
|
-
import type { FastEventListener } from '../fast/types.js';
|
|
20
|
-
import
|
|
21
|
+
import type { FastEventListener, FastSnapshot } from '../fast/types.js';
|
|
22
|
+
import { ContextMeter, type ContextUsageListener } from '../compaction/meter.js';
|
|
23
|
+
import type { CompactionEventListener, CompactionSnapshot, ContextUsageSnapshot } from '../compaction/types.js';
|
|
21
24
|
import type { TodoEventListener, TodoSnapshot } from '../todo/types.js';
|
|
22
25
|
import { type HumanInputGate } from '../tools/human-input.js';
|
|
23
26
|
import { SkillService, type ApprovalGate } from '../skills/service.js';
|
|
@@ -176,6 +179,34 @@ export declare class AgentController {
|
|
|
176
179
|
private readonly outputListeners;
|
|
177
180
|
private readonly fast;
|
|
178
181
|
private readonly compaction;
|
|
182
|
+
private readonly contextMeter;
|
|
183
|
+
private readonly procs;
|
|
184
|
+
/**
|
|
185
|
+
* The host's notice channel, kept so `prompt()`'s totality has somewhere to
|
|
186
|
+
* report to (I-8). Every other consumer reads `deps.notify` through a closure
|
|
187
|
+
* built in the constructor; this one is called from a method, which is why it
|
|
188
|
+
* needs a field.
|
|
189
|
+
*/
|
|
190
|
+
private readonly notifyHostFn;
|
|
191
|
+
/** Whether the SERVICE half is on: tools, prompt block, `background` param. */
|
|
192
|
+
private readonly bashBackgroundRegistered;
|
|
193
|
+
/** Release the exit reaper. Called by `dispose()`. */
|
|
194
|
+
private readonly releaseSignalHook;
|
|
195
|
+
/**
|
|
196
|
+
* Bumped by `forceStop()`; captured by `App` when it subscribes to a run.
|
|
197
|
+
*
|
|
198
|
+
* THE VIEW AND THE ENGINE DELIBERATELY DISAGREE AFTER A FORCE-STOP (D-10 /
|
|
199
|
+
* I-7). Rung two dispatches `runEnd` locally so the composer is usable
|
|
200
|
+
* immediately, but the engine keeps unwinding and keeps EMITTING -
|
|
201
|
+
* `turn_start`, `tool_call_start`, `turn_end`, `agent_end` - and
|
|
202
|
+
* `runStart`/`turnStart` would set `status: 'running'` again, bouncing the
|
|
203
|
+
* view straight back out of the `idle` the user was just given and appending
|
|
204
|
+
* entries to a transcript they believe is finished. `App` drops every event
|
|
205
|
+
* whose generation is stale, which is the same shape as `abortRequested`
|
|
206
|
+
* above and exists for the same reason: the loop legitimately emits after an
|
|
207
|
+
* abort lands.
|
|
208
|
+
*/
|
|
209
|
+
private runGen;
|
|
179
210
|
/**
|
|
180
211
|
* Set SYNCHRONOUSLY by `abort()` before `agent.abort()` (§3.5.4a guard 1).
|
|
181
212
|
* Cleared at the next `agent_start`.
|
|
@@ -234,7 +265,97 @@ export declare class AgentController {
|
|
|
234
265
|
* never rejects, so callers must not treat resolution as success.
|
|
235
266
|
*/
|
|
236
267
|
prompt(text: string): Promise<void>;
|
|
268
|
+
/**
|
|
269
|
+
* Wait for the engine to unwind, bounded.
|
|
270
|
+
*
|
|
271
|
+
* BOUNDED BECAUSE THE UNBOUNDED CASE IS THE ONE THIS FEATURE IS ABOUT: a tool
|
|
272
|
+
* that never settles is exactly why rung two exists, and `Agent.waitForIdle()`
|
|
273
|
+
* alone would hang here for as long as it hangs there. The budget is the two
|
|
274
|
+
* graces a wedged `bash` can legitimately spend, plus the executor's own.
|
|
275
|
+
*/
|
|
276
|
+
private waitForEngineIdle;
|
|
277
|
+
/** The pre-round body of `prompt`, unchanged apart from being private. */
|
|
278
|
+
private startPrompt;
|
|
237
279
|
abort(): void;
|
|
280
|
+
/**
|
|
281
|
+
* Rung two of the Esc ladder: stop the AGENT, whatever it is blocked on
|
|
282
|
+
* (§3.6 / G3).
|
|
283
|
+
*
|
|
284
|
+
* FOUR STEPS, AND THE FOURTH IS AN ABSENCE.
|
|
285
|
+
*
|
|
286
|
+
* 1. `abort()` - everything it does today, unchanged.
|
|
287
|
+
* 2. `killForeground('force')` - hard-kill every tracked foreground `bash`
|
|
288
|
+
* child. THIS is what actually unblocks a wedged `await tool.execute`;
|
|
289
|
+
* an abort signal a tool ignores is advisory, and rung two exists for
|
|
290
|
+
* precisely the tools that ignore it.
|
|
291
|
+
* 3. `runGen += 1` - so `App` can drop the events the engine will keep
|
|
292
|
+
* emitting while it unwinds (I-7). Without it the view bounces straight
|
|
293
|
+
* back out of the `idle` the user was just given.
|
|
294
|
+
* 4. IT DOES NOT TOUCH BACKGROUND SERVICES. `Esc` interrupts the AGENT;
|
|
295
|
+
* `Ctrl+C` stops the SERVICES. That asymmetry is the user's own two
|
|
296
|
+
* sentences and it is exactly the kind of thing a later reader will
|
|
297
|
+
* "fix" by making this kill everything - which would mean a user who
|
|
298
|
+
* pressed Esc twice to stop a runaway turn also lost the dev server they
|
|
299
|
+
* had been working against for an hour. It is invariant I-4.
|
|
300
|
+
*
|
|
301
|
+
* UNCONDITIONAL ON `bash.background` (P1-6 / D-9). The supervisor is always
|
|
302
|
+
* constructed; with services off its foreground registry is all there is, and
|
|
303
|
+
* that is the half this method uses.
|
|
304
|
+
*/
|
|
305
|
+
forceStop(): void;
|
|
306
|
+
/**
|
|
307
|
+
* The current run generation (I-7).
|
|
308
|
+
*
|
|
309
|
+
* `App` captures it when it subscribes to a run and drops every engine event
|
|
310
|
+
* whose generation is stale. Same shape as the `abortRequested` guard the fast
|
|
311
|
+
* reviewer already uses, and for the same reason: the loop legitimately emits
|
|
312
|
+
* after an abort lands.
|
|
313
|
+
*/
|
|
314
|
+
get runGeneration(): number;
|
|
315
|
+
/** Whether `bash_output` / `bash_kill` are in `this.tools`. Fixed at construction. */
|
|
316
|
+
isBackgroundRegistered(): boolean;
|
|
317
|
+
/**
|
|
318
|
+
* Subscribe to the CLI-local `ProcEvent` stream.
|
|
319
|
+
*
|
|
320
|
+
* Returns a live unsubscribe even when services are off, because the
|
|
321
|
+
* supervisor exists either way - the contract `subscribeTeam` /
|
|
322
|
+
* `subscribeTodos` / `subscribeFast` / `subscribeToolOutput` already set. With
|
|
323
|
+
* services off nothing is ever emitted, so an unconditional subscription in
|
|
324
|
+
* `App` costs one `Set` entry.
|
|
325
|
+
*/
|
|
326
|
+
subscribeProc(listener: ProcEventListener): () => void;
|
|
327
|
+
getServiceSnapshot(id: string): ServiceSnapshot | undefined;
|
|
328
|
+
listServices(): ServiceSnapshot[];
|
|
329
|
+
/** `starting | ready | running`. Drives the status chip and the Ctrl+C rung. */
|
|
330
|
+
liveServiceCount(): number;
|
|
331
|
+
readServiceLog(id: string, since?: number): ReturnType<ProcSupervisor['read']>;
|
|
332
|
+
/**
|
|
333
|
+
* Stop one service, or every service when `id` is `'all'`.
|
|
334
|
+
*
|
|
335
|
+
* The GRACEFUL ladder (`SIGTERM` -> `SIGKILL` after `stopGraceMs`), because
|
|
336
|
+
* this path has a live event loop to run it on. `reapServicesSync` is the
|
|
337
|
+
* other one, and it is the only one an exit path may use.
|
|
338
|
+
*/
|
|
339
|
+
stopService(id: string): Promise<ServiceSnapshot[]>;
|
|
340
|
+
/**
|
|
341
|
+
* Rung one of `Ctrl+C`: stop every live service (§3.6 / G4).
|
|
342
|
+
*
|
|
343
|
+
* `force: true` means `reapSync()` SEMANTICS - immediate `SIGKILL`, no
|
|
344
|
+
* `stopGraceMs` - and is what `doExit` uses, because `doExit` awaits nothing
|
|
345
|
+
* and must not start (§3.6 step 3). The graceful ladder belongs to `Ctrl+C`,
|
|
346
|
+
* `bash_kill` and `/bg stop`.
|
|
347
|
+
*/
|
|
348
|
+
stopAllServices(opts?: {
|
|
349
|
+
force?: boolean;
|
|
350
|
+
}): Promise<ServiceSnapshot[]>;
|
|
351
|
+
/**
|
|
352
|
+
* The synchronous reaper (I-9).
|
|
353
|
+
*
|
|
354
|
+
* Exposed so `doExit` can call it without awaiting anything. It is also what
|
|
355
|
+
* the signal hook registered in the constructor calls, and it is idempotent -
|
|
356
|
+
* which it has to be, since a normal quit reaches it twice.
|
|
357
|
+
*/
|
|
358
|
+
reapServicesSync(): void;
|
|
238
359
|
steer(text: string): void;
|
|
239
360
|
followUp(text: string): void;
|
|
240
361
|
isRunning(): boolean;
|
|
@@ -493,6 +614,41 @@ export declare class AgentController {
|
|
|
493
614
|
* `subscribeTodos` already set.
|
|
494
615
|
*/
|
|
495
616
|
subscribeFast(listener: FastEventListener): () => void;
|
|
617
|
+
/**
|
|
618
|
+
* The FIFTH thin forwarder: the current fast-tier snapshot, or `null` when
|
|
619
|
+
* this session never registered a tier at all
|
|
620
|
+
* (web-use-tier-cooperation-and-control-closure §4.2.1).
|
|
621
|
+
*
|
|
622
|
+
* `null` and "a snapshot with `live: false`" are different answers and callers
|
|
623
|
+
* depend on the difference: the first means "there is no tier here", the
|
|
624
|
+
* second means "there is one and it is not usable right now".
|
|
625
|
+
*
|
|
626
|
+
* Deliberately NOT folded into the existing `review_end` event: that shape is
|
|
627
|
+
* consumed by `App` too, and this round promised to be purely additive.
|
|
628
|
+
*/
|
|
629
|
+
fastSnapshot(): FastSnapshot | null;
|
|
630
|
+
/**
|
|
631
|
+
* Subscribe to occupancy publications. Returns an unsubscribe function.
|
|
632
|
+
*
|
|
633
|
+
* THE SOLE UPSTREAM OF `ViewState.context` (I-1). The gauge used to have two
|
|
634
|
+
* writers - `turnEnd` and a `contextTokensEstimated` dispatch fired from two
|
|
635
|
+
* places in `App` - which is the entire cause of P0-1: both wrote in the same
|
|
636
|
+
* synchronous fan-out and the second one won, restoring the pre-compaction
|
|
637
|
+
* figure one statement after the bar had correctly fallen. One writer makes
|
|
638
|
+
* that class of bug unrepresentable rather than merely fixed.
|
|
639
|
+
*/
|
|
640
|
+
subscribeContextUsage(listener: ContextUsageListener): () => void;
|
|
641
|
+
/**
|
|
642
|
+
* Occupancy right now, re-measuring if the history has moved.
|
|
643
|
+
*
|
|
644
|
+
* `/context` READS THIS AND NOT `getCompactionSnapshot().pressure` (RV-8). The
|
|
645
|
+
* latter returns `offCompactionSnapshot()`'s hardcoded zero pressure when
|
|
646
|
+
* compaction was never registered, so a report built on it would read 0 % for
|
|
647
|
+
* precisely the sessions this feature exists to fix.
|
|
648
|
+
*/
|
|
649
|
+
getContextUsage(): ContextUsageSnapshot;
|
|
650
|
+
/** The meter itself, for the wiring's single-instance assertion and tests. */
|
|
651
|
+
getContextMeter(): ContextMeter;
|
|
496
652
|
/** Whether a `ContextManager` exists at all. Fixed at construction. */
|
|
497
653
|
isCompactionRegistered(): boolean;
|
|
498
654
|
/** Whether it will actually fire. Flipped live by `/compact on|off`. */
|