@aragon-agent/cli 0.5.8 → 0.5.10

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 (156) hide show
  1. package/CHANGELOG.md +1157 -747
  2. package/README.md +1552 -1163
  3. package/dist/agent/coalesce.d.ts +13 -0
  4. package/dist/agent/coalesce.js +50 -11
  5. package/dist/agent/controller.d.ts +141 -2
  6. package/dist/agent/controller.js +396 -4
  7. package/dist/agent/headless.d.ts +8 -0
  8. package/dist/agent/headless.js +40 -0
  9. package/dist/agent/reducer.d.ts +245 -3
  10. package/dist/agent/reducer.js +490 -17
  11. package/dist/agent/retry-view.d.ts +68 -0
  12. package/dist/agent/retry-view.js +95 -0
  13. package/dist/agent/system-prompt.d.ts +11 -0
  14. package/dist/agent/system-prompt.js +2 -0
  15. package/dist/boot/guard.d.ts +135 -0
  16. package/dist/boot/guard.js +218 -0
  17. package/dist/boot/rollback.d.ts +86 -0
  18. package/dist/boot/rollback.js +185 -0
  19. package/dist/cli.js +368 -3
  20. package/dist/commands/builtins.d.ts +1 -1
  21. package/dist/commands/builtins.js +426 -2
  22. package/dist/commands/registry.d.ts +17 -0
  23. package/dist/config/app-paths.d.ts +31 -0
  24. package/dist/config/app-paths.js +37 -0
  25. package/dist/config/cli-commands.d.ts +79 -2
  26. package/dist/config/cli-commands.js +185 -3
  27. package/dist/config/env.d.ts +15 -3
  28. package/dist/config/env.js +143 -3
  29. package/dist/config/load.d.ts +66 -0
  30. package/dist/config/load.js +107 -1
  31. package/dist/config/schema.d.ts +268 -2
  32. package/dist/config/schema.js +288 -1
  33. package/dist/config/store.js +32 -1
  34. package/dist/fast/critique.d.ts +43 -0
  35. package/dist/fast/critique.js +62 -0
  36. package/dist/fast/digest.d.ts +42 -0
  37. package/dist/fast/digest.js +85 -0
  38. package/dist/fast/frames.d.ts +99 -0
  39. package/dist/fast/frames.js +180 -0
  40. package/dist/fast/limits.d.ts +98 -0
  41. package/dist/fast/limits.js +98 -0
  42. package/dist/fast/prompt.d.ts +72 -0
  43. package/dist/fast/prompt.js +94 -0
  44. package/dist/fast/resolve.d.ts +43 -0
  45. package/dist/fast/resolve.js +105 -0
  46. package/dist/fast/review-call.d.ts +99 -0
  47. package/dist/fast/review-call.js +130 -0
  48. package/dist/fast/reviewer.d.ts +248 -0
  49. package/dist/fast/reviewer.js +664 -0
  50. package/dist/fast/types.d.ts +128 -0
  51. package/dist/fast/types.js +14 -0
  52. package/dist/fast/wiring.d.ts +170 -0
  53. package/dist/fast/wiring.js +316 -0
  54. package/dist/launcher.d.ts +14 -0
  55. package/dist/launcher.js +43 -0
  56. package/dist/logging/install.d.ts +15 -1
  57. package/dist/logging/install.js +37 -4
  58. package/dist/logging/logger.d.ts +1 -1
  59. package/dist/session/persist.js +57 -1
  60. package/dist/team/normalize.d.ts +26 -1
  61. package/dist/team/normalize.js +23 -3
  62. package/dist/team/prompt.d.ts +11 -0
  63. package/dist/team/prompt.js +10 -0
  64. package/dist/team/report.d.ts +18 -0
  65. package/dist/team/report.js +27 -1
  66. package/dist/team/runtime.d.ts +13 -2
  67. package/dist/team/runtime.js +33 -6
  68. package/dist/team/subagent.d.ts +19 -1
  69. package/dist/team/subagent.js +72 -10
  70. package/dist/team/task-tool.d.ts +26 -0
  71. package/dist/team/task-tool.js +48 -4
  72. package/dist/team/types.d.ts +80 -1
  73. package/dist/tools/bash-tool.js +19 -3
  74. package/dist/tools/diff.d.ts +25 -5
  75. package/dist/tools/diff.js +72 -41
  76. package/dist/tools/file-change-store.d.ts +34 -0
  77. package/dist/tools/file-change-store.js +57 -0
  78. package/dist/tools/fs-tools.d.ts +26 -0
  79. package/dist/tools/fs-tools.js +62 -5
  80. package/dist/tools/index.d.ts +31 -0
  81. package/dist/tools/index.js +7 -1
  82. package/dist/tools/patch.d.ts +115 -0
  83. package/dist/tools/patch.js +453 -0
  84. package/dist/tools/terminal-output.d.ts +107 -0
  85. package/dist/tools/terminal-output.js +198 -0
  86. package/dist/tools/tool-output-store.d.ts +68 -0
  87. package/dist/tools/tool-output-store.js +102 -0
  88. package/dist/ui/ActivityLine.d.ts +48 -0
  89. package/dist/ui/ActivityLine.js +22 -0
  90. package/dist/ui/App.d.ts +11 -4
  91. package/dist/ui/App.js +359 -37
  92. package/dist/ui/BottomStatusRow.d.ts +65 -0
  93. package/dist/ui/BottomStatusRow.js +17 -0
  94. package/dist/ui/Composer.d.ts +1 -6
  95. package/dist/ui/Composer.js +2 -2
  96. package/dist/ui/PromptInput.d.ts +1 -15
  97. package/dist/ui/PromptInput.js +1 -38
  98. package/dist/ui/StatusBar.d.ts +37 -0
  99. package/dist/ui/StatusBar.js +5 -3
  100. package/dist/ui/TeamPanel.d.ts +5 -4
  101. package/dist/ui/TeamPanel.js +1 -1
  102. package/dist/ui/TodoPanel.d.ts +5 -4
  103. package/dist/ui/Transcript.d.ts +26 -3
  104. package/dist/ui/Transcript.js +76 -10
  105. package/dist/ui/UpdateLine.d.ts +44 -0
  106. package/dist/ui/UpdateLine.js +129 -0
  107. package/dist/ui/activity-phrases.d.ts +33 -0
  108. package/dist/ui/activity-phrases.js +50 -0
  109. package/dist/ui/entries/AssistantEntry.d.ts +20 -0
  110. package/dist/ui/entries/AssistantEntry.js +3 -2
  111. package/dist/ui/entries/DiffView.d.ts +67 -0
  112. package/dist/ui/entries/DiffView.js +103 -0
  113. package/dist/ui/entries/FastCard.d.ts +53 -0
  114. package/dist/ui/entries/FastCard.js +87 -0
  115. package/dist/ui/entries/RetryCard.d.ts +56 -0
  116. package/dist/ui/entries/RetryCard.js +60 -0
  117. package/dist/ui/entries/TeamCard.js +6 -1
  118. package/dist/ui/entries/ToolCard.d.ts +38 -1
  119. package/dist/ui/entries/ToolCard.js +68 -5
  120. package/dist/ui/glyphs.d.ts +9 -0
  121. package/dist/ui/glyphs.js +2 -0
  122. package/dist/ui/layout/AppShell.d.ts +13 -22
  123. package/dist/ui/layout/AppShell.js +3 -38
  124. package/dist/ui/layout/virtual-window.d.ts +1 -1
  125. package/dist/ui/layout/virtual-window.js +109 -5
  126. package/dist/ui/overlays/HelpOverlay.js +16 -2
  127. package/dist/ui/overlays/SettingsScreen.d.ts +82 -1
  128. package/dist/ui/overlays/SettingsScreen.js +147 -1
  129. package/dist/ui/transcript-text.js +27 -0
  130. package/dist/ui/use-wheel-routing.d.ts +16 -32
  131. package/dist/ui/use-wheel-routing.js +21 -38
  132. package/dist/update/classify-failure.d.ts +32 -0
  133. package/dist/update/classify-failure.js +60 -0
  134. package/dist/update/install-lock.d.ts +55 -0
  135. package/dist/update/install-lock.js +184 -0
  136. package/dist/update/install-source.d.ts +97 -0
  137. package/dist/update/install-source.js +218 -0
  138. package/dist/update/installer.d.ts +108 -0
  139. package/dist/update/installer.js +242 -0
  140. package/dist/update/limits.d.ts +111 -0
  141. package/dist/update/limits.js +111 -0
  142. package/dist/update/npm-view.d.ts +62 -0
  143. package/dist/update/npm-view.js +133 -0
  144. package/dist/update/registry.d.ts +52 -0
  145. package/dist/update/registry.js +161 -0
  146. package/dist/update/semver.d.ts +89 -0
  147. package/dist/update/semver.js +295 -0
  148. package/dist/update/service.d.ts +193 -0
  149. package/dist/update/service.js +636 -0
  150. package/dist/update/state.d.ts +103 -0
  151. package/dist/update/state.js +142 -0
  152. package/dist/update/types.d.ts +169 -0
  153. package/dist/update/types.js +68 -0
  154. package/package.json +3 -3
  155. package/dist/ui/layout/regions.d.ts +0 -55
  156. package/dist/ui/layout/regions.js +0 -52
@@ -6,7 +6,7 @@
6
6
  * legitimately long single tool run can never be watchdog-killed.
7
7
  */
8
8
  import process from 'node:process';
9
- import { DEFAULT_CONFIG, IDLE_TIMEOUT_MARGIN_MS, clampAskRounds, clampDensity, clampHumanTimeout, clampLogConfig, clampSkillsConfig, clampTeamConfig, clampTodoConfig, clampTheme, clampThinkingLevel, clampMaxTokens, clampMaxRenderInterval, clampTranscriptRetain, clampTranscriptWindow, coercePositiveInt, isAutoToken, isSkillsToolPolicyMode, } from './schema.js';
9
+ import { DEFAULT_CONFIG, IDLE_TIMEOUT_MARGIN_MS, clampAskRounds, clampDensity, clampHumanTimeout, clampLogConfig, clampFastConfig, clampRetryConfig, clampSkillsConfig, clampTeamConfig, clampTodoConfig, clampUpdateConfig, clampTheme, clampThinkingLevel, clampMaxTokens, clampMaxRenderInterval, clampTranscriptRetain, clampTranscriptWindow, coercePositiveInt, isAutoToken, isSkillsToolPolicyMode, } from './schema.js';
10
10
  import { loadDotenv, readEnvConfig, readEnvDisabledSkills } from './env.js';
11
11
  import { readConfigFile } from './store.js';
12
12
  import { getConfigPath } from './app-paths.js';
@@ -121,6 +121,93 @@ function resolveTodoConfig(flags, env, file) {
121
121
  ...(flags.todoFollow !== undefined ? { followThrough: flags.todoFollow } : {}),
122
122
  });
123
123
  }
124
+ /**
125
+ * Merge the `retry` section across all four layers (defaults › file › env ›
126
+ * flags), llm-api-retry-backoff §6.2.
127
+ *
128
+ * `!== undefined` ON BOTH FLAGS, and that is the whole point — the rule
129
+ * `resolveTeamConfig` and `resolveTodoConfig` each state once. Commander
130
+ * materialises a lone `--no-retry` as `opts.retry = true` when the flag is
131
+ * ABSENT, so a truthiness check cannot tell `--no-retry` from "not passed"; and
132
+ * `flags.retryMax` may legitimately be `0`, which a truthiness check would drop
133
+ * on the floor and replace with the default 10 (R-16).
134
+ */
135
+ function resolveRetryConfig(flags, env, file) {
136
+ return clampRetryConfig({
137
+ ...DEFAULT_CONFIG.retry,
138
+ ...(file.retry ?? {}),
139
+ ...(env.retry ?? {}),
140
+ ...(flags.retry !== undefined ? { enabled: flags.retry } : {}),
141
+ ...(flags.retryMax !== undefined && flags.retryMax !== ''
142
+ ? { maxRetries: flags.retryMax }
143
+ : {}),
144
+ });
145
+ }
146
+ /**
147
+ * Merge the `fast` section across all four layers (defaults › file › env ›
148
+ * flags), fast-model-tier §3.7.
149
+ *
150
+ * `!== undefined` ON `flags.fast`, which is the rule `resolveTeamConfig`,
151
+ * `resolveTodoConfig` and `resolveRetryConfig` each state once (C-9): commander
152
+ * materialises a lone `--no-fast` as `opts.fast = true` when the flag is absent,
153
+ * so a truthiness check cannot tell `--no-fast` from "not passed" — and here the
154
+ * damage would run the other way from usual, silently turning a default-OFF
155
+ * feature ON for every run that passed no flag at all.
156
+ *
157
+ * `--fast-review` maps onto TWO keys, so it is parsed rather than spread: `off`
158
+ * is `review: false`, a number is `reviewEveryTurns`, and anything else is
159
+ * ignored (the clamp discipline every other key in this file follows).
160
+ */
161
+ function resolveFastConfig(flags, env, file) {
162
+ const reviewFlag = flags.fastReview?.trim().toLowerCase();
163
+ const reviewPatch = {};
164
+ if (reviewFlag !== undefined && reviewFlag.length > 0) {
165
+ if (reviewFlag === 'off') {
166
+ reviewPatch.review = false;
167
+ }
168
+ else {
169
+ const n = Number.parseInt(reviewFlag, 10);
170
+ if (Number.isFinite(n) && n > 0)
171
+ reviewPatch.reviewEveryTurns = n;
172
+ }
173
+ }
174
+ return clampFastConfig({
175
+ ...DEFAULT_CONFIG.fast,
176
+ ...(file.fast ?? {}),
177
+ ...(env.fast ?? {}),
178
+ ...(flags.fast !== undefined ? { enabled: flags.fast } : {}),
179
+ ...(flags.fastModel !== undefined && flags.fastModel !== ''
180
+ ? { model: flags.fastModel }
181
+ : {}),
182
+ ...(flags.fastProvider !== undefined && flags.fastProvider !== ''
183
+ ? { provider: flags.fastProvider }
184
+ : {}),
185
+ ...reviewPatch,
186
+ });
187
+ }
188
+ /**
189
+ * Merge the `update` section across all four layers (defaults › file › env ›
190
+ * flags), cli-auto-update §4.2.
191
+ *
192
+ * `!== undefined` ON `flags.update`, which is the rule `resolveTeamConfig`,
193
+ * `resolveTodoConfig`, `resolveRetryConfig` and `resolveFastConfig` each state
194
+ * once (C-11): commander materialises a lone `--no-update` as
195
+ * `opts.update = true` when the flag is absent, so a truthiness check cannot
196
+ * tell `--no-update` from "not passed" — and here that would silently re-enable
197
+ * a subsystem the user turned off, which is the one direction this feature must
198
+ * never fail in.
199
+ *
200
+ * The flag maps onto `mode` rather than carrying its own key, so there is
201
+ * exactly one place that says whether the updater runs.
202
+ */
203
+ function resolveUpdateConfig(flags, env, file) {
204
+ return clampUpdateConfig({
205
+ ...DEFAULT_CONFIG.update,
206
+ ...(file.update ?? {}),
207
+ ...(env.update ?? {}),
208
+ ...(flags.update !== undefined ? { mode: flags.update ? 'auto' : 'off' } : {}),
209
+ });
210
+ }
124
211
  /**
125
212
  * Resolve the adaptive render governor: flag › env › file › default `true`
126
213
  * (tui-render-performance L4).
@@ -223,6 +310,16 @@ export function loadConfig(flags = {}) {
223
310
  const model = pick(flags.model, env.partial.model, file.model) ?? DEFAULT_CONFIG.model;
224
311
  const baseUrl = pick(flags.baseUrl, env.partial.baseUrl ?? undefined, file.baseUrl ?? undefined);
225
312
  const thinkingLevel = clampThinkingLevel(pick(flags.thinking, env.partial.thinkingLevel, file.thinkingLevel), DEFAULT_CONFIG.thinkingLevel);
313
+ // BESIDE ITS SIBLING, and through the same three layers (§4.1 / P1-2). This is
314
+ // the ONLY place flags, environment and file are joined, so a key resolved
315
+ // anywhere else reaches the UI from at most one of them.
316
+ const showThinking = pick(flags.showThinking, env.partial.showThinking, file.showThinking) ??
317
+ DEFAULT_CONFIG.showThinking;
318
+ // THE SAME THREE LAYERS, in the same one place (§4.1). Round 1's P1-2 and the
319
+ // fast tier's round-2 IF both record the identical failure: a key resolved
320
+ // anywhere else reaches the UI from at most one of flags, environment and file.
321
+ const liveToolOutput = pick(flags.liveToolOutput, env.partial.liveToolOutput, file.liveToolOutput) ??
322
+ DEFAULT_CONFIG.liveToolOutput;
226
323
  const maxTokens = resolveMaxTokens(flags, env.partial, file);
227
324
  // `clampTheme` is also where the v0.3.0 `dark` name is migrated to `cool`,
228
325
  // so reading a legacy config file needs no extra step here (§4.5 / R-4).
@@ -310,6 +407,8 @@ export function loadConfig(flags = {}) {
310
407
  model,
311
408
  baseUrl,
312
409
  thinkingLevel,
410
+ showThinking,
411
+ liveToolOutput,
313
412
  maxTokens,
314
413
  theme,
315
414
  reducedMotion,
@@ -350,6 +449,9 @@ export function loadConfig(flags = {}) {
350
449
  log: resolveLogConfig(flags, env.partial, file),
351
450
  team: resolveTeamConfig(flags, env.partial, file),
352
451
  todo: resolveTodoConfig(flags, env.partial, file),
452
+ retry: resolveRetryConfig(flags, env.partial, file),
453
+ fast: resolveFastConfig(flags, env.partial, file),
454
+ update: resolveUpdateConfig(flags, env.partial, file),
353
455
  cwd,
354
456
  color,
355
457
  colorLevel,
@@ -386,6 +488,10 @@ function recordResolvedConfig(config) {
386
488
  idleTimeoutMs: config.idleTimeoutMs,
387
489
  historyEnabled: config.historyEnabled,
388
490
  logLevel: config.log.level,
491
+ // Four layers feed this one too, and none of them would otherwise leave a
492
+ // trace — so "why did my failing call sit there for three minutes" (or
493
+ // "why did it not retry at all") has an answer after the fact.
494
+ retry: config.retry.enabled ? config.retry.maxRetries : 'off',
389
495
  hasApiKey: Boolean(config.apiKeys[config.provider]),
390
496
  configPath: getConfigPath(),
391
497
  });
@@ -5,7 +5,7 @@
5
5
  * See spec §3.5 (resolution pipeline), §6.1 (config file), and §3.8 (timeout
6
6
  * invariant).
7
7
  */
8
- import { type ThinkingLevel } from '@aragon-agent/core';
8
+ import { type RetryPolicy, type ThinkingLevel } from '@aragon-agent/core';
9
9
  import { type LogLevelName } from '../logging/levels.js';
10
10
  import type { FollowThroughMode } from '../todo/types.js';
11
11
  /**
@@ -299,12 +299,209 @@ export declare const DEFAULT_TODO_CONFIG: TodoConfig;
299
299
  * setting won't stick".
300
300
  */
301
301
  export declare function clampTodoConfig(raw: unknown): TodoConfig;
302
+ export interface RetryConfig {
303
+ /**
304
+ * The user's switch. KEPT SEPARATE FROM `maxRetries: 0` on purpose: `enabled`
305
+ * survives round-tripping through the settings screen, while `maxRetries: 0` is
306
+ * what `toRetryPolicy` produces from it. Folding them would make
307
+ * `/retry off; /retry on` forget the user's chosen count.
308
+ */
309
+ enabled: boolean;
310
+ /** Retries AFTER the initial attempt. `0` is the kill switch, not a typo. */
311
+ maxRetries: number;
312
+ initialDelayMs: number;
313
+ maxDelayMs: number;
314
+ /** Growth factor. THE ONLY FLOAT KEY in this section. */
315
+ multiplier: number;
316
+ jitter: boolean;
317
+ respectRetryAfter: boolean;
318
+ /** Wall-clock budget from the first failure of one request. */
319
+ maxElapsedMs: number;
320
+ /** Allow a restart after content has already streamed to the transcript. */
321
+ onPartialStream: boolean;
322
+ }
323
+ export declare const DEFAULT_RETRY_CONFIG: RetryConfig;
324
+ /**
325
+ * `hardMaxRetries` re-exported rather than re-spelled, for the reason
326
+ * `HARD_MAX_SUBAGENTS` records: the ceiling is enforced in TWO places — here on
327
+ * the config value, and again by `normalizePolicy` inside the engine — and two
328
+ * copies of the same 20 is exactly how a hand-edited `config.json` ends up able
329
+ * to raise a ceiling the mechanism fixed.
330
+ */
331
+ export declare const HARD_MAX_RETRIES: 20;
332
+ /**
333
+ * THE single gate for every retry-config read AND write, mirroring
334
+ * `clampSkillsConfig` / `clampLogConfig` / `clampTeamConfig` / `clampTodoConfig`
335
+ * for the reason those record: hardening only the read path leaves a bad value on
336
+ * disk that reverts to the default on every launch, which presents to the user as
337
+ * "my setting won't stick".
338
+ *
339
+ * Three invariants live inside the gate:
340
+ *
341
+ * - `maxDelayMs = max(maxDelayMs, initialDelayMs)` — a ceiling under the floor
342
+ * makes the ladder a flat line and the countdown a lie.
343
+ * - `multiplier` goes through `clampNumber`, not `clampInt`: `2.5` is a
344
+ * legitimate factor and `coercePositiveInt` would floor it to 2.
345
+ * - `maxRetries` goes through `clampIntAllowingZero`. THIS IS THE ONE THAT SHIPS
346
+ * BROKEN WITHOUT IT (R-16): `clampInt` returns the fallback for `n <= 0`, so
347
+ * `clampRetryConfig({ maxRetries: 0 })` would yield 10 — the maximum instead
348
+ * of the minimum, silently, for the key that gates the whole feature.
349
+ *
350
+ * `maxElapsedMs` intentionally keeps plain `clampInt`: its floor is 10 000, so it
351
+ * has no `0` to express.
352
+ */
353
+ export declare function clampRetryConfig(raw: unknown): RetryConfig;
354
+ /**
355
+ * `RetryConfig` (user intent) -> `RetryPolicy` (engine policy), or `null` for
356
+ * "the user said no".
357
+ *
358
+ * `null` rather than a policy with `maxRetries: 0` because `ProviderRegistry`
359
+ * short-circuits on a null policy and returns the adapter's iterator DIRECTLY —
360
+ * an opted-out session is then allocation-identical to a pre-feature build.
361
+ *
362
+ * TOTAL, AND IT ACCEPTS A MISSING SECTION. `loadConfig` always supplies one, but
363
+ * a `CliConfig` built by hand — every controller test in this package does exactly
364
+ * that, and so would an embedder — legitimately omits it, and a `TypeError` from a
365
+ * pure translation function is the wrong way to find out. Routing through
366
+ * `clampRetryConfig` also means an out-of-range hand-built value can never reach
367
+ * the engine, which is the same "one gate, both directions" rule every other
368
+ * section in this file follows.
369
+ */
370
+ export declare function toRetryPolicy(cfg: RetryConfig | undefined): RetryPolicy | null;
371
+ export interface FastConfig {
372
+ /**
373
+ * Resolve the tier at all. Defaults to FALSE (R-d).
374
+ *
375
+ * OFF IS BYTE-IDENTICAL (I-2): with this false the system prompt, `task`'s
376
+ * schema, the tool array, the transcript, the status bar and the request
377
+ * payloads are exactly what a pre-feature build produces.
378
+ */
379
+ enabled: boolean;
380
+ /** `''` INHERITS the main provider — what makes `fast.model` alone a complete
381
+ * configuration for the common "same vendor, cheaper model" case. */
382
+ provider: string;
383
+ /** The fast model id. Empty means NOT CONFIGURED, never "same as main": that
384
+ * distinction is what keeps R-e (opt in to fast == main) from being
385
+ * indistinguishable from a typo (D-4). */
386
+ model: string;
387
+ /** `''` inherits only when the provider matches — a base URL belongs to one
388
+ * API, so a fast tier on a different vendor must not borrow it. */
389
+ baseUrl: string;
390
+ /** Applied to fast-tier children and to the review call. Defaults to `'off'`:
391
+ * a "fast" model asked to think for 32 768 tokens is not fast (D-13). */
392
+ thinkingLevel: ThinkingLevel;
393
+ /** Allow `model: "fast"` on `task`. */
394
+ delegate: boolean;
395
+ /** Run the periodic asynchronous review. */
396
+ review: boolean;
397
+ /** Completed turns between reviews. */
398
+ reviewEveryTurns: number;
399
+ /** Turn frames included in one digest. */
400
+ reviewContextTurns: number;
401
+ /** Ceiling on an injected critique, in characters. */
402
+ reviewMaxChars: number;
403
+ /**
404
+ * Reviews STARTED per session, across all runs (fast-model-tier-hardening
405
+ * §4.1 / W1).
406
+ *
407
+ * The one bound on spend the user never asked for. `reviewEveryTurns`
408
+ * controls the PACE; this controls the TOTAL — and the two are different
409
+ * questions, because a session is not one run. `reviewsThisRun` is reset by
410
+ * every user message, so thirty messages buys thirty runs' worth of reviews
411
+ * with nothing counting across them.
412
+ *
413
+ * DENOMINATED IN REVIEWS, NOT CURRENCY (D-H1). The fast tier is by
414
+ * construction the likeliest place in the product to name a model the static
415
+ * cost table has never seen, and `buildRuntimeModel` prices exactly those at
416
+ * zero (C-11) — so a dollar budget would silently never trigger for the
417
+ * configuration that most needs it. A count is exact for every model, and
418
+ * because per-review cost is already bounded on both sides (a 4 000-char
419
+ * digest in, 512 tokens out), `count x bound` is an honest ceiling.
420
+ */
421
+ reviewMaxPerSession: number;
422
+ }
423
+ export declare const DEFAULT_FAST_CONFIG: FastConfig;
424
+ /**
425
+ * THE single gate for every fast-config read AND write, mirroring
426
+ * `clampSkillsConfig` / `clampLogConfig` / `clampTeamConfig` / `clampTodoConfig`
427
+ * for the reason those four record: hardening only the read path leaves a bad
428
+ * value on disk that reverts to the default on every launch, which presents to
429
+ * the user as "my setting won't stick".
430
+ *
431
+ * `provider` is CLAMPED TO `''` rather than rejected when it names something
432
+ * with no adapter. `''` means "inherit the main provider", which is the safe
433
+ * reading of a typo — and `resolveFastTier` reports `no_adapter` for the case a
434
+ * user really did configure a dead vendor as the MAIN one.
435
+ */
436
+ export declare function clampFastConfig(raw: unknown): FastConfig;
437
+ /** `auto` installs; `notify` only reports; `off` disables the subsystem. */
438
+ export declare const UPDATE_MODES: readonly ["auto", "notify", "off"];
439
+ export type UpdateMode = (typeof UPDATE_MODES)[number];
440
+ export declare function isUpdateMode(v: unknown): v is UpdateMode;
441
+ export interface UpdateConfig {
442
+ /**
443
+ * Whether the updater installs, merely reports, or does nothing at all.
444
+ *
445
+ * DEFAULTS TO `'auto'`, and that is a PRODUCT decision rather than a technical
446
+ * one: this CLI's users are overwhelmingly on a stale version they did not
447
+ * choose. The trade it makes — a wider supply-chain window in exchange for
448
+ * users who are actually on the current release — is stated plainly in the
449
+ * README (R-1), and `'off'` plus `ARAGON_UPDATE=0` are the documented kill
450
+ * switches.
451
+ */
452
+ mode: UpdateMode;
453
+ /** Minimum wall-clock between registry checks, MACHINE-WIDE (§3.7). */
454
+ checkIntervalMs: number;
455
+ /** `''` = derive: `ARAGON_UPDATE_REGISTRY` › `npm_config_registry` › npmjs. */
456
+ registry: string;
457
+ /** The dist-tag to track. */
458
+ distTag: string;
459
+ }
460
+ export declare const DEFAULT_UPDATE_CONFIG: UpdateConfig;
461
+ /**
462
+ * THE single gate for every update-config read AND write, mirroring
463
+ * `clampSkillsConfig` / `clampLogConfig` / `clampTeamConfig` / `clampTodoConfig`
464
+ * / `clampRetryConfig` / `clampFastConfig` for the reason all six record:
465
+ * hardening only the read path leaves a bad value on disk that reverts to the
466
+ * default on every launch, which presents to the user as "my setting won't
467
+ * stick".
468
+ *
469
+ * `registry` is CLAMPED TO `''` rather than rejected when it is not an
470
+ * `http(s):` URL. `''` means "derive it" (§3.3), which is the safe reading of a
471
+ * typo — the alternative is a background timer that throws on a value the user
472
+ * cannot see it reading.
473
+ */
474
+ export declare function clampUpdateConfig(raw: unknown): UpdateConfig;
302
475
  export interface PersistedConfig {
303
476
  version: number;
304
477
  provider: string;
305
478
  model: string;
306
479
  baseUrl: string | null;
307
480
  thinkingLevel: ThinkingLevel;
481
+ /**
482
+ * Whether the terminal DRAWS the reasoning that came back
483
+ * (agent-activity-presentation §4.1).
484
+ *
485
+ * ADJACENT TO `thinkingLevel` AND DELIBERATELY NAMED DIFFERENTLY: that key is
486
+ * the effort the provider is asked to SPEND, this one is whether the transcript
487
+ * shows it. They are one word apart in the config file and must never be
488
+ * confused, which is why the flag is `--show-thinking` rather than the shorter
489
+ * `--thinking` the existing key already resembles.
490
+ */
491
+ showThinking: boolean;
492
+ /**
493
+ * Whether a RUNNING tool card draws a bounded tail of its live output
494
+ * (agent-activity-presentation-live §4.1).
495
+ *
496
+ * DEFAULT `true`, unlike `showThinking` next door (D-28). That key hides
497
+ * information by default because reasoning is noise most of the time; this one
498
+ * ADDS the information the requirement asks for, and its cost is bounded by
499
+ * construction -- eight rows per call, sixteen calls, whatever the command
500
+ * emits. It exists as a KILL SWITCH, not as an opt-in: "a build's output
501
+ * redraws the transcript" is exactly the kind of change a user on a slow SSH
502
+ * link may want off.
503
+ */
504
+ liveToolOutput: boolean;
308
505
  /**
309
506
  * Output token cap.
310
507
  *
@@ -353,7 +550,8 @@ export interface PersistedConfig {
353
550
  hints: boolean;
354
551
  /**
355
552
  * Enable SGR mouse reporting in full-screen mode so the wheel scrolls the
356
- * region under the pointer (mouse-wheel-region-routing §5.7).
553
+ * transcript, whatever row the pointer is on (wheel-scrolls-transcript-only
554
+ * §4.1).
357
555
  *
358
556
  * A PLAIN BOOLEAN, not a `fullscreen`-style tri-state: there are no
359
557
  * heuristics for an explicit `true` to override (D-10).
@@ -373,6 +571,12 @@ export interface PersistedConfig {
373
571
  team: TeamConfig;
374
572
  /** Todo planning. The FIFTH nested object; scalars only (see TodoConfig). */
375
573
  todo: TodoConfig;
574
+ /** API retry. The SIXTH nested object; scalars only (see RetryConfig). */
575
+ retry: RetryConfig;
576
+ /** Fast model tier. The SEVENTH nested object; scalars only (see FastConfig). */
577
+ fast: FastConfig;
578
+ /** Auto-update. The EIGHTH nested object; scalars only (see UpdateConfig). */
579
+ update: UpdateConfig;
376
580
  }
377
581
  export declare const DEFAULT_CONFIG: PersistedConfig;
378
582
  /**
@@ -404,6 +608,28 @@ export interface CliConfig {
404
608
  model: string;
405
609
  baseUrl?: string;
406
610
  thinkingLevel: ThinkingLevel;
611
+ /**
612
+ * Seeds `ViewState.thinkingVisible` on the first frame (§4.1 / P1-2).
613
+ *
614
+ * IT MUST EXIST HERE AND NOT ONLY IN `PersistedConfig`. `App` reads `cfg.*`,
615
+ * where `cfg` is a `CliConfig`; a key added to the persisted shape alone would
616
+ * round-trip through `config set`, appear in `config list` — and never reach
617
+ * `initialViewState`. `--show-thinking` and `ARAGON_SHOW_THINKING` would parse
618
+ * and be discarded. Nothing would fail; the setting would simply do nothing.
619
+ */
620
+ showThinking: boolean;
621
+ /**
622
+ * Whether `AgentController` allocates the live-output store and binds
623
+ * `recordOutput` (agent-activity-presentation-live §4.1).
624
+ *
625
+ * IT MUST EXIST HERE AND NOT ONLY IN `PersistedConfig`, for the reason its
626
+ * neighbour records one comment up: the controller reads `config.*`, where
627
+ * `config` is a `CliConfig`, so a key added to the persisted shape alone would
628
+ * round-trip through `config set`, appear in `config list` -- and never reach
629
+ * the constructor. `--live-tool-output` and `ARAGON_LIVE_TOOL_OUTPUT` would
630
+ * parse and be discarded, with nothing failing.
631
+ */
632
+ liveToolOutput: boolean;
407
633
  /** The resolved cap, or `undefined` for AUTO (per-model ceiling, ≤ 64000). */
408
634
  maxTokens?: number;
409
635
  theme: ThemeName;
@@ -499,6 +725,46 @@ export interface CliConfig {
499
725
  * must call `setTodoConfig` as well as persisting (P1-2).
500
726
  */
501
727
  todo: TodoConfig;
728
+ /**
729
+ * Resolved API-retry settings (llm-api-retry-backoff §6.2).
730
+ *
731
+ * Unlike `team.enabled` / `todo.enabled` this decides NOTHING at construction
732
+ * time: the policy lives on the `ProviderRegistry` and `setRetryConfig()`
733
+ * replaces it live, so `/retry off` takes effect in the running session. That is
734
+ * why the controller has no `retryRegistered` twin of the two flags above.
735
+ */
736
+ retry: RetryConfig;
737
+ /**
738
+ * Resolved fast-tier settings (fast-model-tier §4.2).
739
+ *
740
+ * `enabled` here decides `fastRegistered` — whether `task`'s schema carries a
741
+ * `model` property at all — which happens once at construction and can never
742
+ * be undone (C-2). The live on/off switch `/fast` flips is a separate flag on
743
+ * `FastWiring`.
744
+ *
745
+ * THE OTHER NINE KEYS ARE READ LIVE, and that is not the same statement.
746
+ * `provider` / `model` / `baseUrl` feed `resolveFastTier`, which is re-run on
747
+ * every config mutation (§3.2 rule 8 / RV-3) because `''` INHERITS from
748
+ * `config.provider` / `config.baseUrl` and those are rewritten by `/model`,
749
+ * `/provider`, `/reload` and the settings screen.
750
+ */
751
+ fast: FastConfig;
752
+ /**
753
+ * Resolved auto-update settings (cli-auto-update §4.1).
754
+ *
755
+ * `mode` here decides whether `runInteractive` CONSTRUCTS the service at all
756
+ * (§3.8), which is what makes `'off'` byte-identical to a pre-feature build:
757
+ * no timer, no file read, no socket. The other three keys are read by the
758
+ * service on every check, so a `/update off` mid-session stops the next one.
759
+ *
760
+ * IT MUST EXIST HERE AND NOT ONLY IN `PersistedConfig`, for the reason
761
+ * `showThinking` and `liveToolOutput` each record above: the gate reads
762
+ * `cfg.update`, where `cfg` is a `CliConfig`, so a key added to the persisted
763
+ * shape alone would round-trip through `config set`, appear in `config list` —
764
+ * and never reach the gate. `--no-update` and `ARAGON_UPDATE=0` would parse
765
+ * and be discarded, with no compile error and no runtime error.
766
+ */
767
+ update: UpdateConfig;
502
768
  /**
503
769
  * Lifetime submit count driving the composer hint fade (`HINT_FADE_AFTER`).
504
770
  *