@aragon-agent/cli 0.6.2 → 0.6.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +321 -0
- package/README.md +297 -2
- package/dist/agent/controller.d.ts +193 -1
- package/dist/agent/controller.js +475 -2
- package/dist/agent/headless.d.ts +8 -0
- package/dist/agent/headless.js +47 -0
- package/dist/agent/reducer.d.ts +189 -0
- package/dist/agent/reducer.js +301 -2
- package/dist/agent/system-prompt.d.ts +14 -0
- package/dist/agent/system-prompt.js +2 -0
- package/dist/cli.js +297 -16
- package/dist/commands/builtins.js +165 -24
- package/dist/commands/registry.d.ts +27 -0
- package/dist/compaction/archive.d.ts +175 -0
- package/dist/compaction/archive.js +267 -0
- package/dist/compaction/child.d.ts +97 -0
- package/dist/compaction/child.js +118 -0
- package/dist/compaction/command.d.ts +41 -0
- package/dist/compaction/command.js +355 -0
- package/dist/compaction/compactor.d.ts +302 -0
- package/dist/compaction/compactor.js +810 -0
- package/dist/compaction/digest.d.ts +62 -0
- package/dist/compaction/digest.js +164 -0
- package/dist/compaction/limits.d.ts +165 -0
- package/dist/compaction/limits.js +172 -0
- package/dist/compaction/pressure.d.ts +135 -0
- package/dist/compaction/pressure.js +167 -0
- package/dist/compaction/summarize-call.d.ts +70 -0
- package/dist/compaction/summarize-call.js +86 -0
- package/dist/compaction/summary-prompt.d.ts +85 -0
- package/dist/compaction/summary-prompt.js +197 -0
- package/dist/compaction/tail-budget.d.ts +52 -0
- package/dist/compaction/tail-budget.js +67 -0
- package/dist/compaction/types.d.ts +215 -0
- package/dist/compaction/types.js +22 -0
- package/dist/compaction/wiring.d.ts +264 -0
- package/dist/compaction/wiring.js +577 -0
- package/dist/config/app-paths.d.ts +14 -0
- package/dist/config/app-paths.js +16 -0
- package/dist/config/cli-commands.d.ts +41 -0
- package/dist/config/cli-commands.js +77 -1
- package/dist/config/env.d.ts +5 -2
- package/dist/config/env.js +140 -3
- package/dist/config/load.d.ts +42 -0
- package/dist/config/load.js +101 -1
- package/dist/config/schema.d.ts +244 -0
- package/dist/config/schema.js +170 -0
- package/dist/config/store.js +37 -1
- package/dist/config/ui-state.d.ts +28 -1
- package/dist/config/ui-state.js +9 -0
- package/dist/exec/events.d.ts +50 -1
- package/dist/exec/runner.js +42 -0
- package/dist/input/limits.d.ts +72 -0
- package/dist/input/limits.js +63 -0
- package/dist/input/mouse-events.d.ts +31 -5
- package/dist/input/mouse-events.js +86 -27
- package/dist/input/paste-parse.d.ts +71 -0
- package/dist/input/paste-parse.js +95 -0
- package/dist/input/stdin-filter.d.ts +81 -0
- package/dist/input/stdin-filter.js +379 -0
- package/dist/logging/install.d.ts +53 -1
- package/dist/logging/install.js +81 -1
- package/dist/logging/logger.d.ts +1 -1
- package/dist/proc/classify.d.ts +52 -0
- package/dist/proc/classify.js +143 -0
- package/dist/proc/kill-tree.d.ts +42 -0
- package/dist/proc/kill-tree.js +119 -0
- package/dist/proc/limits.d.ts +84 -0
- package/dist/proc/limits.js +84 -0
- package/dist/proc/log-ring.d.ts +68 -0
- package/dist/proc/log-ring.js +102 -0
- package/dist/proc/prompt.d.ts +24 -0
- package/dist/proc/prompt.js +49 -0
- package/dist/proc/readiness.d.ts +102 -0
- package/dist/proc/readiness.js +219 -0
- package/dist/proc/supervisor.d.ts +103 -0
- package/dist/proc/supervisor.js +465 -0
- package/dist/proc/types.d.ts +175 -0
- package/dist/proc/types.js +15 -0
- package/dist/session/persist.js +55 -1
- package/dist/team/report.js +7 -1
- package/dist/team/runtime.d.ts +10 -0
- package/dist/team/runtime.js +7 -0
- package/dist/team/subagent.d.ts +31 -1
- package/dist/team/subagent.js +42 -15
- package/dist/team/types.d.ts +8 -0
- package/dist/tools/bash-tool.d.ts +51 -2
- package/dist/tools/bash-tool.js +321 -51
- package/dist/tools/fs-tools.d.ts +17 -0
- package/dist/tools/index.d.ts +55 -2
- package/dist/tools/index.js +39 -1
- package/dist/tools/proc-tools.d.ts +25 -0
- package/dist/tools/proc-tools.js +102 -0
- package/dist/ui/ActivityLine.d.ts +19 -1
- package/dist/ui/ActivityLine.js +10 -2
- package/dist/ui/App.d.ts +62 -2
- package/dist/ui/App.js +546 -16
- package/dist/ui/Composer.d.ts +66 -1
- package/dist/ui/Composer.js +50 -6
- package/dist/ui/PromptInput.d.ts +82 -3
- package/dist/ui/PromptInput.js +232 -49
- package/dist/ui/StatusBar.d.ts +59 -0
- package/dist/ui/StatusBar.js +16 -4
- package/dist/ui/TeamPanel.js +7 -1
- package/dist/ui/Transcript.d.ts +21 -1
- package/dist/ui/Transcript.js +61 -3
- package/dist/ui/clipboard.d.ts +52 -0
- package/dist/ui/clipboard.js +91 -0
- package/dist/ui/composer-limits.d.ts +31 -0
- package/dist/ui/composer-limits.js +50 -0
- package/dist/ui/composer-rows.d.ts +73 -0
- package/dist/ui/composer-rows.js +201 -0
- package/dist/ui/editor-reducer.d.ts +37 -0
- package/dist/ui/editor-reducer.js +88 -12
- package/dist/ui/entries/CompactionCard.d.ts +75 -0
- package/dist/ui/entries/CompactionCard.js +158 -0
- package/dist/ui/entries/ServiceCard.d.ts +66 -0
- package/dist/ui/entries/ServiceCard.js +116 -0
- package/dist/ui/entries/UserEntry.d.ts +17 -3
- package/dist/ui/entries/UserEntry.js +34 -5
- package/dist/ui/frame-differ.d.ts +46 -0
- package/dist/ui/frame-differ.js +94 -10
- package/dist/ui/gauge.d.ts +16 -1
- package/dist/ui/gauge.js +25 -6
- package/dist/ui/glyphs.d.ts +11 -0
- package/dist/ui/glyphs.js +2 -0
- package/dist/ui/layout/ScrollViewport.d.ts +43 -6
- package/dist/ui/layout/ScrollViewport.js +128 -21
- package/dist/ui/layout/budget.d.ts +44 -9
- package/dist/ui/layout/budget.js +42 -10
- package/dist/ui/layout/follow-state.d.ts +137 -0
- package/dist/ui/layout/follow-state.js +150 -0
- package/dist/ui/layout/virtual-window.d.ts +11 -0
- package/dist/ui/layout/virtual-window.js +85 -1
- package/dist/ui/overlays/HelpOverlay.js +9 -1
- package/dist/ui/overlays/PlanReviewOverlay.js +10 -2
- package/dist/ui/overlays/QuestionOverlay.js +5 -1
- package/dist/ui/overlays/SettingsScreen.d.ts +47 -1
- package/dist/ui/overlays/SettingsScreen.js +74 -2
- package/dist/ui/palettes.d.ts +16 -0
- package/dist/ui/palettes.js +6 -0
- package/dist/ui/paste-frames.d.ts +87 -0
- package/dist/ui/paste-frames.js +112 -0
- package/dist/ui/paste-tokens.d.ts +90 -0
- package/dist/ui/paste-tokens.js +147 -0
- package/dist/ui/screen.d.ts +38 -0
- package/dist/ui/screen.js +113 -8
- package/dist/ui/selection/highlight.d.ts +39 -0
- package/dist/ui/selection/highlight.js +64 -0
- package/dist/ui/selection/screen-mirror.d.ts +24 -0
- package/dist/ui/selection/screen-mirror.js +35 -0
- package/dist/ui/selection/selection-controller.d.ts +88 -0
- package/dist/ui/selection/selection-controller.js +282 -0
- package/dist/ui/selection/selection.d.ts +90 -0
- package/dist/ui/selection/selection.js +223 -0
- package/dist/ui/stdout-frame-writer.d.ts +33 -0
- package/dist/ui/stdout-frame-writer.js +15 -0
- package/dist/ui/theme.d.ts +11 -0
- package/dist/ui/theme.js +2 -0
- package/dist/ui/transcript-text.js +72 -0
- package/dist/ui/use-startup-notices.d.ts +27 -1
- package/dist/ui/use-startup-notices.js +43 -11
- package/dist/ui/use-wheel-routing.d.ts +1 -1
- package/dist/ui/use-wheel-routing.js +8 -0
- package/package.json +4 -2
- package/dist/input/stdin-mouse-filter.d.ts +0 -42
- package/dist/input/stdin-mouse-filter.js +0 -153
|
@@ -13,7 +13,7 @@ import process from 'node:process';
|
|
|
13
13
|
import { getConfigBackupPath, getConfigPath, getHomeRoot, getLogsDir, getPromptHistoryPath, getUiStatePath, isHomeOverridden, } from './app-paths.js';
|
|
14
14
|
import { getHomeMigrationBreadcrumbPath } from './migrate-home.js';
|
|
15
15
|
import { loadPersistedConfig, updatePersistedConfig } from './store.js';
|
|
16
|
-
import { clampFastConfig, clampRetryConfig, clampUpdateConfig, coercePositiveInt, maskSecret, DEFAULT_FAST_CONFIG, DEFAULT_RETRY_CONFIG, DEFAULT_TEAM_CONFIG, DEFAULT_UPDATE_CONFIG, } from './schema.js';
|
|
16
|
+
import { clampFastConfig, clampRetryConfig, clampCompactionConfig, parseThresholdInput, clampUpdateConfig, coercePositiveInt, maskSecret, DEFAULT_FAST_CONFIG, DEFAULT_RETRY_CONFIG, DEFAULT_TEAM_CONFIG, DEFAULT_COMPACTION_CONFIG, DEFAULT_UPDATE_CONFIG, } from './schema.js';
|
|
17
17
|
import { clampLogLevel } from '../logging/levels.js';
|
|
18
18
|
/** Config keys under `log.` that `aragon config set` accepts. */
|
|
19
19
|
export const LOG_CONFIG_SET_KEYS = [
|
|
@@ -103,6 +103,33 @@ export const UPDATE_CONFIG_SET_KEYS = [
|
|
|
103
103
|
'update.registry',
|
|
104
104
|
'update.distTag',
|
|
105
105
|
];
|
|
106
|
+
/**
|
|
107
|
+
* Config keys under `compaction.` that `aragon config set` accepts
|
|
108
|
+
* (context-auto-compaction §4.2).
|
|
109
|
+
*
|
|
110
|
+
* A DEDICATED SETTER RATHER THAN A GENERIC DOTTED WRITER, for the reason the
|
|
111
|
+
* five sets above each record: a generic setter would write `compaction` as a
|
|
112
|
+
* FLAT string key (`"compaction.enabled": "false"` at the top level of the
|
|
113
|
+
* file), the section would silently never take effect, and `config set` would
|
|
114
|
+
* still print `Set compaction.enabled = false`.
|
|
115
|
+
*
|
|
116
|
+
* THIS SET IS WHAT MAKES THE KILL SWITCH REACHABLE FROM A SCRIPT. `config list`
|
|
117
|
+
* enumerates the section dynamically and so shows these keys whether they are
|
|
118
|
+
* here or not; `config set` does not, so without this block
|
|
119
|
+
* `aragon config set compaction.enabled false` fails with "Unknown config key"
|
|
120
|
+
* while the key is visibly listed one command over. Manual-test row 9 — the
|
|
121
|
+
* persisted-off-survives-a-flagless-run check — runs exactly that command.
|
|
122
|
+
*/
|
|
123
|
+
export const COMPACTION_CONFIG_SET_KEYS = [
|
|
124
|
+
'compaction.enabled',
|
|
125
|
+
'compaction.threshold',
|
|
126
|
+
'compaction.warnThreshold',
|
|
127
|
+
'compaction.keepRecentTurns',
|
|
128
|
+
'compaction.useFastTier',
|
|
129
|
+
'compaction.onFailure',
|
|
130
|
+
'compaction.subagents',
|
|
131
|
+
'compaction.archive',
|
|
132
|
+
];
|
|
106
133
|
function isTrue(value) {
|
|
107
134
|
return value === 'true' || value === '1';
|
|
108
135
|
}
|
|
@@ -294,6 +321,55 @@ export function applyUpdateConfigSet(key, value) {
|
|
|
294
321
|
return null;
|
|
295
322
|
}
|
|
296
323
|
}
|
|
324
|
+
/**
|
|
325
|
+
* Translate a `compaction.*` dotted key into a patch, or `null` for anything
|
|
326
|
+
* else (context-auto-compaction §4.2).
|
|
327
|
+
*
|
|
328
|
+
* EVERY KEY ROUTES THROUGH `clampCompactionConfig`, not through a local parse,
|
|
329
|
+
* for the reason `applyRetryConfigSet`, `applyFastConfigSet` and
|
|
330
|
+
* `applyUpdateConfigSet` all record: one gate for both directions means no key
|
|
331
|
+
* here can pick up a different coercion later, and `config set
|
|
332
|
+
* compaction.threshold 0.2` writes the clamped `0.5` while the caller echoes the
|
|
333
|
+
* STORED value.
|
|
334
|
+
*
|
|
335
|
+
* `threshold` and `warnThreshold` additionally accept a PERCENTAGE, because that
|
|
336
|
+
* is the unit the status bar shows and `/compact threshold` accepts.
|
|
337
|
+
*
|
|
338
|
+
* A VALUE THE PARSER REJECTS RESOLVES TO THE DEFAULT, NOT TO THE CURRENT SETTING
|
|
339
|
+
* — the same thing `config set retry.maxRetries banana` does, because `clampOne`
|
|
340
|
+
* merges the field onto `DEFAULT_COMPACTION_CONFIG` before clamping it. That is
|
|
341
|
+
* the house behaviour and it is not silent: `cli.tsx` echoes the STORED value, so
|
|
342
|
+
* a typo prints the number that was actually written rather than the one that was
|
|
343
|
+
* typed. Unlike the settings screen and `/compact threshold`, both of which
|
|
344
|
+
* genuinely ignore an unparseable value, this surface has no third state.
|
|
345
|
+
*/
|
|
346
|
+
export function applyCompactionConfigSet(key, value) {
|
|
347
|
+
const patch = (compaction) => ({ compaction });
|
|
348
|
+
const clampOne = (field, raw = value) => {
|
|
349
|
+
const merged = clampCompactionConfig({ ...DEFAULT_COMPACTION_CONFIG, [field]: raw });
|
|
350
|
+
return { [field]: merged[field] };
|
|
351
|
+
};
|
|
352
|
+
switch (key) {
|
|
353
|
+
case 'compaction.enabled':
|
|
354
|
+
return patch(clampOne('enabled', isTrue(value)));
|
|
355
|
+
case 'compaction.threshold':
|
|
356
|
+
return patch(clampOne('threshold', parseThresholdInput(value) ?? undefined));
|
|
357
|
+
case 'compaction.warnThreshold':
|
|
358
|
+
return patch(clampOne('warnThreshold', parseThresholdInput(value) ?? undefined));
|
|
359
|
+
case 'compaction.keepRecentTurns':
|
|
360
|
+
return patch(clampOne('keepRecentTurns'));
|
|
361
|
+
case 'compaction.useFastTier':
|
|
362
|
+
return patch(clampOne('useFastTier', isTrue(value)));
|
|
363
|
+
case 'compaction.onFailure':
|
|
364
|
+
return patch(clampOne('onFailure'));
|
|
365
|
+
case 'compaction.subagents':
|
|
366
|
+
return patch(clampOne('subagents', isTrue(value)));
|
|
367
|
+
case 'compaction.archive':
|
|
368
|
+
return patch(clampOne('archive', isTrue(value)));
|
|
369
|
+
default:
|
|
370
|
+
return null;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
297
373
|
/**
|
|
298
374
|
* `log.redactSecrets false` is the one setting that lets credentials reach the
|
|
299
375
|
* disk. It is command-line-only (there is no settings-screen entry) and it says
|
package/dist/config/env.d.ts
CHANGED
|
@@ -7,14 +7,17 @@
|
|
|
7
7
|
* - Overrides: ARAGON_PROVIDER, ARAGON_MODEL, ARAGON_BASE_URL, ARAGON_THINKING,
|
|
8
8
|
* ARAGON_SHOW_THINKING,
|
|
9
9
|
* ARAGON_MAX_TOKENS (a number, or `auto` / `0` for the per-model ceiling),
|
|
10
|
-
* ARAGON_THEME, ARAGON_MOUSE, ARAGON_PLAN, ARAGON_TEAM,
|
|
10
|
+
* ARAGON_THEME, ARAGON_MOUSE, ARAGON_PASTE, ARAGON_PLAN, ARAGON_TEAM,
|
|
11
11
|
* ARAGON_TEAM_MAX, ARAGON_RETRY, ARAGON_RETRY_MAX, ARAGON_FAST,
|
|
12
12
|
* ARAGON_FAST_PROVIDER, ARAGON_FAST_MODEL, ARAGON_FAST_BASE_URL,
|
|
13
13
|
* ARAGON_LOG_LEVEL,
|
|
14
14
|
* ARAGON_LOG_FILE, ARAGON_LOG_DIR, ARAGON_TRANSCRIPT_RETAIN,
|
|
15
15
|
* ARAGON_RENDER_GOVERNOR, ARAGON_MAX_RENDER_INTERVAL_MS,
|
|
16
16
|
* ARAGON_DIFF_RENDER, ARAGON_SYNC_OUTPUT,
|
|
17
|
-
* ARAGON_UPDATE
|
|
17
|
+
* ARAGON_UPDATE,
|
|
18
|
+
* ARAGON_COMPACTION, ARAGON_COMPACTION_THRESHOLD,
|
|
19
|
+
* ARAGON_COMPACTION_KEEP_TURNS, ARAGON_COMPACTION_SUBAGENTS,
|
|
20
|
+
* ARAGON_COMPACTION_ARCHIVE.
|
|
18
21
|
*
|
|
19
22
|
* READ ELSEWHERE, ON PURPOSE: `ARAGON_UPDATE_REGISTRY` and `npm_config_registry`
|
|
20
23
|
* are resolved by `update/registry.ts::resolveRegistryUrl`, NOT here, because
|
package/dist/config/env.js
CHANGED
|
@@ -7,14 +7,17 @@
|
|
|
7
7
|
* - Overrides: ARAGON_PROVIDER, ARAGON_MODEL, ARAGON_BASE_URL, ARAGON_THINKING,
|
|
8
8
|
* ARAGON_SHOW_THINKING,
|
|
9
9
|
* ARAGON_MAX_TOKENS (a number, or `auto` / `0` for the per-model ceiling),
|
|
10
|
-
* ARAGON_THEME, ARAGON_MOUSE, ARAGON_PLAN, ARAGON_TEAM,
|
|
10
|
+
* ARAGON_THEME, ARAGON_MOUSE, ARAGON_PASTE, ARAGON_PLAN, ARAGON_TEAM,
|
|
11
11
|
* ARAGON_TEAM_MAX, ARAGON_RETRY, ARAGON_RETRY_MAX, ARAGON_FAST,
|
|
12
12
|
* ARAGON_FAST_PROVIDER, ARAGON_FAST_MODEL, ARAGON_FAST_BASE_URL,
|
|
13
13
|
* ARAGON_LOG_LEVEL,
|
|
14
14
|
* ARAGON_LOG_FILE, ARAGON_LOG_DIR, ARAGON_TRANSCRIPT_RETAIN,
|
|
15
15
|
* ARAGON_RENDER_GOVERNOR, ARAGON_MAX_RENDER_INTERVAL_MS,
|
|
16
16
|
* ARAGON_DIFF_RENDER, ARAGON_SYNC_OUTPUT,
|
|
17
|
-
* ARAGON_UPDATE
|
|
17
|
+
* ARAGON_UPDATE,
|
|
18
|
+
* ARAGON_COMPACTION, ARAGON_COMPACTION_THRESHOLD,
|
|
19
|
+
* ARAGON_COMPACTION_KEEP_TURNS, ARAGON_COMPACTION_SUBAGENTS,
|
|
20
|
+
* ARAGON_COMPACTION_ARCHIVE.
|
|
18
21
|
*
|
|
19
22
|
* READ ELSEWHERE, ON PURPOSE: `ARAGON_UPDATE_REGISTRY` and `npm_config_registry`
|
|
20
23
|
* are resolved by `update/registry.ts::resolveRegistryUrl`, NOT here, because
|
|
@@ -34,7 +37,7 @@ import process from 'node:process';
|
|
|
34
37
|
import dotenv from 'dotenv';
|
|
35
38
|
import { registerSecretsFrom } from '../logging/secret-registry.js';
|
|
36
39
|
import { clampLogLevel } from '../logging/levels.js';
|
|
37
|
-
import { clampMaxTokens, clampTheme, clampThinkingLevel, isAutoToken, } from './schema.js';
|
|
40
|
+
import { clampMaxTokens, clampTheme, clampThinkingLevel, isAutoToken, parseThresholdInput, } from './schema.js';
|
|
38
41
|
/**
|
|
39
42
|
* Load a project `.env` from the given directory into `process.env` (existing
|
|
40
43
|
* process env wins — dotenv never overrides already-set variables).
|
|
@@ -127,6 +130,36 @@ export function readEnvConfig() {
|
|
|
127
130
|
if (mouse !== undefined && mouse.length > 0) {
|
|
128
131
|
partial.mouse = mouse === '1' || mouse === 'true' || mouse === 'on' || mouse === 'yes';
|
|
129
132
|
}
|
|
133
|
+
// ARAGON_MOUSE_SELECT=0 turns drag-select off while leaving the wheel alone —
|
|
134
|
+
// the third rung of the mouse ladder (`--no-mouse` is the first two). Parsed by
|
|
135
|
+
// the POSITIVE list, exactly as its neighbour above is.
|
|
136
|
+
const mouseSelect = process.env.ARAGON_MOUSE_SELECT?.trim().toLowerCase();
|
|
137
|
+
if (mouseSelect !== undefined && mouseSelect.length > 0) {
|
|
138
|
+
partial.mouseSelect =
|
|
139
|
+
mouseSelect === '1' ||
|
|
140
|
+
mouseSelect === 'true' ||
|
|
141
|
+
mouseSelect === 'on' ||
|
|
142
|
+
mouseSelect === 'yes';
|
|
143
|
+
}
|
|
144
|
+
// ARAGON_PASTE=0 turns paste recognition off, which is the documented one-env
|
|
145
|
+
// revert to v0.6.3 input handling (tui-paste-handling section 7.2). Parsed by
|
|
146
|
+
// the POSITIVE list, exactly as its two neighbours above are.
|
|
147
|
+
const paste = process.env.ARAGON_PASTE?.trim().toLowerCase();
|
|
148
|
+
if (paste !== undefined && paste.length > 0) {
|
|
149
|
+
partial.paste = paste === '1' || paste === 'true' || paste === 'on' || paste === 'yes';
|
|
150
|
+
}
|
|
151
|
+
// ARAGON_SCROLL_RESUME_MS=<n> — idle delay before a paused viewport returns to
|
|
152
|
+
// the newest line; `0` disables auto-resume. THE ONLY CHANNEL BESIDES THE
|
|
153
|
+
// CONFIG FILE, because §6.1 gives this key no CLI flag on purpose. `load.ts`
|
|
154
|
+
// clamps it to [0, 120000]; a non-numeric value is LEFT ABSENT rather than
|
|
155
|
+
// written, so a typo falls through to the config file underneath instead of
|
|
156
|
+
// silently replacing it (the rule `ARAGON_MAX_TOKENS` above already follows).
|
|
157
|
+
const scrollResume = process.env.ARAGON_SCROLL_RESUME_MS?.trim();
|
|
158
|
+
if (scrollResume !== undefined && scrollResume.length > 0) {
|
|
159
|
+
const n = Number.parseInt(scrollResume, 10);
|
|
160
|
+
if (Number.isFinite(n) && n >= 0)
|
|
161
|
+
partial.scrollResumeMs = n;
|
|
162
|
+
}
|
|
130
163
|
// ARAGON_PLAN=1 starts the session in PLAN mode — the same channel story as
|
|
131
164
|
// ARAGON_FULLSCREEN, for terminals reached through a wrapper that owns argv.
|
|
132
165
|
const plan = process.env.ARAGON_PLAN?.trim().toLowerCase();
|
|
@@ -213,6 +246,46 @@ export function readEnvConfig() {
|
|
|
213
246
|
if (Object.keys(section).length > 0)
|
|
214
247
|
partial.todo = section;
|
|
215
248
|
}
|
|
249
|
+
// ARAGON_BASH_BACKGROUND=0 turns background services off entirely (no
|
|
250
|
+
// `background` param, no `bash_output`/`bash_kill`, no prompt block, no chip);
|
|
251
|
+
// ARAGON_BASH_AUTO_BACKGROUND=0 keeps them but stops the classifier firing on
|
|
252
|
+
// an unset `background`. Parsed by the POSITIVE list, exactly as
|
|
253
|
+
// ARAGON_FULLSCREEN / ARAGON_MOUSE / ARAGON_PLAN / ARAGON_TEAM / ARAGON_TODO
|
|
254
|
+
// are - NOT by `envBool` below, which uses a negative list.
|
|
255
|
+
//
|
|
256
|
+
// Both pass the test every env var in this file has to pass: an unattended run
|
|
257
|
+
// in a container with a fixed entrypoint can reach neither a flag nor a config
|
|
258
|
+
// file, and "do not leave a dev server running in my CI job" is exactly the
|
|
259
|
+
// kind of decision that channel needs to make.
|
|
260
|
+
//
|
|
261
|
+
// ONE ACCUMULATED SECTION, ASSIGNED ONCE - the shape the `team` and `todo`
|
|
262
|
+
// branches above already use, and NOT two `if` blocks each assigning
|
|
263
|
+
// `partial.bash` (the `todo` P1-4 trap). THE CAST IS WHAT WOULD MAKE THAT
|
|
264
|
+
// MISTAKE SILENT: a second assignment compiles clean and drops the first key,
|
|
265
|
+
// so `ARAGON_BASH_BACKGROUND=0 ARAGON_BASH_AUTO_BACKGROUND=0` would quietly
|
|
266
|
+
// re-register the tools the user turned off.
|
|
267
|
+
const bashBackground = process.env.ARAGON_BASH_BACKGROUND?.trim().toLowerCase();
|
|
268
|
+
const bashAuto = process.env.ARAGON_BASH_AUTO_BACKGROUND?.trim().toLowerCase();
|
|
269
|
+
if ((bashBackground !== undefined && bashBackground.length > 0) ||
|
|
270
|
+
(bashAuto !== undefined && bashAuto.length > 0)) {
|
|
271
|
+
const section = {};
|
|
272
|
+
if (bashBackground !== undefined && bashBackground.length > 0) {
|
|
273
|
+
section.background =
|
|
274
|
+
bashBackground === '1' ||
|
|
275
|
+
bashBackground === 'true' ||
|
|
276
|
+
bashBackground === 'on' ||
|
|
277
|
+
bashBackground === 'yes';
|
|
278
|
+
}
|
|
279
|
+
if (bashAuto !== undefined && bashAuto.length > 0) {
|
|
280
|
+
section.autoBackground =
|
|
281
|
+
bashAuto === '1' || bashAuto === 'true' || bashAuto === 'on' || bashAuto === 'yes';
|
|
282
|
+
}
|
|
283
|
+
// A PARTIAL section, safe only because every consumer deep-merges it - the
|
|
284
|
+
// same contract `partial.skills`, `partial.log`, `partial.team` and
|
|
285
|
+
// `partial.todo` rely on.
|
|
286
|
+
if (Object.keys(section).length > 0)
|
|
287
|
+
partial.bash = section;
|
|
288
|
+
}
|
|
216
289
|
// ARAGON_RETRY=0 is the kill switch for API retry; ARAGON_RETRY_MAX=<n>
|
|
217
290
|
// overrides the count. Parsed by the POSITIVE list, exactly as
|
|
218
291
|
// ARAGON_FULLSCREEN / ARAGON_MOUSE / ARAGON_PLAN / ARAGON_TEAM / ARAGON_TODO
|
|
@@ -289,6 +362,70 @@ export function readEnvConfig() {
|
|
|
289
362
|
if (Object.keys(section).length > 0)
|
|
290
363
|
partial.fast = section;
|
|
291
364
|
}
|
|
365
|
+
// ARAGON_COMPACTION=0 turns context compaction off; the other two tune it
|
|
366
|
+
// (context-auto-compaction §4.3). Parsed by the POSITIVE list, exactly as
|
|
367
|
+
// ARAGON_FULLSCREEN / ARAGON_MOUSE / ARAGON_PLAN / ARAGON_TEAM / ARAGON_TODO /
|
|
368
|
+
// ARAGON_RETRY / ARAGON_FAST are — NOT by `envBool` below, whose NEGATIVE list
|
|
369
|
+
// disagrees with it on values like `ARAGON_COMPACTION=disable`.
|
|
370
|
+
//
|
|
371
|
+
// THREE VARS, AND DELIBERATELY NO `ARAGON_COMPACTION_ON_FAILURE` /
|
|
372
|
+
// `_USE_FAST_TIER` / `_WARN_THRESHOLD`. The rule this file states is that an
|
|
373
|
+
// environment variable exists only where a flag AND a config file are BOTH
|
|
374
|
+
// unreachable — a container, an ssh session, being spawned by another tool.
|
|
375
|
+
// "Is it on, when does it fire, and how much does it keep" passes that test;
|
|
376
|
+
// "what should it do if the summarizer 500s" does not, and every key that fails
|
|
377
|
+
// it is documentation debt plus a fifth place for the value to disagree with
|
|
378
|
+
// itself.
|
|
379
|
+
//
|
|
380
|
+
// ONE ACCUMULATED SECTION, ASSIGNED ONCE — the shape the four branches above
|
|
381
|
+
// all use, and NOT three `if` blocks each assigning `partial.compaction`. THE
|
|
382
|
+
// CAST IS WHAT WOULD MAKE THAT MISTAKE SILENT: a second assignment compiles
|
|
383
|
+
// clean and drops `enabled`.
|
|
384
|
+
const compaction = process.env.ARAGON_COMPACTION?.trim().toLowerCase();
|
|
385
|
+
const compactionThreshold = process.env.ARAGON_COMPACTION_THRESHOLD?.trim();
|
|
386
|
+
const compactionKeepTurns = process.env.ARAGON_COMPACTION_KEEP_TURNS?.trim();
|
|
387
|
+
// The two hardening kill switches (context-auto-compaction-hardening §4.3).
|
|
388
|
+
// They pass the same test the three above do: both name a behaviour that a
|
|
389
|
+
// container or an automated harness may need to switch off with no flag and no
|
|
390
|
+
// config file in reach - sub-agent compaction because it changes what a
|
|
391
|
+
// dispatch costs, and the archive because it writes conversation content to
|
|
392
|
+
// disk in an environment that may not permit it.
|
|
393
|
+
const compactionSubagents = process.env.ARAGON_COMPACTION_SUBAGENTS?.trim().toLowerCase();
|
|
394
|
+
const compactionArchive = process.env.ARAGON_COMPACTION_ARCHIVE?.trim().toLowerCase();
|
|
395
|
+
const positive = (v) => v === '1' || v === 'true' || v === 'on' || v === 'yes';
|
|
396
|
+
if ((compaction !== undefined && compaction.length > 0) ||
|
|
397
|
+
(compactionThreshold !== undefined && compactionThreshold.length > 0) ||
|
|
398
|
+
(compactionKeepTurns !== undefined && compactionKeepTurns.length > 0) ||
|
|
399
|
+
(compactionSubagents !== undefined && compactionSubagents.length > 0) ||
|
|
400
|
+
(compactionArchive !== undefined && compactionArchive.length > 0)) {
|
|
401
|
+
const section = {};
|
|
402
|
+
if (compaction !== undefined && compaction.length > 0) {
|
|
403
|
+
section.enabled = positive(compaction);
|
|
404
|
+
}
|
|
405
|
+
if (compactionSubagents !== undefined && compactionSubagents.length > 0) {
|
|
406
|
+
section.subagents = positive(compactionSubagents);
|
|
407
|
+
}
|
|
408
|
+
if (compactionArchive !== undefined && compactionArchive.length > 0) {
|
|
409
|
+
section.archive = positive(compactionArchive);
|
|
410
|
+
}
|
|
411
|
+
if (compactionThreshold !== undefined && compactionThreshold.length > 0) {
|
|
412
|
+
// Left ABSENT on a bad value rather than clamped to a default, so a typo
|
|
413
|
+
// falls through to the config layer instead of masking it for the session.
|
|
414
|
+
const parsed = parseThresholdInput(compactionThreshold);
|
|
415
|
+
if (parsed !== null)
|
|
416
|
+
section.threshold = parsed;
|
|
417
|
+
}
|
|
418
|
+
if (compactionKeepTurns !== undefined && compactionKeepTurns.length > 0) {
|
|
419
|
+
const n = Number.parseInt(compactionKeepTurns, 10);
|
|
420
|
+
if (Number.isFinite(n) && n > 0)
|
|
421
|
+
section.keepRecentTurns = n;
|
|
422
|
+
}
|
|
423
|
+
// A PARTIAL section, safe only because every consumer deep-merges it — the
|
|
424
|
+
// same contract the five sections above rely on.
|
|
425
|
+
if (Object.keys(section).length > 0) {
|
|
426
|
+
partial.compaction = section;
|
|
427
|
+
}
|
|
428
|
+
}
|
|
292
429
|
// ARAGON_UPDATE=0|off|false turns auto-update off; `notify` reports without
|
|
293
430
|
// installing; 1|on|true|yes turns it on (cli-auto-update §4.2).
|
|
294
431
|
//
|
package/dist/config/load.d.ts
CHANGED
|
@@ -36,6 +36,30 @@ export interface CliFlags {
|
|
|
36
36
|
liveToolOutput?: boolean;
|
|
37
37
|
/** `--mouse` ⇒ true, `--no-mouse` ⇒ false, absent ⇒ undefined. */
|
|
38
38
|
mouse?: boolean;
|
|
39
|
+
/**
|
|
40
|
+
* `--mouse-select` ⇒ true, `--no-mouse-select` ⇒ false, absent ⇒ undefined
|
|
41
|
+
* (tui-selection-and-scroll-follow §6.1).
|
|
42
|
+
*
|
|
43
|
+
* DECLARED AS A PAIR, and carried through `toFlags`, for the reason the
|
|
44
|
+
* `mouse` note above it records: a flag that reaches neither `CliFlags` nor
|
|
45
|
+
* `toFlags` is inert with no compile error and no runtime error. `mouseSelect`
|
|
46
|
+
* is additionally PERSISTED and defaults to `true`, so a lone
|
|
47
|
+
* `--no-mouse-select` would make commander default `opts.mouseSelect` to
|
|
48
|
+
* `true` — indistinguishable from silence, and silently overriding a stored
|
|
49
|
+
* `false` on every run (the `--todo-panel` trap).
|
|
50
|
+
*/
|
|
51
|
+
mouseSelect?: boolean;
|
|
52
|
+
/**
|
|
53
|
+
* `--paste` ⇒ true, `--no-paste` ⇒ false, absent ⇒ undefined
|
|
54
|
+
* (tui-paste-handling section 7.1).
|
|
55
|
+
*
|
|
56
|
+
* DECLARED AS A PAIR, and carried through `toFlags`, for the reason the two
|
|
57
|
+
* notes above record. `paste` is additionally PERSISTED and defaults to
|
|
58
|
+
* `true`, so a lone `--no-paste` would make commander default `opts.paste` to
|
|
59
|
+
* `true` -- indistinguishable from silence, and silently overriding a stored
|
|
60
|
+
* `false` on every run that passed no flag at all.
|
|
61
|
+
*/
|
|
62
|
+
paste?: boolean;
|
|
39
63
|
/** `--no-skills` ⇒ false. Turns the whole skill subsystem off (§7.5). */
|
|
40
64
|
skills?: boolean;
|
|
41
65
|
/** `--skill <name>` ×N — force Level 2 injection for this run. */
|
|
@@ -178,6 +202,24 @@ export interface CliFlags {
|
|
|
178
202
|
* config file and `ARAGON_UPDATE=notify`.
|
|
179
203
|
*/
|
|
180
204
|
update?: boolean;
|
|
205
|
+
/**
|
|
206
|
+
* `--compaction` ⇒ true, `--no-compaction` ⇒ false, absent ⇒ undefined
|
|
207
|
+
* (context-auto-compaction §4.3).
|
|
208
|
+
*
|
|
209
|
+
* DECLARED AS A PAIR — MANDATORY (C-13 / P1-5), for the reason `--team`,
|
|
210
|
+
* `--todo-panel`, `--render-governor`, `--retry`, `--fast` and `--update` each
|
|
211
|
+
* record in turn, and this one shares the WORST polarity with `--update`:
|
|
212
|
+
* `compaction.enabled` is PERSISTED and defaults to `true`, so a lone
|
|
213
|
+
* `--no-compaction` would make commander default `opts.compaction` to `true`,
|
|
214
|
+
* at which point the flag is indistinguishable from its own default and
|
|
215
|
+
* silently overwrites a stored `false` on EVERY run that passed no flag at all.
|
|
216
|
+
*
|
|
217
|
+
* That would make R-12's whole mitigation ("one config key restores the old
|
|
218
|
+
* behaviour exactly") FALSE — for a feature that spends the user's money.
|
|
219
|
+
*/
|
|
220
|
+
compaction?: boolean;
|
|
221
|
+
/** `--compaction-threshold <0..1|N%>` — session override for `threshold`. */
|
|
222
|
+
compactionThreshold?: string;
|
|
181
223
|
}
|
|
182
224
|
/**
|
|
183
225
|
* Resolve the effective config by merging all layers, then derive the runtime
|
package/dist/config/load.js
CHANGED
|
@@ -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, clampFastConfig, clampRetryConfig, clampSkillsConfig, clampTeamConfig, clampTodoConfig, clampUpdateConfig, clampTheme, clampThinkingLevel, clampMaxTokens, clampMaxRenderInterval, clampTranscriptRetain, clampTranscriptWindow, coercePositiveInt, isAutoToken, isSkillsToolPolicyMode, } from './schema.js';
|
|
9
|
+
import { DEFAULT_CONFIG, IDLE_TIMEOUT_MARGIN_MS, clampAskRounds, clampDensity, clampHumanTimeout, clampCompactionConfig, clampLogConfig, clampFastConfig, clampRetryConfig, clampSkillsConfig, clampTeamConfig, clampTodoConfig, clampBashConfig, clampUpdateConfig, clampTheme, clampThinkingLevel, clampMaxTokens, clampMaxRenderInterval, clampScrollResumeMs, clampTranscriptRetain, clampTranscriptWindow, coercePositiveInt, isAutoToken, isSkillsToolPolicyMode, parseThresholdInput, } 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';
|
|
@@ -59,6 +59,56 @@ function resolveMouse(flags, env, file) {
|
|
|
59
59
|
return file.mouse;
|
|
60
60
|
return DEFAULT_CONFIG.mouse;
|
|
61
61
|
}
|
|
62
|
+
/**
|
|
63
|
+
* Drag-select: flag › env › file › default `true`
|
|
64
|
+
* (tui-selection-and-scroll-follow §6.1).
|
|
65
|
+
*
|
|
66
|
+
* SHAPED EXACTLY LIKE `resolveMouse` above, deliberately and not by copy-paste
|
|
67
|
+
* habit: it has the same four layers, the same "a persisted `true` is a value
|
|
68
|
+
* and not an opinion" property, and the same env var story. Reaching for the
|
|
69
|
+
* `hints` shape instead — `flags.x !== undefined ? … : file.x ?? DEFAULT`, which
|
|
70
|
+
* reads NO ENV AT ALL — would ship `ARAGON_MOUSE_SELECT` as documented-but-dead,
|
|
71
|
+
* which is precisely the failure the note above `resolveMouse` records for
|
|
72
|
+
* `ARAGON_MOUSE`.
|
|
73
|
+
*/
|
|
74
|
+
function resolveMouseSelect(flags, env, file) {
|
|
75
|
+
if (flags.mouseSelect !== undefined)
|
|
76
|
+
return flags.mouseSelect;
|
|
77
|
+
if (env.mouseSelect !== undefined)
|
|
78
|
+
return env.mouseSelect;
|
|
79
|
+
if (file.mouseSelect !== undefined)
|
|
80
|
+
return file.mouseSelect;
|
|
81
|
+
return DEFAULT_CONFIG.mouseSelect;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Paste handling: flag > env > file > default `true` (tui-paste-handling
|
|
85
|
+
* section 7.4).
|
|
86
|
+
*
|
|
87
|
+
* SHAPED EXACTLY LIKE `resolveMouse` above, for the reason its own note gives:
|
|
88
|
+
* reaching for the `hints` shape -- `flags.x !== undefined ? ... : file.x ??
|
|
89
|
+
* DEFAULT`, which reads NO ENV AT ALL -- would ship `ARAGON_PASTE` as
|
|
90
|
+
* documented-but-dead.
|
|
91
|
+
*/
|
|
92
|
+
function resolvePaste(flags, env, file) {
|
|
93
|
+
if (flags.paste !== undefined)
|
|
94
|
+
return flags.paste;
|
|
95
|
+
if (env.paste !== undefined)
|
|
96
|
+
return env.paste;
|
|
97
|
+
if (file.paste !== undefined)
|
|
98
|
+
return file.paste;
|
|
99
|
+
return DEFAULT_CONFIG.paste;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Idle scroll-resume delay: env › file › default 5000, clamped to [0, 120000].
|
|
103
|
+
*
|
|
104
|
+
* NO FLAG LAYER, and the absence is the design rather than an omission (§6.1):
|
|
105
|
+
* this key has no `--scroll-resume-ms`, so `CliFlags` carries no field for one
|
|
106
|
+
* and a resolver that read it would be reading a value nothing can ever set.
|
|
107
|
+
*/
|
|
108
|
+
function resolveScrollResumeMs(env, file) {
|
|
109
|
+
const raw = env.scrollResumeMs ?? file.scrollResumeMs;
|
|
110
|
+
return clampScrollResumeMs(raw, DEFAULT_CONFIG.scrollResumeMs);
|
|
111
|
+
}
|
|
62
112
|
/**
|
|
63
113
|
* Resolve whether logs reach a file: flag › env › an explicit `false` in the
|
|
64
114
|
* file › default `true`.
|
|
@@ -121,6 +171,24 @@ function resolveTodoConfig(flags, env, file) {
|
|
|
121
171
|
...(flags.todoFollow !== undefined ? { followThrough: flags.todoFollow } : {}),
|
|
122
172
|
});
|
|
123
173
|
}
|
|
174
|
+
/**
|
|
175
|
+
* Merge the `bash` section across the three layers that supply it
|
|
176
|
+
* (defaults > file > env), background-service-supervision §5.4.
|
|
177
|
+
*
|
|
178
|
+
* THREE LAYERS, NOT FOUR, AND THAT IS NOT AN OVERSIGHT. There is deliberately no
|
|
179
|
+
* `--no-background` flag: the two switches this section carries are already
|
|
180
|
+
* reachable from `config.json` (a per-machine preference) and from the
|
|
181
|
+
* environment (the channel a container entrypoint has), which is the two-part
|
|
182
|
+
* test every knob in this file is held to. A third spelling would be a third
|
|
183
|
+
* place for the answer to differ.
|
|
184
|
+
*/
|
|
185
|
+
function resolveBashConfig(env, file) {
|
|
186
|
+
return clampBashConfig({
|
|
187
|
+
...DEFAULT_CONFIG.bash,
|
|
188
|
+
...(file.bash ?? {}),
|
|
189
|
+
...(env.bash ?? {}),
|
|
190
|
+
});
|
|
191
|
+
}
|
|
124
192
|
/**
|
|
125
193
|
* Merge the `retry` section across all four layers (defaults › file › env ›
|
|
126
194
|
* flags), llm-api-retry-backoff §6.2.
|
|
@@ -208,6 +276,33 @@ function resolveUpdateConfig(flags, env, file) {
|
|
|
208
276
|
...(flags.update !== undefined ? { mode: flags.update ? 'auto' : 'off' } : {}),
|
|
209
277
|
});
|
|
210
278
|
}
|
|
279
|
+
/**
|
|
280
|
+
* Merge the `compaction` section across all four layers (defaults › file › env ›
|
|
281
|
+
* flags), context-auto-compaction §4.3.
|
|
282
|
+
*
|
|
283
|
+
* `!== undefined` ON `flags.compaction`, WHICH IS THE WHOLE POINT (C-13 / P1-5).
|
|
284
|
+
* The rule `resolveTeamConfig`, `resolveTodoConfig`, `resolveRetryConfig`,
|
|
285
|
+
* `resolveFastConfig` and `resolveUpdateConfig` each state once: commander
|
|
286
|
+
* materialises a lone `--no-compaction` as `opts.compaction = true` when the flag
|
|
287
|
+
* is absent, so a truthiness check cannot tell `--no-compaction` from "not
|
|
288
|
+
* passed" — and here the damage runs in the worst direction, silently re-enabling
|
|
289
|
+
* a subsystem the user turned off, on every flagless run, for a feature that
|
|
290
|
+
* spends money.
|
|
291
|
+
*
|
|
292
|
+
* `--compaction-threshold` is PARSED rather than spread, because `90%` and `0.9`
|
|
293
|
+
* are both legitimate spellings and a typo must change NOTHING rather than
|
|
294
|
+
* resolve to a default (`parseThresholdInput` returns `null`).
|
|
295
|
+
*/
|
|
296
|
+
function resolveCompactionConfig(flags, env, file) {
|
|
297
|
+
const thresholdFlag = flags.compactionThreshold !== undefined ? parseThresholdInput(flags.compactionThreshold) : null;
|
|
298
|
+
return clampCompactionConfig({
|
|
299
|
+
...DEFAULT_CONFIG.compaction,
|
|
300
|
+
...(file.compaction ?? {}),
|
|
301
|
+
...(env.compaction ?? {}),
|
|
302
|
+
...(flags.compaction !== undefined ? { enabled: flags.compaction } : {}),
|
|
303
|
+
...(thresholdFlag !== null ? { threshold: thresholdFlag } : {}),
|
|
304
|
+
});
|
|
305
|
+
}
|
|
211
306
|
/**
|
|
212
307
|
* Resolve the adaptive render governor: flag › env › file › default `true`
|
|
213
308
|
* (tui-render-performance L4).
|
|
@@ -460,6 +555,9 @@ export function loadConfig(flags = {}) {
|
|
|
460
555
|
density,
|
|
461
556
|
hints,
|
|
462
557
|
mouse: resolveMouse(flags, env.partial, file),
|
|
558
|
+
mouseSelect: resolveMouseSelect(flags, env.partial, file),
|
|
559
|
+
paste: resolvePaste(flags, env.partial, file),
|
|
560
|
+
scrollResumeMs: resolveScrollResumeMs(env.partial, file),
|
|
463
561
|
// From `<home>/state.json`, not the config file — see `ui-state.ts`.
|
|
464
562
|
submitCount: readSubmitCount(),
|
|
465
563
|
startInPlanMode,
|
|
@@ -483,6 +581,8 @@ export function loadConfig(flags = {}) {
|
|
|
483
581
|
retry: resolveRetryConfig(flags, env.partial, file),
|
|
484
582
|
fast: resolveFastConfig(flags, env.partial, file),
|
|
485
583
|
update: resolveUpdateConfig(flags, env.partial, file),
|
|
584
|
+
compaction: resolveCompactionConfig(flags, env.partial, file),
|
|
585
|
+
bash: resolveBashConfig(env.partial, file),
|
|
486
586
|
cwd,
|
|
487
587
|
color,
|
|
488
588
|
colorLevel,
|