@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,255 @@
1
+ /**
2
+ * `CompactionWiring` — the controller-side glue for context compaction
3
+ * (context-auto-compaction §3.2.1 / §5.2).
4
+ *
5
+ * ASCII ONLY: `src/compaction/**` is inside the glyph scanner's scope.
6
+ *
7
+ * CONSTRUCT BEFORE THE `Agent`, ATTACH AFTER IT (C-12 / D-19), and the split is
8
+ * the whole reason this class has an `attach` method at all:
9
+ *
10
+ * - The PORT has to be INSIDE the `Agent`'s constructor argument, because
11
+ * `AgentConfig.contextManager` has no setter and the loop reads it from the
12
+ * loop context.
13
+ * - The WIRING has to SUBSCRIBE to the `Agent`, because `compaction_end` is
14
+ * where the engine's `applied` verdict arrives and `agent_start` is what
15
+ * resets the per-run cap.
16
+ *
17
+ * `AgentController` cannot do both in one step: `new Agent({...})` runs before
18
+ * every optional subsystem, precisely because `FastWiring`'s constructor
19
+ * subscribes. So THIS CONSTRUCTOR MUST NOT SUBSCRIBE. A field assigned after the
20
+ * `new Agent` call and spread into it conditionally produces a build where the
21
+ * feature is registered, enabled, and SILENTLY ABSENT - the exact shape of
22
+ * failure `controller.ts`'s `toolOutputs` comment documents.
23
+ *
24
+ * `manager()` returns a STABLE object for the controller's lifetime, whose two
25
+ * methods delegate to a compactor that reads config LIVE - which is what lets
26
+ * `/compact off`, `/compact threshold 0.8` and a settings-screen save take effect
27
+ * mid-session without touching the `Agent`.
28
+ */
29
+ import { type AgentEvent, type ContextManager, type Message, type ModelInfo, type ModelRef, type ProviderRegistry, type ProviderRegistryOptions, type TokenUsage } from '@aragon-agent/core';
30
+ import type { CliConfig } from '../config/schema.js';
31
+ import type { NoticeLevel } from '../agent/reducer.js';
32
+ import { type ChildContextManagerFactory } from './child.js';
33
+ import type { CompactionEventListener, CompactionSnapshot } from './types.js';
34
+ export interface CompactionWiringDeps {
35
+ /** Read LIVE on every call - the controller replaces the object on mutation. */
36
+ getConfig: () => CliConfig;
37
+ hasKey: (providerId: string) => boolean;
38
+ getApiKey: (providerId: string) => string | undefined;
39
+ getModelInfoFor: (ref: Pick<ModelRef, 'providerId' | 'modelId'>) => ModelInfo;
40
+ isPricedModel: (ref: Pick<ModelRef, 'providerId' | 'modelId'>) => boolean;
41
+ /**
42
+ * LAZY, and they must be: this class is constructed BEFORE the `Agent`, so a
43
+ * closure that touches it is only valid from inside an event handler.
44
+ */
45
+ getMessages: () => readonly Message[];
46
+ getSystemPrompt: () => string;
47
+ notify: (level: NoticeLevel, text: string) => void;
48
+ /**
49
+ * How the summarizer's own registry is built. Defaults to `initProviders`.
50
+ *
51
+ * THE ONE PRODUCTION SEAM ADDED FOR TESTABILITY (hardening DH-13 / W6).
52
+ * Everything else the offline harness needs is already public:
53
+ * `ProviderRegistry.register` overwrites by id, `AgentController` exposes the
54
+ * lead's registry, and `Agent` accepts one in its config. `getRegistry()` was
55
+ * the only closed door - it calls `initProviders` with no injection point, so
56
+ * the lead's transport was scriptable in a test and the SUMMARIZER'S was not.
57
+ * A test-only seam per module is how a codebase acquires a shadow API; this is
58
+ * one, and it is named.
59
+ */
60
+ createRegistry?: (options: ProviderRegistryOptions) => ProviderRegistry;
61
+ /**
62
+ * The archive directory, injected by the tests. Production passes nothing and
63
+ * `archive.ts` resolves `<home>/compaction` itself.
64
+ */
65
+ archiveDir?: string;
66
+ }
67
+ /** The status of a session that never had compaction (the wiring is `null`). */
68
+ export declare function offCompactionSnapshot(): CompactionSnapshot;
69
+ export declare class CompactionWiring {
70
+ private readonly deps;
71
+ private readonly log;
72
+ private readonly listeners;
73
+ private readonly compactor;
74
+ /** The compactor's OWN transport (D-10). Lazy - see `getRegistry()`. */
75
+ private registry;
76
+ private unsubscribe;
77
+ /** The stable port handed to `new Agent({...})`. Never reassigned. */
78
+ private readonly port;
79
+ /**
80
+ * The record the compactor produced, waiting for the ENGINE's verdict.
81
+ *
82
+ * `applied` is not knowable on the host side: validation happens after
83
+ * `compact()` returns, inside the loop. So the compactor's record is held here
84
+ * and corrected when the core `compaction_end` arrives (§3.2.1). The IDLE
85
+ * `/compact` path has no core event and settles its own record directly.
86
+ */
87
+ private pending;
88
+ /**
89
+ * What the CLI-local `compaction_start` announced, and `null` once the card has
90
+ * been settled.
91
+ *
92
+ * THE ENGINE'S VERDICT CAN ARRIVE BEFORE THE COMPACTOR'S RECORD, and Esc is the
93
+ * ordinary way it happens: `runCompaction` races `compact()` against the run's
94
+ * signal, so an abort resolves the race and emits `compaction_end` while
95
+ * `compact()` is still unwinding its own call. With nothing held here,
96
+ * `settlePending` would find no record, return, and leave the card `live:
97
+ * true` FOREVER — which is C-8's failure mode exactly: `Transcript`'s settled
98
+ * boundary is monotonic, so the whole tail re-renders on every frame for the
99
+ * rest of the session, and the card goes on claiming a compaction is running.
100
+ * `manager_timeout` and a `compact()` that rejects outright reach the same
101
+ * place.
102
+ *
103
+ * So the verdict settles the card from whatever is available — the compactor's
104
+ * record when it exists, this skeleton when it does not — and clearing this
105
+ * field is what tells a LATE record that its card is already closed.
106
+ */
107
+ private open;
108
+ /** Live flag, flipped by `/compact on|off`. Starts equal to `enabled`. */
109
+ private enabled;
110
+ /**
111
+ * Identifies THIS RUN's archives in a directory several runs share (RV-6).
112
+ *
113
+ * NOT `SessionMeta.id`: that exists only once a session has been saved, and the
114
+ * unattended long run this feature serves is exactly the one nobody saved.
115
+ * Short, filename-safe, and only ever compared for equality - it is a grouping
116
+ * key, not an identity.
117
+ */
118
+ private readonly runId;
119
+ constructor(deps: CompactionWiringDeps);
120
+ /**
121
+ * The port for `new Agent({...})`.
122
+ *
123
+ * Spread CONDITIONALLY at the call site so `contextManager` stays genuinely
124
+ * `undefined` when the feature is off (AC-1): the loop's gate is
125
+ * `if (!ctx.contextManager) return false` against an ABSENT field, not a live
126
+ * object whose predicate says no.
127
+ */
128
+ manager(): ContextManager;
129
+ /**
130
+ * Subscribe to the lead agent's stream. IDEMPOTENT, and separate from the
131
+ * constructor - see the file header.
132
+ */
133
+ attach(subscribe: (listener: (event: AgentEvent) => void) => () => void): void;
134
+ dispose(): void;
135
+ isEnabled(): boolean;
136
+ setEnabled(enabled: boolean): void;
137
+ /** Re-emit the snapshot after any config mutation, so the chip and the gauge move. */
138
+ onConfigChanged(): void;
139
+ abort(): void;
140
+ /**
141
+ * The host replaced or cleared the history (hardening §3.2.3, sites 3 and 4).
142
+ *
143
+ * `/clear`, `/resume`, and any future host-side rewrite. A recorded prefix
144
+ * length indexes an array that no longer exists, so the delta must be
145
+ * abandoned rather than applied to a different history.
146
+ */
147
+ onHistoryReplaced(): void;
148
+ /**
149
+ * The per-child manager factory, or `null` when children get none
150
+ * (hardening §3.4 / W3).
151
+ *
152
+ * `null` RATHER THAN A NO-OP FACTORY, so `subagent.ts` can spread NOTHING and
153
+ * the child's loop gate tests a genuinely absent `contextManager` - the same
154
+ * byte-identity argument `AgentController` makes for the lead (AC-H10).
155
+ */
156
+ childFactory(): ChildContextManagerFactory | null;
157
+ queueManual(instructions?: string): void;
158
+ hasPendingManual(): boolean;
159
+ clearPendingManual(): void;
160
+ /**
161
+ * The IDLE `/compact` path (§4.4 / D-25).
162
+ *
163
+ * IT VALIDATES BEFORE IT SPLICES, AND THAT IS NOT OPTIONAL (P1-7). When the
164
+ * agent is idle there is no loop, so §3.3 step 5 does not run — and the only
165
+ * way to replace the history is `Agent.replaceMessages`, which validates
166
+ * nothing. D-4 declares that gate unbypassable and R-2 calls an invalid splice
167
+ * the worst possible outcome, so this path mirrors the engine's steps 3-5
168
+ * exactly, INCLUDING the failure vocabulary: the card, the log and
169
+ * `/compact status` cannot tell the two paths apart.
170
+ *
171
+ * No watchdog handling is needed — `runLoopWithLifecycle`'s `finally` already
172
+ * called `watchdog.stop()`, so nothing is armed while idle.
173
+ *
174
+ * ITS CALLER MUST ADOPT `messages` — THE ARCHIVE IS ALREADY WRITTEN BY THE
175
+ * TIME THIS RETURNS (hardening RV-7). This path settles `applied: true` here,
176
+ * one statement before the caller splices, so the "never archive a live
177
+ * history" rule holds only because that caller applies unconditionally. That is
178
+ * a fact about one call site rather than an invariant, which is why it is
179
+ * written down where it can be checked.
180
+ */
181
+ compactNow(args: {
182
+ messages: readonly Message[];
183
+ systemPrompt: string;
184
+ model: ModelRef;
185
+ signal: AbortSignal;
186
+ lastUsage?: TokenUsage;
187
+ instructions?: string;
188
+ }): Promise<{
189
+ ok: true;
190
+ messages: Message[];
191
+ } | {
192
+ ok: false;
193
+ reason: string;
194
+ }>;
195
+ snapshot(): CompactionSnapshot;
196
+ /**
197
+ * `snapshot()` with the pressure argument substituted for the re-measurement.
198
+ *
199
+ * SO THE CHECKPOINT DOES NOT MEASURE TWICE. `shouldCompact` has already walked
200
+ * the appended slice; measuring again here would double the one cost DH-15
201
+ * accepted, and - worse - the second measurement could differ from the one the
202
+ * decision was made on if anything appended in between.
203
+ */
204
+ private snapshotWith;
205
+ /** The summarizer that would be used right now, for `/compact status`. */
206
+ summarizerRef(): ModelRef | null;
207
+ subscribe(listener: CompactionEventListener): () => void;
208
+ /**
209
+ * The transport one summarization call goes through - separate from the lead's,
210
+ * and fail-fast (D-10).
211
+ *
212
+ * LAZY, SO OFF STAYS BYTE-IDENTICAL. Nothing is constructed until a compaction
213
+ * actually calls, so a session that never crosses the threshold allocates no
214
+ * registry and registers no adapters.
215
+ */
216
+ private getRegistry;
217
+ private onCompactorEvent;
218
+ private onAgentEvent;
219
+ /**
220
+ * Settle the held record with the authoritative verdict, then emit it.
221
+ *
222
+ * `tokensBefore` / `tokensAfter` come from CORE'S OWN estimator on BOTH sides
223
+ * (§5.1), so the card's headline claim compares two numbers in one unit rather
224
+ * than a measurement against a guess. `tokensReclaimed` is accumulated from the
225
+ * same pair, which is what keeps `/compact status` and the card agreeing.
226
+ */
227
+ private settlePending;
228
+ /**
229
+ * Write the archive, if there is one to write (hardening §3.5.3 / W4).
230
+ *
231
+ * ONLY ON `applied: true`, because the rule the writer enforces is "never
232
+ * archive a history that is still live" - and the two paths reach that verdict
233
+ * at different moments relative to the splice. In loop, the ENGINE decides
234
+ * after `validateHistory`, so this runs AFTER adoption. On the manual path the
235
+ * WIRING decides and `compactNow`'s caller adopts on the next statement, so
236
+ * this runs BEFORE adoption; `compactNow`'s doc comment carries that obligation
237
+ * for its one caller (RV-7).
238
+ *
239
+ * BEST-EFFORT AND SYNCHRONOUS-BUT-GUARDED. `writeArchive` never throws and
240
+ * logs its own failure; a failed archive never affects the compaction, and it
241
+ * never notifies - a toast for a best-effort audit file trains users to ignore
242
+ * toasts.
243
+ */
244
+ private archive;
245
+ /** This run's archive key, for `/compact history` and `/compact show`. */
246
+ archiveRunId(): string;
247
+ /**
248
+ * The minimum a card needs to settle when the compactor's own record has not
249
+ * arrived (see `open`). `null` when no card was ever opened — the
250
+ * `shouldCompact`-threw path, where the engine emits a pair of events the CLI
251
+ * stream knows nothing about.
252
+ */
253
+ private skeletonRecord;
254
+ private emit;
255
+ }