@aragon-agent/cli 0.6.2 → 0.6.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (167) hide show
  1. package/CHANGELOG.md +321 -0
  2. package/README.md +297 -2
  3. package/dist/agent/controller.d.ts +193 -1
  4. package/dist/agent/controller.js +475 -2
  5. package/dist/agent/headless.d.ts +8 -0
  6. package/dist/agent/headless.js +47 -0
  7. package/dist/agent/reducer.d.ts +189 -0
  8. package/dist/agent/reducer.js +301 -2
  9. package/dist/agent/system-prompt.d.ts +14 -0
  10. package/dist/agent/system-prompt.js +2 -0
  11. package/dist/cli.js +297 -16
  12. package/dist/commands/builtins.js +165 -24
  13. package/dist/commands/registry.d.ts +27 -0
  14. package/dist/compaction/archive.d.ts +175 -0
  15. package/dist/compaction/archive.js +267 -0
  16. package/dist/compaction/child.d.ts +97 -0
  17. package/dist/compaction/child.js +118 -0
  18. package/dist/compaction/command.d.ts +41 -0
  19. package/dist/compaction/command.js +355 -0
  20. package/dist/compaction/compactor.d.ts +302 -0
  21. package/dist/compaction/compactor.js +810 -0
  22. package/dist/compaction/digest.d.ts +62 -0
  23. package/dist/compaction/digest.js +164 -0
  24. package/dist/compaction/limits.d.ts +165 -0
  25. package/dist/compaction/limits.js +172 -0
  26. package/dist/compaction/pressure.d.ts +135 -0
  27. package/dist/compaction/pressure.js +167 -0
  28. package/dist/compaction/summarize-call.d.ts +70 -0
  29. package/dist/compaction/summarize-call.js +86 -0
  30. package/dist/compaction/summary-prompt.d.ts +85 -0
  31. package/dist/compaction/summary-prompt.js +197 -0
  32. package/dist/compaction/tail-budget.d.ts +52 -0
  33. package/dist/compaction/tail-budget.js +67 -0
  34. package/dist/compaction/types.d.ts +215 -0
  35. package/dist/compaction/types.js +22 -0
  36. package/dist/compaction/wiring.d.ts +264 -0
  37. package/dist/compaction/wiring.js +577 -0
  38. package/dist/config/app-paths.d.ts +14 -0
  39. package/dist/config/app-paths.js +16 -0
  40. package/dist/config/cli-commands.d.ts +41 -0
  41. package/dist/config/cli-commands.js +77 -1
  42. package/dist/config/env.d.ts +5 -2
  43. package/dist/config/env.js +140 -3
  44. package/dist/config/load.d.ts +42 -0
  45. package/dist/config/load.js +101 -1
  46. package/dist/config/schema.d.ts +244 -0
  47. package/dist/config/schema.js +170 -0
  48. package/dist/config/store.js +37 -1
  49. package/dist/config/ui-state.d.ts +28 -1
  50. package/dist/config/ui-state.js +9 -0
  51. package/dist/exec/events.d.ts +50 -1
  52. package/dist/exec/runner.js +42 -0
  53. package/dist/input/limits.d.ts +72 -0
  54. package/dist/input/limits.js +63 -0
  55. package/dist/input/mouse-events.d.ts +31 -5
  56. package/dist/input/mouse-events.js +86 -27
  57. package/dist/input/paste-parse.d.ts +71 -0
  58. package/dist/input/paste-parse.js +95 -0
  59. package/dist/input/stdin-filter.d.ts +81 -0
  60. package/dist/input/stdin-filter.js +379 -0
  61. package/dist/logging/install.d.ts +53 -1
  62. package/dist/logging/install.js +81 -1
  63. package/dist/logging/logger.d.ts +1 -1
  64. package/dist/proc/classify.d.ts +52 -0
  65. package/dist/proc/classify.js +143 -0
  66. package/dist/proc/kill-tree.d.ts +42 -0
  67. package/dist/proc/kill-tree.js +119 -0
  68. package/dist/proc/limits.d.ts +84 -0
  69. package/dist/proc/limits.js +84 -0
  70. package/dist/proc/log-ring.d.ts +68 -0
  71. package/dist/proc/log-ring.js +102 -0
  72. package/dist/proc/prompt.d.ts +24 -0
  73. package/dist/proc/prompt.js +49 -0
  74. package/dist/proc/readiness.d.ts +102 -0
  75. package/dist/proc/readiness.js +219 -0
  76. package/dist/proc/supervisor.d.ts +103 -0
  77. package/dist/proc/supervisor.js +465 -0
  78. package/dist/proc/types.d.ts +175 -0
  79. package/dist/proc/types.js +15 -0
  80. package/dist/session/persist.js +55 -1
  81. package/dist/team/report.js +7 -1
  82. package/dist/team/runtime.d.ts +10 -0
  83. package/dist/team/runtime.js +7 -0
  84. package/dist/team/subagent.d.ts +31 -1
  85. package/dist/team/subagent.js +42 -15
  86. package/dist/team/types.d.ts +8 -0
  87. package/dist/tools/bash-tool.d.ts +51 -2
  88. package/dist/tools/bash-tool.js +321 -51
  89. package/dist/tools/fs-tools.d.ts +17 -0
  90. package/dist/tools/index.d.ts +55 -2
  91. package/dist/tools/index.js +39 -1
  92. package/dist/tools/proc-tools.d.ts +25 -0
  93. package/dist/tools/proc-tools.js +102 -0
  94. package/dist/ui/ActivityLine.d.ts +19 -1
  95. package/dist/ui/ActivityLine.js +10 -2
  96. package/dist/ui/App.d.ts +62 -2
  97. package/dist/ui/App.js +546 -16
  98. package/dist/ui/Composer.d.ts +66 -1
  99. package/dist/ui/Composer.js +50 -6
  100. package/dist/ui/PromptInput.d.ts +82 -3
  101. package/dist/ui/PromptInput.js +232 -49
  102. package/dist/ui/StatusBar.d.ts +59 -0
  103. package/dist/ui/StatusBar.js +16 -4
  104. package/dist/ui/TeamPanel.js +7 -1
  105. package/dist/ui/Transcript.d.ts +21 -1
  106. package/dist/ui/Transcript.js +61 -3
  107. package/dist/ui/clipboard.d.ts +52 -0
  108. package/dist/ui/clipboard.js +91 -0
  109. package/dist/ui/composer-limits.d.ts +31 -0
  110. package/dist/ui/composer-limits.js +50 -0
  111. package/dist/ui/composer-rows.d.ts +73 -0
  112. package/dist/ui/composer-rows.js +201 -0
  113. package/dist/ui/editor-reducer.d.ts +37 -0
  114. package/dist/ui/editor-reducer.js +88 -12
  115. package/dist/ui/entries/CompactionCard.d.ts +75 -0
  116. package/dist/ui/entries/CompactionCard.js +158 -0
  117. package/dist/ui/entries/ServiceCard.d.ts +66 -0
  118. package/dist/ui/entries/ServiceCard.js +116 -0
  119. package/dist/ui/entries/UserEntry.d.ts +17 -3
  120. package/dist/ui/entries/UserEntry.js +34 -5
  121. package/dist/ui/frame-differ.d.ts +46 -0
  122. package/dist/ui/frame-differ.js +94 -10
  123. package/dist/ui/gauge.d.ts +16 -1
  124. package/dist/ui/gauge.js +25 -6
  125. package/dist/ui/glyphs.d.ts +11 -0
  126. package/dist/ui/glyphs.js +2 -0
  127. package/dist/ui/layout/ScrollViewport.d.ts +43 -6
  128. package/dist/ui/layout/ScrollViewport.js +128 -21
  129. package/dist/ui/layout/budget.d.ts +44 -9
  130. package/dist/ui/layout/budget.js +42 -10
  131. package/dist/ui/layout/follow-state.d.ts +137 -0
  132. package/dist/ui/layout/follow-state.js +150 -0
  133. package/dist/ui/layout/virtual-window.d.ts +11 -0
  134. package/dist/ui/layout/virtual-window.js +85 -1
  135. package/dist/ui/overlays/HelpOverlay.js +9 -1
  136. package/dist/ui/overlays/PlanReviewOverlay.js +10 -2
  137. package/dist/ui/overlays/QuestionOverlay.js +5 -1
  138. package/dist/ui/overlays/SettingsScreen.d.ts +47 -1
  139. package/dist/ui/overlays/SettingsScreen.js +74 -2
  140. package/dist/ui/palettes.d.ts +16 -0
  141. package/dist/ui/palettes.js +6 -0
  142. package/dist/ui/paste-frames.d.ts +87 -0
  143. package/dist/ui/paste-frames.js +112 -0
  144. package/dist/ui/paste-tokens.d.ts +90 -0
  145. package/dist/ui/paste-tokens.js +147 -0
  146. package/dist/ui/screen.d.ts +38 -0
  147. package/dist/ui/screen.js +113 -8
  148. package/dist/ui/selection/highlight.d.ts +39 -0
  149. package/dist/ui/selection/highlight.js +64 -0
  150. package/dist/ui/selection/screen-mirror.d.ts +24 -0
  151. package/dist/ui/selection/screen-mirror.js +35 -0
  152. package/dist/ui/selection/selection-controller.d.ts +88 -0
  153. package/dist/ui/selection/selection-controller.js +282 -0
  154. package/dist/ui/selection/selection.d.ts +90 -0
  155. package/dist/ui/selection/selection.js +223 -0
  156. package/dist/ui/stdout-frame-writer.d.ts +33 -0
  157. package/dist/ui/stdout-frame-writer.js +15 -0
  158. package/dist/ui/theme.d.ts +11 -0
  159. package/dist/ui/theme.js +2 -0
  160. package/dist/ui/transcript-text.js +72 -0
  161. package/dist/ui/use-startup-notices.d.ts +27 -1
  162. package/dist/ui/use-startup-notices.js +43 -11
  163. package/dist/ui/use-wheel-routing.d.ts +1 -1
  164. package/dist/ui/use-wheel-routing.js +8 -0
  165. package/package.json +4 -2
  166. package/dist/input/stdin-mouse-filter.d.ts +0 -42
  167. package/dist/input/stdin-mouse-filter.js +0 -153
package/CHANGELOG.md CHANGED
@@ -5,6 +5,259 @@ 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
+ ### Added
11
+
12
+ - **The composer understands pasting.** Until now it did not have the concept at
13
+ all: every byte the terminal delivered on stdin was a keystroke, and a
14
+ clipboard block is thousands of bytes arriving in an unpredictable number of
15
+ chunks. Three separate failures fell out of that one omission, and on Windows
16
+ you hit all three at once.
17
+
18
+ A carriage return that landed alone in a chunk **sent the half-finished
19
+ message** — a fifteen-line paste could arrive as a dozen separate messages,
20
+ interleaved with the agent's replies. A carriage return in the middle of a
21
+ chunk was inserted into the draft as a literal `\r`, which the terminal obeyed
22
+ by **overwriting the row it was drawn on**. And a paste that survived both grew
23
+ the composer to the height of the pasted text, pushing the transcript out of a
24
+ frame whose row accounting still believed the composer was three rows tall.
25
+
26
+ Pasting now works the way it reads:
27
+
28
+ - **A paste never submits.** Line breaks become buffer newlines, exactly one
29
+ per source line break, `CRLF` and lone `CR` alike.
30
+ - **A short paste appears verbatim.** At or below 6 lines and 400 characters it
31
+ is inserted as-is, indentation intact, and renders exactly like typed text.
32
+ - **A large paste collapses to a placeholder** — `[Pasted text #1 +218 lines]`
33
+ — which occupies one line, carries its own size in its label, deletes as a
34
+ single unit (one `Backspace`, and `Ctrl+W` / `Ctrl+U` / `Ctrl+K` cannot leave
35
+ half of one behind), and expands back to the full text the moment you send.
36
+ The model receives every byte; the composer never has to draw them.
37
+ - **No pasted byte is executed as a terminal control.** `\r`, `\x1b`, NUL, DEL
38
+ and the C1 range are stripped from the payload — never from your keystrokes,
39
+ so `Ctrl+A` and Escape are untouched.
40
+ - **The composer has a ceiling.** A draft of any length occupies at most 3 / 6 /
41
+ 10 rows depending on terminal height, scrolls internally to keep the caret
42
+ visible, shows how many rows are hidden above and below, and reports its true
43
+ height to the layout budget. Four hundred presses of `Shift+Enter` were
44
+ already able to destroy the frame; they no longer are.
45
+ - **A submitted message cannot make the transcript unresponsive.** A user entry
46
+ renders at most 40 rows plus a `... +N more lines` tail. The full text is kept
47
+ and the exit transcript is uncapped.
48
+
49
+ On terminals that support it, detection is **exact**: aragon asks for bracketed
50
+ paste (`DECSET 2004`) in full-screen mode and reads the markers the terminal
51
+ wraps your paste in. Where that is unavailable — inline mode, an old Windows
52
+ console — a heuristic on chunk shape catches the same cases, and it needs no
53
+ cooperation from the terminal at all. Both feed one code path.
54
+
55
+ Turn it off with `--no-paste`, `ARAGON_PASTE=0`, or
56
+ `aragon config set paste false`; the input path is then byte-for-byte what
57
+ 0.6.2 did.
58
+
59
+ ### Fixed
60
+
61
+ - **A pasted API key is stored correctly again.** Ink broadcasts each stdin chunk
62
+ to every mounted input handler, so the settings screen, the question overlay
63
+ and the plan-review feedback field all see what the composer sees. Without
64
+ this, a ~100-character key pasted into Settings would have been stored wrapped
65
+ in invisible framing bytes, masked on screen by the password dots, and would
66
+ have failed to authenticate on every request afterwards with nothing anywhere
67
+ explaining why.
68
+
69
+ - **`--no-mouse` still writes no mouse sequence.** Paste support installs a
70
+ stdin filter, and `paste` defaults to on, so the filter now exists in sessions
71
+ that disabled the mouse. Whether the mouse is on is a separate question from
72
+ whether the stream is wrapped, and the four places that used to conflate them
73
+ now ask the right one: `aragon --no-mouse` writes no `?1000h`, no `?1006h` and
74
+ no `?1002h`, leaves your terminal's own click-drag selection alone, and reports
75
+ `/mouse` as off — while pasting still works.
76
+
77
+ ### Changed
78
+
79
+ - **Auto-compaction no longer reports compactions that did not happen.** A long
80
+ unattended run used to print a red `context not compacted #2: nothing_to_drop`
81
+ card into the transcript. The card was accurate; nobody had asked for it.
82
+ Auto-compaction evaluates itself at every turn boundary, and a checkpoint that
83
+ looks at the history and finds nothing worth dropping has changed nothing,
84
+ called nothing and spent nothing — a smoke alarm announcing "no fire" twice an
85
+ hour, in error colours, with a machine reason attached.
86
+
87
+ A compaction now announces itself **if and only if it commits to doing work**.
88
+ That is a position in the control flow, not a list of reason strings: everything
89
+ decided before the first spend is silent, and everything decided after it —
90
+ including every failure, the truncation fallback, an Esc, and a host fault — is
91
+ as loud as it ever was. A declined `pressure` checkpoint is now
92
+ indistinguishable from a turn on which the threshold was never crossed.
93
+
94
+ **`/compact` and overflow recovery are unchanged.** A compaction you asked for
95
+ is owed an answer, and a reactive compaction running after the provider has
96
+ already refused your request is the one moment the diagnosis matters most. Both
97
+ still report on every outcome.
98
+
99
+ **Quiet, not unrecorded.** Every attempt is still written to the diagnostic log
100
+ (its `compaction` line gains an `announced` field, so `announced: false` is one
101
+ grep), still charged to the anti-loop guards, and still counted by
102
+ `/compact status` — which now reads
103
+ `This session: 1 compaction (2 checkpoints declined), 94.2k tokens reclaimed`
104
+ when checkpoints declined, and is byte-identical to before when none did. If
105
+ declines keep happening, the self-disable notice still says so out loud, once,
106
+ naming the cause and the remedies. Card numbers are also contiguous again: `#N`
107
+ counts compactions that ran, not checkpoints that fired.
108
+
109
+ **Behaviour change for wrapper scripts.** A declined `pressure` compaction no
110
+ longer emits a `{ type: 'compaction', subtype: 'start' | 'end' }` pair on the
111
+ `--output-format json` stream, and no longer prints `[compaction] skipped:` on
112
+ `-p` stderr. The pairs stay balanced, so only consumers counting *attempts* are
113
+ affected; the diagnostic log reports those more accurately.
114
+
115
+ ### Added
116
+
117
+ - **Context compaction, hardened — the trigger now counts the whole history, the
118
+ recent turns can no longer wedge a run, sub-agents get the same protection, and
119
+ a compaction is no longer irreversible.**
120
+
121
+ **The trigger was systematically late.** It fired on the provider's reported
122
+ usage for the PREVIOUS request, read at a checkpoint that runs AFTER the current
123
+ turn's tool results were appended — and tool results are the largest single
124
+ increment in this loop (100 KB per call, several per turn, ~25 k tokens each).
125
+ A session reading 88 % could be sending 110 %. Occupancy is now the measured
126
+ base PLUS an estimate of everything appended since that measurement, and the
127
+ status gauge reads the same number the trigger does, on every turn — including
128
+ the turns where a guard declines to compact, which is exactly when the number
129
+ matters most.
130
+
131
+ **The recent turns can no longer wedge a run.** Every previous rung of the
132
+ ladder operated on the head of the conversation. When the RETAINED tail was what
133
+ did not fit, each rung reported success or "nothing to drop" while the history
134
+ stayed un-sendable and the run died. Oversized `tool_result` bodies inside the
135
+ retained turns are now clipped, oldest first, only when the alternative is a
136
+ request the provider cannot accept. Nothing is removed — no message, no
137
+ tool-call id, no role — so a valid history stays valid. Every clip is announced
138
+ in the text the model reads, at the exact place the data went, and on the card,
139
+ in `/compact status`, on the JSON stream and in the archive.
140
+
141
+ **Sub-agents compact their own history** (`compaction.subagents`, default
142
+ `true`). A `task` child is bounded by 24 turns and fifteen minutes, and when one
143
+ overflowed its entire history was discarded and the dispatch reached the lead as
144
+ one partial sentence. Children run under tighter bounds than the lead: two
145
+ retained turns, at most two compactions, the fast tier preferred, and failure
146
+ forced to truncate because nobody is watching a background worker. No transcript
147
+ card — the lead's transcript describes the lead's context. Set
148
+ `compaction.subagents: false` to restore the previous behaviour exactly.
149
+
150
+ **A compaction is no longer irreversible** (`compaction.archive`, default
151
+ `true`). The dropped messages are written verbatim to `~/.aragon/compaction/`
152
+ before the splice is adopted. `/compact history` lists this run's archives,
153
+ `/compact show <n>` prints one's metadata and summary — never message bodies.
154
+ The directory is shared by every `aragon` on the machine, so files carry a
155
+ per-process run id and retention is two-tier: 20 files per run by count, plus a
156
+ seven-day sweep across all runs, so one session can never prune a live
157
+ neighbour's work. Writing is best-effort: a failure is logged and never affects
158
+ the compaction. This is deliberately **not** undo — restoring an over-full
159
+ history restores the condition that triggered the compaction.
160
+
161
+ **The long moment is legible.** The live card counts elapsed seconds and says
162
+ `esc to cancel`, which `AgentController.abort()` has always made true and no
163
+ surface has ever stated. A compaction that could only clip says so and names no
164
+ model, because none was called.
165
+
166
+ Two new config keys (`compaction.subagents`, `compaction.archive`), two new
167
+ environment variables (`ARAGON_COMPACTION_SUBAGENTS`,
168
+ `ARAGON_COMPACTION_ARCHIVE`), two new `/compact` verbs (`history`, `show <n>`),
169
+ and two new settings-screen rows. No flags were added.
170
+
171
+ - **Context compaction — a long run no longer dies when the window fills, and it
172
+ is ON by default.** A session's conversation only grows: nothing anywhere
173
+ removed a message, so a 40-turn tool-heavy run had exactly one ending available
174
+ to it once the context window filled — an HTTP 400 and a banner reading
175
+ *"Context length exceeded — start a new conversation with /reset."* The
176
+ product's answer to running out of context was "throw away everything you were
177
+ doing."
178
+
179
+ Now, at **90 %** occupancy, the run pauses at a turn boundary, hands the older
180
+ part of the history to a summarizer, and swaps it for a structured record. Your
181
+ original task stays **verbatim**, the most recent turns stay **verbatim**, and
182
+ the run continues in the same loop with the same tools, the same todo list and
183
+ the same working directory.
184
+
185
+ **This changes behaviour for existing users, in the direction of not dying.**
186
+ `--no-compaction`, or `compaction.enabled: false`, restores the old behaviour
187
+ exactly: no manager is constructed, nothing is subscribed, no registry is
188
+ allocated, and a full window ends the run as it did before. Both flag forms are
189
+ declared, so a stored `false` survives a run that passes no flags.
190
+
191
+ Three ways it fires. **Proactively** on measured occupancy — the case that
192
+ happens almost every time. **Reactively** when the provider returns
193
+ `context_overflow` anyway, because the model is not in the static window table
194
+ or you are pointed at a proxy in front of a smaller one: one compaction, one
195
+ re-send, run continues. And **manually**, via `/compact`, which runs
196
+ immediately when idle and queues to the next turn boundary when running.
197
+
198
+ The trigger has two terms. 90 % of a 200 k window leaves 20 k, which is plenty;
199
+ 90 % of a 32 k window leaves 3.2 k, which is less than a single `max_tokens` of
200
+ 8192 — the request is already impossible. So compaction also fires whenever the
201
+ remaining headroom drops below one full response.
202
+
203
+ **The default summarizer is your own model, and that costs real money.**
204
+ `compaction.useFastTier` is `true`, but it is a *preference*: the fast tier is
205
+ off unless you configured it, so out of the box the first compaction is a
206
+ ~30 k-token call on the session's own model. It happens at most 5 times per
207
+ run, the alternative is losing the run entirely, and the spend is visible — in
208
+ the session total, priced with the summarizer's own table, and reported as
209
+ `pricing unknown` rather than `$0.00` when that table has never seen the model.
210
+ Configure the fast tier to make it cheap.
211
+
212
+ Summarization fails sometimes. The ladder is one retry (on your **main** model
213
+ if the first attempt used the fast tier), then a **truncation** that says so on
214
+ the card, on the JSON event stream, and inside the block the model itself
215
+ reads. `compaction.onFailure: "stop"` makes the other trade.
216
+
217
+ Four guards stop it looping on your money: never two on consecutive turns,
218
+ never more than 5 per run, a progress requirement, and a self-disable after two
219
+ no-progress attempts with a notice naming the cause and the fix. The guards are
220
+ **trigger-aware** — the reactive path stays armed even after a self-disable,
221
+ because a compaction answering a request the provider has already refused is
222
+ the difference between a live run and a dead one.
223
+
224
+ Three UI surfaces: `Compacting context…` on the activity row while it runs, a
225
+ `compacting` chip plus threshold-aligned gauge colours as state, and a
226
+ transcript card with the before/after counts, the summarizer, the duration and
227
+ an expandable summary as the record. The gauge falls **immediately** rather
228
+ than waiting for the next turn. `/compact status` is the guaranteed surface at
229
+ any width.
230
+
231
+ New: `compaction` config section (6 keys), `--compaction` / `--no-compaction` /
232
+ `--compaction-threshold`, `ARAGON_COMPACTION*` (3 vars), `/compact` (6 forms),
233
+ three settings-screen rows, a `compaction` event on the `aragon exec` JSON
234
+ stream (`EXEC_SCHEMA_VERSION` **unchanged** — adding an event type never bumps
235
+ it), and two stderr lines under `-p`.
236
+
237
+ ### Changed
238
+
239
+ - **The context gauge now counts cache tokens**, through the same
240
+ `occupiedTokens` the compaction trigger reads. Anthropic reports `input_tokens`
241
+ *excluding* cached tokens and puts them in two separate fields, so the old
242
+ `inputTokens + outputTokens` silently under-reported occupancy for anyone
243
+ behind a caching gateway. That was already a defect in the number on the status
244
+ bar; it becomes a much worse one the moment a trigger fires on a different
245
+ number from the one you are watching.
246
+
247
+ - **`context_overflow` now names `/compact` alongside `/reset`.** That remedy
248
+ list was complete until this release, because throwing the conversation away
249
+ really was the only exit.
250
+
251
+ ### Known limitation
252
+
253
+ - **A summarizer that is 90 % faithful will, eventually, drop something the run
254
+ needed,** and no amount of prompt engineering closes that. The design bounds it
255
+ — verbatim task, verbatim recent turns, a block that tells the model the record
256
+ is partial, and three surfaces that make it visible so a human can step in —
257
+ but it does not eliminate it. That is inherent to compaction as a technique, it
258
+ is the same trade Claude Code and Codex make, and it is preferable by a wide
259
+ margin to the previous behaviour, which was to lose the entire run.
260
+
8
261
  ## 0.6.0
9
262
 
10
263
  ### Added
@@ -84,6 +337,74 @@ were written.
84
337
 
85
338
  ## Unreleased
86
339
 
340
+ ### Added
341
+
342
+ - **Drag the mouse to select text, and release to copy it.** Full-screen mode
343
+ takes the alternate screen, turns on mouse reporting so the wheel can scroll a
344
+ transcript the terminal no longer knows how to scroll, and draws every row
345
+ itself. Each of those is right on its own; together they took your terminal's
346
+ own drag-to-select away and put nothing in its place. The only thing shipped
347
+ in its place was a one-line notice naming a bypass key that is Shift on some
348
+ emulators, Fn on others and a preference elsewhere — a workaround, told once,
349
+ in a line that scrolls away.
350
+
351
+ Press the left button and drag: the cells you drag across are highlighted as
352
+ you go, and releasing copies exactly them. The copy goes out over **OSC 52**
353
+ first, so it reaches the clipboard of the machine you are *sitting at* rather
354
+ than the one you are ssh'd into, with the platform clipboard binary attempted
355
+ alongside it for terminals that ignore the sequence. Neither mechanism is
356
+ detectable, so the toast names what was sent rather than claiming a success it
357
+ cannot verify. `/copy` now goes through the same path and gained ssh support on
358
+ the way.
359
+
360
+ The highlight is painted in the frame pipeline rather than in React, so a drag
361
+ costs one to three re-addressed rows instead of a re-render of the whole tree,
362
+ and the text that is copied is read from the same mirrored rows the highlight
363
+ was painted over — what you see is what you get by construction, not by a
364
+ staleness check that can be wrong.
365
+
366
+ Two switches, both reversible without a restart: `/mouse off` hands the mouse
367
+ back to your terminal for the session (and says plainly that the wheel goes
368
+ inert while it is off), `/mouse on` takes it back, and
369
+ `aragon config set mouseSelect false` keeps wheel scrolling while leaving
370
+ drag-select off — which also stops the CLI asking the terminal for motion
371
+ reports at all, so that session puts exactly the bytes on the wire that it did
372
+ before this release. `--no-mouse` remains the switch that captures nothing.
373
+
374
+ ### Changed
375
+
376
+ - **Scrolling up now actually stops the transcript.** The viewport followed the
377
+ newest output by holding a *fixed distance from the bottom*, so scrolling up
378
+ during a run did not pause anything: twelve new rows of output moved the
379
+ window twelve rows down, and whatever you had scrolled up to read slid off the
380
+ top while you were reading it. The faster the agent talked, the faster your
381
+ reading position ran away.
382
+
383
+ While you are scrolled up, the transcript is now anchored to the **content**:
384
+ new output accumulates below the window instead of dragging the window along
385
+ with it, and the rows on screen hold still. After five seconds with no
386
+ scrolling the viewport returns to the newest line by itself — but only if
387
+ something actually arrived while you were paused, so reading a *finished*
388
+ transcript is never interrupted by a jump to a bottom that has not moved.
389
+ Every gesture restarts the countdown, a selection drag suspends it, and
390
+ `aragon config set scrollResumeMs 0` turns the return off entirely
391
+ (`ARAGON_SCROLL_RESUME_MS` sets it too).
392
+
393
+ The number the hint shows means something sharper as a result: it is now
394
+ literally "rows of newer output below your reading position", which is what
395
+ `PgDn` traverses and what the status bar's `↑N` has always shown.
396
+
397
+ - **The "N new lines · PgDn" hint moved inside the input box.** It used to be
398
+ rendered as the viewport's own last row, which spent a line of your transcript
399
+ on chrome at exactly the moment the transcript was longest — and, because the
400
+ hint's presence shrank the viewport, it fed back into the very number it was
401
+ displaying. It is now a right-aligned chip on the composer's input row, inside
402
+ the border, where it costs no rows at all. The chip sits in a fixed-width cell
403
+ so the number gaining a digit cannot re-wrap a draft, it never truncates (the
404
+ draft wraps first), and unlike the teaching row below the box it neither fades
405
+ with experience nor disappears on a short terminal: how far behind you are is
406
+ state, not a tutorial.
407
+
87
408
  ### Fixed
88
409
 
89
410
  - **The working spinner no longer disappears when an ack takes its row.** Steer a