@aragon-agent/cli 0.6.2 → 0.6.3

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 (118) hide show
  1. package/CHANGELOG.md +216 -0
  2. package/README.md +202 -0
  3. package/dist/agent/controller.d.ts +74 -1
  4. package/dist/agent/controller.js +200 -1
  5. package/dist/agent/headless.d.ts +8 -0
  6. package/dist/agent/headless.js +47 -0
  7. package/dist/agent/reducer.d.ts +120 -0
  8. package/dist/agent/reducer.js +201 -2
  9. package/dist/cli.js +224 -5
  10. package/dist/commands/builtins.js +73 -23
  11. package/dist/commands/registry.d.ts +27 -0
  12. package/dist/compaction/archive.d.ts +175 -0
  13. package/dist/compaction/archive.js +267 -0
  14. package/dist/compaction/child.d.ts +97 -0
  15. package/dist/compaction/child.js +113 -0
  16. package/dist/compaction/command.d.ts +41 -0
  17. package/dist/compaction/command.js +342 -0
  18. package/dist/compaction/compactor.d.ts +268 -0
  19. package/dist/compaction/compactor.js +689 -0
  20. package/dist/compaction/digest.d.ts +62 -0
  21. package/dist/compaction/digest.js +164 -0
  22. package/dist/compaction/limits.d.ts +165 -0
  23. package/dist/compaction/limits.js +172 -0
  24. package/dist/compaction/pressure.d.ts +135 -0
  25. package/dist/compaction/pressure.js +167 -0
  26. package/dist/compaction/summarize-call.d.ts +70 -0
  27. package/dist/compaction/summarize-call.js +86 -0
  28. package/dist/compaction/summary-prompt.d.ts +85 -0
  29. package/dist/compaction/summary-prompt.js +197 -0
  30. package/dist/compaction/tail-budget.d.ts +52 -0
  31. package/dist/compaction/tail-budget.js +67 -0
  32. package/dist/compaction/types.d.ts +179 -0
  33. package/dist/compaction/types.js +22 -0
  34. package/dist/compaction/wiring.d.ts +255 -0
  35. package/dist/compaction/wiring.js +556 -0
  36. package/dist/config/app-paths.d.ts +14 -0
  37. package/dist/config/app-paths.js +16 -0
  38. package/dist/config/cli-commands.d.ts +41 -0
  39. package/dist/config/cli-commands.js +77 -1
  40. package/dist/config/env.d.ts +4 -1
  41. package/dist/config/env.js +92 -2
  42. package/dist/config/load.d.ts +31 -0
  43. package/dist/config/load.js +63 -1
  44. package/dist/config/schema.d.ts +159 -0
  45. package/dist/config/schema.js +137 -0
  46. package/dist/config/store.js +17 -1
  47. package/dist/config/ui-state.d.ts +28 -1
  48. package/dist/config/ui-state.js +9 -0
  49. package/dist/exec/events.d.ts +50 -1
  50. package/dist/exec/runner.js +42 -0
  51. package/dist/input/mouse-events.d.ts +31 -5
  52. package/dist/input/mouse-events.js +86 -27
  53. package/dist/input/stdin-mouse-filter.d.ts +8 -3
  54. package/dist/logging/install.d.ts +51 -1
  55. package/dist/logging/install.js +28 -0
  56. package/dist/logging/logger.d.ts +1 -1
  57. package/dist/session/persist.js +19 -0
  58. package/dist/team/report.js +7 -1
  59. package/dist/team/runtime.d.ts +10 -0
  60. package/dist/team/runtime.js +7 -0
  61. package/dist/team/subagent.d.ts +31 -1
  62. package/dist/team/subagent.js +42 -15
  63. package/dist/team/types.d.ts +8 -0
  64. package/dist/ui/ActivityLine.d.ts +19 -1
  65. package/dist/ui/ActivityLine.js +10 -2
  66. package/dist/ui/App.d.ts +48 -1
  67. package/dist/ui/App.js +294 -13
  68. package/dist/ui/Composer.d.ts +13 -1
  69. package/dist/ui/Composer.js +2 -2
  70. package/dist/ui/PromptInput.d.ts +34 -1
  71. package/dist/ui/PromptInput.js +54 -3
  72. package/dist/ui/StatusBar.d.ts +40 -0
  73. package/dist/ui/StatusBar.js +13 -4
  74. package/dist/ui/TeamPanel.js +7 -1
  75. package/dist/ui/Transcript.d.ts +21 -1
  76. package/dist/ui/Transcript.js +32 -2
  77. package/dist/ui/clipboard.d.ts +52 -0
  78. package/dist/ui/clipboard.js +91 -0
  79. package/dist/ui/entries/CompactionCard.d.ts +75 -0
  80. package/dist/ui/entries/CompactionCard.js +158 -0
  81. package/dist/ui/frame-differ.d.ts +46 -0
  82. package/dist/ui/frame-differ.js +94 -10
  83. package/dist/ui/gauge.d.ts +16 -1
  84. package/dist/ui/gauge.js +25 -6
  85. package/dist/ui/glyphs.d.ts +11 -0
  86. package/dist/ui/glyphs.js +2 -0
  87. package/dist/ui/layout/ScrollViewport.d.ts +43 -6
  88. package/dist/ui/layout/ScrollViewport.js +128 -21
  89. package/dist/ui/layout/budget.d.ts +10 -3
  90. package/dist/ui/layout/budget.js +10 -3
  91. package/dist/ui/layout/follow-state.d.ts +137 -0
  92. package/dist/ui/layout/follow-state.js +150 -0
  93. package/dist/ui/layout/virtual-window.d.ts +11 -0
  94. package/dist/ui/layout/virtual-window.js +34 -0
  95. package/dist/ui/overlays/HelpOverlay.js +6 -1
  96. package/dist/ui/overlays/SettingsScreen.d.ts +47 -1
  97. package/dist/ui/overlays/SettingsScreen.js +60 -1
  98. package/dist/ui/palettes.d.ts +16 -0
  99. package/dist/ui/palettes.js +6 -0
  100. package/dist/ui/screen.d.ts +22 -0
  101. package/dist/ui/screen.js +70 -8
  102. package/dist/ui/selection/highlight.d.ts +39 -0
  103. package/dist/ui/selection/highlight.js +64 -0
  104. package/dist/ui/selection/screen-mirror.d.ts +24 -0
  105. package/dist/ui/selection/screen-mirror.js +35 -0
  106. package/dist/ui/selection/selection-controller.d.ts +88 -0
  107. package/dist/ui/selection/selection-controller.js +282 -0
  108. package/dist/ui/selection/selection.d.ts +90 -0
  109. package/dist/ui/selection/selection.js +223 -0
  110. package/dist/ui/stdout-frame-writer.d.ts +33 -0
  111. package/dist/ui/stdout-frame-writer.js +15 -0
  112. package/dist/ui/theme.d.ts +11 -0
  113. package/dist/ui/theme.js +2 -0
  114. package/dist/ui/transcript-text.js +23 -0
  115. package/dist/ui/use-startup-notices.d.ts +27 -1
  116. package/dist/ui/use-startup-notices.js +43 -11
  117. package/dist/ui/use-wheel-routing.js +8 -0
  118. package/package.json +4 -2
@@ -0,0 +1,268 @@
1
+ /**
2
+ * `Compactor` — the `ContextManager` implementation (context-auto-compaction
3
+ * §3.4 / §3.6 / §3.7 / §3.8).
4
+ *
5
+ * ASCII ONLY: `src/compaction/**` is inside the glyph scanner's scope.
6
+ *
7
+ * THIS IS THE POLICY HALF OF THE FEATURE. The engine owns exactly one thing -
8
+ * structural validity - and every other decision is here: when to fire, what to
9
+ * keep, which model summarizes, what the prompt asks for, what happens when the
10
+ * call fails, and when to stop spending.
11
+ */
12
+ import { type Message, type ModelInfo, type ModelRef, type TokenUsage, type AssistantMessage, type CompactionContext, type CompactionOutcome, type CompactionProbe, type ContextManager, type LLMRequest } from '@aragon-agent/core';
13
+ import type { CliConfig } from '../config/schema.js';
14
+ import type { NoticeLevel } from '../agent/reducer.js';
15
+ import type { CompactionEvent, Pressure } from './types.js';
16
+ export interface CompactorDeps {
17
+ /** Read LIVE on every call — the controller replaces the object on mutation. */
18
+ getConfig: () => CliConfig;
19
+ hasKey: (providerId: string) => boolean;
20
+ getApiKey: (providerId: string) => string | undefined;
21
+ /**
22
+ * The engine's live history and system prompt.
23
+ *
24
+ * `shouldCompact` NEEDS THEM, and that is the whole reason they are here.
25
+ * `CompactionProbe` carries `messageCount` but not the messages — the port is
26
+ * synchronous and cheap by design (D-3) — so the ESTIMATE fallback (§3.4.2)
27
+ * has nothing to measure unless the host supplies it. Estimating over an empty
28
+ * array yields 0 %, which is exactly the naive answer §3.4.2 exists to reject:
29
+ * the first request of a resumed 180 k-token session is the most dangerous
30
+ * moment in this feature's life, `lastUsage` is `undefined` there by
31
+ * definition, and a trigger that reads 0 % never fires.
32
+ *
33
+ * LAZY, and they must be: the wiring is constructed BEFORE the `Agent` (C-12),
34
+ * so a closure that touches it is only valid from inside a call the loop makes.
35
+ */
36
+ getMessages: () => readonly Message[];
37
+ getSystemPrompt: () => string;
38
+ /** `ModelInfo` for ANY model, so the summarizer's own window and price resolve. */
39
+ getModelInfoFor: (ref: Pick<ModelRef, 'providerId' | 'modelId'>) => ModelInfo;
40
+ isPricedModel: (ref: Pick<ModelRef, 'providerId' | 'modelId'>) => boolean;
41
+ /** The compactor's OWN fail-fast transport (D-10). Supplied by the wiring. */
42
+ complete: (providerId: string, request: LLMRequest) => Promise<AssistantMessage>;
43
+ emit: (event: CompactionEvent) => void;
44
+ notify: (level: NoticeLevel, text: string) => void;
45
+ /**
46
+ * Publish the occupancy this checkpoint measured (hardening §3.2.4 / DH-15).
47
+ *
48
+ * REPORTING IS NOT A SIDE EFFECT OF DECIDING; it is the other half of R-11.
49
+ * `shouldCompact` measures ONCE, ABOVE the guards, and calls this
50
+ * unconditionally on every enabled checkpoint - so the gauge and the trigger
51
+ * keep reading one number even on the turns a guard declines to compact.
52
+ * Optional, so a `Compactor` built without a UI (the child manager, W3) passes
53
+ * nothing and the call is one `?.` per turn.
54
+ */
55
+ onPressure?: (pressure: Pressure) => void;
56
+ }
57
+ /** Per-instance bounds a child manager tightens (hardening §3.4.2 mechanism B). */
58
+ export interface CompactorOptions {
59
+ /**
60
+ * Guard 2's ceiling for THIS compactor.
61
+ *
62
+ * A FIELD RATHER THAN A DIRECT `COMPACTION_LIMITS` READ, because a child gets a
63
+ * tighter one (W3 / DH-6) and `maxPerRun` is STRUCTURAL, not policy - there is
64
+ * no config path to it by design (`limits.ts` header). Defaults to the lead's
65
+ * value, so every existing construction site is unchanged.
66
+ */
67
+ maxPerRun?: number;
68
+ }
69
+ /** The summarizer the next compaction would use. */
70
+ export interface SummarizerChoice {
71
+ ref: ModelRef;
72
+ /** Whether the fast tier supplied it, for `/compact status` and the card. */
73
+ fromFastTier: boolean;
74
+ }
75
+ export declare class Compactor implements ContextManager {
76
+ private readonly deps;
77
+ private readonly log;
78
+ private compactionsThisRun;
79
+ private lastCompactionTurn;
80
+ private compactions;
81
+ private tokensReclaimed;
82
+ private sessionUsage;
83
+ private pricingUnknown;
84
+ private inFlight;
85
+ private consecutiveNoProgress;
86
+ private selfDisabled;
87
+ private selfDisabledReason;
88
+ private pendingManual;
89
+ private generation;
90
+ /** Calibration for every ESTIMATED figure (D-23). Recomputed on every turn_end. */
91
+ private estimateOffset;
92
+ /** The last pressure computed, so the status bar and `/compact status` agree. */
93
+ private lastPressure;
94
+ /**
95
+ * The history LENGTH the measurement in `lastUsage` covered (hardening W1).
96
+ *
97
+ * `undefined` DISABLES THE DELTA and reproduces round 1's arithmetic exactly.
98
+ * Every host-side mutation that is not an append must clear it - see
99
+ * `invalidateMeasurement`.
100
+ */
101
+ private measuredPrefixLength;
102
+ /**
103
+ * The messages the last splice dropped, held ONLY until the wiring collects
104
+ * them for the archive (W4 / RV-3).
105
+ *
106
+ * NOT ON `CompactionRecord`: that record is dispatched into the reducer and
107
+ * retained in view state for the card's lifetime, so putting a megabyte of
108
+ * history on it would park the dropped conversation in React state - precisely
109
+ * the memory this compaction just reclaimed.
110
+ *
111
+ * SET ONLY WHEN ARCHIVING IS ON, so with the key off the slice is never
112
+ * retained and W4 costs nothing.
113
+ */
114
+ private lastDropped;
115
+ private callAbort;
116
+ private callAbortReason;
117
+ /** Guard 2's ceiling for this instance (hardening §3.4.2 mechanism B / DH-16). */
118
+ private readonly maxPerRun;
119
+ constructor(deps: CompactorDeps, opts?: CompactorOptions);
120
+ /** `agent_start` — the per-run cap resets, the session totals do not. */
121
+ onRunStart(): void;
122
+ /**
123
+ * `turn_end` — recompute the calibration offset (D-23).
124
+ *
125
+ * RE-MEASURED EVERY TURN, not once, so it tracks a toolset that changed
126
+ * mid-session (`/tools`, a skill that registers one).
127
+ */
128
+ onTurnEnd(usage: TokenUsage, messages: readonly Message[], systemPrompt: string): void;
129
+ /**
130
+ * Any host-side history mutation that is NOT an append (hardening §3.2.3).
131
+ *
132
+ * `/clear`, `/resume`, and the splice itself: after any of them a recorded
133
+ * index means nothing, and the delta would be measured against the wrong
134
+ * array. `estimateAppendedTokens` bounds-checks as well, so a MISSED call here
135
+ * costs accuracy - the number degrades to round 1's - and never correctness.
136
+ */
137
+ invalidateMeasurement(): void;
138
+ /**
139
+ * The dropped messages, released as they are returned (W4 / RV-3).
140
+ *
141
+ * `take` RATHER THAN `get`: the reference is dropped on read, so a wiring that
142
+ * declines to archive (key off, or `applied: false`) cannot pin it and a second
143
+ * read cannot double-write. `settlePending` calls this on EVERY verdict and
144
+ * discards on the ones that do not archive, which is what guarantees the array
145
+ * cannot outlive one compaction regardless of which branch was taken.
146
+ */
147
+ takeLastDropped(): Message[] | null;
148
+ /** Cancel an in-flight summarization (Esc, `dispose`). */
149
+ abort(): void;
150
+ /**
151
+ * Ask for a compaction at the next turn boundary.
152
+ *
153
+ * THE BOUNDARY IS THE ONLY MOMENT THE ENGINE IS SINGLE-THREADED WITH RESPECT
154
+ * TO THE HISTORY, by construction. Replacing `messages` under a live loop is a
155
+ * race; a flag `shouldCompact` honours there is not.
156
+ */
157
+ queueManual(instructions?: string): void;
158
+ hasPendingManual(): boolean;
159
+ clearPendingManual(): void;
160
+ /**
161
+ * SYNCHRONOUS AND CHEAP. Two deliberate effects: the pressure cache, and
162
+ * `deps.onPressure` (hardening DH-15).
163
+ *
164
+ * THE MEASUREMENT IS TAKEN ONCE, ABOVE THE GUARDS, AND REPORTED
165
+ * UNCONDITIONALLY. Below them it is skipped on five paths — the per-run cap,
166
+ * the cooldown, manual, overflow and guard 4 — and TWO OF THOSE NEVER CLEAR
167
+ * WITHIN A RUN. A gauge fed from the measurement would therefore go dark
168
+ * exactly when compaction is exhausted and the window is still filling, which
169
+ * is the one state where the corrected number is the user's only warning. It
170
+ * would silently revert to the measured base — the very figure W1 exists
171
+ * because it under-reports.
172
+ *
173
+ * `!config.enabled` STAYS THE FIRST STATEMENT, so a session that turned the
174
+ * feature off pays nothing at all and AC-1's byte-identity claim is untouched.
175
+ */
176
+ shouldCompact(probe: CompactionProbe): boolean;
177
+ compact(ctx: CompactionContext): Promise<CompactionOutcome>;
178
+ private runCompaction;
179
+ /** Tail relief against this session's window (hardening §3.3.3 / W2). */
180
+ private relieveInPlace;
181
+ /**
182
+ * The failure ladder (§3.7).
183
+ *
184
+ * Rung 1 is the fast tier (or the main model); rung 2 is ONE retry on the MAIN
185
+ * model when rung 1 used the fast tier, because "a fast model that cannot
186
+ * summarize" is the most likely single failure. Rungs 3 and 4 are the caller's,
187
+ * because they depend on `onFailure`.
188
+ */
189
+ private runLadder;
190
+ private callOnce;
191
+ /**
192
+ * Guard 3 — the progress requirement (§3.8).
193
+ *
194
+ * ADVISORY ON OVERFLOW, NEVER A VETO (D-24 / P1-13). The arithmetic that makes
195
+ * this guard sensible for the proactive trigger INVERTS on the reactive one: a
196
+ * pressure compaction that reclaims little has spent money to buy two turns and
197
+ * should stop, while an overflow compaction that reclaims little is the
198
+ * difference between a continuing run and a dead one, because the provider has
199
+ * already refused the request.
200
+ *
201
+ * The projection is ESTIMATED — no usage exists for a history that has not been
202
+ * sent yet — and is therefore CALIBRATED with `estimateOffset` (D-23).
203
+ *
204
+ * IT TAKES THE *UI* TRIGGER, not `ctx.trigger`. A queued `/compact` reaches the
205
+ * loop as an ordinary `pressure` checkpoint (that is what the queue IS), so
206
+ * charging its result to guard 4's counter would let a user who types
207
+ * `/compact` twice on a short conversation self-disable the proactive trigger
208
+ * for the rest of the session — and be told, wrongly, that their recent turns
209
+ * exceed the threshold. `uiTrigger` is the only value that knows the difference.
210
+ */
211
+ private checkProgress;
212
+ /**
213
+ * Guard 4 — stuck detection (§3.8).
214
+ *
215
+ * PRESSURE ONLY, AND `pressure` HERE MEANS THE *UI* TRIGGER. A session that
216
+ * self-disables still survives an overflow rather than dying at the next
217
+ * request, and if the tail really is too large the overflow attempt is the one
218
+ * that can do something about it (D-24). A `manual` compaction is excluded for
219
+ * a different reason: this guard exists to stop UNREQUESTED spend, and
220
+ * `/compact` on a conversation with nothing worth dropping is a user who asked
221
+ * — twice — not a runaway loop.
222
+ */
223
+ private noteNoProgress;
224
+ private finish;
225
+ /**
226
+ * The pressure the trigger and the gauge both read.
227
+ *
228
+ * CACHED on every evaluation, so `/compact status` reports the same number the
229
+ * last decision used rather than recomputing one that has since moved.
230
+ */
231
+ measure(probe: Pick<CompactionProbe, 'lastUsage'> & {
232
+ messages?: readonly Message[];
233
+ systemPrompt?: string;
234
+ }): Pressure;
235
+ lastMeasured(): Pressure | null;
236
+ /** Written by the wiring once the engine has reported its verdict. */
237
+ recordApplied(tokensBefore: number, tokensAfter: number): void;
238
+ sessionTotals(): {
239
+ compactions: number;
240
+ tokensReclaimed: number;
241
+ usage: TokenUsage;
242
+ pricingUnknown: boolean;
243
+ inFlight: boolean;
244
+ selfDisabled: boolean;
245
+ selfDisabledReason?: string;
246
+ generation: number;
247
+ };
248
+ /** `/compact on` after a self-disable — the user overriding the guard. */
249
+ clearSelfDisable(): void;
250
+ isSelfDisabled(): boolean;
251
+ /**
252
+ * Which model summarizes (§3.6.4).
253
+ *
254
+ * SAY THE DEFAULT OUT LOUD (P2-8): FOR ALMOST EVERYONE THIS IS THE MAIN MODEL.
255
+ * `resolveFastTier` returns `{ok: false, reason: 'disabled'}` on
256
+ * `fast.enabled !== true` alone, and `fast.enabled` defaults to `false` — so
257
+ * `useFastTier: true` describes a PREFERENCE, not the common path, and the
258
+ * out-of-the-box first compaction is a ~30 k-token call on the session's own
259
+ * model. Three things make that the right trade rather than a hidden cost: it
260
+ * happens at most `maxPerRun` times per run, the alternative is losing the
261
+ * entire run, and the spend is on the card with the summarizer's own price.
262
+ */
263
+ resolveSummarizer(): SummarizerChoice | null;
264
+ private mainRef;
265
+ private modelInfo;
266
+ private effectiveMaxOutputTokens;
267
+ private noteUsage;
268
+ }