@aragon-agent/cli 0.6.38 → 0.6.40
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +263 -0
- package/README.md +544 -11
- package/dist/agent/controller.d.ts +245 -10
- package/dist/agent/controller.js +367 -22
- package/dist/agent/model-profile-settings.js +12 -1
- package/dist/agent/plan-prompt.d.ts +1 -3
- package/dist/agent/plan-prompt.js +13 -7
- package/dist/agent/reducer.d.ts +70 -2
- package/dist/agent/reducer.js +59 -6
- package/dist/agent/skill-triage-prompt.d.ts +42 -0
- package/dist/agent/skill-triage-prompt.js +74 -0
- package/dist/agent/system-prompt.d.ts +28 -2
- package/dist/agent/system-prompt.js +12 -4
- package/dist/cli.js +106 -32
- package/dist/commands/builtins.js +24 -3
- package/dist/commands/keys-command.d.ts +23 -0
- package/dist/commands/keys-command.js +38 -0
- package/dist/commands/registry.d.ts +39 -0
- package/dist/commands/skills.js +86 -1
- package/dist/commands/subagent-command.d.ts +25 -0
- package/dist/commands/subagent-command.js +242 -0
- package/dist/commands/task-command.d.ts +39 -0
- package/dist/commands/task-command.js +102 -0
- package/dist/compaction/command.js +16 -3
- package/dist/compaction/compactor.d.ts +25 -0
- package/dist/compaction/compactor.js +111 -10
- package/dist/compaction/digest.d.ts +24 -1
- package/dist/compaction/digest.js +139 -17
- package/dist/compaction/limits.d.ts +21 -0
- package/dist/compaction/limits.js +21 -0
- package/dist/compaction/reason-text.d.ts +36 -0
- package/dist/compaction/reason-text.js +78 -0
- package/dist/compaction/types.d.ts +82 -14
- package/dist/compaction/wiring.d.ts +13 -8
- package/dist/compaction/wiring.js +1 -0
- package/dist/config/cli-commands.d.ts +23 -0
- package/dist/config/cli-commands.js +36 -0
- package/dist/config/env.js +17 -4
- package/dist/config/load.js +55 -3
- package/dist/config/schema.d.ts +125 -10
- package/dist/config/schema.js +138 -14
- package/dist/config/store.js +23 -3
- package/dist/diagnostics/doctor.d.ts +9 -0
- package/dist/diagnostics/doctor.js +34 -0
- package/dist/diagnostics/info.d.ts +71 -0
- package/dist/diagnostics/info.js +91 -5
- package/dist/exec/bridge/caller-tools.d.ts +96 -0
- package/dist/exec/bridge/caller-tools.js +213 -0
- package/dist/exec/bridge/decisions.d.ts +78 -0
- package/dist/exec/bridge/decisions.js +116 -0
- package/dist/exec/bridge/human-answers.d.ts +38 -0
- package/dist/exec/bridge/human-answers.js +164 -0
- package/dist/exec/bridge/limits.d.ts +68 -0
- package/dist/exec/bridge/limits.js +68 -0
- package/dist/exec/bridge/ndjson.d.ts +17 -0
- package/dist/exec/bridge/ndjson.js +83 -0
- package/dist/exec/bridge/pending.d.ts +70 -0
- package/dist/exec/bridge/pending.js +132 -0
- package/dist/exec/bridge/protocol.d.ts +346 -0
- package/dist/exec/bridge/protocol.js +256 -0
- package/dist/exec/bridge/server.d.ts +142 -0
- package/dist/exec/bridge/server.js +502 -0
- package/dist/exec/bridge/source.d.ts +58 -0
- package/dist/exec/bridge/source.js +145 -0
- package/dist/exec/bridge/writer.d.ts +26 -0
- package/dist/exec/bridge/writer.js +156 -0
- package/dist/exec/cli-commands.js +30 -2
- package/dist/exec/emitter.d.ts +16 -2
- package/dist/exec/emitter.js +26 -6
- package/dist/exec/events.d.ts +465 -10
- package/dist/exec/events.js +47 -1
- package/dist/exec/hooks/dispatch.d.ts +76 -0
- package/dist/exec/hooks/dispatch.js +169 -0
- package/dist/exec/hooks/index.d.ts +83 -0
- package/dist/exec/hooks/index.js +205 -0
- package/dist/exec/hooks/limits.d.ts +56 -0
- package/dist/exec/hooks/limits.js +49 -0
- package/dist/exec/hooks/registry.d.ts +49 -0
- package/dist/exec/hooks/registry.js +91 -0
- package/dist/exec/hooks/tool-wrapper.d.ts +94 -0
- package/dist/exec/hooks/tool-wrapper.js +154 -0
- package/dist/exec/hooks/turn.d.ts +61 -0
- package/dist/exec/hooks/turn.js +59 -0
- package/dist/exec/hooks/validate.d.ts +85 -0
- package/dist/exec/hooks/validate.js +310 -0
- package/dist/exec/index.d.ts +130 -4
- package/dist/exec/index.js +501 -10
- package/dist/exec/options.d.ts +124 -2
- package/dist/exec/options.js +413 -6
- package/dist/exec/permission.d.ts +9 -1
- package/dist/exec/permission.js +7 -1
- package/dist/exec/request/limits.d.ts +51 -0
- package/dist/exec/request/limits.js +49 -0
- package/dist/exec/request/scope.d.ts +106 -0
- package/dist/exec/request/scope.js +149 -0
- package/dist/exec/result/limits.d.ts +74 -0
- package/dist/exec/result/limits.js +72 -0
- package/dist/exec/result/prompt.d.ts +28 -0
- package/dist/exec/result/prompt.js +74 -0
- package/dist/exec/result/schema.d.ts +99 -0
- package/dist/exec/result/schema.js +464 -0
- package/dist/exec/result/sink.d.ts +56 -0
- package/dist/exec/result/sink.js +50 -0
- package/dist/exec/result/tool.d.ts +37 -0
- package/dist/exec/result/tool.js +118 -0
- package/dist/exec/runner.d.ts +395 -1
- package/dist/exec/runner.js +860 -8
- package/dist/exec/threads/aggregate.d.ts +34 -0
- package/dist/exec/threads/aggregate.js +30 -0
- package/dist/exec/threads/capacity.d.ts +23 -0
- package/dist/exec/threads/capacity.js +38 -0
- package/dist/exec/threads/dispatch-source.d.ts +60 -0
- package/dist/exec/threads/dispatch-source.js +106 -0
- package/dist/exec/threads/execute-threads.d.ts +53 -0
- package/dist/exec/threads/execute-threads.js +234 -0
- package/dist/exec/threads/gate.d.ts +42 -0
- package/dist/exec/threads/gate.js +81 -0
- package/dist/exec/threads/identity.d.ts +36 -0
- package/dist/exec/threads/identity.js +67 -0
- package/dist/exec/threads/interrupt.d.ts +29 -0
- package/dist/exec/threads/interrupt.js +79 -0
- package/dist/exec/threads/limits.d.ts +58 -0
- package/dist/exec/threads/limits.js +35 -0
- package/dist/exec/threads/outcome.d.ts +47 -0
- package/dist/exec/threads/outcome.js +26 -0
- package/dist/exec/threads/registry.d.ts +81 -0
- package/dist/exec/threads/registry.js +427 -0
- package/dist/exec/threads/runtime.d.ts +107 -0
- package/dist/exec/threads/runtime.js +523 -0
- package/dist/exec/threads/thread-source.d.ts +20 -0
- package/dist/exec/threads/thread-source.js +134 -0
- package/dist/fast/limits.d.ts +54 -0
- package/dist/fast/limits.js +54 -0
- package/dist/fast/summary-call.d.ts +72 -0
- package/dist/fast/summary-call.js +133 -0
- package/dist/fast/summary-prompt.d.ts +106 -0
- package/dist/fast/summary-prompt.js +320 -0
- package/dist/fast/task-summary-types.d.ts +66 -0
- package/dist/fast/task-summary-types.js +17 -0
- package/dist/logging/logger.d.ts +1 -1
- package/dist/proc/limits.d.ts +7 -0
- package/dist/proc/limits.js +7 -0
- package/dist/proc/log-mirror.d.ts +21 -4
- package/dist/proc/log-mirror.js +29 -7
- package/dist/proc/output-streams.d.ts +50 -0
- package/dist/proc/output-streams.js +54 -0
- package/dist/skills/service.d.ts +41 -0
- package/dist/skills/service.js +62 -0
- package/dist/skills/triage.d.ts +194 -0
- package/dist/skills/triage.js +393 -0
- package/dist/team/forced-dispatch.d.ts +95 -0
- package/dist/team/forced-dispatch.js +208 -0
- package/dist/team/limits.d.ts +21 -1
- package/dist/team/limits.js +21 -1
- package/dist/team/normalize.d.ts +15 -0
- package/dist/team/normalize.js +21 -4
- package/dist/team/prompt.d.ts +6 -3
- package/dist/team/prompt.js +9 -5
- package/dist/team/runtime.d.ts +9 -0
- package/dist/team/runtime.js +8 -0
- package/dist/team/subagent.d.ts +15 -0
- package/dist/team/subagent.js +45 -1
- package/dist/team/task-tool.js +11 -7
- package/dist/tools/bash-tool.d.ts +10 -0
- package/dist/tools/bash-tool.js +71 -6
- package/dist/tools/human-input.d.ts +35 -2
- package/dist/tools/human-input.js +38 -0
- package/dist/tools/index.d.ts +93 -1
- package/dist/tools/index.js +112 -3
- package/dist/tools/plan-tools.d.ts +20 -12
- package/dist/tools/plan-tools.js +24 -17
- package/dist/tools/tool-gate.d.ts +100 -0
- package/dist/tools/tool-gate.js +87 -0
- package/dist/ui/App.js +238 -12
- package/dist/ui/Header.d.ts +28 -16
- package/dist/ui/Header.js +21 -19
- package/dist/ui/StatusBar.d.ts +1 -0
- package/dist/ui/StatusBar.js +1 -0
- package/dist/ui/Transcript.js +1 -1
- package/dist/ui/entries/CompactionCard.d.ts +11 -1
- package/dist/ui/entries/CompactionCard.js +65 -4
- package/dist/ui/interaction-hints.js +6 -0
- package/dist/ui/layout/OverlayFrame.d.ts +18 -0
- package/dist/ui/layout/OverlayFrame.js +19 -4
- package/dist/ui/layout/header-hints.d.ts +55 -62
- package/dist/ui/layout/header-hints.js +59 -166
- package/dist/ui/layout/header-left.d.ts +115 -0
- package/dist/ui/layout/header-left.js +206 -0
- package/dist/ui/layout/shortcut-panel-layout.d.ts +191 -0
- package/dist/ui/layout/shortcut-panel-layout.js +321 -0
- package/dist/ui/layout/status-detail-layout.js +5 -1
- package/dist/ui/layout/status-layout.d.ts +10 -0
- package/dist/ui/layout/status-layout.js +18 -1
- package/dist/ui/layout/task-summary-cell.d.ts +61 -0
- package/dist/ui/layout/task-summary-cell.js +65 -0
- package/dist/ui/overlays/HelpOverlay.d.ts +12 -0
- package/dist/ui/overlays/HelpOverlay.js +29 -2
- package/dist/ui/overlays/SettingsScreen.js +29 -5
- package/dist/ui/overlays/ShortcutPanel.d.ts +39 -0
- package/dist/ui/overlays/ShortcutPanel.js +106 -0
- package/dist/ui/overlays/TeamFanoutPage.d.ts +35 -0
- package/dist/ui/overlays/TeamFanoutPage.js +78 -0
- package/dist/ui/overlays/model-profile-state.d.ts +19 -1
- package/dist/ui/overlays/model-profile-state.js +12 -0
- package/dist/ui/overlays/team-fanout-state.d.ts +73 -0
- package/dist/ui/overlays/team-fanout-state.js +97 -0
- package/dist/ui/shortcuts.d.ts +81 -0
- package/dist/ui/shortcuts.js +221 -0
- package/package.json +2 -2
|
@@ -55,6 +55,23 @@ export type CompactionMode = 'summarized' | 'truncated' | 'relieved' | 'none';
|
|
|
55
55
|
* thing a CLI-local type is for.
|
|
56
56
|
*/
|
|
57
57
|
export type CompactionUiTrigger = 'pressure' | 'overflow' | 'manual';
|
|
58
|
+
/**
|
|
59
|
+
* Where one attempt currently is, so "compacting context" can also say WHAT it is
|
|
60
|
+
* doing for the forty-five seconds it is on screen.
|
|
61
|
+
*
|
|
62
|
+
* IT EXISTS BECAUSE THE GATES WERE INVISIBLE (context-compaction-never-fires
|
|
63
|
+
* RC-3). Planning and digesting both run BEFORE any model call, and both used to
|
|
64
|
+
* be able to reject while the only surface said `Context 95%` and nothing else.
|
|
65
|
+
* A phase is the CLI's answer to "is this stuck, or merely slow", and it is
|
|
66
|
+
* CLI-LOCAL for the reason the whole stream is: the engine has no phases, only a
|
|
67
|
+
* splice.
|
|
68
|
+
*
|
|
69
|
+
* THERE IS NO `settled` MEMBER, deliberately: the settle is already the
|
|
70
|
+
* `compaction_end` record. A phase restating it would give the card two ways to
|
|
71
|
+
* learn one fact, and the extra phase would race the record whenever the engine's
|
|
72
|
+
* verdict comes back first.
|
|
73
|
+
*/
|
|
74
|
+
export type CompactionPhase = 'planning' | 'digesting' | 'summarizing' | 'validating' | 'applying';
|
|
58
75
|
/** Whether a figure was measured by the provider or estimated by us. */
|
|
59
76
|
export type PressureSource = 'usage' | 'estimate';
|
|
60
77
|
/** The exact occupancy evidence at the compaction checkpoint. */
|
|
@@ -183,6 +200,36 @@ export interface CompactionRecord {
|
|
|
183
200
|
usage?: TokenUsage;
|
|
184
201
|
/** Set when an overflow attempt halved `keepRecentTurns` for itself (D-24). */
|
|
185
202
|
keepRecentTurnsUsed?: number;
|
|
203
|
+
/**
|
|
204
|
+
* Set when `planCompaction` had to relax `keepRecentTurns` to find a cut
|
|
205
|
+
* (context-compaction-never-fires B).
|
|
206
|
+
*
|
|
207
|
+
* DISCLOSED ON THE CARD, never silent: the relaxation trades "the last N turns
|
|
208
|
+
* are verbatim" for "compaction happens at all", and a user who is not told
|
|
209
|
+
* which side they got cannot tell a lossless compaction from a lossy one.
|
|
210
|
+
* `retainedTurns` and `retainedMessages` are what actually survived, so the card
|
|
211
|
+
* can state all three numbers instead of implying one.
|
|
212
|
+
*/
|
|
213
|
+
keepRelaxed?: boolean;
|
|
214
|
+
retainedTurns?: number;
|
|
215
|
+
/**
|
|
216
|
+
* How many MESSAGES the relaxed cut left verbatim.
|
|
217
|
+
*
|
|
218
|
+
* `retainedTurns` COUNTS USER TURNS, and in the sessions this fix exists for - one
|
|
219
|
+
* prompt followed by a hundred tool calls - that number is zero even though forty
|
|
220
|
+
* messages survived word for word. A card reading "kept 0 recent turns" at that
|
|
221
|
+
* moment says the opposite of what happened, so both numbers are recorded.
|
|
222
|
+
*/
|
|
223
|
+
retainedMessages?: number;
|
|
224
|
+
/**
|
|
225
|
+
* Messages left OUT of the digest text and therefore not quotable by the
|
|
226
|
+
* summarizer (context-compaction-never-fires A1).
|
|
227
|
+
*
|
|
228
|
+
* The elision is LOUD in three places: the digest text itself carries an
|
|
229
|
+
* `[elided ...]` marker, this field puts the count on the card, and the elided
|
|
230
|
+
* ids never enter the source map, so a delta citing one is rejected.
|
|
231
|
+
*/
|
|
232
|
+
elidedMessages?: number;
|
|
186
233
|
/**
|
|
187
234
|
* Present ONLY when tail relief fired (hardening §3.3.4 / W2).
|
|
188
235
|
*
|
|
@@ -221,14 +268,24 @@ export interface CompactionSnapshot {
|
|
|
221
268
|
/** The summarizer's model id, or `''`. */
|
|
222
269
|
model: string;
|
|
223
270
|
/**
|
|
224
|
-
* How many compactions ANNOUNCED themselves
|
|
271
|
+
* How many compactions ANNOUNCED themselves, i.e. how many cards the user saw.
|
|
225
272
|
*
|
|
226
|
-
*
|
|
227
|
-
*
|
|
228
|
-
*
|
|
229
|
-
* the
|
|
273
|
+
* IT COUNTS ATTEMPTS, NOT SPLICES (context-compaction-never-fires C). Before
|
|
274
|
+
* this change only attempts that committed to work announced, so this was
|
|
275
|
+
* "compactions that ran"; now every attempt opens a card - including the ones
|
|
276
|
+
* that decline at the planner or the digest - because a silent decline is
|
|
277
|
+
* indistinguishable from a dead feature, which is the bug this feature shipped
|
|
278
|
+
* with. `applied` below is the other half, and `/compact status` prints both.
|
|
230
279
|
*/
|
|
231
280
|
compactions: number;
|
|
281
|
+
/**
|
|
282
|
+
* How many of those attempts actually replaced the history.
|
|
283
|
+
*
|
|
284
|
+
* OPTIONAL SO EVERY EXISTING CONSTRUCTION SITE STAYS UNTOUCHED. Absent means
|
|
285
|
+
* "not reported", which `/compact status` renders exactly as the pre-change
|
|
286
|
+
* wording did.
|
|
287
|
+
*/
|
|
288
|
+
applied?: number;
|
|
232
289
|
/**
|
|
233
290
|
* How many `pressure` checkpoints declined BEFORE committing to any work
|
|
234
291
|
* (quiet-noop D-9 / P1-2).
|
|
@@ -260,19 +317,26 @@ export interface CompactionSnapshot {
|
|
|
260
317
|
/**
|
|
261
318
|
* THE COMPACTION EVENT STREAM.
|
|
262
319
|
*
|
|
263
|
-
*
|
|
264
|
-
*
|
|
265
|
-
*
|
|
266
|
-
*
|
|
267
|
-
*
|
|
320
|
+
* EVERY ATTEMPT ANNOUNCES ITSELF (context-compaction-never-fires C, which
|
|
321
|
+
* REVERSES quiet-noop §3.1). A `pressure` compaction used to reach
|
|
322
|
+
* `compaction_start` only after it committed to paid work, so an attempt that
|
|
323
|
+
* declined at the planner (`nothing_to_drop`) or at the digest budget produced
|
|
324
|
+
* no card at all - and a user sitting at 95 % with a dead auto-compaction had no
|
|
325
|
+
* way to learn that the feature was trying and failing 96 times. The card is now
|
|
326
|
+
* opened at the entry of `compact()` and ALWAYS settled, so `#N` counts attempts
|
|
327
|
+
* and the transcript carries one line per attempt, applied or not.
|
|
328
|
+
*
|
|
329
|
+
* WHY THE OLD DESIGN WAS DEFENSIBLE AND IS STILL WRONG. Its stated worry was a
|
|
330
|
+
* red `context not compacted` card every two turns flooding the transcript. The
|
|
331
|
+
* guards bound that to `stuckLimit` declines per run (`limits.ts`), and after
|
|
332
|
+
* them the auto path self-disables and says so once - so the flood never
|
|
333
|
+
* happens, while the silence happened every time.
|
|
268
334
|
*
|
|
269
335
|
* The pair is still BALANCED: every `compaction_start` is followed by exactly
|
|
270
336
|
* one `compaction_end` (a `finally` in the engine guarantees the verdict, and
|
|
271
337
|
* `settlePending` synthesizes a skeleton record when the compactor's own has not
|
|
272
|
-
* arrived).
|
|
273
|
-
*
|
|
274
|
-
* CORE's own `compaction_start` / `compaction_end` pair still fires for every
|
|
275
|
-
* attempt, declined or not, and that is the stream the log subscribes to.
|
|
338
|
+
* arrived). `phase` events land BETWEEN them, in order, and only for the live
|
|
339
|
+
* card.
|
|
276
340
|
*/
|
|
277
341
|
export type CompactionEvent = {
|
|
278
342
|
type: 'compaction_start';
|
|
@@ -282,6 +346,10 @@ export type CompactionEvent = {
|
|
|
282
346
|
} | {
|
|
283
347
|
type: 'compaction_end';
|
|
284
348
|
record: CompactionRecord;
|
|
349
|
+
} | {
|
|
350
|
+
type: 'phase';
|
|
351
|
+
index: number;
|
|
352
|
+
phase: CompactionPhase;
|
|
285
353
|
} | ({
|
|
286
354
|
type: 'usage';
|
|
287
355
|
usage: TokenUsage;
|
|
@@ -27,14 +27,19 @@ import type { CompactionIdentity } from './memory-identity.js';
|
|
|
27
27
|
* `/compact off`, `/compact threshold 0.8` and a settings-screen save take effect
|
|
28
28
|
* mid-session without touching the `Agent`.
|
|
29
29
|
*
|
|
30
|
-
* DECLINED COMPACTIONS
|
|
31
|
-
*
|
|
32
|
-
* `compaction_start`, so `onCompactorEvent` never
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
30
|
+
* DECLINED COMPACTIONS ARE VISIBLE (context-compaction-never-fires C, which
|
|
31
|
+
* REVERSES quiet-noop §3.6). A `pressure` compaction that changes nothing used to
|
|
32
|
+
* emit no `compaction_start`, so `onCompactorEvent` never opened a card and the
|
|
33
|
+
* only trace of an attempt was a counter in `/compact status`. The compactor now
|
|
34
|
+
* announces at the entry of `compact()` and always settles, so this class holds a
|
|
35
|
+
* record for every attempt and `settlePending` emits it - declined attempts
|
|
36
|
+
* included, with the reason on the card.
|
|
37
|
+
*
|
|
38
|
+
* WHAT THE OLD RULE PROTECTED IS STILL PROTECTED, by a different mechanism: the
|
|
39
|
+
* transcript cannot flood, because `maxPerRun` (5) and `stuckLimit` (2) bound the
|
|
40
|
+
* attempts and the auto path self-disables and says so once. `onCompactorEvent`'s
|
|
41
|
+
* `if (!this.open)` guard is still load-bearing: it is what stops a late record
|
|
42
|
+
* from re-opening a card the engine's verdict already closed.
|
|
38
43
|
*/
|
|
39
44
|
import type { ModelRole } from '../config/model-profiles.js';
|
|
40
45
|
import { type AgentEvent, type ContextManager, type Message, type ModelInfo, type ModelRef, type ProviderRegistry, type ProviderRegistryOptions, type TokenUsage } from '@aragon-agent/core';
|
|
@@ -368,6 +368,7 @@ export class CompactionWiring {
|
|
|
368
368
|
live: this.enabled && summarizer !== null,
|
|
369
369
|
model: summarizer?.ref.modelId ?? '',
|
|
370
370
|
compactions: totals.compactions,
|
|
371
|
+
applied: totals.applied,
|
|
371
372
|
// OMITTED WHEN ZERO (quiet-noop D-9), so a healthy session's snapshot is
|
|
372
373
|
// shaped exactly as it was before this feature and `/compact status` has
|
|
373
374
|
// nothing extra to render.
|
|
@@ -34,6 +34,17 @@ export declare const TEAM_CONFIG_SET_KEYS: readonly ["team.enabled", "team.maxSu
|
|
|
34
34
|
* so `jobs.waitSeconds` resolves and `jobs.mirror.enabled` would not.
|
|
35
35
|
*/
|
|
36
36
|
export declare const JOBS_CONFIG_SET_KEYS: readonly ["jobs.enabled", "jobs.waitSeconds", "jobs.stallSeconds", "jobs.persistLog", "jobs.noticeSteer"];
|
|
37
|
+
/**
|
|
38
|
+
* Config keys under `taskSummary.` that `aragon config set` accepts
|
|
39
|
+
* (tui-shortcut-drawer-and-task-summary §4.8).
|
|
40
|
+
*
|
|
41
|
+
* BOTH SWITCHES ARE WRITABLE, which is why this section needs the same pair every
|
|
42
|
+
* other writable section has: a membership set here AND a case in `cli.tsx`'s
|
|
43
|
+
* `runConfigSet`. Only the second makes the key actually write; only the first
|
|
44
|
+
* makes it pass the `Unknown config key` gate. `config.test.ts`'s static guard is
|
|
45
|
+
* what catches a half-done pair, and `jobs` is the precedent it was written for.
|
|
46
|
+
*/
|
|
47
|
+
export declare const TASK_SUMMARY_CONFIG_SET_KEYS: readonly ["taskSummary.enabled", "taskSummary.fallback"];
|
|
37
48
|
/**
|
|
38
49
|
* Config keys under `retry.` that `aragon config set` accepts
|
|
39
50
|
* (llm-api-retry-backoff §8.2).
|
|
@@ -108,6 +119,18 @@ export declare function applyLogConfigSet(key: string, value: string): Partial<P
|
|
|
108
119
|
* recorded in `store.ts`.
|
|
109
120
|
*/
|
|
110
121
|
export declare function applyJobsConfigSet(key: string, value: string): Partial<PersistedConfig> | null;
|
|
122
|
+
/**
|
|
123
|
+
* Translate a `taskSummary.*` dotted key into a patch, or `null` for anything else.
|
|
124
|
+
*
|
|
125
|
+
* THE PATCH IS A PARTIAL SECTION, safe only because `updatePersistedConfig`
|
|
126
|
+
* deep-merges `taskSummary` - the eighth time that trap is recorded in `store.ts`.
|
|
127
|
+
* Both values are booleans, so `isTrue` is the whole parser. It accepts `1` and
|
|
128
|
+
* `true` only, which is NARROWER than the env layer's `on`/`yes` on purpose: an
|
|
129
|
+
* environment switch is typed by a human at a shell prompt, while `config set` is
|
|
130
|
+
* also driven by scripts, and `config set taskSummary.enabled on` should fail loudly
|
|
131
|
+
* rather than silently mean `false`.
|
|
132
|
+
*/
|
|
133
|
+
export declare function applyTaskSummaryConfigSet(key: string, value: string): Partial<PersistedConfig> | null;
|
|
111
134
|
/**
|
|
112
135
|
* Translate a `team.*` dotted key into a patch, or `null` for anything else.
|
|
113
136
|
*
|
|
@@ -67,6 +67,20 @@ export const JOBS_CONFIG_SET_KEYS = [
|
|
|
67
67
|
'jobs.persistLog',
|
|
68
68
|
'jobs.noticeSteer',
|
|
69
69
|
];
|
|
70
|
+
/**
|
|
71
|
+
* Config keys under `taskSummary.` that `aragon config set` accepts
|
|
72
|
+
* (tui-shortcut-drawer-and-task-summary §4.8).
|
|
73
|
+
*
|
|
74
|
+
* BOTH SWITCHES ARE WRITABLE, which is why this section needs the same pair every
|
|
75
|
+
* other writable section has: a membership set here AND a case in `cli.tsx`'s
|
|
76
|
+
* `runConfigSet`. Only the second makes the key actually write; only the first
|
|
77
|
+
* makes it pass the `Unknown config key` gate. `config.test.ts`'s static guard is
|
|
78
|
+
* what catches a half-done pair, and `jobs` is the precedent it was written for.
|
|
79
|
+
*/
|
|
80
|
+
export const TASK_SUMMARY_CONFIG_SET_KEYS = [
|
|
81
|
+
'taskSummary.enabled',
|
|
82
|
+
'taskSummary.fallback',
|
|
83
|
+
];
|
|
70
84
|
/**
|
|
71
85
|
* Config keys under `retry.` that `aragon config set` accepts
|
|
72
86
|
* (llm-api-retry-backoff §8.2).
|
|
@@ -219,6 +233,28 @@ export function applyJobsConfigSet(key, value) {
|
|
|
219
233
|
return null;
|
|
220
234
|
}
|
|
221
235
|
}
|
|
236
|
+
/**
|
|
237
|
+
* Translate a `taskSummary.*` dotted key into a patch, or `null` for anything else.
|
|
238
|
+
*
|
|
239
|
+
* THE PATCH IS A PARTIAL SECTION, safe only because `updatePersistedConfig`
|
|
240
|
+
* deep-merges `taskSummary` - the eighth time that trap is recorded in `store.ts`.
|
|
241
|
+
* Both values are booleans, so `isTrue` is the whole parser. It accepts `1` and
|
|
242
|
+
* `true` only, which is NARROWER than the env layer's `on`/`yes` on purpose: an
|
|
243
|
+
* environment switch is typed by a human at a shell prompt, while `config set` is
|
|
244
|
+
* also driven by scripts, and `config set taskSummary.enabled on` should fail loudly
|
|
245
|
+
* rather than silently mean `false`.
|
|
246
|
+
*/
|
|
247
|
+
export function applyTaskSummaryConfigSet(key, value) {
|
|
248
|
+
const patch = (taskSummary) => ({ taskSummary });
|
|
249
|
+
switch (key) {
|
|
250
|
+
case 'taskSummary.enabled':
|
|
251
|
+
return patch({ enabled: isTrue(value) });
|
|
252
|
+
case 'taskSummary.fallback':
|
|
253
|
+
return patch({ fallback: isTrue(value) });
|
|
254
|
+
default:
|
|
255
|
+
return null;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
222
258
|
/**
|
|
223
259
|
* Translate a `team.*` dotted key into a patch, or `null` for anything else.
|
|
224
260
|
*
|
package/dist/config/env.js
CHANGED
|
@@ -308,16 +308,29 @@ export function readEnvConfig() {
|
|
|
308
308
|
partial.jobs = section;
|
|
309
309
|
}
|
|
310
310
|
// ARAGON_PROMPTS=0 is the kill switch for the whole quick-prompt surface: no
|
|
311
|
-
// `Ctrl+P
|
|
312
|
-
//
|
|
313
|
-
//
|
|
314
|
-
//
|
|
311
|
+
// `Ctrl+P` and `/prompts` reports that the feature is off (D-19 / AC-31). ONLY
|
|
312
|
+
// `enabled` IS REACHABLE HERE. `insertMode` is a preference a human sets once, and
|
|
313
|
+
// an environment variable that could silently flip a fill into "overwrite what you
|
|
314
|
+
// had typed" is not a kill switch.
|
|
315
315
|
const prompts = process.env.ARAGON_PROMPTS?.trim().toLowerCase();
|
|
316
316
|
if (prompts !== undefined && prompts.length > 0) {
|
|
317
317
|
partial.prompts = {
|
|
318
318
|
enabled: prompts === '1' || prompts === 'true' || prompts === 'on' || prompts === 'yes',
|
|
319
319
|
};
|
|
320
320
|
}
|
|
321
|
+
// ARAGON_TASK_SUMMARY is the header label's kill switch
|
|
322
|
+
// (tui-shortcut-drawer-and-task-summary §4.8 / P2-7), and it maps `enabled` and
|
|
323
|
+
// NOTHING ELSE - the same wording and the same reason as the block above. A
|
|
324
|
+
// variable that could also flip `fallback` would let an environment decide
|
|
325
|
+
// whether a FAILED call shows the user's own words or an empty cell, which is a
|
|
326
|
+
// silent change to what the header claims to know.
|
|
327
|
+
const taskSummary = process.env.ARAGON_TASK_SUMMARY?.trim().toLowerCase();
|
|
328
|
+
if (taskSummary !== undefined && taskSummary.length > 0) {
|
|
329
|
+
partial.taskSummary = {
|
|
330
|
+
enabled: taskSummary === '1' || taskSummary === 'true'
|
|
331
|
+
|| taskSummary === 'on' || taskSummary === 'yes',
|
|
332
|
+
};
|
|
333
|
+
}
|
|
321
334
|
const retry = process.env.ARAGON_RETRY?.trim().toLowerCase();
|
|
322
335
|
const retryMax = process.env.ARAGON_RETRY_MAX?.trim();
|
|
323
336
|
if ((retry !== undefined && retry.length > 0) || (retryMax !== undefined && retryMax.length > 0)) {
|
package/dist/config/load.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import process from 'node:process';
|
|
9
9
|
import { JOB_WAIT_MARGIN_MS } from '../proc/limits.js';
|
|
10
|
-
import { DEFAULT_CONFIG, DEFAULT_SCROLL_MODE, IDLE_TIMEOUT_MARGIN_MS,
|
|
10
|
+
import { DEFAULT_CONFIG, DEFAULT_SCROLL_MODE, IDLE_TIMEOUT_MARGIN_MS, clampDensity, clampHumanTimeout, clampCompactionConfig, clampLogConfig, clampFastConfig, clampRetryConfig, clampSkillsConfig, clampTeamConfig, clampTodoConfig, clampBashConfig, clampJobsConfig, clampPromptsConfig, clampTaskSummaryConfig, clampUpdateConfig, clampTheme, clampThinkingLevel, clampContextWindow, clampMaxTokens, clampMaxRenderInterval, clampScrollMode, clampScrollResumeMs, clampTranscriptRetain, clampTranscriptWindow, coercePositiveInt, isAutoToken, isSkillsToolPolicyMode, legacyTeamCeilingPatch, legacyTeamFanoutPatch, LEGACY_TEAM_FANOUT_DEFAULTS, parseThresholdInput, } from './schema.js';
|
|
11
11
|
import { loadDotenv, readEnvConfig, readEnvDisabledSkills } from './env.js';
|
|
12
12
|
import { readConfigFile, updatePersistedConfig } from './store.js';
|
|
13
13
|
import { projectModelProfiles, resolveModelProfileState, resolveModelRoleKey, } from './model-profile-resolution.js';
|
|
@@ -517,6 +517,49 @@ function migrateLegacyTeamCeilings(raw) {
|
|
|
517
517
|
keys: Object.keys(patch).join(','),
|
|
518
518
|
});
|
|
519
519
|
}
|
|
520
|
+
/**
|
|
521
|
+
* Rewrite the cli<=0.6.x persisted fan-out defaults (5 / 3) to the new ones
|
|
522
|
+
* (8 / 8) and persist the change (subagent-fanout D-3 / D-4).
|
|
523
|
+
*
|
|
524
|
+
* ONE-SHOT and IDEMPOTENT, and the FILE LAYER ONLY, for the reasons
|
|
525
|
+
* `migrateLegacyTeamCeilings` records one block above: env (`ARAGON_TEAM_MAX`)
|
|
526
|
+
* and `--team-max` are THIS launch's intent and are never rewritten, the raw
|
|
527
|
+
* file object is patched IN PLACE so the `file` layer resolved below already
|
|
528
|
+
* reads 8/8, and a failed write leaves the marker absent so the next launch
|
|
529
|
+
* retries the whole migration.
|
|
530
|
+
*
|
|
531
|
+
* WHY A MARKER AND NOT JUST THE NUMBERS: `fanoutMigrated` is what keeps a user
|
|
532
|
+
* who deliberately returns to 5/3 from being migrated again on every launch
|
|
533
|
+
* (`legacyTeamFanoutPatch` returns `null` once it is set). The price of
|
|
534
|
+
* exact-equality is that one deliberate 5/3 is widened once; the marker bounds
|
|
535
|
+
* that to at most once.
|
|
536
|
+
*/
|
|
537
|
+
function migrateLegacyTeamFanout(raw) {
|
|
538
|
+
const patch = legacyTeamFanoutPatch(raw?.team);
|
|
539
|
+
if (patch === null)
|
|
540
|
+
return;
|
|
541
|
+
// READ THE STARTING POINT BEFORE THE IN-PLACE PATCH, and never hardcode
|
|
542
|
+
// `5/3`: rule 4 of the matcher accepts an ABSENT `maxConcurrent`, in which
|
|
543
|
+
// case the honest starting point is "unset" - a log line the user cannot find
|
|
544
|
+
// on disk is worse than no log line.
|
|
545
|
+
const from = `${LEGACY_TEAM_FANOUT_DEFAULTS.maxSubagents}/${raw?.team?.maxConcurrent ?? 'unset'}`;
|
|
546
|
+
// THE FULL SECTION, not the bare patch: the write port types `team` as a
|
|
547
|
+
// whole `TeamConfig`, and the section the file already carries plus the three
|
|
548
|
+
// keys IS the section we want on disk.
|
|
549
|
+
const migratedTeam = { ...raw.team, ...patch };
|
|
550
|
+
Object.assign(raw.team, patch);
|
|
551
|
+
try {
|
|
552
|
+
updatePersistedConfig({ team: migratedTeam });
|
|
553
|
+
}
|
|
554
|
+
catch {
|
|
555
|
+
// Unwritable config dir: in-memory values are already migrated; retry next
|
|
556
|
+
// launch (idempotent, because the marker never made it to disk).
|
|
557
|
+
}
|
|
558
|
+
getLogger().warn('config', 'team_fanout_migrated', {
|
|
559
|
+
from,
|
|
560
|
+
to: `${patch.maxSubagents}/${patch.maxConcurrent}`,
|
|
561
|
+
});
|
|
562
|
+
}
|
|
520
563
|
/**
|
|
521
564
|
* Resolve the effective config by merging all layers, then derive the runtime
|
|
522
565
|
* (non-persisted) fields and enforce the timeout invariant.
|
|
@@ -527,6 +570,12 @@ export function loadConfig(flags = {}, options = {}) {
|
|
|
527
570
|
loadDotenv(cwd);
|
|
528
571
|
const read = readConfigFile();
|
|
529
572
|
migrateLegacyTeamCeilings(read.config);
|
|
573
|
+
// THE NEXT LINE, not a shared pass: the two migrations are independent, and
|
|
574
|
+
// keeping them as two statements keeps each one's "returns null when nothing
|
|
575
|
+
// matches" contract visible. Both run BEFORE `projectModelProfiles` for the
|
|
576
|
+
// same reason - the `file` layer resolved below must already read the migrated
|
|
577
|
+
// numbers, and neither migration needs a second projection path.
|
|
578
|
+
migrateLegacyTeamFanout(read.config);
|
|
530
579
|
const projection = projectModelProfiles(read.config ?? {});
|
|
531
580
|
const file = projection.file;
|
|
532
581
|
const env = readEnvConfig();
|
|
@@ -570,7 +619,6 @@ export function loadConfig(flags = {}, options = {}) {
|
|
|
570
619
|
// a config file that turned plan mode on.
|
|
571
620
|
const startInPlanMode = pick(flags.plan, env.partial.planModeDefault, file.planModeDefault) ??
|
|
572
621
|
DEFAULT_CONFIG.planModeDefault;
|
|
573
|
-
const planModeMaxAskRounds = clampAskRounds(file.planModeMaxAskRounds, DEFAULT_CONFIG.planModeMaxAskRounds);
|
|
574
622
|
const planModeHumanTimeoutMs = clampHumanTimeout(file.planModeHumanTimeoutMs, DEFAULT_CONFIG.planModeHumanTimeoutMs);
|
|
575
623
|
const toolTimeoutMs = coercePositiveInt(pick(flags.toolTimeout, file.toolTimeoutMs), DEFAULT_CONFIG.toolTimeoutMs);
|
|
576
624
|
// THE `jobs` SECTION IS RESOLVED HERE, ABOVE THE TIMEOUT BLOCK, and the
|
|
@@ -706,7 +754,6 @@ export function loadConfig(flags = {}, options = {}) {
|
|
|
706
754
|
// From `<home>/state.json`, not the config file — see `ui-state.ts`.
|
|
707
755
|
submitCount: readSubmitCount(),
|
|
708
756
|
startInPlanMode,
|
|
709
|
-
planModeMaxAskRounds,
|
|
710
757
|
planModeHumanTimeoutMs,
|
|
711
758
|
skills,
|
|
712
759
|
skillsRuntime: {
|
|
@@ -738,6 +785,11 @@ export function loadConfig(flags = {}, options = {}) {
|
|
|
738
785
|
// two different shapes on `CliConfig`.
|
|
739
786
|
prompts: clampPromptsConfig({ ...DEFAULT_CONFIG.prompts, ...(env.partial.prompts ?? {}),
|
|
740
787
|
...(file.prompts ?? {}) }),
|
|
788
|
+
// The header task label's two switches, composed EXACTLY like `prompts` above:
|
|
789
|
+
// env + file + clamp, so an `ARAGON_TASK_SUMMARY=0` and a file-only
|
|
790
|
+
// `taskSummary.enabled: false` cannot arrive as two different shapes.
|
|
791
|
+
taskSummary: clampTaskSummaryConfig({ ...DEFAULT_CONFIG.taskSummary,
|
|
792
|
+
...(env.partial.taskSummary ?? {}), ...(file.taskSummary ?? {}) }),
|
|
741
793
|
cwd,
|
|
742
794
|
color,
|
|
743
795
|
colorLevel,
|
package/dist/config/schema.d.ts
CHANGED
|
@@ -206,15 +206,15 @@ export declare const DEFAULT_SCROLL_RESUME_MS = 5000;
|
|
|
206
206
|
* Exactly the trap `retry.maxRetries` needed this helper for.
|
|
207
207
|
*/
|
|
208
208
|
export declare function clampScrollResumeMs(v: unknown, fallback: number): number;
|
|
209
|
-
/** `ask_user` calls allowed per user turn. */
|
|
210
|
-
export declare const DEFAULT_PLAN_MAX_ASK_ROUNDS = 4;
|
|
211
209
|
/**
|
|
212
210
|
* Ceiling on ONE human wait, in ms. Thirty minutes is far outside "the user
|
|
213
211
|
* went to get coffee", but a ceiling has to exist: an unattended terminal must
|
|
214
212
|
* not wedge a CI job or a stale ssh session forever.
|
|
213
|
+
*
|
|
214
|
+
* THIS IS NOT A ROUND LIMIT and the distinction matters. It bounds a single wait
|
|
215
|
+
* (liveness); it says nothing about how many times the model may ask.
|
|
215
216
|
*/
|
|
216
217
|
export declare const DEFAULT_PLAN_HUMAN_TIMEOUT_MS = 1800000;
|
|
217
|
-
export declare function clampAskRounds(v: unknown, fallback: number): number;
|
|
218
218
|
export declare function clampHumanTimeout(v: unknown, fallback: number): number;
|
|
219
219
|
export interface SkillsConfig {
|
|
220
220
|
enabled: boolean;
|
|
@@ -259,6 +259,18 @@ export interface SkillsConfig {
|
|
|
259
259
|
* just be a second decorative field.
|
|
260
260
|
*/
|
|
261
261
|
toolPolicy: SkillsToolPolicyMode;
|
|
262
|
+
/**
|
|
263
|
+
* Automatic skill triage (skill-triage-and-unbounded-ask §4.2.9): compute a
|
|
264
|
+
* short candidate list for each new task and put it in the system prompt, so
|
|
265
|
+
* "is a skill applicable?" becomes a question the protocol forces the model to
|
|
266
|
+
* answer rather than one it has to remember to ask.
|
|
267
|
+
*
|
|
268
|
+
* DEFAULT ON, and OFF must be byte-identical to the pre-feature prompt. That is
|
|
269
|
+
* what the block's conditional splice in `buildSystemPrompt` guarantees
|
|
270
|
+
* (invariant I-T1) — a permanently-on block would be a prompt change nobody
|
|
271
|
+
* could turn off.
|
|
272
|
+
*/
|
|
273
|
+
triage: boolean;
|
|
262
274
|
}
|
|
263
275
|
export declare const SKILLS_INTEGRITY_MODES: readonly ["off", "warn", "strict"];
|
|
264
276
|
export type SkillsIntegrityMode = (typeof SKILLS_INTEGRITY_MODES)[number];
|
|
@@ -343,6 +355,16 @@ export interface TeamConfig {
|
|
|
343
355
|
* failed subagent.
|
|
344
356
|
*/
|
|
345
357
|
maxConcurrent: number;
|
|
358
|
+
/**
|
|
359
|
+
* The one-shot marker `migrateLegacyTeamFanout` writes (subagent-fanout
|
|
360
|
+
* D-3), and NOTHING else may ever write it.
|
|
361
|
+
*
|
|
362
|
+
* It exists because the fan-out default moved 5/3 -> 8/8 while every save
|
|
363
|
+
* materializes the whole section: without a marker, a user who deliberately
|
|
364
|
+
* returns to 5/3 is migrated back to 8/8 on the next launch, for ever. Absent
|
|
365
|
+
* means "not yet migrated"; it is never written as `false`.
|
|
366
|
+
*/
|
|
367
|
+
fanoutMigrated?: boolean;
|
|
346
368
|
/**
|
|
347
369
|
* One child's wall clock before its own abort. `0` (the default) means NO
|
|
348
370
|
* ceiling: a subagent runs until it finishes or is aborted, exactly like
|
|
@@ -465,6 +487,40 @@ export declare const LEGACY_TEAM_CEILING_DEFAULTS: Readonly<{
|
|
|
465
487
|
* equality test lives beside the constants it reads.
|
|
466
488
|
*/
|
|
467
489
|
export declare function legacyTeamCeilingPatch(raw: unknown): Partial<TeamConfig> | null;
|
|
490
|
+
/**
|
|
491
|
+
* The fan-out defaults cli <= 0.6.x persisted as its OWN defaults
|
|
492
|
+
* (subagent-fanout F-2 / R-1).
|
|
493
|
+
*
|
|
494
|
+
* THE SAME TRAP AS THE CEILINGS ABOVE, ONE SECTION OVER. `mergePersistedConfig`
|
|
495
|
+
* writes the WHOLE `team` section on every save, so a user who has ever touched
|
|
496
|
+
* any setting carries this exact pair in `config.json` - changing
|
|
497
|
+
* `DEFAULT_TEAM_CONFIG` alone would never reach them, and they would keep
|
|
498
|
+
* seeing "only 3 subagents at once" for ever.
|
|
499
|
+
*/
|
|
500
|
+
export declare const LEGACY_TEAM_FANOUT_DEFAULTS: {
|
|
501
|
+
readonly maxSubagents: 5;
|
|
502
|
+
readonly maxConcurrent: 3;
|
|
503
|
+
};
|
|
504
|
+
/**
|
|
505
|
+
* The `{ maxSubagents, maxConcurrent, fanoutMigrated }` patch for the legacy
|
|
506
|
+
* default pair, or `null` when nothing matches (subagent-fanout D-3).
|
|
507
|
+
*
|
|
508
|
+
* EXACT-EQUALITY ONLY, the rule `legacyTeamCeilingPatch` records: a value that
|
|
509
|
+
* differs was a deliberate user choice and survives untouched. Two differences
|
|
510
|
+
* from that function, both deliberate:
|
|
511
|
+
*
|
|
512
|
+
* - `fanoutMigrated: true` short-circuits to `null`. That is what makes "the
|
|
513
|
+
* user changed their mind and went back to 5/3" stick: without it the next
|
|
514
|
+
* launch would migrate them again, every launch, for ever.
|
|
515
|
+
* - `maxConcurrent` is allowed to be ABSENT as well as 3, because a
|
|
516
|
+
* hand-written section may name only one key and a half-written pair is
|
|
517
|
+
* still the legacy intent, not a user decision.
|
|
518
|
+
*
|
|
519
|
+
* Pure on purpose: `loadConfig` decides WHERE the patch is applied and
|
|
520
|
+
* persisted; this function only answers WHICH keys match, so the equality test
|
|
521
|
+
* lives beside the constants it reads.
|
|
522
|
+
*/
|
|
523
|
+
export declare function legacyTeamFanoutPatch(raw: unknown): Partial<TeamConfig> | null;
|
|
468
524
|
export interface TodoConfig {
|
|
469
525
|
/** Register `todo_write` at all. Default TRUE. */
|
|
470
526
|
enabled: boolean;
|
|
@@ -886,8 +942,6 @@ export interface PromptsConfig {
|
|
|
886
942
|
* `insert` keeps the user's words; `replace` overwrites them.
|
|
887
943
|
*/
|
|
888
944
|
insertMode: 'insert' | 'replace';
|
|
889
|
-
/** Whether the header's right-hand column may teach `^P prompts`. */
|
|
890
|
-
hint: boolean;
|
|
891
945
|
}
|
|
892
946
|
export declare const DEFAULT_PROMPTS_CONFIG: PromptsConfig;
|
|
893
947
|
/**
|
|
@@ -899,6 +953,35 @@ export declare const DEFAULT_PROMPTS_CONFIG: PromptsConfig;
|
|
|
899
953
|
* what the user has already typed into the composer.
|
|
900
954
|
*/
|
|
901
955
|
export declare function clampPromptsConfig(raw: unknown): PromptsConfig;
|
|
956
|
+
/**
|
|
957
|
+
* The task label's two switches (tui-shortcut-drawer-and-task-summary §4.8).
|
|
958
|
+
*
|
|
959
|
+
* ONE LEVEL DEEP, like every section beside it: `runConfigGet` splits on a single
|
|
960
|
+
* dot, so `taskSummary.enabled` resolves and a nested key would not (F-18).
|
|
961
|
+
*
|
|
962
|
+
* NEITHER KEY IS ABOUT THE LABEL'S CONTENT. `enabled` is the kill switch: off
|
|
963
|
+
* means no call is made and no cell is drawn. `fallback` decides what happens when
|
|
964
|
+
* the call cannot produce a label - the deterministic verbatim-prefix floor, or
|
|
965
|
+
* nothing at all. Both are BEHAVIOUR, which is why they are here rather than in
|
|
966
|
+
* `fast/limits.ts` (F-13).
|
|
967
|
+
*/
|
|
968
|
+
export interface TaskSummaryConfig {
|
|
969
|
+
/** The kill switch. `false` removes the header cell and the automatic call. */
|
|
970
|
+
enabled: boolean;
|
|
971
|
+
/** The deterministic verbatim-prefix floor (D-9). `false` = show nothing instead. */
|
|
972
|
+
fallback: boolean;
|
|
973
|
+
}
|
|
974
|
+
export declare const DEFAULT_TASK_SUMMARY_CONFIG: TaskSummaryConfig;
|
|
975
|
+
/**
|
|
976
|
+
* THE single gate for every `taskSummary` read AND write, like the twelve sections
|
|
977
|
+
* above it.
|
|
978
|
+
*
|
|
979
|
+
* BOTH DEFAULTS ARE `true`, AND THE DIRECTION MATTERS: a corrupt or hand-edited
|
|
980
|
+
* section must not silently switch off a feature the user asked for, and - more
|
|
981
|
+
* importantly - it must not switch off the FLOOR, which is the only thing standing
|
|
982
|
+
* between a failed call and an empty header cell.
|
|
983
|
+
*/
|
|
984
|
+
export declare function clampTaskSummaryConfig(raw: unknown): TaskSummaryConfig;
|
|
902
985
|
/**
|
|
903
986
|
* Parse `0.9`, `90%` or `90` into a ratio, or `null` when it is neither.
|
|
904
987
|
*
|
|
@@ -1037,8 +1120,6 @@ export interface PersistedConfig {
|
|
|
1037
1120
|
scrollResumeMs: number;
|
|
1038
1121
|
/** Start every session in PLAN mode (plan-mode §4.4). */
|
|
1039
1122
|
planModeDefault: boolean;
|
|
1040
|
-
/** `ask_user` rounds allowed per user turn; clamped to [1, 10]. */
|
|
1041
|
-
planModeMaxAskRounds: number;
|
|
1042
1123
|
/** Ceiling on a single human wait in ms; clamped to [60_000, 7_200_000]. */
|
|
1043
1124
|
planModeHumanTimeoutMs: number;
|
|
1044
1125
|
/** Skill system settings. The SECOND nested object in this file after apiKeys. */
|
|
@@ -1061,8 +1142,10 @@ export interface PersistedConfig {
|
|
|
1061
1142
|
bash: BashConfig;
|
|
1062
1143
|
/** Background jobs and bounded waiting. The ELEVENTH; scalars only (see JobsConfig). */
|
|
1063
1144
|
jobs: JobsConfig;
|
|
1064
|
-
/** Quick prompts. The TWELFTH;
|
|
1145
|
+
/** Quick prompts. The TWELFTH; two scalars (see PromptsConfig). */
|
|
1065
1146
|
prompts: PromptsConfig;
|
|
1147
|
+
/** The header task label. The THIRTEENTH; two scalars (see TaskSummaryConfig). */
|
|
1148
|
+
taskSummary: TaskSummaryConfig;
|
|
1066
1149
|
}
|
|
1067
1150
|
export declare const DEFAULT_CONFIG: PersistedConfig;
|
|
1068
1151
|
/**
|
|
@@ -1089,6 +1172,29 @@ export declare const LEGACY_STATE_KEYS: readonly ["promptHistory", "submitCount"
|
|
|
1089
1172
|
* one door for both directions.
|
|
1090
1173
|
*/
|
|
1091
1174
|
export declare function stripLegacyStateKeys<T extends object>(raw: T): T;
|
|
1175
|
+
/**
|
|
1176
|
+
* Config keys whose MEANING was removed, mapped to the explanation a user gets if
|
|
1177
|
+
* they still try to set one.
|
|
1178
|
+
*
|
|
1179
|
+
* SEPARATE FROM `LEGACY_STATE_KEYS`, because the disposition differs: those keys'
|
|
1180
|
+
* values were MOVED somewhere else, while these have nowhere to go — the feature
|
|
1181
|
+
* they configured no longer exists. Merging the two lists would erase that
|
|
1182
|
+
* difference at exactly the moment someone is reading the file to find out what
|
|
1183
|
+
* happened to their setting.
|
|
1184
|
+
*
|
|
1185
|
+
* Stripped on the READ side for the same reason `stripLegacyStateKeys` is:
|
|
1186
|
+
* `loadPersistedConfig()` merges `{ ...DEFAULT_CONFIG, ...partial }`, so a key
|
|
1187
|
+
* left on disk rides that spread into memory and `updatePersistedConfig` writes it
|
|
1188
|
+
* straight back. The user deletes the line, launches once, and watches it return.
|
|
1189
|
+
*/
|
|
1190
|
+
export declare const RETIRED_CONFIG_KEYS: Readonly<Record<string, string>>;
|
|
1191
|
+
/**
|
|
1192
|
+
* THE single gate that keeps retired keys out of `config.json`. Applied on the
|
|
1193
|
+
* read side, so it is self-healing: every write is read-strip-merge-write, and a
|
|
1194
|
+
* hand-edited file, a downgrade to an older CLI and back, or a half-finished
|
|
1195
|
+
* migration all converge on a clean file at the next write.
|
|
1196
|
+
*/
|
|
1197
|
+
export declare function stripRetiredConfigKeys<T extends object>(raw: T): T;
|
|
1092
1198
|
export interface CliConfig {
|
|
1093
1199
|
/** A committed model snapshot failed to apply; no further requests may start. */
|
|
1094
1200
|
modelSettingsRestartRequired?: boolean;
|
|
@@ -1283,7 +1389,6 @@ export interface CliConfig {
|
|
|
1283
1389
|
* live mode from here on belongs to the controller.
|
|
1284
1390
|
*/
|
|
1285
1391
|
startInPlanMode: boolean;
|
|
1286
|
-
planModeMaxAskRounds: number;
|
|
1287
1392
|
planModeHumanTimeoutMs: number;
|
|
1288
1393
|
skills: SkillsConfig;
|
|
1289
1394
|
/** Flag/env-only skill switches for this run (§7.5). Never persisted. */
|
|
@@ -1406,7 +1511,7 @@ export interface CliConfig {
|
|
|
1406
1511
|
* scalars, one level deep.
|
|
1407
1512
|
*
|
|
1408
1513
|
* ON `CliConfig` AS WELL AS `PersistedConfig`, for the reason every section above
|
|
1409
|
-
* records: `App` reads `cfg.prompts?.enabled` / `.
|
|
1514
|
+
* records: `App` reads `cfg.prompts?.enabled` / `.insertMode` from a
|
|
1410
1515
|
* `CliConfig`, so a key added to the persisted shape alone would round-trip
|
|
1411
1516
|
* through the `config` commands, appear in `config list`, and change nothing.
|
|
1412
1517
|
*
|
|
@@ -1419,6 +1524,16 @@ export interface CliConfig {
|
|
|
1419
1524
|
* disabled or destructive one.
|
|
1420
1525
|
*/
|
|
1421
1526
|
prompts?: PromptsConfig;
|
|
1527
|
+
/**
|
|
1528
|
+
* The header task label (tui-shortcut-drawer-and-task-summary §4.8). The
|
|
1529
|
+
* THIRTEENTH nested object; two scalars, one level deep.
|
|
1530
|
+
*
|
|
1531
|
+
* OPTIONAL HERE FOR THE SAME REASON AS `prompts` ABOVE: `CliConfig` is built by
|
|
1532
|
+
* hand in many fixtures, and every reader uses `!== false`, so a missing section
|
|
1533
|
+
* behaves exactly like a default session (label on, floor on) rather than like a
|
|
1534
|
+
* switched-off feature.
|
|
1535
|
+
*/
|
|
1536
|
+
taskSummary?: TaskSummaryConfig;
|
|
1422
1537
|
/**
|
|
1423
1538
|
* Lifetime submit count driving the composer hint fade (`HINT_FADE_AFTER`).
|
|
1424
1539
|
*
|