@aragon-agent/cli 0.6.22 → 0.6.24
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/README.md +20 -2
- package/dist/agent/controller.d.ts +11 -0
- package/dist/agent/controller.js +42 -4
- package/dist/agent/model-profile-settings.js +29 -2
- package/dist/agent/reducer.js +8 -6
- package/dist/commands/builtins.js +87 -3
- package/dist/compaction/child.d.ts +15 -0
- package/dist/compaction/child.js +14 -3
- package/dist/compaction/compactor.js +1 -0
- package/dist/compaction/context-command.js +10 -1
- package/dist/compaction/meter.d.ts +9 -0
- package/dist/compaction/meter.js +16 -1
- package/dist/compaction/pressure.d.ts +7 -0
- package/dist/compaction/pressure.js +5 -0
- package/dist/compaction/types.d.ts +11 -0
- package/dist/compaction/wiring.js +1 -0
- package/dist/config/cli-commands.d.ts +1 -1
- package/dist/config/cli-commands.js +12 -0
- package/dist/config/load.js +66 -9
- package/dist/config/model-profile-resolution.d.ts +8 -0
- package/dist/config/model-profile-resolution.js +13 -6
- package/dist/config/model-profile-store.d.ts +4 -2
- package/dist/config/model-profiles.d.ts +13 -0
- package/dist/config/model-profiles.js +18 -2
- package/dist/config/schema.d.ts +86 -0
- package/dist/config/schema.js +74 -0
- package/dist/team/model.d.ts +88 -0
- package/dist/team/model.js +136 -0
- package/dist/team/overseer.d.ts +5 -3
- package/dist/team/overseer.js +15 -4
- package/dist/team/report.d.ts +11 -0
- package/dist/team/report.js +24 -1
- package/dist/team/runtime.js +20 -3
- package/dist/team/subagent.d.ts +10 -0
- package/dist/team/subagent.js +57 -27
- package/dist/team/task-tool.d.ts +25 -6
- package/dist/team/task-tool.js +15 -9
- package/dist/team/types.d.ts +4 -3
- package/dist/ui/App.js +5 -0
- package/dist/ui/overlays/ModelProfileEditor.js +18 -4
- package/dist/ui/overlays/ModelProfilePicker.d.ts +14 -2
- package/dist/ui/overlays/ModelProfilePicker.js +51 -10
- package/dist/ui/overlays/QuestionOverlay.js +47 -6
- package/dist/ui/overlays/SettingsScreen.d.ts +9 -0
- package/dist/ui/overlays/SettingsScreen.js +119 -17
- package/dist/ui/overlays/model-profile-state.d.ts +53 -4
- package/dist/ui/overlays/model-profile-state.js +111 -14
- package/package.json +2 -2
|
@@ -1,17 +1,29 @@
|
|
|
1
1
|
import { randomUUID } from 'node:crypto';
|
|
2
2
|
import { emptyModelProfiles, duplicateModelProfile, normalizeModelProfiles, validateModelProfiles } from '../../config/model-profiles.js';
|
|
3
|
+
import { parseContextWindowInput } from '../../config/schema.js';
|
|
4
|
+
/** The picker's built-in `Fast tier model` row; never a profile id on disk. */
|
|
5
|
+
export const SUBAGENT_FAST_ROW_ID = '__fast__';
|
|
3
6
|
/** Keep the original secret separate from the empty replacement field. */
|
|
4
7
|
export function createProfileEditor(profile) {
|
|
5
8
|
return { original: { ...profile }, name: profile.name, provider: profile.provider,
|
|
6
9
|
model: profile.model, baseUrl: profile.baseUrl ?? '', apiKey: '',
|
|
10
|
+
contextWindow: profile.contextWindow === null ? '' : String(profile.contextWindow),
|
|
7
11
|
credentialMode: profile.apiKey ? 'keep' : 'shared', endpointChanged: false };
|
|
8
12
|
}
|
|
9
13
|
/** Validate locally before merging the child form into the root transaction. */
|
|
10
14
|
export function finishProfileEditor(editor) {
|
|
15
|
+
// STRICT IN THE UI, TOLERANT ON DISK (§6.5 / invariant 4): a typo is refused
|
|
16
|
+
// here with an inline error and the focus jump its `field` enables; it never
|
|
17
|
+
// reaches the draft. The message prefix matches the editor's LABELS row.
|
|
18
|
+
const window = parseContextWindowInput(editor.contextWindow);
|
|
19
|
+
if (window.kind === 'invalid') {
|
|
20
|
+
return { error: 'Context window: use a number or auto.', field: 'contextWindow' };
|
|
21
|
+
}
|
|
11
22
|
const profile = { id: editor.original.id, name: editor.name.trim(),
|
|
12
23
|
provider: editor.provider, model: editor.model.trim(), baseUrl: editor.baseUrl.trim() || null,
|
|
13
24
|
apiKey: editor.credentialMode === 'keep' ? editor.original.apiKey
|
|
14
|
-
: editor.credentialMode === 'replace' ? editor.apiKey.trim() : null
|
|
25
|
+
: editor.credentialMode === 'replace' ? editor.apiKey.trim() : null,
|
|
26
|
+
contextWindow: window.kind === 'auto' ? null : window.value };
|
|
15
27
|
const library = { ...emptyModelProfiles(), entries: [profile] };
|
|
16
28
|
const issue = validateModelProfiles(library)[0];
|
|
17
29
|
if (issue)
|
|
@@ -30,10 +42,52 @@ export function createModelProfileState(draft) {
|
|
|
30
42
|
bindNew: false, dirty: false };
|
|
31
43
|
}
|
|
32
44
|
/** Describe references using text so ASCII and no-color modes remain usable. */
|
|
33
|
-
export function profileUsers(profiles, id) {
|
|
34
|
-
return [profiles?.mainId === id ? 'Main' : '', profiles?.fastId === id ? 'Fast' : ''
|
|
45
|
+
export function profileUsers(profiles, id, subagentProfileId) {
|
|
46
|
+
return [profiles?.mainId === id ? 'Main' : '', profiles?.fastId === id ? 'Fast' : '',
|
|
47
|
+
subagentProfileId === id ? 'Subagent' : '']
|
|
35
48
|
.filter(Boolean).join(' + ');
|
|
36
49
|
}
|
|
50
|
+
/**
|
|
51
|
+
* The team section a draft would save: the patch first, then the disk baseline
|
|
52
|
+
* (subagent-model §3.6). The explicit-`undefined` test is what makes an
|
|
53
|
+
* explicit `null` in the patch win over the baseline - `??` would fold it away.
|
|
54
|
+
*/
|
|
55
|
+
export function draftTeam(draft) {
|
|
56
|
+
const patch = draft.patch.team;
|
|
57
|
+
const baseline = draft.baseline.team;
|
|
58
|
+
return {
|
|
59
|
+
model: patch?.model !== undefined ? patch.model : baseline?.model ?? 'main',
|
|
60
|
+
modelProfileId: patch?.modelProfileId !== undefined ? patch.modelProfileId
|
|
61
|
+
: baseline?.modelProfileId ?? null,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
/** The profile id the draft's team section binds, for reference checks (3.7). */
|
|
65
|
+
export function draftSubagentProfileId(draft) {
|
|
66
|
+
return draftTeam(draft).model === 'profile' ? draftTeam(draft).modelProfileId : null;
|
|
67
|
+
}
|
|
68
|
+
/** The projected picker selection for the subagent role (6.2). */
|
|
69
|
+
export function subagentSelectedId(draft) {
|
|
70
|
+
const team = draftTeam(draft);
|
|
71
|
+
if (team.model === 'profile')
|
|
72
|
+
return team.modelProfileId;
|
|
73
|
+
return team.model === 'fast' ? SUBAGENT_FAST_ROW_ID : null;
|
|
74
|
+
}
|
|
75
|
+
export function subagentModelSummary(input) {
|
|
76
|
+
if (input.mode === 'main')
|
|
77
|
+
return `Same as main (${input.mainConnection})`;
|
|
78
|
+
if (input.mode === 'fast') {
|
|
79
|
+
return input.fastConnection
|
|
80
|
+
? `Fast tier (${input.fastConnection})`
|
|
81
|
+
: 'Fast tier (off - falls back to main)';
|
|
82
|
+
}
|
|
83
|
+
const entry = input.modelProfileId
|
|
84
|
+
? input.profiles?.entries.find((candidate) => candidate.id === input.modelProfileId)
|
|
85
|
+
: undefined;
|
|
86
|
+
if (!entry)
|
|
87
|
+
return 'Profile missing - falls back to main';
|
|
88
|
+
const missing = !entry.apiKey && !input.hasKey(entry.provider);
|
|
89
|
+
return `${entry.name} ${entry.provider}:${entry.model}${missing ? ' [Missing API key]' : ''}`;
|
|
90
|
+
}
|
|
37
91
|
/** Adopt persisted fields only, resolving the old fast inheritance once. */
|
|
38
92
|
export function createCustomProfile(draft, role) {
|
|
39
93
|
const file = draft.baseline;
|
|
@@ -45,7 +99,11 @@ export function createCustomProfile(draft, role) {
|
|
|
45
99
|
|| (provider === (file.provider || 'anthropic') ? file.baseUrl : null)
|
|
46
100
|
: file.baseUrl) || null;
|
|
47
101
|
return { id: randomUUID(), name: '', provider, model, baseUrl,
|
|
48
|
-
apiKey: role === 'fast' && !model ? null : file.apiKeys?.[provider] || null
|
|
102
|
+
apiKey: role === 'fast' && !model ? null : file.apiKeys?.[provider] || null,
|
|
103
|
+
// Carry the user's existing top-level correction into the first profile
|
|
104
|
+
// (§6.5): binding an AUTO profile would otherwise silently retire it
|
|
105
|
+
// (tradeoff B's migration risk, mitigated exactly here).
|
|
106
|
+
contextWindow: file.contextWindow ?? null };
|
|
49
107
|
}
|
|
50
108
|
function editField(state, action) {
|
|
51
109
|
if (!state.editor)
|
|
@@ -85,9 +143,24 @@ export function modelProfileReducer(state, action) {
|
|
|
85
143
|
case 'reload': return createModelProfileState(action.draft);
|
|
86
144
|
case 'page': return { ...state, page: action.page, role: action.role ?? state.role,
|
|
87
145
|
error: undefined };
|
|
88
|
-
case 'select':
|
|
89
|
-
|
|
90
|
-
|
|
146
|
+
case 'select': {
|
|
147
|
+
// THE SUBAGENT BRANCH (D-5): selection writes the DRAFT's team patch -
|
|
148
|
+
// `profiles` and `activateRoles` are untouched, because 'subagent' is a
|
|
149
|
+
// picker-only role with no `${role}Id` library key (6.2). Save is the
|
|
150
|
+
// one place the patch ever reaches disk (I-5).
|
|
151
|
+
if (action.role === 'subagent') {
|
|
152
|
+
const team = action.id === null
|
|
153
|
+
? { model: 'main', modelProfileId: null }
|
|
154
|
+
: action.id === SUBAGENT_FAST_ROW_ID
|
|
155
|
+
? { model: 'fast', modelProfileId: null }
|
|
156
|
+
: { model: 'profile', modelProfileId: action.id };
|
|
157
|
+
return { ...state, page: 'root', dirty: true, error: undefined,
|
|
158
|
+
draft: { ...state.draft, patch: { ...state.draft.patch, team } } };
|
|
159
|
+
}
|
|
160
|
+
return { ...state, page: 'root', dirty: true, error: undefined,
|
|
161
|
+
draft: { ...state.draft, profiles: { ...library, [`${action.role}Id`]: action.id },
|
|
162
|
+
activateRoles: [...new Set([...state.draft.activateRoles, action.role])] } };
|
|
163
|
+
}
|
|
91
164
|
case 'edit': return { ...state, editor: createProfileEditor(action.profile), page: 'editor',
|
|
92
165
|
returnPage: state.page === 'picker' ? 'picker' : 'manager',
|
|
93
166
|
bindNew: action.bindNew ?? false, error: undefined };
|
|
@@ -107,13 +180,37 @@ export function modelProfileReducer(state, action) {
|
|
|
107
180
|
: state;
|
|
108
181
|
}
|
|
109
182
|
case 'delete': {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
183
|
+
// UNBIND-AND-DELETE (D-6): being referenced no longer refuses the flow.
|
|
184
|
+
// The references - subagent included - are computed here, shown on the
|
|
185
|
+
// confirm page, and cleared by `confirm-delete` inside the draft.
|
|
186
|
+
const users = profileUsers(library, action.id, draftSubagentProfileId(state.draft));
|
|
187
|
+
return { ...state, page: 'delete-confirm', deleteId: action.id,
|
|
188
|
+
deleteUsers: users, error: undefined };
|
|
189
|
+
}
|
|
190
|
+
case 'confirm-delete': {
|
|
191
|
+
const id = state.deleteId;
|
|
192
|
+
if (!id)
|
|
193
|
+
return state;
|
|
194
|
+
// THE DRAFT-SIDE UNBIND: Main/Fast bindings pointing at the entry are
|
|
195
|
+
// nulled here (not refused) and the subagent binding resets to main
|
|
196
|
+
// when it named THIS entry. `removeModelProfile`'s throw stays as the
|
|
197
|
+
// bottom-line defense - the UI has already unbound, so it cannot fire
|
|
198
|
+
// on this path.
|
|
199
|
+
const profiles = {
|
|
200
|
+
...library,
|
|
201
|
+
mainId: library.mainId === id ? null : library.mainId,
|
|
202
|
+
fastId: library.fastId === id ? null : library.fastId,
|
|
203
|
+
entries: library.entries.filter((entry) => entry.id !== id),
|
|
204
|
+
};
|
|
205
|
+
const teamReset = draftSubagentProfileId(state.draft) === id
|
|
206
|
+
? { team: { model: 'main', modelProfileId: null } }
|
|
207
|
+
: {};
|
|
208
|
+
return { ...state, page: 'manager', dirty: true,
|
|
209
|
+
draft: { ...state.draft, profiles,
|
|
210
|
+
patch: { ...state.draft.patch, ...teamReset } },
|
|
211
|
+
deleteId: undefined, deleteUsers: undefined,
|
|
212
|
+
// No orphan editor for a deleted entry (3.7).
|
|
213
|
+
editor: state.editor?.original.id === id ? undefined : state.editor };
|
|
113
214
|
}
|
|
114
|
-
case 'confirm-delete': return { ...state, page: 'manager', dirty: true,
|
|
115
|
-
draft: { ...state.draft, profiles: { ...library,
|
|
116
|
-
entries: library.entries.filter((entry) => entry.id !== state.deleteId) } },
|
|
117
|
-
deleteId: undefined };
|
|
118
215
|
}
|
|
119
216
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aragon-agent/cli",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.24",
|
|
4
4
|
"description": "AragonAgent CLI — a Claude-Code / Codex-style interactive terminal UI (TUI) on top of the @aragon-agent/core engine. Installable and runnable via npm / npx.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "AragonAgent contributors",
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"prepublishOnly": "npm run build"
|
|
57
57
|
},
|
|
58
58
|
"dependencies": {
|
|
59
|
-
"@aragon-agent/core": "^0.2.
|
|
59
|
+
"@aragon-agent/core": "^0.2.36",
|
|
60
60
|
"chalk": "^5.6.2",
|
|
61
61
|
"cli-highlight": "^2.0.0",
|
|
62
62
|
"commander": "^12.1.0",
|