@aragon-agent/cli 0.5.9 → 0.5.11
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 +1157 -1026
- package/README.md +123 -0
- package/dist/boot/guard.d.ts +135 -0
- package/dist/boot/guard.js +218 -0
- package/dist/boot/rollback.d.ts +86 -0
- package/dist/boot/rollback.js +185 -0
- package/dist/cli.js +376 -2
- package/dist/commands/builtins.js +118 -0
- package/dist/commands/perf.d.ts +5 -1
- package/dist/commands/perf.js +43 -1
- package/dist/commands/registry.d.ts +17 -0
- package/dist/config/app-paths.d.ts +31 -0
- package/dist/config/app-paths.js +37 -0
- package/dist/config/cli-commands.d.ts +27 -1
- package/dist/config/cli-commands.js +51 -2
- package/dist/config/env.d.ts +11 -1
- package/dist/config/env.js +58 -1
- package/dist/config/load.d.ts +30 -0
- package/dist/config/load.js +56 -1
- package/dist/config/schema.d.ts +91 -0
- package/dist/config/schema.js +107 -0
- package/dist/config/store.js +13 -1
- package/dist/launcher.d.ts +14 -0
- package/dist/launcher.js +43 -0
- package/dist/logging/logger.d.ts +1 -1
- package/dist/ui/App.d.ts +11 -1
- package/dist/ui/App.js +88 -2
- package/dist/ui/BottomStatusRow.d.ts +25 -3
- package/dist/ui/BottomStatusRow.js +10 -7
- package/dist/ui/PromptInput.d.ts +10 -0
- package/dist/ui/PromptInput.js +41 -48
- package/dist/ui/UpdateLine.d.ts +44 -0
- package/dist/ui/UpdateLine.js +129 -0
- package/dist/ui/editor-reducer.d.ts +62 -0
- package/dist/ui/editor-reducer.js +90 -0
- package/dist/ui/frame-differ.d.ts +95 -0
- package/dist/ui/frame-differ.js +230 -0
- package/dist/ui/stdout-frame-writer.d.ts +41 -0
- package/dist/ui/stdout-frame-writer.js +102 -0
- package/dist/update/classify-failure.d.ts +32 -0
- package/dist/update/classify-failure.js +60 -0
- package/dist/update/install-lock.d.ts +55 -0
- package/dist/update/install-lock.js +184 -0
- package/dist/update/install-source.d.ts +97 -0
- package/dist/update/install-source.js +218 -0
- package/dist/update/installer.d.ts +108 -0
- package/dist/update/installer.js +242 -0
- package/dist/update/limits.d.ts +111 -0
- package/dist/update/limits.js +111 -0
- package/dist/update/npm-view.d.ts +62 -0
- package/dist/update/npm-view.js +133 -0
- package/dist/update/registry.d.ts +52 -0
- package/dist/update/registry.js +161 -0
- package/dist/update/semver.d.ts +89 -0
- package/dist/update/semver.js +295 -0
- package/dist/update/service.d.ts +193 -0
- package/dist/update/service.js +636 -0
- package/dist/update/state.d.ts +103 -0
- package/dist/update/state.js +142 -0
- package/dist/update/types.d.ts +169 -0
- package/dist/update/types.js +68 -0
- package/package.json +3 -3
package/dist/commands/perf.js
CHANGED
|
@@ -30,10 +30,51 @@ let resetGovernor = null;
|
|
|
30
30
|
export function setPerfResetHook(fn) {
|
|
31
31
|
resetGovernor = fn;
|
|
32
32
|
}
|
|
33
|
+
/**
|
|
34
|
+
* Frame-writer counters (tui-input-flicker-fix §5.4).
|
|
35
|
+
*
|
|
36
|
+
* A SECOND MODULE-LEVEL SLOT rather than a prop on `App`, and that is this
|
|
37
|
+
* file's own documented convention rather than a shortcut: the writer is built
|
|
38
|
+
* in `runInteractive`, lives entirely outside React, and its counters never
|
|
39
|
+
* render — so routing them through a 1900-line component's props would buy
|
|
40
|
+
* nothing and cost `App.tsx` plus `app.test.tsx` churn (P1-2).
|
|
41
|
+
*
|
|
42
|
+
* `null` means the writer was never built — `--no-diff-render`, inline mode, or
|
|
43
|
+
* a non-interactive path. `/perf` says so in words, so "the flag is off" and
|
|
44
|
+
* "the writer crashed" never look alike.
|
|
45
|
+
*/
|
|
46
|
+
let frameStats = null;
|
|
47
|
+
/** Called by `cli.tsx` after building the writer. Passing `null` detaches. */
|
|
48
|
+
export function setFrameStatsProvider(fn) {
|
|
49
|
+
frameStats = fn;
|
|
50
|
+
}
|
|
51
|
+
export function readFrameStats() {
|
|
52
|
+
return frameStats ? frameStats() : null;
|
|
53
|
+
}
|
|
33
54
|
function mb(bytes) {
|
|
34
55
|
return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
|
|
35
56
|
}
|
|
36
|
-
|
|
57
|
+
function ratio(total, frames) {
|
|
58
|
+
return frames > 0 ? (total / frames).toFixed(1) : '0.0';
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* The writer line (§5.4), in this function's existing ASCII separator shape.
|
|
62
|
+
*
|
|
63
|
+
* `fallbacks > 0` on a healthy session is the single most useful diagnostic this
|
|
64
|
+
* feature can emit: it means something wrote to stdout behind Ink's back and
|
|
65
|
+
* absolute addressing lost its origin.
|
|
66
|
+
*/
|
|
67
|
+
function formatWriterLine() {
|
|
68
|
+
const stats = readFrameStats();
|
|
69
|
+
if (!stats)
|
|
70
|
+
return 'writer full - diff render off';
|
|
71
|
+
const bytesPerFrame = stats.framesTotal > 0 ? Math.round(stats.bytesWritten / stats.framesTotal) : 0;
|
|
72
|
+
return (`writer diff - frames ${stats.framesTotal} ` +
|
|
73
|
+
`(diffed ${stats.framesDiffed}, full ${stats.framesFull}) - ` +
|
|
74
|
+
`lines/frame ${ratio(stats.linesWritten, stats.framesTotal)} - ` +
|
|
75
|
+
`bytes/frame ${bytesPerFrame} - fallbacks ${stats.fallbacks}`);
|
|
76
|
+
}
|
|
77
|
+
/** Format a snapshot as the six-line block documented in §5.4. */
|
|
37
78
|
export function formatPerfReport(snap) {
|
|
38
79
|
const caches = renderCacheStats();
|
|
39
80
|
const eco = snap.rung > 0 ? ' - eco' : '';
|
|
@@ -49,6 +90,7 @@ export function formatPerfReport(snap) {
|
|
|
49
90
|
`hl ${caches.highlightEntries} (${mb(caches.highlightBytes)}) - ` +
|
|
50
91
|
`lines ${caches.lineEntries}`,
|
|
51
92
|
`mode ${snap.mode} - viewport ${snap.viewportRows} rows - offset ${snap.offset}`,
|
|
93
|
+
formatWriterLine(),
|
|
52
94
|
].join('\n');
|
|
53
95
|
}
|
|
54
96
|
export const perfCommand = {
|
|
@@ -7,6 +7,7 @@ import type { AgentMode } from '../agent/agent-mode.js';
|
|
|
7
7
|
import type { NoticeLevel, Overlay, ToastLevel, ViewAction, ViewState } from '../agent/reducer.js';
|
|
8
8
|
import type { PersistedConfig } from '../config/schema.js';
|
|
9
9
|
import type { FollowThroughBudget } from '../todo/follow-through.js';
|
|
10
|
+
import type { UpdateCommandPort } from '../update/types.js';
|
|
10
11
|
export interface CommandContext {
|
|
11
12
|
/** Raw argument string after the command word (may be empty). */
|
|
12
13
|
args: string;
|
|
@@ -52,6 +53,22 @@ export interface CommandContext {
|
|
|
52
53
|
* change; absent means the clause degrades to naming the ceiling alone.
|
|
53
54
|
*/
|
|
54
55
|
followBudget?: FollowThroughBudget;
|
|
56
|
+
/**
|
|
57
|
+
* The updater, when this session has one (cli-auto-update §4.4 / C-14 / P0-2).
|
|
58
|
+
*
|
|
59
|
+
* `/fast`, `/team` and `/todo` reach their subsystems through `controller`,
|
|
60
|
+
* because those subsystems live on `AgentController`. This one does not, and
|
|
61
|
+
* by §3.1 it MUST NOT — `update/` may not import `agent/` — so it needs its
|
|
62
|
+
* own field, and this is the only seam a slash command has.
|
|
63
|
+
*
|
|
64
|
+
* OPTIONAL, for two independent reasons. The service is legitimately absent
|
|
65
|
+
* under `update.mode: 'off'`, on a non-TTY and in CI (§3.8), so `/update` has
|
|
66
|
+
* to have something honest to say when it is missing; and a REQUIRED field
|
|
67
|
+
* would break every existing `CommandContext` fixture in this package at
|
|
68
|
+
* compile time, for a feature none of them are about. `followBudget` above is
|
|
69
|
+
* the precedent for an optional, read-at-command-time member.
|
|
70
|
+
*/
|
|
71
|
+
update?: UpdateCommandPort;
|
|
55
72
|
/** Rebuild the system prompt and the dynamic command list after a skill change. */
|
|
56
73
|
refreshSkills: () => void;
|
|
57
74
|
/**
|
|
@@ -14,6 +14,9 @@
|
|
|
14
14
|
* ├── config.json.bak `aragon config edit` pre-edit backup
|
|
15
15
|
* ├── prompt-history.jsonl submitted prompts, append-only (0600 on POSIX)
|
|
16
16
|
* ├── state.json UI bookkeeping scalars (0600 on POSIX)
|
|
17
|
+
* ├── update-state.json auto-update coordination (0600 on POSIX)
|
|
18
|
+
* ├── update-install.lock held by the running `npm i -g` child
|
|
19
|
+
* ├── update-install.log that child's stdout+stderr; unlinked on exit
|
|
17
20
|
* ├── logs/ JSONL logs (0700 on POSIX)
|
|
18
21
|
* ├── sessions/ /save · /resume
|
|
19
22
|
* ├── skills/ `aragon skills install` target
|
|
@@ -79,6 +82,34 @@ export declare function getConfigBackupPath(): string;
|
|
|
79
82
|
export declare function getPromptHistoryPath(): string;
|
|
80
83
|
/** `<home>/state.json` — UI bookkeeping scalars only; see `ui-state.ts`. */
|
|
81
84
|
export declare function getUiStatePath(): string;
|
|
85
|
+
/**
|
|
86
|
+
* `<home>/update-state.json` — cross-process auto-update coordination
|
|
87
|
+
* (cli-auto-update §5.2).
|
|
88
|
+
*
|
|
89
|
+
* Deliberately NOT inside `state.json`: that file is documented as UI
|
|
90
|
+
* bookkeeping scalars only (C-6), and this is coordination state that a SECOND
|
|
91
|
+
* aragon process reads to decide whether anyone has already asked the registry.
|
|
92
|
+
* Different lifetime, different failure policy, different reader.
|
|
93
|
+
*/
|
|
94
|
+
export declare function getUpdateStatePath(): string;
|
|
95
|
+
/**
|
|
96
|
+
* `<home>/update-install.lock` — the `wx` lock the running installer child holds
|
|
97
|
+
* (cli-auto-update §3.7).
|
|
98
|
+
*
|
|
99
|
+
* A FILE, and a direct child of the root, for the reason the two files above
|
|
100
|
+
* are: `logs/`, `sessions/` and `skills/` are all scan roots, and every extra
|
|
101
|
+
* file inside one is another thing each walk has to recognise and skip.
|
|
102
|
+
*/
|
|
103
|
+
export declare function getUpdateLockPath(): string;
|
|
104
|
+
/**
|
|
105
|
+
* `<home>/update-install.log` — the installer child's stdout+stderr
|
|
106
|
+
* (cli-auto-update §3.5 / U-5).
|
|
107
|
+
*
|
|
108
|
+
* A REAL FILE and not a pipe: the child is detached and outlives the parent
|
|
109
|
+
* (D-10), and a pipe whose parent has exited takes EPIPE on the next write. The
|
|
110
|
+
* parent tails it on the child's exit, redacts, logs, and unlinks.
|
|
111
|
+
*/
|
|
112
|
+
export declare function getUpdateInstallLogPath(): string;
|
|
82
113
|
export declare function getLogsDir(): string;
|
|
83
114
|
export declare function getSessionsDir(): string;
|
|
84
115
|
/** `<home>` — parent of `skills/`, and where sidecar state such as usage lives. */
|
package/dist/config/app-paths.js
CHANGED
|
@@ -14,6 +14,9 @@
|
|
|
14
14
|
* ├── config.json.bak `aragon config edit` pre-edit backup
|
|
15
15
|
* ├── prompt-history.jsonl submitted prompts, append-only (0600 on POSIX)
|
|
16
16
|
* ├── state.json UI bookkeeping scalars (0600 on POSIX)
|
|
17
|
+
* ├── update-state.json auto-update coordination (0600 on POSIX)
|
|
18
|
+
* ├── update-install.lock held by the running `npm i -g` child
|
|
19
|
+
* ├── update-install.log that child's stdout+stderr; unlinked on exit
|
|
17
20
|
* ├── logs/ JSONL logs (0700 on POSIX)
|
|
18
21
|
* ├── sessions/ /save · /resume
|
|
19
22
|
* ├── skills/ `aragon skills install` target
|
|
@@ -140,6 +143,40 @@ export function getPromptHistoryPath() {
|
|
|
140
143
|
export function getUiStatePath() {
|
|
141
144
|
return join(resolution.root, 'state.json');
|
|
142
145
|
}
|
|
146
|
+
/**
|
|
147
|
+
* `<home>/update-state.json` — cross-process auto-update coordination
|
|
148
|
+
* (cli-auto-update §5.2).
|
|
149
|
+
*
|
|
150
|
+
* Deliberately NOT inside `state.json`: that file is documented as UI
|
|
151
|
+
* bookkeeping scalars only (C-6), and this is coordination state that a SECOND
|
|
152
|
+
* aragon process reads to decide whether anyone has already asked the registry.
|
|
153
|
+
* Different lifetime, different failure policy, different reader.
|
|
154
|
+
*/
|
|
155
|
+
export function getUpdateStatePath() {
|
|
156
|
+
return join(resolution.root, 'update-state.json');
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* `<home>/update-install.lock` — the `wx` lock the running installer child holds
|
|
160
|
+
* (cli-auto-update §3.7).
|
|
161
|
+
*
|
|
162
|
+
* A FILE, and a direct child of the root, for the reason the two files above
|
|
163
|
+
* are: `logs/`, `sessions/` and `skills/` are all scan roots, and every extra
|
|
164
|
+
* file inside one is another thing each walk has to recognise and skip.
|
|
165
|
+
*/
|
|
166
|
+
export function getUpdateLockPath() {
|
|
167
|
+
return join(resolution.root, 'update-install.lock');
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* `<home>/update-install.log` — the installer child's stdout+stderr
|
|
171
|
+
* (cli-auto-update §3.5 / U-5).
|
|
172
|
+
*
|
|
173
|
+
* A REAL FILE and not a pipe: the child is detached and outlives the parent
|
|
174
|
+
* (D-10), and a pipe whose parent has exited takes EPIPE on the next write. The
|
|
175
|
+
* parent tails it on the child's exit, redacts, logs, and unlinks.
|
|
176
|
+
*/
|
|
177
|
+
export function getUpdateInstallLogPath() {
|
|
178
|
+
return join(resolution.root, 'update-install.log');
|
|
179
|
+
}
|
|
143
180
|
export function getLogsDir() {
|
|
144
181
|
return join(resolution.root, 'logs');
|
|
145
182
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `aragon config get | list | edit | home`, plus the `log.*`, `team.*`,
|
|
3
|
-
* `retry.*` and `
|
|
3
|
+
* `retry.*`, `fast.*` and `update.*` branches of `config set`.
|
|
4
4
|
*
|
|
5
5
|
* These live here rather than in `cli.tsx` because `runConfigSet` is already a
|
|
6
6
|
* 21-case switch — well past the complexity ceiling this package writes down —
|
|
@@ -43,6 +43,17 @@ export declare const RETRY_CONFIG_SET_KEYS: readonly ["retry.enabled", "retry.ma
|
|
|
43
43
|
* `Set fast.model = haiku`.
|
|
44
44
|
*/
|
|
45
45
|
export declare const FAST_CONFIG_SET_KEYS: readonly ["fast.enabled", "fast.provider", "fast.model", "fast.baseUrl", "fast.thinkingLevel", "fast.delegate", "fast.review", "fast.reviewEveryTurns", "fast.reviewContextTurns", "fast.reviewMaxChars", "fast.reviewMaxPerSession"];
|
|
46
|
+
/**
|
|
47
|
+
* Config keys under `update.` that `aragon config set` accepts (cli-auto-update
|
|
48
|
+
* §4.1).
|
|
49
|
+
*
|
|
50
|
+
* A DEDICATED SETTER RATHER THAN A GENERIC DOTTED WRITER, for the reason the
|
|
51
|
+
* four sets above each record: a generic setter would write `update` as a FLAT
|
|
52
|
+
* string key (`"update.mode": "notify"` at the top level of the file), the
|
|
53
|
+
* section would silently never take effect, and `config set` would still print
|
|
54
|
+
* `Set update.mode = notify`.
|
|
55
|
+
*/
|
|
56
|
+
export declare const UPDATE_CONFIG_SET_KEYS: readonly ["update.mode", "update.checkIntervalMs", "update.registry", "update.distTag"];
|
|
46
57
|
/**
|
|
47
58
|
* Translate a `log.*` dotted key into a patch, or `null` for anything else.
|
|
48
59
|
*
|
|
@@ -94,6 +105,21 @@ export declare function applyRetryConfigSet(key: string, value: string): Partial
|
|
|
94
105
|
* the clamped 50 while the caller echoes the STORED value (AC-13).
|
|
95
106
|
*/
|
|
96
107
|
export declare function applyFastConfigSet(key: string, value: string): Partial<PersistedConfig> | null;
|
|
108
|
+
/**
|
|
109
|
+
* Translate an `update.*` dotted key into a patch, or `null` for anything else.
|
|
110
|
+
*
|
|
111
|
+
* The patch is a PARTIAL `update` section, safe only because
|
|
112
|
+
* `updatePersistedConfig` deep-merges that section — with a shallow merge,
|
|
113
|
+
* setting the mode would silently reset the interval, the registry mirror and
|
|
114
|
+
* the dist-tag (C-4 / R-10).
|
|
115
|
+
*
|
|
116
|
+
* EVERY KEY ROUTES THROUGH `clampUpdateConfig`, not through a local parse, for
|
|
117
|
+
* the reason `applyRetryConfigSet` and `applyFastConfigSet` both record: one
|
|
118
|
+
* gate for both directions means no key here can pick up a different coercion
|
|
119
|
+
* later, and `config set update.checkIntervalMs 5` writes the clamped 900000
|
|
120
|
+
* while the caller echoes the STORED value (AC-20).
|
|
121
|
+
*/
|
|
122
|
+
export declare function applyUpdateConfigSet(key: string, value: string): Partial<PersistedConfig> | null;
|
|
97
123
|
/**
|
|
98
124
|
* `log.redactSecrets false` is the one setting that lets credentials reach the
|
|
99
125
|
* disk. It is command-line-only (there is no settings-screen entry) and it says
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `aragon config get | list | edit | home`, plus the `log.*`, `team.*`,
|
|
3
|
-
* `retry.*` and `
|
|
3
|
+
* `retry.*`, `fast.*` and `update.*` branches of `config set`.
|
|
4
4
|
*
|
|
5
5
|
* These live here rather than in `cli.tsx` because `runConfigSet` is already a
|
|
6
6
|
* 21-case switch — well past the complexity ceiling this package writes down —
|
|
@@ -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, coercePositiveInt, maskSecret, DEFAULT_FAST_CONFIG, DEFAULT_RETRY_CONFIG, DEFAULT_TEAM_CONFIG, } from './schema.js';
|
|
16
|
+
import { clampFastConfig, clampRetryConfig, clampUpdateConfig, coercePositiveInt, maskSecret, DEFAULT_FAST_CONFIG, DEFAULT_RETRY_CONFIG, DEFAULT_TEAM_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 = [
|
|
@@ -87,6 +87,22 @@ export const FAST_CONFIG_SET_KEYS = [
|
|
|
87
87
|
'fast.reviewMaxChars',
|
|
88
88
|
'fast.reviewMaxPerSession',
|
|
89
89
|
];
|
|
90
|
+
/**
|
|
91
|
+
* Config keys under `update.` that `aragon config set` accepts (cli-auto-update
|
|
92
|
+
* §4.1).
|
|
93
|
+
*
|
|
94
|
+
* A DEDICATED SETTER RATHER THAN A GENERIC DOTTED WRITER, for the reason the
|
|
95
|
+
* four sets above each record: a generic setter would write `update` as a FLAT
|
|
96
|
+
* string key (`"update.mode": "notify"` at the top level of the file), the
|
|
97
|
+
* section would silently never take effect, and `config set` would still print
|
|
98
|
+
* `Set update.mode = notify`.
|
|
99
|
+
*/
|
|
100
|
+
export const UPDATE_CONFIG_SET_KEYS = [
|
|
101
|
+
'update.mode',
|
|
102
|
+
'update.checkIntervalMs',
|
|
103
|
+
'update.registry',
|
|
104
|
+
'update.distTag',
|
|
105
|
+
];
|
|
90
106
|
function isTrue(value) {
|
|
91
107
|
return value === 'true' || value === '1';
|
|
92
108
|
}
|
|
@@ -245,6 +261,39 @@ export function applyFastConfigSet(key, value) {
|
|
|
245
261
|
return null;
|
|
246
262
|
}
|
|
247
263
|
}
|
|
264
|
+
/**
|
|
265
|
+
* Translate an `update.*` dotted key into a patch, or `null` for anything else.
|
|
266
|
+
*
|
|
267
|
+
* The patch is a PARTIAL `update` section, safe only because
|
|
268
|
+
* `updatePersistedConfig` deep-merges that section — with a shallow merge,
|
|
269
|
+
* setting the mode would silently reset the interval, the registry mirror and
|
|
270
|
+
* the dist-tag (C-4 / R-10).
|
|
271
|
+
*
|
|
272
|
+
* EVERY KEY ROUTES THROUGH `clampUpdateConfig`, not through a local parse, for
|
|
273
|
+
* the reason `applyRetryConfigSet` and `applyFastConfigSet` both record: one
|
|
274
|
+
* gate for both directions means no key here can pick up a different coercion
|
|
275
|
+
* later, and `config set update.checkIntervalMs 5` writes the clamped 900000
|
|
276
|
+
* while the caller echoes the STORED value (AC-20).
|
|
277
|
+
*/
|
|
278
|
+
export function applyUpdateConfigSet(key, value) {
|
|
279
|
+
const patch = (update) => ({ update });
|
|
280
|
+
const clampOne = (field) => {
|
|
281
|
+
const merged = clampUpdateConfig({ ...DEFAULT_UPDATE_CONFIG, [field]: value });
|
|
282
|
+
return { [field]: merged[field] };
|
|
283
|
+
};
|
|
284
|
+
switch (key) {
|
|
285
|
+
case 'update.mode':
|
|
286
|
+
return patch(clampOne('mode'));
|
|
287
|
+
case 'update.checkIntervalMs':
|
|
288
|
+
return patch(clampOne('checkIntervalMs'));
|
|
289
|
+
case 'update.registry':
|
|
290
|
+
return patch(clampOne('registry'));
|
|
291
|
+
case 'update.distTag':
|
|
292
|
+
return patch(clampOne('distTag'));
|
|
293
|
+
default:
|
|
294
|
+
return null;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
248
297
|
/**
|
|
249
298
|
* `log.redactSecrets false` is the one setting that lets credentials reach the
|
|
250
299
|
* disk. It is command-line-only (there is no settings-screen entry) and it says
|
package/dist/config/env.d.ts
CHANGED
|
@@ -12,7 +12,17 @@
|
|
|
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
|
-
* ARAGON_RENDER_GOVERNOR, ARAGON_MAX_RENDER_INTERVAL_MS
|
|
15
|
+
* ARAGON_RENDER_GOVERNOR, ARAGON_MAX_RENDER_INTERVAL_MS,
|
|
16
|
+
* ARAGON_DIFF_RENDER, ARAGON_SYNC_OUTPUT,
|
|
17
|
+
* ARAGON_UPDATE.
|
|
18
|
+
*
|
|
19
|
+
* READ ELSEWHERE, ON PURPOSE: `ARAGON_UPDATE_REGISTRY` and `npm_config_registry`
|
|
20
|
+
* are resolved by `update/registry.ts::resolveRegistryUrl`, NOT here, because
|
|
21
|
+
* §3.3 puts them BELOW `config.update.registry` in precedence — the opposite of
|
|
22
|
+
* the env-beats-file rule this file implements. Writing them into `partial`
|
|
23
|
+
* would silently invert that order and make a config-file mirror unreachable on
|
|
24
|
+
* any machine where npm exports its own registry (which is every machine npm
|
|
25
|
+
* runs a script on).
|
|
16
26
|
*
|
|
17
27
|
* NOT here: `ARAGON_HOME`. It is read when `config/app-paths.ts` is first
|
|
18
28
|
* evaluated, which is long before `loadDotenv()` runs, so a `.env` can never
|
package/dist/config/env.js
CHANGED
|
@@ -12,7 +12,17 @@
|
|
|
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
|
-
* ARAGON_RENDER_GOVERNOR, ARAGON_MAX_RENDER_INTERVAL_MS
|
|
15
|
+
* ARAGON_RENDER_GOVERNOR, ARAGON_MAX_RENDER_INTERVAL_MS,
|
|
16
|
+
* ARAGON_DIFF_RENDER, ARAGON_SYNC_OUTPUT,
|
|
17
|
+
* ARAGON_UPDATE.
|
|
18
|
+
*
|
|
19
|
+
* READ ELSEWHERE, ON PURPOSE: `ARAGON_UPDATE_REGISTRY` and `npm_config_registry`
|
|
20
|
+
* are resolved by `update/registry.ts::resolveRegistryUrl`, NOT here, because
|
|
21
|
+
* §3.3 puts them BELOW `config.update.registry` in precedence — the opposite of
|
|
22
|
+
* the env-beats-file rule this file implements. Writing them into `partial`
|
|
23
|
+
* would silently invert that order and make a config-file mirror unreachable on
|
|
24
|
+
* any machine where npm exports its own registry (which is every machine npm
|
|
25
|
+
* runs a script on).
|
|
16
26
|
*
|
|
17
27
|
* NOT here: `ARAGON_HOME`. It is read when `config/app-paths.ts` is first
|
|
18
28
|
* evaluated, which is long before `loadDotenv()` runs, so a `.env` can never
|
|
@@ -279,6 +289,37 @@ export function readEnvConfig() {
|
|
|
279
289
|
if (Object.keys(section).length > 0)
|
|
280
290
|
partial.fast = section;
|
|
281
291
|
}
|
|
292
|
+
// ARAGON_UPDATE=0|off|false turns auto-update off; `notify` reports without
|
|
293
|
+
// installing; 1|on|true|yes turns it on (cli-auto-update §4.2).
|
|
294
|
+
//
|
|
295
|
+
// A TRI-STATE, so it is parsed by an EXPLICIT POSITIVE LIST PER OUTCOME rather
|
|
296
|
+
// than by the boolean positive list its neighbours use — and emphatically not
|
|
297
|
+
// by `envBool` below, whose NEGATIVE list would resolve `ARAGON_UPDATE=disable`
|
|
298
|
+
// to `true`.
|
|
299
|
+
//
|
|
300
|
+
// ANYTHING UNRECOGNISED IS LEFT ABSENT, which is the invariant this file
|
|
301
|
+
// states three times over (`ARAGON_TEAM_MAX`, `ARAGON_RETRY_MAX`,
|
|
302
|
+
// `ARAGON_MAX_TOKENS`): a value that resolves to a default looks PERMANENTLY
|
|
303
|
+
// SUPPLIED, and the config file underneath can then never win again. For a
|
|
304
|
+
// kill switch that is the worst possible failure — `ARAGON_UPDATE=disabled`
|
|
305
|
+
// would read as "on" while the user believes they turned it off.
|
|
306
|
+
//
|
|
307
|
+
// `ARAGON_TODO_FOLLOW` is the tri-state precedent: the recognised string is
|
|
308
|
+
// written through and `clampUpdateConfig` stays the single gate, so there is
|
|
309
|
+
// never a second validator that can disagree with the first.
|
|
310
|
+
const update = process.env.ARAGON_UPDATE?.trim().toLowerCase();
|
|
311
|
+
if (update !== undefined && update.length > 0) {
|
|
312
|
+
const mode = update === '0' || update === 'false' || update === 'off' || update === 'no'
|
|
313
|
+
? 'off'
|
|
314
|
+
: update === 'notify'
|
|
315
|
+
? 'notify'
|
|
316
|
+
: update === '1' || update === 'true' || update === 'on' || update === 'yes'
|
|
317
|
+
? 'auto'
|
|
318
|
+
: undefined;
|
|
319
|
+
if (mode !== undefined) {
|
|
320
|
+
partial.update = { mode };
|
|
321
|
+
}
|
|
322
|
+
}
|
|
282
323
|
// Render bounds (tui-render-performance §5.3). Same channel story as
|
|
283
324
|
// ARAGON_FULLSCREEN: a container or a wrapper that owns argv can reach neither
|
|
284
325
|
// a flag nor a config file, and a session that freezes is exactly the case
|
|
@@ -307,6 +348,22 @@ export function readEnvConfig() {
|
|
|
307
348
|
if (Number.isFinite(parsed) && parsed > 0)
|
|
308
349
|
partial.maxRenderIntervalMs = parsed;
|
|
309
350
|
}
|
|
351
|
+
// ARAGON_DIFF_RENDER=0 restores the pre-fix full-frame repaint;
|
|
352
|
+
// ARAGON_SYNC_OUTPUT=0 drops the DEC 2026 envelope (tui-input-flicker-fix
|
|
353
|
+
// §5.3). Parsed by the POSITIVE list, exactly as ARAGON_FULLSCREEN /
|
|
354
|
+
// ARAGON_MOUSE / ARAGON_PLAN / ARAGON_TEAM / ARAGON_TODO / ARAGON_RENDER_GOVERNOR
|
|
355
|
+
// are — NOT by `envBool` below, whose NEGATIVE list disagrees with it on values
|
|
356
|
+
// like `ARAGON_DIFF_RENDER=disable`.
|
|
357
|
+
const diffRender = process.env.ARAGON_DIFF_RENDER?.trim().toLowerCase();
|
|
358
|
+
if (diffRender !== undefined && diffRender.length > 0) {
|
|
359
|
+
partial.diffRender =
|
|
360
|
+
diffRender === '1' || diffRender === 'true' || diffRender === 'on' || diffRender === 'yes';
|
|
361
|
+
}
|
|
362
|
+
const syncOutput = process.env.ARAGON_SYNC_OUTPUT?.trim().toLowerCase();
|
|
363
|
+
if (syncOutput !== undefined && syncOutput.length > 0) {
|
|
364
|
+
partial.syncOutput =
|
|
365
|
+
syncOutput === '1' || syncOutput === 'true' || syncOutput === 'on' || syncOutput === 'yes';
|
|
366
|
+
}
|
|
310
367
|
const log = readEnvLogConfig();
|
|
311
368
|
if (log)
|
|
312
369
|
partial.log = log;
|
package/dist/config/load.d.ts
CHANGED
|
@@ -106,6 +106,19 @@ export interface CliFlags {
|
|
|
106
106
|
renderGovernor?: boolean;
|
|
107
107
|
/** `--max-render-interval <ms>` — the governor ceiling for this run (L4). */
|
|
108
108
|
maxRenderInterval?: string | number;
|
|
109
|
+
/**
|
|
110
|
+
* `--diff-render` ⇒ true, `--no-diff-render` ⇒ false, absent ⇒ undefined
|
|
111
|
+
* (tui-input-flicker-fix §5.2).
|
|
112
|
+
*
|
|
113
|
+
* DECLARED AS A PAIR for the reason `--render-governor` records one field up:
|
|
114
|
+
* `diffRender` is PERSISTED and defaults to `true`, so a lone
|
|
115
|
+
* `--no-diff-render` would make commander default `opts.diffRender` to `true`
|
|
116
|
+
* and silently overwrite a stored `false` on every run that passed no flag at
|
|
117
|
+
* all — i.e. the documented escape hatch would quietly un-set itself.
|
|
118
|
+
*/
|
|
119
|
+
diffRender?: boolean;
|
|
120
|
+
/** `--sync-output` ⇒ true, `--no-sync-output` ⇒ false, absent ⇒ undefined (§5.2). */
|
|
121
|
+
syncOutput?: boolean;
|
|
109
122
|
/**
|
|
110
123
|
* `--retry` ⇒ true, `--no-retry` ⇒ false, absent ⇒ undefined
|
|
111
124
|
* (llm-api-retry-backoff §6.2).
|
|
@@ -148,6 +161,23 @@ export interface CliFlags {
|
|
|
148
161
|
* to keep in step with `toFlags`.
|
|
149
162
|
*/
|
|
150
163
|
fastReview?: string;
|
|
164
|
+
/**
|
|
165
|
+
* `--update` ⇒ true, `--no-update` ⇒ false, absent ⇒ undefined
|
|
166
|
+
* (cli-auto-update §4.2).
|
|
167
|
+
*
|
|
168
|
+
* DECLARED AS A PAIR — MANDATORY (C-11), for the reason `--team`,
|
|
169
|
+
* `--todo-panel`, `--render-governor`, `--retry` and `--fast` each record in
|
|
170
|
+
* turn. `update.mode` is PERSISTED and defaults to `'auto'`, so a lone
|
|
171
|
+
* `--no-update` would make commander default `opts.update` to `true` and
|
|
172
|
+
* silently overwrite a stored `off` on every run that passed no flag at all —
|
|
173
|
+
* i.e. the kill switch would un-set itself.
|
|
174
|
+
*
|
|
175
|
+
* A BOOLEAN FOR A TRI-STATE KEY, deliberately: the flag is a SESSION override
|
|
176
|
+
* and `notify` is a preference, not something a user reaches for once. `true`
|
|
177
|
+
* maps to `'auto'`, `false` to `'off'`; `notify` is reachable through the
|
|
178
|
+
* config file and `ARAGON_UPDATE=notify`.
|
|
179
|
+
*/
|
|
180
|
+
update?: boolean;
|
|
151
181
|
}
|
|
152
182
|
/**
|
|
153
183
|
* 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, 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';
|
|
@@ -185,6 +185,29 @@ function resolveFastConfig(flags, env, file) {
|
|
|
185
185
|
...reviewPatch,
|
|
186
186
|
});
|
|
187
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
|
+
}
|
|
188
211
|
/**
|
|
189
212
|
* Resolve the adaptive render governor: flag › env › file › default `true`
|
|
190
213
|
* (tui-render-performance L4).
|
|
@@ -204,6 +227,35 @@ function resolveRenderGovernor(flags, env, file) {
|
|
|
204
227
|
return file.renderGovernor;
|
|
205
228
|
return DEFAULT_CONFIG.renderGovernor;
|
|
206
229
|
}
|
|
230
|
+
/**
|
|
231
|
+
* Resolve per-line frame diffing: flag › env › file › default `true`
|
|
232
|
+
* (tui-input-flicker-fix §5.1).
|
|
233
|
+
*
|
|
234
|
+
* Shaped exactly like `resolveRenderGovernor` above, and for the same reason:
|
|
235
|
+
* there are no heuristics for an explicit `true` to override, so a persisted
|
|
236
|
+
* `true` is a value rather than an opinion that has to be told apart from
|
|
237
|
+
* silence. `!== undefined` on the flag is what makes `--no-diff-render` beat a
|
|
238
|
+
* config file that left the key at its default.
|
|
239
|
+
*/
|
|
240
|
+
function resolveDiffRender(flags, env, file) {
|
|
241
|
+
if (flags.diffRender !== undefined)
|
|
242
|
+
return flags.diffRender;
|
|
243
|
+
if (env.diffRender !== undefined)
|
|
244
|
+
return env.diffRender;
|
|
245
|
+
if (file.diffRender !== undefined)
|
|
246
|
+
return file.diffRender;
|
|
247
|
+
return DEFAULT_CONFIG.diffRender;
|
|
248
|
+
}
|
|
249
|
+
/** Same ladder for the DEC 2026 envelope (§5.1). */
|
|
250
|
+
function resolveSyncOutput(flags, env, file) {
|
|
251
|
+
if (flags.syncOutput !== undefined)
|
|
252
|
+
return flags.syncOutput;
|
|
253
|
+
if (env.syncOutput !== undefined)
|
|
254
|
+
return env.syncOutput;
|
|
255
|
+
if (file.syncOutput !== undefined)
|
|
256
|
+
return file.syncOutput;
|
|
257
|
+
return DEFAULT_CONFIG.syncOutput;
|
|
258
|
+
}
|
|
207
259
|
/** Merge the `log` section across all four layers (defaults › file › env › flags). */
|
|
208
260
|
function resolveLogConfig(flags, env, file) {
|
|
209
261
|
const merged = clampLogConfig({
|
|
@@ -398,6 +450,8 @@ export function loadConfig(flags = {}) {
|
|
|
398
450
|
...(requestedRetain < transcriptRetain ? { transcriptRetainRequested: requestedRetain } : {}),
|
|
399
451
|
renderGovernor: resolveRenderGovernor(flags, env.partial, file),
|
|
400
452
|
maxRenderIntervalMs: clampMaxRenderInterval(pick(flags.maxRenderInterval, env.partial.maxRenderIntervalMs, file.maxRenderIntervalMs), DEFAULT_CONFIG.maxRenderIntervalMs),
|
|
453
|
+
diffRender: resolveDiffRender(flags, env.partial, file),
|
|
454
|
+
syncOutput: resolveSyncOutput(flags, env.partial, file),
|
|
401
455
|
confirmTools,
|
|
402
456
|
toolTimeoutMs,
|
|
403
457
|
idleTimeoutMs,
|
|
@@ -428,6 +482,7 @@ export function loadConfig(flags = {}) {
|
|
|
428
482
|
todo: resolveTodoConfig(flags, env.partial, file),
|
|
429
483
|
retry: resolveRetryConfig(flags, env.partial, file),
|
|
430
484
|
fast: resolveFastConfig(flags, env.partial, file),
|
|
485
|
+
update: resolveUpdateConfig(flags, env.partial, file),
|
|
431
486
|
cwd,
|
|
432
487
|
color,
|
|
433
488
|
colorLevel,
|