@aragon-agent/cli 0.5.2 → 0.5.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 +127 -0
- package/README.md +193 -3
- package/dist/agent/controller.d.ts +51 -1
- package/dist/agent/controller.js +177 -2
- package/dist/agent/headless.d.ts +12 -0
- package/dist/agent/headless.js +41 -1
- package/dist/agent/reducer.d.ts +48 -0
- package/dist/agent/reducer.js +91 -2
- package/dist/agent/system-prompt.d.ts +17 -0
- package/dist/agent/system-prompt.js +4 -0
- package/dist/cli.js +98 -7
- package/dist/commands/builtins.d.ts +2 -2
- package/dist/commands/builtins.js +133 -3
- package/dist/config/app-paths.d.ts +17 -0
- package/dist/config/app-paths.js +21 -0
- package/dist/config/cli-commands.d.ts +26 -2
- package/dist/config/cli-commands.js +83 -6
- package/dist/config/env.d.ts +3 -2
- package/dist/config/env.js +44 -6
- package/dist/config/history-commands.d.ts +20 -0
- package/dist/config/history-commands.js +71 -0
- package/dist/config/load.d.ts +13 -0
- package/dist/config/load.js +107 -6
- package/dist/config/migrate-state-out-of-config.d.ts +32 -0
- package/dist/config/migrate-state-out-of-config.js +85 -0
- package/dist/config/prompt-history.d.ts +86 -0
- package/dist/config/prompt-history.js +332 -0
- package/dist/config/schema.d.ts +176 -18
- package/dist/config/schema.js +162 -8
- package/dist/config/store.js +40 -4
- package/dist/config/ui-state.d.ts +52 -0
- package/dist/config/ui-state.js +149 -0
- package/dist/logging/install.d.ts +85 -0
- package/dist/logging/install.js +94 -0
- package/dist/logging/logger.d.ts +1 -1
- package/dist/session/persist.d.ts +16 -0
- package/dist/session/persist.js +19 -1
- package/dist/team/activity.d.ts +67 -0
- package/dist/team/activity.js +130 -0
- package/dist/team/bus.d.ts +190 -0
- package/dist/team/bus.js +366 -0
- package/dist/team/comm-tools.d.ts +61 -0
- package/dist/team/comm-tools.js +221 -0
- package/dist/team/human-queue.d.ts +55 -0
- package/dist/team/human-queue.js +72 -0
- package/dist/team/limits.d.ts +123 -0
- package/dist/team/limits.js +128 -0
- package/dist/team/normalize.d.ts +39 -0
- package/dist/team/normalize.js +106 -0
- package/dist/team/panel-rows.d.ts +48 -0
- package/dist/team/panel-rows.js +75 -0
- package/dist/team/prompt.d.ts +49 -0
- package/dist/team/prompt.js +87 -0
- package/dist/team/report.d.ts +58 -0
- package/dist/team/report.js +205 -0
- package/dist/team/retry.d.ts +48 -0
- package/dist/team/retry.js +56 -0
- package/dist/team/runtime.d.ts +122 -0
- package/dist/team/runtime.js +406 -0
- package/dist/team/subagent.d.ts +90 -0
- package/dist/team/subagent.js +294 -0
- package/dist/team/task-tool.d.ts +47 -0
- package/dist/team/task-tool.js +118 -0
- package/dist/team/types.d.ts +172 -0
- package/dist/team/types.js +13 -0
- package/dist/tools/index.d.ts +48 -2
- package/dist/tools/index.js +26 -1
- package/dist/ui/App.d.ts +22 -1
- package/dist/ui/App.js +144 -18
- package/dist/ui/StatusBar.d.ts +21 -0
- package/dist/ui/StatusBar.js +5 -2
- package/dist/ui/TeamPanel.d.ts +57 -0
- package/dist/ui/TeamPanel.js +134 -0
- package/dist/ui/Transcript.js +10 -0
- package/dist/ui/entries/TeamCard.d.ts +31 -0
- package/dist/ui/entries/TeamCard.js +39 -0
- package/dist/ui/glyphs.d.ts +10 -0
- package/dist/ui/glyphs.js +6 -0
- package/dist/ui/layout/AppShell.d.ts +11 -1
- package/dist/ui/layout/AppShell.js +3 -3
- package/dist/ui/overlays/HelpOverlay.js +13 -0
- package/dist/ui/overlays/SettingsScreen.d.ts +12 -1
- package/dist/ui/overlays/SettingsScreen.js +38 -1
- package/dist/ui/transcript-text.js +20 -0
- package/dist/ui/use-startup-notices.d.ts +1 -1
- package/dist/ui/use-startup-notices.js +2 -1
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -21,11 +21,13 @@ import { loadConfig } from './config/load.js';
|
|
|
21
21
|
import { getConfigPath, readConfigFile, updatePersistedConfig } from './config/store.js';
|
|
22
22
|
import { formatMigrationNotice, migrateLegacyState } from './config/migrate-legacy-state.js';
|
|
23
23
|
import { formatHomeMigrationNotice, migrateToHome } from './config/migrate-home.js';
|
|
24
|
-
import {
|
|
25
|
-
import {
|
|
24
|
+
import { migrateStateOutOfConfig } from './config/migrate-state-out-of-config.js';
|
|
25
|
+
import { runHistoryCommand } from './config/history-commands.js';
|
|
26
|
+
import { LOG_CONFIG_SET_KEYS, TEAM_CONFIG_SET_KEYS, applyLogConfigSet, applyTeamConfigSet, runConfigEdit, runConfigGet, runConfigHome, runConfigList, warnIfRedactionDisabled, } from './config/cli-commands.js';
|
|
27
|
+
import { attachAgentEvents, attachTeamEvents, installLogging, setScreenRestore, setSignalTerminator, } from './logging/install.js';
|
|
26
28
|
import { getLogger } from './logging/logger.js';
|
|
27
29
|
import { runLogsCommand } from './logging/cli-commands.js';
|
|
28
|
-
import { ADAPTER_PROVIDERS, clampDensity, clampTheme, clampThinkingLevel, clampAskRounds, clampHumanTimeout, clampSkillsIntegrity, clampSkillsToolPolicy, clampTranscriptWindow,
|
|
30
|
+
import { ADAPTER_PROVIDERS, clampDensity, clampTheme, clampThinkingLevel, clampAskRounds, clampHumanTimeout, clampSkillsIntegrity, clampSkillsToolPolicy, clampTranscriptWindow, coercePositiveInt, isAdapterProvider, parseMaxTokensInput, DEFAULT_MAX_TOKENS, DEFAULT_PLAN_HUMAN_TIMEOUT_MS, DEFAULT_PLAN_MAX_ASK_ROUNDS, DEFAULT_SKILLS_CONFIG, } from './config/schema.js';
|
|
29
31
|
import { makeGetApiKey } from './config/load.js';
|
|
30
32
|
import { AgentController, DENY_ALL_APPROVAL } from './agent/controller.js';
|
|
31
33
|
import { runSkillsCommand } from './skills/cli-commands.js';
|
|
@@ -79,6 +81,11 @@ function toFlags(opts) {
|
|
|
79
81
|
skillsYes: opts.skillsYes,
|
|
80
82
|
skillToolPolicy: opts.skillToolPolicy,
|
|
81
83
|
plan: opts.plan,
|
|
84
|
+
// These two lines are the same failure the `mouse` note above records, one
|
|
85
|
+
// feature later (P1-4): without them `--no-team` and `--team-max` never
|
|
86
|
+
// reach `CliFlags` and are inert, with no compile error and no runtime error.
|
|
87
|
+
team: opts.team,
|
|
88
|
+
teamMax: opts.teamMax,
|
|
82
89
|
// `--verbose` is just a shorthand for `--log-level debug`; an explicit
|
|
83
90
|
// `--log-level` still wins, so the two can be combined without surprise.
|
|
84
91
|
logLevel: opts.logLevel ?? (opts.verbose ? 'debug' : undefined),
|
|
@@ -166,6 +173,11 @@ function runInteractive(flags, extras = {}) {
|
|
|
166
173
|
const logger = getLogger();
|
|
167
174
|
logger.info('cli', 'run_interactive', { mode, provider: config.provider, model: config.model });
|
|
168
175
|
attachAgentEvents(logger, controller);
|
|
176
|
+
// The team stream is CLI-local (D-10), so `attachAgentEvents` cannot see it.
|
|
177
|
+
// Without this a dispatch leaves NO trace in the log file at all — the wrong
|
|
178
|
+
// outcome for the one feature here that runs five agents the user cannot
|
|
179
|
+
// watch (§3.13 / P1-2 / R-19).
|
|
180
|
+
attachTeamEvents(logger, controller);
|
|
169
181
|
let screen = null;
|
|
170
182
|
let replayed = false;
|
|
171
183
|
// --- Mouse wheel region routing (mouse-wheel-region-routing §4.2). -------
|
|
@@ -264,11 +276,16 @@ function runInteractive(flags, extras = {}) {
|
|
|
264
276
|
.then(() => {
|
|
265
277
|
screen?.restore();
|
|
266
278
|
disposeMouse();
|
|
279
|
+
// Orphaned subagents survive `Ctrl+C` otherwise, and a live child holds
|
|
280
|
+
// the event loop open so `aragon` never returns to the shell (R-15). The
|
|
281
|
+
// App's unmount cleanup also calls this; `dispose()` is idempotent.
|
|
282
|
+
controller.dispose();
|
|
267
283
|
replayTranscript();
|
|
268
284
|
})
|
|
269
285
|
.catch(() => {
|
|
270
286
|
screen?.restore();
|
|
271
287
|
disposeMouse();
|
|
288
|
+
controller.dispose();
|
|
272
289
|
});
|
|
273
290
|
}
|
|
274
291
|
async function runOneShot(flags, prompt, quiet) {
|
|
@@ -282,6 +299,11 @@ async function runOneShot(flags, prompt, quiet) {
|
|
|
282
299
|
// toast channel `App.tsx` uses does not exist here.
|
|
283
300
|
logger.onFailure((reason) => process.stderr.write(`[log] ${reason}\n`));
|
|
284
301
|
attachAgentEvents(logger, controller);
|
|
302
|
+
// The team stream is CLI-local (D-10), so `attachAgentEvents` cannot see it.
|
|
303
|
+
// Without this a dispatch leaves NO trace in the log file at all — the wrong
|
|
304
|
+
// outcome for the one feature here that runs five agents the user cannot
|
|
305
|
+
// watch (§3.13 / P1-2 / R-19).
|
|
306
|
+
attachTeamEvents(logger, controller);
|
|
285
307
|
const untrusted = controller.getSkillService().untrustedDirs();
|
|
286
308
|
for (const dir of untrusted) {
|
|
287
309
|
process.stderr.write(`[skills] project skills in ${dir} skipped (untrusted). Run: aragon skills trust ${dir}\n`);
|
|
@@ -354,6 +376,7 @@ const CONFIG_SET_KEYS = new Set([
|
|
|
354
376
|
// falls through every case, writes nothing, and still prints
|
|
355
377
|
// `Set mouse = false` (P1-2) -- exactly what happened to `density`/`hints`.
|
|
356
378
|
'mouse',
|
|
379
|
+
'historyEnabled',
|
|
357
380
|
'planModeDefault',
|
|
358
381
|
'planModeMaxAskRounds',
|
|
359
382
|
'planModeHumanTimeoutMs',
|
|
@@ -368,7 +391,35 @@ const CONFIG_SET_KEYS = new Set([
|
|
|
368
391
|
// `log.*` keys are handled by `applyLogConfigSet` below, NOT by the switch:
|
|
369
392
|
// that switch is already past this package's complexity ceiling.
|
|
370
393
|
...LOG_CONFIG_SET_KEYS,
|
|
394
|
+
// `team.*` keys are handled by `applyTeamConfigSet`, for the same reason
|
|
395
|
+
// `log.*` are: the switch below is already past this package's complexity
|
|
396
|
+
// ceiling, and a key listed here but forgotten there writes nothing while
|
|
397
|
+
// still printing `Set team.enabled = false`.
|
|
398
|
+
...TEAM_CONFIG_SET_KEYS,
|
|
371
399
|
]);
|
|
400
|
+
/**
|
|
401
|
+
* `aragon config set maxTokens <n|auto|default>`.
|
|
402
|
+
*
|
|
403
|
+
* REJECTS nonsense rather than clamping it, unlike `theme` and `thinkingLevel`.
|
|
404
|
+
* Those two clamp because their bad values are out-of-VOCABULARY; here a
|
|
405
|
+
* non-numeric argument is almost always a typo for a number the user meant, and
|
|
406
|
+
* storing 64000 for `3200O` would quietly discard their intent. An out-of-RANGE
|
|
407
|
+
* number is still clamped, in both directions, by the store's single gate.
|
|
408
|
+
*/
|
|
409
|
+
function runConfigSetMaxTokens(value) {
|
|
410
|
+
const raw = value.trim().toLowerCase();
|
|
411
|
+
const parsed = raw === 'default'
|
|
412
|
+
? { kind: 'value', value: DEFAULT_MAX_TOKENS, clamped: false }
|
|
413
|
+
: parseMaxTokensInput(value);
|
|
414
|
+
if (parsed.kind === 'invalid') {
|
|
415
|
+
process.stderr.write(`Invalid maxTokens "${value}". Use a number, "auto", or "default".\n`);
|
|
416
|
+
process.exitCode = 2;
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
const stored = parsed.kind === 'auto' ? null : parsed.value;
|
|
420
|
+
const merged = updatePersistedConfig({ maxTokens: stored });
|
|
421
|
+
process.stdout.write(`Set maxTokens = ${merged.maxTokens ?? 'auto'}\n`);
|
|
422
|
+
}
|
|
372
423
|
function runConfigSet(key, value) {
|
|
373
424
|
if (!CONFIG_SET_KEYS.has(key)) {
|
|
374
425
|
process.stderr.write(`Unknown config key "${key}". Known keys: ${[...CONFIG_SET_KEYS].join(', ')}.\n`);
|
|
@@ -382,6 +433,23 @@ function runConfigSet(key, value) {
|
|
|
382
433
|
process.stdout.write(`Set ${key} = ${value}\n`);
|
|
383
434
|
return;
|
|
384
435
|
}
|
|
436
|
+
// Handled ahead of the switch because it needs to echo the STORED value, not
|
|
437
|
+
// the typed one: `config set maxTokens 900000` must not report a number that
|
|
438
|
+
// was never written. Same reason `team.*` has its own branch.
|
|
439
|
+
if (key === 'maxTokens') {
|
|
440
|
+
runConfigSetMaxTokens(value);
|
|
441
|
+
return;
|
|
442
|
+
}
|
|
443
|
+
const teamPatch = applyTeamConfigSet(key, value);
|
|
444
|
+
if (teamPatch) {
|
|
445
|
+
// The written value is echoed from the CLAMPED result rather than from the
|
|
446
|
+
// input, so `config set team.maxSubagents 40` says 10 instead of silently
|
|
447
|
+
// reporting a number that was never stored (R-g).
|
|
448
|
+
const merged = updatePersistedConfig(teamPatch);
|
|
449
|
+
const field = key.slice('team.'.length);
|
|
450
|
+
process.stdout.write(`Set ${key} = ${String(merged.team[field])}\n`);
|
|
451
|
+
return;
|
|
452
|
+
}
|
|
385
453
|
const patch = {};
|
|
386
454
|
switch (key) {
|
|
387
455
|
case 'provider':
|
|
@@ -396,9 +464,6 @@ function runConfigSet(key, value) {
|
|
|
396
464
|
case 'thinkingLevel':
|
|
397
465
|
patch.thinkingLevel = clampThinkingLevel(value, 'off');
|
|
398
466
|
break;
|
|
399
|
-
case 'maxTokens':
|
|
400
|
-
patch.maxTokens = coerceMaxTokens(value) ?? null;
|
|
401
|
-
break;
|
|
402
467
|
case 'theme':
|
|
403
468
|
patch.theme = clampTheme(value, 'auto');
|
|
404
469
|
break;
|
|
@@ -429,6 +494,11 @@ function runConfigSet(key, value) {
|
|
|
429
494
|
case 'mouse':
|
|
430
495
|
patch.mouse = value === 'true' || value === '1';
|
|
431
496
|
break;
|
|
497
|
+
// Turning this off stops new prompts being recorded; it does NOT delete
|
|
498
|
+
// what is already in `prompt-history.jsonl` (that is `aragon history clear`).
|
|
499
|
+
case 'historyEnabled':
|
|
500
|
+
patch.historyEnabled = value === 'true' || value === '1';
|
|
501
|
+
break;
|
|
432
502
|
// Clamped rather than rejected, for the same reason as `theme` and
|
|
433
503
|
// `skills.integrity`: hardening only the READ path leaves a bad value on
|
|
434
504
|
// disk that reverts to the default on every launch, which presents as
|
|
@@ -497,7 +567,7 @@ function buildProgram() {
|
|
|
497
567
|
.option('--base-url <url>', 'Override the provider base URL')
|
|
498
568
|
.option('--api-key <key>', 'One-shot API key override (not persisted)')
|
|
499
569
|
.option('--thinking <level>', 'off|minimal|low|medium|high|xhigh')
|
|
500
|
-
.option('--max-tokens <n>', 'Output token cap')
|
|
570
|
+
.option('--max-tokens <n|auto>', 'Output token cap: a number, or "auto" for the model ceiling (default 64000)')
|
|
501
571
|
.option('--cwd <dir>', 'Working directory for tools')
|
|
502
572
|
.option('--confirm', 'Confirm each mutating tool call')
|
|
503
573
|
.option('--tool-timeout <ms>', 'Per-tool executor ceiling (default 180000)')
|
|
@@ -525,6 +595,13 @@ function buildProgram() {
|
|
|
525
595
|
// config layer win when neither flag was given.
|
|
526
596
|
.option('--plan', 'Start the session in PLAN mode (read-only research + review)')
|
|
527
597
|
.option('--no-plan', 'Start the session in BUILD mode (overrides planModeDefault)')
|
|
598
|
+
// BOTH FORMS, positive first, and the pair is mandatory (team-subagents
|
|
599
|
+
// §4.4 / P1-4). Declaring only `--no-team` would make commander default
|
|
600
|
+
// `opts.team` to `true`, at which point the flag is indistinguishable from
|
|
601
|
+
// its own default and silently overrides `config.json` on every run.
|
|
602
|
+
.option('--team', 'Enable team subagents for this session (the default)')
|
|
603
|
+
.option('--no-team', 'Disable team subagents (the task tool is not registered at all)')
|
|
604
|
+
.option('--team-max <n>', 'Max subagents per dispatch for this run (1-10)')
|
|
528
605
|
.option('--no-skills', 'Disable the skill system entirely (no catalog, no skill tools)')
|
|
529
606
|
.option('--skill <name>', 'Force-load a skill at Level 2 for this run (repeatable)', (value, previous = []) => [...previous, value])
|
|
530
607
|
.option('--skills-yes', 'Approve skill installs for this run (CI / headless)')
|
|
@@ -618,6 +695,16 @@ function buildProgram() {
|
|
|
618
695
|
.action(async (subcommand, opts) => {
|
|
619
696
|
process.exitCode = await runLogsCommand(subcommand ?? 'path', opts, toFlags(program.opts()));
|
|
620
697
|
});
|
|
698
|
+
// aragon history <sub> [-n N] [--json] [--yes]
|
|
699
|
+
program
|
|
700
|
+
.command('history [subcommand]')
|
|
701
|
+
.description('Inspect the prompt history: path | list | clear')
|
|
702
|
+
.option('-n, --lines <n>', 'Entries for `history list` (default 20)')
|
|
703
|
+
.option('--json', 'Print raw entries instead of rendered lines')
|
|
704
|
+
.option('--yes', 'Confirm destructive actions (required by `history clear`)')
|
|
705
|
+
.action((subcommand, opts) => {
|
|
706
|
+
process.exitCode = runHistoryCommand(subcommand ?? 'path', opts);
|
|
707
|
+
});
|
|
621
708
|
// aragon skills <sub> [arg] [--scope] [--name] [--description] [--yes] [--json]
|
|
622
709
|
program
|
|
623
710
|
.command('skills [subcommand] [argument]')
|
|
@@ -666,6 +753,10 @@ async function main() {
|
|
|
666
753
|
// may just have created. What ① and ② did is replayed from `pending` rather
|
|
667
754
|
// than lost.
|
|
668
755
|
installLogging({ pending: migrationNotes(legacy, home) });
|
|
756
|
+
// ③.5 — after ③ because it writes a log record, and before anything that
|
|
757
|
+
// resolves config because every `loadConfig()` from here on must already see
|
|
758
|
+
// the post-migration world. Never throws, never prints (D-8).
|
|
759
|
+
migrateStateOutOfConfig();
|
|
669
760
|
// An unparseable config.json still falls back to defaults — the CLI has to
|
|
670
761
|
// start — but it must not do so in silence, or a stray comma presents as
|
|
671
762
|
// "every setting I ever chose is gone". stderr, never stdout, so
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Built-in slash commands (spec §5.2):
|
|
3
|
-
* /help /model /settings /thinking /tools /clear /reset /cwd /save
|
|
4
|
-
* /copy /exit (/quit).
|
|
3
|
+
* /help /model /settings /thinking /max-tokens /tools /clear /reset /cwd /save
|
|
4
|
+
* /resume /copy /exit (/quit).
|
|
5
5
|
*/
|
|
6
6
|
import { CommandRegistry } from './registry.js';
|
|
7
7
|
export declare function registerBuiltinCommands(registry: CommandRegistry): void;
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Built-in slash commands (spec §5.2):
|
|
3
|
-
* /help /model /settings /thinking /tools /clear /reset /cwd /save
|
|
4
|
-
* /copy /exit (/quit).
|
|
3
|
+
* /help /model /settings /thinking /max-tokens /tools /clear /reset /cwd /save
|
|
4
|
+
* /resume /copy /exit (/quit).
|
|
5
5
|
*/
|
|
6
6
|
import { spawn } from 'node:child_process';
|
|
7
7
|
import { existsSync, statSync } from 'node:fs';
|
|
8
8
|
import { isAbsolute, resolve } from 'node:path';
|
|
9
9
|
import process from 'node:process';
|
|
10
|
-
import {
|
|
10
|
+
import { resolveOutputTokens } from '@aragon-agent/core';
|
|
11
|
+
import { clampThinkingLevel, clampTheme, isThemeName, parseMaxTokensInput, DEFAULT_MAX_TOKENS, LEGACY_DARK_THEME, THEME_NAMES, THINKING_LEVELS, } from '../config/schema.js';
|
|
11
12
|
import { MODE_LABEL, nextMode } from '../agent/agent-mode.js';
|
|
12
13
|
import { loadConfig } from '../config/load.js';
|
|
13
14
|
import { loadSession, resolveSessionPath, saveSession } from '../session/persist.js';
|
|
@@ -43,6 +44,53 @@ const COMMANDS = [
|
|
|
43
44
|
ctx.toast('info', `Thinking level set to "${clamped}".`);
|
|
44
45
|
},
|
|
45
46
|
},
|
|
47
|
+
{
|
|
48
|
+
name: 'max-tokens',
|
|
49
|
+
description: 'Show or set the output token cap (<n> | auto | default)',
|
|
50
|
+
/**
|
|
51
|
+
* Exists next to the settings screen for the reason `/theme` and `/plan` do:
|
|
52
|
+
* the slash palette is the discoverable surface, and this is one keystroke
|
|
53
|
+
* instead of five arrow presses.
|
|
54
|
+
*
|
|
55
|
+
* The no-argument branch reports the EFFECTIVE cap, not just the setting.
|
|
56
|
+
* "I set 64000" and "this model will produce 8192" are different facts, and
|
|
57
|
+
* only the second one explains a truncated answer.
|
|
58
|
+
*/
|
|
59
|
+
run: (ctx) => {
|
|
60
|
+
const arg = ctx.args.trim();
|
|
61
|
+
const cfg = ctx.controller.getConfig();
|
|
62
|
+
if (!arg) {
|
|
63
|
+
const resolution = resolveOutputTokens({
|
|
64
|
+
providerId: cfg.provider,
|
|
65
|
+
modelId: cfg.model,
|
|
66
|
+
...(cfg.maxTokens !== undefined ? { requested: cfg.maxTokens } : {}),
|
|
67
|
+
});
|
|
68
|
+
const setting = cfg.maxTokens === undefined ? 'auto' : String(cfg.maxTokens);
|
|
69
|
+
const why = resolution.clampedBy === 'ceiling' ? ` (${cfg.model} ceiling)` : '';
|
|
70
|
+
ctx.notify('info', `Max tokens: ${setting}. Effective for ${cfg.provider}:${cfg.model}: ` +
|
|
71
|
+
`${resolution.value}${why}.\nUse /max-tokens <n|auto|default>.`);
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
const parsed = arg.toLowerCase() === 'default'
|
|
75
|
+
? { kind: 'value', value: DEFAULT_MAX_TOKENS, clamped: false }
|
|
76
|
+
: parseMaxTokensInput(arg);
|
|
77
|
+
if (parsed.kind === 'invalid') {
|
|
78
|
+
// Change NOTHING on a typo: silently resolving it to a default would
|
|
79
|
+
// discard the number the user meant to type.
|
|
80
|
+
ctx.notify('warn', `Invalid value "${arg}" - use /max-tokens <n|auto|default>.`);
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
if (parsed.kind === 'auto') {
|
|
84
|
+
ctx.controller.setMaxTokens(undefined);
|
|
85
|
+
ctx.persistConfig({ maxTokens: null });
|
|
86
|
+
ctx.toast('success', 'Max tokens: auto (per-model ceiling).');
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
ctx.controller.setMaxTokens(parsed.value);
|
|
90
|
+
ctx.persistConfig({ maxTokens: parsed.value });
|
|
91
|
+
ctx.toast('success', `Max tokens set to ${parsed.value}.`);
|
|
92
|
+
},
|
|
93
|
+
},
|
|
46
94
|
{
|
|
47
95
|
name: 'theme',
|
|
48
96
|
description: 'Switch the color theme (auto|warm|cool|light)',
|
|
@@ -90,6 +138,88 @@ const COMMANDS = [
|
|
|
90
138
|
ctx.applyAgentMode(target);
|
|
91
139
|
},
|
|
92
140
|
},
|
|
141
|
+
{
|
|
142
|
+
name: 'team',
|
|
143
|
+
description: 'Team subagents: status | on | off | max <n>',
|
|
144
|
+
/**
|
|
145
|
+
* `/team on` CANNOT turn team mode on in a session that started without it,
|
|
146
|
+
* and this command must not pretend otherwise (§4.5 / D-17 / P0-2).
|
|
147
|
+
*
|
|
148
|
+
* `controller.ts` builds the tool array ONCE and its own comment forbids
|
|
149
|
+
* rebuilding it: `Agent.setTools()` mutates the live `ToolRegistry`, and
|
|
150
|
+
* `submit_plan` flips the session mode from INSIDE a tool execution, so a
|
|
151
|
+
* rebuild at that moment would mutate the registry mid-iteration. But
|
|
152
|
+
* `rebuildSystemPrompt()` IS a live path — so the naive reading of `/team on`
|
|
153
|
+
* (flip a flag, re-splice `<team_mode>`) produces a session where the model
|
|
154
|
+
* is told it has a `task` tool that was never registered. Every call comes
|
|
155
|
+
* back "unknown tool", and the model has no way to discover why.
|
|
156
|
+
*
|
|
157
|
+
* So the answer splits by what was decided at construction, and the honest
|
|
158
|
+
* branch — persist it, say the session is unchanged — is the whole point.
|
|
159
|
+
*/
|
|
160
|
+
run: (ctx) => {
|
|
161
|
+
const arg = ctx.args.trim().toLowerCase();
|
|
162
|
+
const [verb, value] = arg.split(/\s+/, 2);
|
|
163
|
+
const controller = ctx.controller;
|
|
164
|
+
// Refused mid-dispatch for the reason `/reload` already records: half a
|
|
165
|
+
// dispatch under one ceiling and half under another produces a result
|
|
166
|
+
// nothing can afterwards explain.
|
|
167
|
+
if (verb && verb !== 'status' && controller.isTeamBusy()) {
|
|
168
|
+
ctx.notify('warn', 'Cannot change team settings mid-dispatch.');
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
if (!verb || verb === 'status') {
|
|
172
|
+
const cfg = controller.getTeamConfig();
|
|
173
|
+
const state = !controller.isTeamRegistered()
|
|
174
|
+
? 'off for this session (started with --no-team)'
|
|
175
|
+
: controller.isTeamEnabled()
|
|
176
|
+
? 'on'
|
|
177
|
+
: 'off';
|
|
178
|
+
const snapshot = controller.getTeamSnapshot();
|
|
179
|
+
const roster = snapshot
|
|
180
|
+
? `\nRunning: ${snapshot.runs.map((r) => `${r.label} (${r.phase})`).join(', ')}`
|
|
181
|
+
: '';
|
|
182
|
+
ctx.notify('info', `Team mode: ${state}. Max subagents: ${cfg.maxSubagents}, ` +
|
|
183
|
+
`concurrent: ${cfg.maxConcurrent}.${roster}`);
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
if (verb === 'on' || verb === 'off') {
|
|
187
|
+
const enabled = verb === 'on';
|
|
188
|
+
// A PARTIAL `team` section, safe only because `updatePersistedConfig`
|
|
189
|
+
// deep-merges it — the same contract `/skills disable` relies on.
|
|
190
|
+
ctx.persistConfig({ team: { enabled } });
|
|
191
|
+
if (!controller.isTeamRegistered()) {
|
|
192
|
+
// The bottom-right cell of §4.5's table. It is honest, it is one
|
|
193
|
+
// sentence, and it keeps AC-11 intact: a `--no-team` session never
|
|
194
|
+
// grows a wrapper or an entry, whatever the user types afterwards.
|
|
195
|
+
ctx.notify('info', enabled
|
|
196
|
+
? 'Team mode is off for this session (started with --no-team). Saved for next launch.'
|
|
197
|
+
: 'Team mode is already off for this session. Saved for next launch.');
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
controller.setTeamEnabled(enabled);
|
|
201
|
+
ctx.toast('success', `Team mode ${enabled ? 'on' : 'off'}.`);
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
if (verb === 'max') {
|
|
205
|
+
const n = Number.parseInt(value ?? '', 10);
|
|
206
|
+
if (!Number.isFinite(n) || n <= 0) {
|
|
207
|
+
ctx.notify('warn', 'Usage: /team max <n>');
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
// Clamped by `setTeamConfig` and again on the persist path, so a value
|
|
211
|
+
// above the requirement's ceiling can reach neither the runtime nor the
|
|
212
|
+
// file (R-g).
|
|
213
|
+
const applied = controller.setTeamConfig({ maxSubagents: n });
|
|
214
|
+
ctx.persistConfig({
|
|
215
|
+
team: { maxSubagents: applied.maxSubagents },
|
|
216
|
+
});
|
|
217
|
+
ctx.toast('success', `Max subagents set to ${applied.maxSubagents}.`);
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
ctx.notify('warn', `Unknown argument "${verb}" - use /team [status|on|off|max <n>].`);
|
|
221
|
+
},
|
|
222
|
+
},
|
|
93
223
|
{
|
|
94
224
|
name: 'expand',
|
|
95
225
|
description: 'Expand / collapse a recent tool card (default: last)',
|
|
@@ -12,11 +12,18 @@
|
|
|
12
12
|
* ~/.aragon-agent/
|
|
13
13
|
* ├── config.json persisted config (0600 on POSIX)
|
|
14
14
|
* ├── config.json.bak `aragon config edit` pre-edit backup
|
|
15
|
+
* ├── prompt-history.jsonl submitted prompts, append-only (0600 on POSIX)
|
|
16
|
+
* ├── state.json UI bookkeeping scalars (0600 on POSIX)
|
|
15
17
|
* ├── logs/ JSONL logs (0700 on POSIX)
|
|
16
18
|
* ├── sessions/ /save · /resume
|
|
17
19
|
* ├── skills/ `aragon skills install` target
|
|
18
20
|
* └── skill-usage.json
|
|
19
21
|
*
|
|
22
|
+
* The two files added by config-state-separation are DIRECT CHILDREN of the
|
|
23
|
+
* root, siblings of `skill-usage.json` rather than children of any directory
|
|
24
|
+
* here: `logs/`, `sessions/` and `skills/` are all scan roots, and every extra
|
|
25
|
+
* file inside one is another thing each walk has to recognise and skip.
|
|
26
|
+
*
|
|
20
27
|
* The same path on all three platforms, deliberately. Claude Code, git and npm
|
|
21
28
|
* all put their dot-directory in the user's home; one path means documentation,
|
|
22
29
|
* support scripts and community answers have exactly one thing to say. A user
|
|
@@ -62,6 +69,16 @@ export declare function getHomeRoot(): string;
|
|
|
62
69
|
export declare function getConfigPath(): string;
|
|
63
70
|
/** Written by `aragon config edit` before spawning the editor. */
|
|
64
71
|
export declare function getConfigBackupPath(): string;
|
|
72
|
+
/**
|
|
73
|
+
* `<home>/prompt-history.jsonl` — the prompts the user submitted, one JSON
|
|
74
|
+
* object per line. Deliberately NOT under `logs/`: that directory is governed
|
|
75
|
+
* by `log.toFile`, `log.maxFiles` and `aragon logs clear`, and turning
|
|
76
|
+
* diagnostics off or reclaiming disk must not also delete the user's `↑`
|
|
77
|
+
* recall (config-state-separation D-1).
|
|
78
|
+
*/
|
|
79
|
+
export declare function getPromptHistoryPath(): string;
|
|
80
|
+
/** `<home>/state.json` — UI bookkeeping scalars only; see `ui-state.ts`. */
|
|
81
|
+
export declare function getUiStatePath(): string;
|
|
65
82
|
export declare function getLogsDir(): string;
|
|
66
83
|
export declare function getSessionsDir(): string;
|
|
67
84
|
/** `<home>` — parent of `skills/`, and where sidecar state such as usage lives. */
|
package/dist/config/app-paths.js
CHANGED
|
@@ -12,11 +12,18 @@
|
|
|
12
12
|
* ~/.aragon-agent/
|
|
13
13
|
* ├── config.json persisted config (0600 on POSIX)
|
|
14
14
|
* ├── config.json.bak `aragon config edit` pre-edit backup
|
|
15
|
+
* ├── prompt-history.jsonl submitted prompts, append-only (0600 on POSIX)
|
|
16
|
+
* ├── state.json UI bookkeeping scalars (0600 on POSIX)
|
|
15
17
|
* ├── logs/ JSONL logs (0700 on POSIX)
|
|
16
18
|
* ├── sessions/ /save · /resume
|
|
17
19
|
* ├── skills/ `aragon skills install` target
|
|
18
20
|
* └── skill-usage.json
|
|
19
21
|
*
|
|
22
|
+
* The two files added by config-state-separation are DIRECT CHILDREN of the
|
|
23
|
+
* root, siblings of `skill-usage.json` rather than children of any directory
|
|
24
|
+
* here: `logs/`, `sessions/` and `skills/` are all scan roots, and every extra
|
|
25
|
+
* file inside one is another thing each walk has to recognise and skip.
|
|
26
|
+
*
|
|
20
27
|
* The same path on all three platforms, deliberately. Claude Code, git and npm
|
|
21
28
|
* all put their dot-directory in the user's home; one path means documentation,
|
|
22
29
|
* support scripts and community answers have exactly one thing to say. A user
|
|
@@ -119,6 +126,20 @@ export function getConfigPath() {
|
|
|
119
126
|
export function getConfigBackupPath() {
|
|
120
127
|
return join(resolution.root, 'config.json.bak');
|
|
121
128
|
}
|
|
129
|
+
/**
|
|
130
|
+
* `<home>/prompt-history.jsonl` — the prompts the user submitted, one JSON
|
|
131
|
+
* object per line. Deliberately NOT under `logs/`: that directory is governed
|
|
132
|
+
* by `log.toFile`, `log.maxFiles` and `aragon logs clear`, and turning
|
|
133
|
+
* diagnostics off or reclaiming disk must not also delete the user's `↑`
|
|
134
|
+
* recall (config-state-separation D-1).
|
|
135
|
+
*/
|
|
136
|
+
export function getPromptHistoryPath() {
|
|
137
|
+
return join(resolution.root, 'prompt-history.jsonl');
|
|
138
|
+
}
|
|
139
|
+
/** `<home>/state.json` — UI bookkeeping scalars only; see `ui-state.ts`. */
|
|
140
|
+
export function getUiStatePath() {
|
|
141
|
+
return join(resolution.root, 'state.json');
|
|
142
|
+
}
|
|
122
143
|
export function getLogsDir() {
|
|
123
144
|
return join(resolution.root, 'logs');
|
|
124
145
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `aragon config get | list | edit | home`, plus the `log.*`
|
|
3
|
-
* `config set`.
|
|
2
|
+
* `aragon config get | list | edit | home`, plus the `log.*` and `team.*`
|
|
3
|
+
* 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 —
|
|
@@ -10,6 +10,17 @@
|
|
|
10
10
|
import { type PersistedConfig } from './schema.js';
|
|
11
11
|
/** Config keys under `log.` that `aragon config set` accepts. */
|
|
12
12
|
export declare const LOG_CONFIG_SET_KEYS: readonly ["log.level", "log.toFile", "log.dir", "log.maxFileBytes", "log.maxFiles", "log.redactSecrets", "log.previewChars"];
|
|
13
|
+
/**
|
|
14
|
+
* Config keys under `team.` that `aragon config set` accepts (team-subagents
|
|
15
|
+
* §4.3).
|
|
16
|
+
*
|
|
17
|
+
* Handled here rather than in `cli.tsx`'s switch for the reason this module's
|
|
18
|
+
* header already gives about `log.*`: that switch is past this package's
|
|
19
|
+
* complexity ceiling, and a key added to the membership set but forgotten in the
|
|
20
|
+
* switch falls through every case, writes nothing, and still prints
|
|
21
|
+
* `Set team.enabled = false`.
|
|
22
|
+
*/
|
|
23
|
+
export declare const TEAM_CONFIG_SET_KEYS: readonly ["team.enabled", "team.maxSubagents", "team.maxConcurrent", "team.subagentTimeoutMs", "team.dispatchTimeoutMs", "team.maxTurnsPerSubagent"];
|
|
13
24
|
/**
|
|
14
25
|
* Translate a `log.*` dotted key into a patch, or `null` for anything else.
|
|
15
26
|
*
|
|
@@ -19,6 +30,19 @@ export declare const LOG_CONFIG_SET_KEYS: readonly ["log.level", "log.toFile", "
|
|
|
19
30
|
* included.
|
|
20
31
|
*/
|
|
21
32
|
export declare function applyLogConfigSet(key: string, value: string): Partial<PersistedConfig> | null;
|
|
33
|
+
/**
|
|
34
|
+
* Translate a `team.*` dotted key into a patch, or `null` for anything else.
|
|
35
|
+
*
|
|
36
|
+
* The patch is a PARTIAL `team` section, safe only because
|
|
37
|
+
* `updatePersistedConfig` deep-merges that section — with a shallow merge,
|
|
38
|
+
* setting the fan-out width would silently reset every timeout in the section.
|
|
39
|
+
*
|
|
40
|
+
* Values are CLAMPED rather than rejected, exactly like `theme` and
|
|
41
|
+
* `skills.integrity`: hardening only the read path leaves a bad value on disk
|
|
42
|
+
* that reverts to the default on every launch, which presents as "my setting
|
|
43
|
+
* won't stick". `clampTeamConfig` is the one gate both directions pass through.
|
|
44
|
+
*/
|
|
45
|
+
export declare function applyTeamConfigSet(key: string, value: string): Partial<PersistedConfig> | null;
|
|
22
46
|
/**
|
|
23
47
|
* `log.redactSecrets false` is the one setting that lets credentials reach the
|
|
24
48
|
* disk. It is command-line-only (there is no settings-screen entry) and it says
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `aragon config get | list | edit | home`, plus the `log.*`
|
|
3
|
-
* `config set`.
|
|
2
|
+
* `aragon config get | list | edit | home`, plus the `log.*` and `team.*`
|
|
3
|
+
* 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 —
|
|
@@ -10,10 +10,10 @@
|
|
|
10
10
|
import { spawnSync } from 'node:child_process';
|
|
11
11
|
import { copyFileSync, existsSync, readFileSync } from 'node:fs';
|
|
12
12
|
import process from 'node:process';
|
|
13
|
-
import { getConfigBackupPath, getConfigPath, getHomeRoot, getLogsDir, isHomeOverridden, } from './app-paths.js';
|
|
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 { coercePositiveInt, maskSecret, } from './schema.js';
|
|
16
|
+
import { coercePositiveInt, maskSecret, DEFAULT_TEAM_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 = [
|
|
@@ -25,6 +25,24 @@ export const LOG_CONFIG_SET_KEYS = [
|
|
|
25
25
|
'log.redactSecrets',
|
|
26
26
|
'log.previewChars',
|
|
27
27
|
];
|
|
28
|
+
/**
|
|
29
|
+
* Config keys under `team.` that `aragon config set` accepts (team-subagents
|
|
30
|
+
* §4.3).
|
|
31
|
+
*
|
|
32
|
+
* Handled here rather than in `cli.tsx`'s switch for the reason this module's
|
|
33
|
+
* header already gives about `log.*`: that switch is past this package's
|
|
34
|
+
* complexity ceiling, and a key added to the membership set but forgotten in the
|
|
35
|
+
* switch falls through every case, writes nothing, and still prints
|
|
36
|
+
* `Set team.enabled = false`.
|
|
37
|
+
*/
|
|
38
|
+
export const TEAM_CONFIG_SET_KEYS = [
|
|
39
|
+
'team.enabled',
|
|
40
|
+
'team.maxSubagents',
|
|
41
|
+
'team.maxConcurrent',
|
|
42
|
+
'team.subagentTimeoutMs',
|
|
43
|
+
'team.dispatchTimeoutMs',
|
|
44
|
+
'team.maxTurnsPerSubagent',
|
|
45
|
+
];
|
|
28
46
|
function isTrue(value) {
|
|
29
47
|
return value === 'true' || value === '1';
|
|
30
48
|
}
|
|
@@ -57,6 +75,43 @@ export function applyLogConfigSet(key, value) {
|
|
|
57
75
|
return null;
|
|
58
76
|
}
|
|
59
77
|
}
|
|
78
|
+
/**
|
|
79
|
+
* Translate a `team.*` dotted key into a patch, or `null` for anything else.
|
|
80
|
+
*
|
|
81
|
+
* The patch is a PARTIAL `team` section, safe only because
|
|
82
|
+
* `updatePersistedConfig` deep-merges that section — with a shallow merge,
|
|
83
|
+
* setting the fan-out width would silently reset every timeout in the section.
|
|
84
|
+
*
|
|
85
|
+
* Values are CLAMPED rather than rejected, exactly like `theme` and
|
|
86
|
+
* `skills.integrity`: hardening only the read path leaves a bad value on disk
|
|
87
|
+
* that reverts to the default on every launch, which presents as "my setting
|
|
88
|
+
* won't stick". `clampTeamConfig` is the one gate both directions pass through.
|
|
89
|
+
*/
|
|
90
|
+
export function applyTeamConfigSet(key, value) {
|
|
91
|
+
const patch = (team) => ({ team });
|
|
92
|
+
switch (key) {
|
|
93
|
+
case 'team.enabled':
|
|
94
|
+
return patch({ enabled: isTrue(value) });
|
|
95
|
+
case 'team.maxSubagents':
|
|
96
|
+
return patch({ maxSubagents: coercePositiveInt(value, DEFAULT_TEAM_CONFIG.maxSubagents) });
|
|
97
|
+
case 'team.maxConcurrent':
|
|
98
|
+
return patch({ maxConcurrent: coercePositiveInt(value, DEFAULT_TEAM_CONFIG.maxConcurrent) });
|
|
99
|
+
case 'team.subagentTimeoutMs':
|
|
100
|
+
return patch({
|
|
101
|
+
subagentTimeoutMs: coercePositiveInt(value, DEFAULT_TEAM_CONFIG.subagentTimeoutMs),
|
|
102
|
+
});
|
|
103
|
+
case 'team.dispatchTimeoutMs':
|
|
104
|
+
return patch({
|
|
105
|
+
dispatchTimeoutMs: coercePositiveInt(value, DEFAULT_TEAM_CONFIG.dispatchTimeoutMs),
|
|
106
|
+
});
|
|
107
|
+
case 'team.maxTurnsPerSubagent':
|
|
108
|
+
return patch({
|
|
109
|
+
maxTurnsPerSubagent: coercePositiveInt(value, DEFAULT_TEAM_CONFIG.maxTurnsPerSubagent),
|
|
110
|
+
});
|
|
111
|
+
default:
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
60
115
|
/**
|
|
61
116
|
* `log.redactSecrets false` is the one setting that lets credentials reach the
|
|
62
117
|
* disk. It is command-line-only (there is no settings-screen entry) and it says
|
|
@@ -80,6 +135,20 @@ function maskConfig(config) {
|
|
|
80
135
|
}
|
|
81
136
|
return { ...config, apiKeys };
|
|
82
137
|
}
|
|
138
|
+
/**
|
|
139
|
+
* The human-readable label for a value whose raw form would mislead, or
|
|
140
|
+
* `undefined` to leave the caller's own formatting alone.
|
|
141
|
+
*
|
|
142
|
+
* `maxTokens: null` is AUTO, not "unset". Printing a bare `null` reads as a
|
|
143
|
+
* missing setting and sends the user looking for a bug that is not there.
|
|
144
|
+
* `get` and `list` format everything else differently (unquoted vs. JSON), so
|
|
145
|
+
* this deliberately overrides one case rather than replacing both renderers.
|
|
146
|
+
*/
|
|
147
|
+
function displayOverride(key, value) {
|
|
148
|
+
if (key === 'maxTokens' && value === null)
|
|
149
|
+
return 'auto';
|
|
150
|
+
return undefined;
|
|
151
|
+
}
|
|
83
152
|
/** Resolve a flat or one-level-dotted key against the persisted config. */
|
|
84
153
|
function readKey(config, key) {
|
|
85
154
|
const [head, tail] = key.split('.', 2);
|
|
@@ -98,10 +167,14 @@ export function runConfigGet(key) {
|
|
|
98
167
|
process.exitCode = 2;
|
|
99
168
|
return;
|
|
100
169
|
}
|
|
101
|
-
|
|
170
|
+
const shown = displayOverride(key, value)
|
|
171
|
+
?? (typeof value === 'string' ? value : JSON.stringify(value));
|
|
172
|
+
process.stdout.write(`${shown}\n`);
|
|
102
173
|
}
|
|
103
174
|
export function runConfigList(opts = {}) {
|
|
104
175
|
const masked = maskConfig(loadPersistedConfig());
|
|
176
|
+
// `--json` stays RAW on purpose: it mirrors the file, and a consumer parsing
|
|
177
|
+
// it must see the `null` that is actually on disk.
|
|
105
178
|
if (opts.json) {
|
|
106
179
|
process.stdout.write(`${JSON.stringify(masked, null, 2)}\n`);
|
|
107
180
|
return;
|
|
@@ -113,7 +186,7 @@ export function runConfigList(opts = {}) {
|
|
|
113
186
|
}
|
|
114
187
|
continue;
|
|
115
188
|
}
|
|
116
|
-
process.stdout.write(`${key} = ${JSON.stringify(value)}\n`);
|
|
189
|
+
process.stdout.write(`${key} = ${displayOverride(key, value) ?? JSON.stringify(value)}\n`);
|
|
117
190
|
}
|
|
118
191
|
}
|
|
119
192
|
// ---------------------------------------------------------------------------
|
|
@@ -177,6 +250,10 @@ export function runConfigHome() {
|
|
|
177
250
|
process.stdout.write(`${getHomeRoot()}\n`);
|
|
178
251
|
if (isHomeOverridden())
|
|
179
252
|
process.stdout.write(' (overridden by ARAGON_HOME)\n');
|
|
253
|
+
// Named here because config.json no longer holds either of them, and a user
|
|
254
|
+
// looking for "where did my prompt history go" has to land somewhere.
|
|
255
|
+
process.stdout.write(` prompt history: ${getPromptHistoryPath()}\n`);
|
|
256
|
+
process.stdout.write(` ui state: ${getUiStatePath()}\n`);
|
|
180
257
|
const breadcrumb = getHomeMigrationBreadcrumbPath();
|
|
181
258
|
if (!existsSync(breadcrumb))
|
|
182
259
|
return;
|
package/dist/config/env.d.ts
CHANGED
|
@@ -5,8 +5,9 @@
|
|
|
5
5
|
* - Provider secrets: ANTHROPIC_API_KEY, OPENAI_API_KEY, GOOGLE_API_KEY /
|
|
6
6
|
* GEMINI_API_KEY.
|
|
7
7
|
* - Overrides: ARAGON_PROVIDER, ARAGON_MODEL, ARAGON_BASE_URL, ARAGON_THINKING,
|
|
8
|
-
* ARAGON_MAX_TOKENS
|
|
9
|
-
*
|
|
8
|
+
* ARAGON_MAX_TOKENS (a number, or `auto` / `0` for the per-model ceiling),
|
|
9
|
+
* ARAGON_THEME, ARAGON_MOUSE, ARAGON_PLAN, ARAGON_TEAM,
|
|
10
|
+
* ARAGON_TEAM_MAX, ARAGON_LOG_LEVEL, ARAGON_LOG_FILE, ARAGON_LOG_DIR.
|
|
10
11
|
*
|
|
11
12
|
* NOT here: `ARAGON_HOME`. It is read when `config/app-paths.ts` is first
|
|
12
13
|
* evaluated, which is long before `loadDotenv()` runs, so a `.env` can never
|