@aragon-agent/cli 0.6.21 → 0.6.23
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 +32 -12
- package/dist/agent/controller.js +22 -1
- package/dist/agent/reducer.js +8 -6
- package/dist/commands/builtins.js +2 -1
- package/dist/config/cli-commands.d.ts +1 -1
- package/dist/config/cli-commands.js +3 -0
- package/dist/config/load.js +42 -3
- package/dist/config/schema.d.ts +53 -12
- package/dist/config/schema.js +42 -0
- package/dist/team/limits.d.ts +73 -13
- package/dist/team/limits.js +82 -15
- package/dist/team/normalize.js +7 -2
- package/dist/team/overseer.d.ts +158 -18
- package/dist/team/overseer.js +356 -49
- package/dist/team/report.d.ts +9 -0
- package/dist/team/report.js +32 -4
- package/dist/team/runtime.d.ts +51 -9
- package/dist/team/runtime.js +498 -74
- package/dist/team/subagent.d.ts +10 -0
- package/dist/team/subagent.js +20 -6
- package/dist/team/task-tool.d.ts +7 -0
- package/dist/team/task-tool.js +2 -0
- package/dist/team/types.d.ts +44 -2
- package/dist/ui/App.js +14 -0
- package/dist/ui/TeamPanel.d.ts +22 -0
- package/dist/ui/TeamPanel.js +71 -2
- package/dist/ui/layout/team-panel.js +4 -1
- package/package.json +2 -2
package/dist/team/subagent.d.ts
CHANGED
|
@@ -135,6 +135,16 @@ export interface SubagentHooks {
|
|
|
135
135
|
* so the phase read at fire time is current.
|
|
136
136
|
*/
|
|
137
137
|
onActivity?: () => void;
|
|
138
|
+
/**
|
|
139
|
+
* THE TURN CAP AS AN INSPECTION TRIGGER (F-8 A'2). Called ONCE, at the turn
|
|
140
|
+
* that crossed `maxTurnsPerSubagent`, ONLY when the dispatch supervisor is
|
|
141
|
+
* live - the runtime wires this hook under the same gate as
|
|
142
|
+
* `overseerActive`, so its presence IS the supervised/legacy branch. The
|
|
143
|
+
* child is NOT stopped: the supervisor decides wait / nudge / replace /
|
|
144
|
+
* abandon through the same `inspectAndApply` path every other trigger
|
|
145
|
+
* uses, and a child it lets run carries no `truncated` flag.
|
|
146
|
+
*/
|
|
147
|
+
onTurnCapReached?: (label: string) => void;
|
|
138
148
|
}
|
|
139
149
|
export interface SubagentHandle {
|
|
140
150
|
spec: SubagentSpec;
|
package/dist/team/subagent.js
CHANGED
|
@@ -359,12 +359,26 @@ export function createSubagent(spec, deps, hooks) {
|
|
|
359
359
|
// not runaway - it is working.
|
|
360
360
|
const turnCap = deps.config.team.maxTurnsPerSubagent;
|
|
361
361
|
if (turnCap > 0 && run.turns >= turnCap) {
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
362
|
+
if (hooks.onTurnCapReached !== undefined) {
|
|
363
|
+
// A'2, D-4 for the turn cap: SUPERVISED means the ceiling is
|
|
364
|
+
// an inspection trigger, not a death sentence. ONE look at the
|
|
365
|
+
// crossing turn (`===`), never a per-turn storm; the child
|
|
366
|
+
// keeps working unless the supervisor decides replace or
|
|
367
|
+
// abandon, and a child that keeps running carries NO
|
|
368
|
+
// `truncated` flag - the report must not call it partial.
|
|
369
|
+
if (run.turns === turnCap)
|
|
370
|
+
hooks.onTurnCapReached(spec.label);
|
|
371
|
+
}
|
|
372
|
+
else {
|
|
373
|
+
// LEGACY regime (no supervisor for this dispatch): the hard
|
|
374
|
+
// stop, byte for byte what it always was.
|
|
375
|
+
run.truncated = true;
|
|
376
|
+
// THE FLAG FIRST, exactly like `handle.abort()`: the child's
|
|
377
|
+
// reviewer reads `abortRequested` as its guard-1 fact, and a
|
|
378
|
+
// turn-cap stop must be visible to it in the same tick.
|
|
379
|
+
abortRequested = true;
|
|
380
|
+
agent.abort();
|
|
381
|
+
}
|
|
368
382
|
}
|
|
369
383
|
break;
|
|
370
384
|
}
|
package/dist/team/task-tool.d.ts
CHANGED
|
@@ -39,6 +39,13 @@ export interface TaskToolDeps {
|
|
|
39
39
|
activeProvider: () => string;
|
|
40
40
|
/** The lead's cost table, so the report header states real spend (R-5). */
|
|
41
41
|
modelCost: () => ModelCost | undefined;
|
|
42
|
+
/**
|
|
43
|
+
* The FAST tier's cost table, so the report's supervisor spend line states
|
|
44
|
+
* real spend (subagent-overseer-v2 D-7 / R-P1-2). OPTIONAL and returning
|
|
45
|
+
* `undefined`: an unpriced fast model renders `pricing unknown`, never a
|
|
46
|
+
* fabricated `$0.00` - the C-11 / RV-4 rule.
|
|
47
|
+
*/
|
|
48
|
+
fastModelCost?: () => ModelCost | undefined;
|
|
42
49
|
/**
|
|
43
50
|
* Run the dispatch with the LEAD's idle watchdog paused, `try/finally` inside.
|
|
44
51
|
*
|
package/dist/team/task-tool.js
CHANGED
|
@@ -123,8 +123,10 @@ export function createTaskTool(deps) {
|
|
|
123
123
|
// shape, and D-14 one level up). Every child ran the lead's own model,
|
|
124
124
|
// so the lead's cost table is the one honest price for the total.
|
|
125
125
|
const cost = deps.modelCost();
|
|
126
|
+
const fastCost = deps.fastModelCost?.();
|
|
126
127
|
return textResult(buildDispatchReport(outcome, {
|
|
127
128
|
...(cost ? { cost } : {}),
|
|
129
|
+
...(fastCost ? { fastCost } : {}),
|
|
128
130
|
}));
|
|
129
131
|
},
|
|
130
132
|
};
|
package/dist/team/types.d.ts
CHANGED
|
@@ -159,6 +159,22 @@ export interface SubagentRun {
|
|
|
159
159
|
* report reads "this row is the Nth body of the same brief".
|
|
160
160
|
*/
|
|
161
161
|
replacements?: number;
|
|
162
|
+
/**
|
|
163
|
+
* The most recent supervisor decision applied to this child
|
|
164
|
+
* (subagent-overseer-v2 section 6). TRANSIENT, never persisted - the
|
|
165
|
+
* same rule as `activity` / `activityArgs`; a resumed session has no
|
|
166
|
+
* live dispatch.
|
|
167
|
+
*
|
|
168
|
+
* `at` is ABSOLUTE epoch ms, the same units as `startedAt` / `endedAt`
|
|
169
|
+
* (R-P2-3), so the panel renders `nudged 2m` with one subtraction and
|
|
170
|
+
* no second clock convention. `reasonHead` <= 60 chars, for the UI
|
|
171
|
+
* badge line only.
|
|
172
|
+
*/
|
|
173
|
+
lastIntervention?: {
|
|
174
|
+
action: OverseerAction;
|
|
175
|
+
at: number;
|
|
176
|
+
reasonHead: string;
|
|
177
|
+
};
|
|
162
178
|
}
|
|
163
179
|
/** What the supervisor may do with one inspected child. */
|
|
164
180
|
export type OverseerAction = 'wait' | 'nudge' | 'replace' | 'abandon';
|
|
@@ -184,8 +200,15 @@ export interface OverseerIntervention {
|
|
|
184
200
|
at: number;
|
|
185
201
|
action: OverseerAction;
|
|
186
202
|
reason: string;
|
|
187
|
-
/**
|
|
188
|
-
|
|
203
|
+
/**
|
|
204
|
+
* What the trigger was: event stall, wall-clock check, the child's turn
|
|
205
|
+
* cap (F-8 A'2 - an inspection the supervisor then ruled on), post-mortem,
|
|
206
|
+
* or the supervisor going QUIET (subagent-overseer-v2 D-10) - the look
|
|
207
|
+
* budget ran out and supervision stopped waking this child. A VALUE OF
|
|
208
|
+
* THE UNION, never a reason prefix: a human-readable sentence is not a
|
|
209
|
+
* machine contract (the `run.error` rule).
|
|
210
|
+
*/
|
|
211
|
+
trigger: 'silence' | 'clock' | 'turncap' | 'postmortem' | 'quiet';
|
|
189
212
|
}
|
|
190
213
|
/**
|
|
191
214
|
* A terminal supervisor decision handed to the WORKER LOOP, which is the only
|
|
@@ -231,6 +254,25 @@ export interface DispatchOutcome {
|
|
|
231
254
|
* total priced at the lead's table is the honest accounting.
|
|
232
255
|
*/
|
|
233
256
|
usage: TokenUsage;
|
|
257
|
+
/**
|
|
258
|
+
* The supervisor's own fast-tier spend for this dispatch
|
|
259
|
+
* (subagent-overseer-v2 D-7). Absent when nothing supervised the
|
|
260
|
+
* dispatch; read straight off the provider at dispatch end so there is
|
|
261
|
+
* exactly one accounting of it.
|
|
262
|
+
*/
|
|
263
|
+
overseerUsage?: TokenUsage;
|
|
264
|
+
/** Inspection calls made, including ones that failed softly. */
|
|
265
|
+
overseerCalls?: number;
|
|
266
|
+
/**
|
|
267
|
+
* EDGE-LATCHED, once per dispatch (D-10): the fast tier was missing at
|
|
268
|
+
* least one cadence tick and the children waited UNASSISTED - announced,
|
|
269
|
+
* never killed. The per-child wait events of a degraded tick
|
|
270
|
+
* deliberately do NOT enter `interventions`; this flag plus the tick
|
|
271
|
+
* count below are the report's aggregate note.
|
|
272
|
+
*/
|
|
273
|
+
overseerDegraded?: boolean;
|
|
274
|
+
/** How many cadence ticks ran unassisted (the aggregate note's number). */
|
|
275
|
+
overseerDegradedTicks?: number;
|
|
234
276
|
}
|
|
235
277
|
/**
|
|
236
278
|
* What the UI renders: a cheap immutable projection, rebuilt per event.
|
package/dist/ui/App.js
CHANGED
|
@@ -664,6 +664,20 @@ export function App({ controller, version, initialOverlay, initialPrompt, confir
|
|
|
664
664
|
const snap = controller.getTeamSnapshot();
|
|
665
665
|
if (snap)
|
|
666
666
|
dispatch({ type: 'teamUpdate', snapshot: snap });
|
|
667
|
+
// G-4 / AC-5 (subagent-overseer-v2): a TERMINAL verdict is the
|
|
668
|
+
// one decision the user must not discover from the final report
|
|
669
|
+
// - it removes work they watched running. wait and nudge stay
|
|
670
|
+
// panel-only so the transcript gains no per-tick noise.
|
|
671
|
+
if (event.decision.action === 'replace' || event.decision.action === 'abandon') {
|
|
672
|
+
const verb = event.decision.action === 'replace' ? 'replaced' : 'abandoned';
|
|
673
|
+
const level = event.decision.action === 'replace' ? 'info' : 'warn';
|
|
674
|
+
const reason = event.decision.reason.slice(0, 120);
|
|
675
|
+
dispatch({
|
|
676
|
+
type: 'notice',
|
|
677
|
+
level,
|
|
678
|
+
text: `team supervisor ${verb} ${event.label} - ${reason}`,
|
|
679
|
+
});
|
|
680
|
+
}
|
|
667
681
|
break;
|
|
668
682
|
}
|
|
669
683
|
case 'usage': {
|
package/dist/ui/TeamPanel.d.ts
CHANGED
|
@@ -57,4 +57,26 @@ export declare function activityBudget(cols: number): number;
|
|
|
57
57
|
* columns and break at 80.
|
|
58
58
|
*/
|
|
59
59
|
export declare function activityLine(run: SubagentRun, cols: number): string;
|
|
60
|
+
/**
|
|
61
|
+
* The row's supervisor badge (subagent-overseer-v2 AC-5): what the supervisor
|
|
62
|
+
* last did to THIS child and how long ago, e.g. `nudged 2m03s`.
|
|
63
|
+
*
|
|
64
|
+
* `lastIntervention.at` is ABSOLUTE epoch ms (R-P2-3), the same units as
|
|
65
|
+
* `startedAt`, so this is one subtraction - no second clock convention.
|
|
66
|
+
*/
|
|
67
|
+
export declare function overseerBadge(run: SubagentRun, at: number): string;
|
|
68
|
+
/**
|
|
69
|
+
* The activity column WITH the badge composed in (AC-5 / risk table): the
|
|
70
|
+
* badge rides the SAME `activityBudget(cols)` allocation the prose uses, so
|
|
71
|
+
* a row can never grow past its terminal; on a narrow terminal the badge
|
|
72
|
+
* degrades to the action word alone - the who-acted fact outranks the
|
|
73
|
+
* what-they-are-doing tail exactly when there is room for only one.
|
|
74
|
+
*/
|
|
75
|
+
export declare function activityWithBadge(run: SubagentRun, cols: number, at: number): string;
|
|
76
|
+
/**
|
|
77
|
+
* The panel's one supervisor status line (AC-5): the most recent intervention
|
|
78
|
+
* across the roster, human-phrased. Empty when the supervisor has not acted
|
|
79
|
+
* yet - furniture that says nothing is worse than no line.
|
|
80
|
+
*/
|
|
81
|
+
export declare function supervisorStatusLine(runs: SubagentRun[], at: number): string;
|
|
60
82
|
export declare function TeamPanel({ snapshot, rows, cols, reducedMotion, theme, caps, now, layout, }: TeamPanelProps): React.ReactElement | null;
|
package/dist/ui/TeamPanel.js
CHANGED
|
@@ -101,6 +101,69 @@ export function activityLine(run, cols) {
|
|
|
101
101
|
return 'aborted';
|
|
102
102
|
}
|
|
103
103
|
}
|
|
104
|
+
/** The past-tense word the supervisor badge and status line render. */
|
|
105
|
+
function interventionWord(action) {
|
|
106
|
+
switch (action) {
|
|
107
|
+
case 'nudge':
|
|
108
|
+
return 'nudged';
|
|
109
|
+
case 'replace':
|
|
110
|
+
return 'replaced';
|
|
111
|
+
case 'abandon':
|
|
112
|
+
return 'abandoned';
|
|
113
|
+
default:
|
|
114
|
+
return 'waited';
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* The row's supervisor badge (subagent-overseer-v2 AC-5): what the supervisor
|
|
119
|
+
* last did to THIS child and how long ago, e.g. `nudged 2m03s`.
|
|
120
|
+
*
|
|
121
|
+
* `lastIntervention.at` is ABSOLUTE epoch ms (R-P2-3), the same units as
|
|
122
|
+
* `startedAt`, so this is one subtraction - no second clock convention.
|
|
123
|
+
*/
|
|
124
|
+
export function overseerBadge(run, at) {
|
|
125
|
+
const last = run.lastIntervention;
|
|
126
|
+
if (last === undefined)
|
|
127
|
+
return '';
|
|
128
|
+
return `${interventionWord(last.action)} ${formatDuration(Math.max(0, at - last.at))}`;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* The activity column WITH the badge composed in (AC-5 / risk table): the
|
|
132
|
+
* badge rides the SAME `activityBudget(cols)` allocation the prose uses, so
|
|
133
|
+
* a row can never grow past its terminal; on a narrow terminal the badge
|
|
134
|
+
* degrades to the action word alone - the who-acted fact outranks the
|
|
135
|
+
* what-they-are-doing tail exactly when there is room for only one.
|
|
136
|
+
*/
|
|
137
|
+
export function activityWithBadge(run, cols, at) {
|
|
138
|
+
const last = run.lastIntervention;
|
|
139
|
+
if (last === undefined)
|
|
140
|
+
return activityLine(run, cols);
|
|
141
|
+
const badge = overseerBadge(run, at);
|
|
142
|
+
if (cols < TEAM_LIMITS.activityWideCols)
|
|
143
|
+
return interventionWord(last.action);
|
|
144
|
+
return sanitizeActivity(`${badge}; ${activityLine(run, cols)}`, activityBudget(cols));
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* The panel's one supervisor status line (AC-5): the most recent intervention
|
|
148
|
+
* across the roster, human-phrased. Empty when the supervisor has not acted
|
|
149
|
+
* yet - furniture that says nothing is worse than no line.
|
|
150
|
+
*/
|
|
151
|
+
export function supervisorStatusLine(runs, at) {
|
|
152
|
+
let label = '';
|
|
153
|
+
let latest;
|
|
154
|
+
for (const run of runs) {
|
|
155
|
+
const last = run.lastIntervention;
|
|
156
|
+
if (last !== undefined && (latest === undefined || last.at > latest.at)) {
|
|
157
|
+
latest = last;
|
|
158
|
+
label = run.label;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
if (latest === undefined)
|
|
162
|
+
return '';
|
|
163
|
+
const ago = formatDuration(Math.max(0, at - latest.at));
|
|
164
|
+
const head = latest.reasonHead.length > 0 ? ` (${latest.reasonHead})` : '';
|
|
165
|
+
return `supervisor: ${interventionWord(latest.action)} ${label} ${ago} ago${head}`;
|
|
166
|
+
}
|
|
104
167
|
export function TeamPanel({ snapshot, rows, cols, reducedMotion, theme, caps, now, layout, }) {
|
|
105
168
|
const projection = layout ?? buildTeamPanelLayout({
|
|
106
169
|
snapshot, terminalRows: rows, availableRows: Infinity,
|
|
@@ -130,8 +193,14 @@ export function TeamPanel({ snapshot, rows, cols, reducedMotion, theme, caps, no
|
|
|
130
193
|
// `reducedMotion` and a non-Unicode terminal fall back to the same
|
|
131
194
|
// static marker, exactly as `AssistantEntry` and `ToolCard` already do.
|
|
132
195
|
const animate = isRunning(run) && !reducedMotion && caps.unicode;
|
|
133
|
-
return (_jsxs(Box, { flexDirection: "row", children: [_jsxs(Text, { color: color, children: [' ', animate ? _jsx(Spinner, { type: "dots" }) : marker(run, glyphs), ' '] }), _jsx(Text, { color: theme.primary, children: run.label.padEnd(8).slice(0, 8) }), _jsx(Box, { flexGrow: 1, flexShrink: 1, overflow: "hidden", children: _jsx(Text, { wrap: "truncate", color: theme.muted, children: run.description.replace(/\s+/g, ' ') }) }), _jsx(Box, { flexShrink: 1, overflow: "hidden", children: _jsxs(Text, { wrap: "truncate", color: color, children: [' ',
|
|
134
|
-
}), hiddenTotal > 0 && (_jsxs(Text, { wrap: "truncate", color: theme.muted, children: [' ', "+", hiddenTotal, " more", hiddenRunning > 0 ? ` (${hiddenRunning} running)` : ''] })),
|
|
196
|
+
return (_jsxs(Box, { flexDirection: "row", children: [_jsxs(Text, { color: color, children: [' ', animate ? _jsx(Spinner, { type: "dots" }) : marker(run, glyphs), ' '] }), _jsx(Text, { color: theme.primary, children: run.label.padEnd(8).slice(0, 8) }), _jsx(Box, { flexGrow: 1, flexShrink: 1, overflow: "hidden", children: _jsx(Text, { wrap: "truncate", color: theme.muted, children: run.description.replace(/\s+/g, ' ') }) }), _jsx(Box, { flexShrink: 1, overflow: "hidden", children: _jsxs(Text, { wrap: "truncate", color: color, children: [' ', activityWithBadge(run, cols, at)] }) }), _jsxs(Text, { wrap: "truncate", color: theme.muted, children: [' ', run.startedAt ? formatDuration(Math.max(0, (run.endedAt ?? at) - run.startedAt)) : ''] })] }, run.label));
|
|
197
|
+
}), hiddenTotal > 0 && (_jsxs(Text, { wrap: "truncate", color: theme.muted, children: [' ', "+", hiddenTotal, " more", hiddenRunning > 0 ? ` (${hiddenRunning} running)` : ''] })), (() => {
|
|
198
|
+
// The panel's supervisor line (AC-5): one row, only when the
|
|
199
|
+
// supervisor has actually acted - the per-row badges above already
|
|
200
|
+
// carry the per-child facts.
|
|
201
|
+
const line = supervisorStatusLine(snapshot.runs, at);
|
|
202
|
+
return line ? (_jsxs(Text, { wrap: "truncate", color: theme.muted, children: [' ', line] })) : null;
|
|
203
|
+
})(), snapshot.lastMessage && (_jsxs(Text, { wrap: "truncate", color: theme.muted, children: [' ', glyphs.teamMail, " ", snapshot.lastMessage.from, " ", glyphs.arrowRight, " ", snapshot.lastMessage.to, ": ", snapshot.lastMessage.subject.replace(/\s+/g, ' ')] }))] }));
|
|
135
204
|
}
|
|
136
205
|
function marker(run, glyphs) {
|
|
137
206
|
if (run.phase === 'done')
|
|
@@ -12,7 +12,10 @@ export function buildTeamPanelLayout(input) {
|
|
|
12
12
|
}
|
|
13
13
|
const selection = selectPanelRows(input.snapshot.runs, TEAM_LIMITS.panelMaxRows);
|
|
14
14
|
const natural = 1 + selection.visible.length + Number(selection.hiddenTotal > 0)
|
|
15
|
-
+ Number(Boolean(input.snapshot.lastMessage))
|
|
15
|
+
+ Number(Boolean(input.snapshot.lastMessage))
|
|
16
|
+
// The supervisor status line (subagent-overseer-v2 AC-5) occupies one
|
|
17
|
+
// row whenever any run carries an intervention badge.
|
|
18
|
+
+ Number(input.snapshot.runs.some((run) => run.lastIntervention !== undefined));
|
|
16
19
|
const collapsed = nonNegativeInt(input.terminalRows) < TEAM_LIMITS.panelCollapseRows
|
|
17
20
|
|| available - natural < TODO_LIMITS.panelMinRows;
|
|
18
21
|
return { ...selection, collapsed, rowCount: collapsed ? 1 : natural };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aragon-agent/cli",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.23",
|
|
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.35",
|
|
60
60
|
"chalk": "^5.6.2",
|
|
61
61
|
"cli-highlight": "^2.0.0",
|
|
62
62
|
"commander": "^12.1.0",
|