@aragon-agent/cli 0.5.12 → 0.6.2
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 +100 -0
- package/README.md +322 -6
- package/dist/agent/agent-mode.d.ts +39 -0
- package/dist/agent/agent-mode.js +36 -0
- package/dist/agent/controller.d.ts +32 -0
- package/dist/agent/controller.js +25 -0
- package/dist/agent/system-prompt.d.ts +16 -0
- package/dist/agent/system-prompt.js +5 -0
- package/dist/cli.js +143 -2
- package/dist/config/ui-state.d.ts +29 -0
- package/dist/config/ui-state.js +14 -4
- package/dist/diagnostics/cli-commands.d.ts +10 -0
- package/dist/diagnostics/cli-commands.js +61 -0
- package/dist/diagnostics/doctor.d.ts +29 -0
- package/dist/diagnostics/doctor.js +207 -0
- package/dist/diagnostics/info.d.ts +30 -0
- package/dist/diagnostics/info.js +99 -0
- package/dist/exec/cli-commands.d.ts +31 -0
- package/dist/exec/cli-commands.js +63 -0
- package/dist/exec/emitter.d.ts +80 -0
- package/dist/exec/emitter.js +127 -0
- package/dist/exec/events.d.ts +226 -0
- package/dist/exec/events.js +43 -0
- package/dist/exec/index.d.ts +56 -0
- package/dist/exec/index.js +439 -0
- package/dist/exec/options.d.ts +76 -0
- package/dist/exec/options.js +221 -0
- package/dist/exec/permission.d.ts +66 -0
- package/dist/exec/permission.js +96 -0
- package/dist/exec/runner.d.ts +204 -0
- package/dist/exec/runner.js +559 -0
- package/dist/exec/stdin-stream.d.ts +46 -0
- package/dist/exec/stdin-stream.js +144 -0
- package/dist/logging/install.d.ts +22 -0
- package/dist/logging/install.js +22 -0
- package/dist/session/cli-commands.d.ts +30 -0
- package/dist/session/cli-commands.js +184 -0
- package/dist/session/persist.d.ts +46 -0
- package/dist/session/persist.js +8 -0
- package/dist/session/store.d.ts +147 -0
- package/dist/session/store.js +442 -0
- package/dist/team/runtime.d.ts +12 -0
- package/dist/team/runtime.js +6 -0
- package/dist/team/subagent.d.ts +12 -0
- package/dist/team/subagent.js +4 -0
- package/dist/tools/index.d.ts +20 -0
- package/dist/tools/index.js +26 -0
- package/dist/ui/ActivityLine.d.ts +16 -0
- package/dist/ui/ActivityLine.js +23 -1
- package/dist/ui/App.d.ts +14 -1
- package/dist/ui/App.js +61 -7
- package/dist/ui/BottomStatusRow.d.ts +33 -1
- package/dist/ui/BottomStatusRow.js +20 -6
- package/dist/ui/Composer.d.ts +14 -1
- package/dist/ui/Composer.js +5 -5
- package/dist/ui/overlays/HelpOverlay.js +12 -1
- package/dist/ui/use-startup-notices.d.ts +98 -4
- package/dist/ui/use-startup-notices.js +108 -2
- package/dist/ui/win-vt-force.d.ts +136 -0
- package/dist/ui/win-vt-force.js +237 -0
- package/dist/ui/win-vt-input.d.ts +57 -0
- package/dist/ui/win-vt-input.js +62 -0
- package/package.json +7 -3
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* THE CONTRACT (cli-integration-surface section 5.1).
|
|
3
|
+
*
|
|
4
|
+
* ASCII ONLY - `src/exec/**` is inside the glyph scanner's scope
|
|
5
|
+
* (`glyphs.test.ts::inScope`, R-3 / AC-25). Every string here can reach a
|
|
6
|
+
* consumer's terminal through `--output-format text` fallbacks or a stderr
|
|
7
|
+
* warning, and the whole point of the scanner is that a legacy `cmd.exe` shows
|
|
8
|
+
* mojibake for anything else.
|
|
9
|
+
*
|
|
10
|
+
* PURE TYPES AND BUILDERS. No I/O, no process access, no imports outside
|
|
11
|
+
* `node:`-free type space, so a consumer of this module cannot accidentally
|
|
12
|
+
* evaluate the runner.
|
|
13
|
+
*
|
|
14
|
+
* `EXEC_SCHEMA_VERSION` appears on `system` and on `result` and NOWHERE ELSE.
|
|
15
|
+
* ADDING A FIELD OR AN EVENT TYPE NEVER BUMPS IT; renaming or removing one does.
|
|
16
|
+
* That rule only holds if consumers keep their side of it, so the README states
|
|
17
|
+
* it in the same words: ignore event types you do not know, ignore fields you do
|
|
18
|
+
* not know. Without that contract the version would have to move for every
|
|
19
|
+
* additive change and every wrapper would pin an exact number forever.
|
|
20
|
+
*/
|
|
21
|
+
export declare const EXEC_SCHEMA_VERSION = 1;
|
|
22
|
+
/** The three baselines of section 4.2. `plan` is a MODE, never a filter. */
|
|
23
|
+
export type ExecPermissionMode = 'auto' | 'plan' | 'strict';
|
|
24
|
+
export type ExecOutputFormat = 'text' | 'json' | 'stream-json';
|
|
25
|
+
export type ExecInputFormat = 'text' | 'stream-json';
|
|
26
|
+
/**
|
|
27
|
+
* Why the run ended.
|
|
28
|
+
*
|
|
29
|
+
* `interrupted` covers ALL THREE signals (section 3.6): which one arrived is an
|
|
30
|
+
* operating-system fact, not an agent outcome, and a wrapper that wants to know
|
|
31
|
+
* reads `exitCode` - which follows the CLI's existing `128 + signo` convention.
|
|
32
|
+
*/
|
|
33
|
+
export type ExecStopReason = 'end_turn' | 'max_turns' | 'timeout' | 'interrupted' | 'error';
|
|
34
|
+
export interface ExecUsage {
|
|
35
|
+
inputTokens: number;
|
|
36
|
+
outputTokens: number;
|
|
37
|
+
totalTokens: number;
|
|
38
|
+
}
|
|
39
|
+
export interface ExecCost {
|
|
40
|
+
amount: number;
|
|
41
|
+
currency: 'USD';
|
|
42
|
+
/**
|
|
43
|
+
* `controller.isPricedModel(...)` (P2-3) - the method the CLI already uses for
|
|
44
|
+
* this question, not a second price table. When it is `false`, `amount` is `0`:
|
|
45
|
+
* a feature that looks free while it is spending money is worse than one that
|
|
46
|
+
* admits it does not know.
|
|
47
|
+
*/
|
|
48
|
+
known: boolean;
|
|
49
|
+
}
|
|
50
|
+
export interface ExecTodoCounts {
|
|
51
|
+
total: number;
|
|
52
|
+
done: number;
|
|
53
|
+
}
|
|
54
|
+
export interface ExecErrorInfo {
|
|
55
|
+
code: string;
|
|
56
|
+
message: string;
|
|
57
|
+
}
|
|
58
|
+
export interface ExecSystemInitEvent {
|
|
59
|
+
type: 'system';
|
|
60
|
+
subtype: 'init';
|
|
61
|
+
schemaVersion: number;
|
|
62
|
+
sessionId: string;
|
|
63
|
+
cli: string;
|
|
64
|
+
cwd: string;
|
|
65
|
+
startedAt: number;
|
|
66
|
+
model: {
|
|
67
|
+
provider: string;
|
|
68
|
+
id: string;
|
|
69
|
+
baseUrl: string | null;
|
|
70
|
+
};
|
|
71
|
+
permissionMode: ExecPermissionMode;
|
|
72
|
+
tools: string[];
|
|
73
|
+
resumed: boolean;
|
|
74
|
+
}
|
|
75
|
+
export interface ExecUserEvent {
|
|
76
|
+
type: 'user';
|
|
77
|
+
sessionId: string;
|
|
78
|
+
turn: number;
|
|
79
|
+
text: string;
|
|
80
|
+
/**
|
|
81
|
+
* `todo_continue` marks a message the CLI generated on the caller's behalf
|
|
82
|
+
* through the follow-through loop. A wrapper replaying a transcript has to be
|
|
83
|
+
* able to tell those apart from what it actually sent.
|
|
84
|
+
*/
|
|
85
|
+
source: 'caller' | 'todo_continue';
|
|
86
|
+
}
|
|
87
|
+
export interface ExecTextDeltaEvent {
|
|
88
|
+
type: 'text_delta';
|
|
89
|
+
sessionId: string;
|
|
90
|
+
turn: number;
|
|
91
|
+
delta: string;
|
|
92
|
+
}
|
|
93
|
+
export interface ExecThinkingEvent {
|
|
94
|
+
type: 'thinking';
|
|
95
|
+
sessionId: string;
|
|
96
|
+
turn: number;
|
|
97
|
+
text: string;
|
|
98
|
+
}
|
|
99
|
+
export interface ExecAssistantEvent {
|
|
100
|
+
type: 'assistant';
|
|
101
|
+
sessionId: string;
|
|
102
|
+
turn: number;
|
|
103
|
+
text: string;
|
|
104
|
+
}
|
|
105
|
+
export interface ExecToolCallEvent {
|
|
106
|
+
type: 'tool_call';
|
|
107
|
+
sessionId: string;
|
|
108
|
+
turn: number;
|
|
109
|
+
id: string;
|
|
110
|
+
name: string;
|
|
111
|
+
input: Record<string, unknown>;
|
|
112
|
+
}
|
|
113
|
+
export interface ExecToolResultEvent {
|
|
114
|
+
type: 'tool_result';
|
|
115
|
+
sessionId: string;
|
|
116
|
+
turn: number;
|
|
117
|
+
id: string;
|
|
118
|
+
name: string;
|
|
119
|
+
isError: boolean;
|
|
120
|
+
durationMs: number;
|
|
121
|
+
/**
|
|
122
|
+
* NOT TRUNCATED A SECOND TIME (AC-26). The core executor already clips at
|
|
123
|
+
* roughly 100 KB, and this event carries what the MODEL saw - the only
|
|
124
|
+
* faithful choice. A consumer therefore needs a line reader without a small
|
|
125
|
+
* buffer cap, and the README says so.
|
|
126
|
+
*/
|
|
127
|
+
output: string;
|
|
128
|
+
}
|
|
129
|
+
export interface ExecTodoEvent {
|
|
130
|
+
type: 'todo';
|
|
131
|
+
sessionId: string;
|
|
132
|
+
total: number;
|
|
133
|
+
done: number;
|
|
134
|
+
activeIndex: number;
|
|
135
|
+
items: {
|
|
136
|
+
content: string;
|
|
137
|
+
status: 'pending' | 'in_progress' | 'completed';
|
|
138
|
+
}[];
|
|
139
|
+
}
|
|
140
|
+
export interface ExecTeamEvent {
|
|
141
|
+
type: 'team';
|
|
142
|
+
sessionId: string;
|
|
143
|
+
subtype: 'dispatch_start' | 'agent_update' | 'dispatch_end';
|
|
144
|
+
label?: string;
|
|
145
|
+
phase?: string;
|
|
146
|
+
description?: string;
|
|
147
|
+
durationMs?: number;
|
|
148
|
+
toolCalls?: number;
|
|
149
|
+
ok?: number;
|
|
150
|
+
total?: number;
|
|
151
|
+
aborted?: boolean;
|
|
152
|
+
}
|
|
153
|
+
export interface ExecFastReviewEvent {
|
|
154
|
+
type: 'fast_review';
|
|
155
|
+
sessionId: string;
|
|
156
|
+
turn: number;
|
|
157
|
+
model: string;
|
|
158
|
+
text: string;
|
|
159
|
+
}
|
|
160
|
+
export interface ExecRetryEvent {
|
|
161
|
+
type: 'retry';
|
|
162
|
+
sessionId: string;
|
|
163
|
+
attempt: number;
|
|
164
|
+
maxRetries: number;
|
|
165
|
+
errorType: string;
|
|
166
|
+
delayMs: number;
|
|
167
|
+
}
|
|
168
|
+
export interface ExecErrorEvent {
|
|
169
|
+
type: 'error';
|
|
170
|
+
sessionId: string;
|
|
171
|
+
/** `false` for a line the run recovered from (a malformed stdin line, say). */
|
|
172
|
+
fatal: boolean;
|
|
173
|
+
code: string;
|
|
174
|
+
message: string;
|
|
175
|
+
}
|
|
176
|
+
export interface ExecResultEvent {
|
|
177
|
+
type: 'result';
|
|
178
|
+
schemaVersion: number;
|
|
179
|
+
sessionId: string;
|
|
180
|
+
isError: boolean;
|
|
181
|
+
stopReason: ExecStopReason;
|
|
182
|
+
/**
|
|
183
|
+
* `0` success | `1` agent error | `2` usage/config | `3` budget |
|
|
184
|
+
* `128 + signo` for a signal (130 SIGINT, 143 SIGTERM, 129 SIGHUP).
|
|
185
|
+
*
|
|
186
|
+
* DELIBERATELY `number`, NOT A UNION (P1-11): `logging/install.ts` holds
|
|
187
|
+
* `SIGNAL_NUMBERS = { SIGINT: 2, SIGTERM: 15, SIGHUP: 1 }` and exits
|
|
188
|
+
* `128 + signo`, so the signal values are open-ended and a union that omitted
|
|
189
|
+
* 143 would make the honest value unrepresentable.
|
|
190
|
+
*/
|
|
191
|
+
exitCode: number;
|
|
192
|
+
/** The final assistant text; `''` when there was none. */
|
|
193
|
+
result: string;
|
|
194
|
+
turns: number;
|
|
195
|
+
durationMs: number;
|
|
196
|
+
usage: ExecUsage;
|
|
197
|
+
cost: ExecCost;
|
|
198
|
+
model: {
|
|
199
|
+
provider: string;
|
|
200
|
+
id: string;
|
|
201
|
+
};
|
|
202
|
+
todos: ExecTodoCounts | null;
|
|
203
|
+
error: ExecErrorInfo | null;
|
|
204
|
+
}
|
|
205
|
+
export type ExecEvent = ExecSystemInitEvent | ExecUserEvent | ExecTextDeltaEvent | ExecThinkingEvent | ExecAssistantEvent | ExecToolCallEvent | ExecToolResultEvent | ExecTodoEvent | ExecTeamEvent | ExecFastReviewEvent | ExecRetryEvent | ExecErrorEvent | ExecResultEvent;
|
|
206
|
+
/** Everything `system/init` needs that the runner cannot derive for itself. */
|
|
207
|
+
export interface ExecInitParams {
|
|
208
|
+
sessionId: string;
|
|
209
|
+
cli: string;
|
|
210
|
+
cwd: string;
|
|
211
|
+
startedAt: number;
|
|
212
|
+
model: {
|
|
213
|
+
provider: string;
|
|
214
|
+
id: string;
|
|
215
|
+
baseUrl: string | null;
|
|
216
|
+
};
|
|
217
|
+
permissionMode: ExecPermissionMode;
|
|
218
|
+
tools: string[];
|
|
219
|
+
resumed: boolean;
|
|
220
|
+
}
|
|
221
|
+
export declare function buildInitEvent(params: ExecInitParams): ExecSystemInitEvent;
|
|
222
|
+
/** Everything `result` needs. `schemaVersion` is stamped here, never by a caller. */
|
|
223
|
+
export type ExecResultParams = Omit<ExecResultEvent, 'type' | 'schemaVersion'>;
|
|
224
|
+
export declare function buildResultEvent(params: ExecResultParams): ExecResultEvent;
|
|
225
|
+
/** Serialize one event as an NDJSON line, terminator included. */
|
|
226
|
+
export declare function toNdjsonLine(event: ExecEvent): string;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* THE CONTRACT (cli-integration-surface section 5.1).
|
|
3
|
+
*
|
|
4
|
+
* ASCII ONLY - `src/exec/**` is inside the glyph scanner's scope
|
|
5
|
+
* (`glyphs.test.ts::inScope`, R-3 / AC-25). Every string here can reach a
|
|
6
|
+
* consumer's terminal through `--output-format text` fallbacks or a stderr
|
|
7
|
+
* warning, and the whole point of the scanner is that a legacy `cmd.exe` shows
|
|
8
|
+
* mojibake for anything else.
|
|
9
|
+
*
|
|
10
|
+
* PURE TYPES AND BUILDERS. No I/O, no process access, no imports outside
|
|
11
|
+
* `node:`-free type space, so a consumer of this module cannot accidentally
|
|
12
|
+
* evaluate the runner.
|
|
13
|
+
*
|
|
14
|
+
* `EXEC_SCHEMA_VERSION` appears on `system` and on `result` and NOWHERE ELSE.
|
|
15
|
+
* ADDING A FIELD OR AN EVENT TYPE NEVER BUMPS IT; renaming or removing one does.
|
|
16
|
+
* That rule only holds if consumers keep their side of it, so the README states
|
|
17
|
+
* it in the same words: ignore event types you do not know, ignore fields you do
|
|
18
|
+
* not know. Without that contract the version would have to move for every
|
|
19
|
+
* additive change and every wrapper would pin an exact number forever.
|
|
20
|
+
*/
|
|
21
|
+
export const EXEC_SCHEMA_VERSION = 1;
|
|
22
|
+
export function buildInitEvent(params) {
|
|
23
|
+
return {
|
|
24
|
+
type: 'system',
|
|
25
|
+
subtype: 'init',
|
|
26
|
+
schemaVersion: EXEC_SCHEMA_VERSION,
|
|
27
|
+
sessionId: params.sessionId,
|
|
28
|
+
cli: params.cli,
|
|
29
|
+
cwd: params.cwd,
|
|
30
|
+
startedAt: params.startedAt,
|
|
31
|
+
model: params.model,
|
|
32
|
+
permissionMode: params.permissionMode,
|
|
33
|
+
tools: params.tools,
|
|
34
|
+
resumed: params.resumed,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
export function buildResultEvent(params) {
|
|
38
|
+
return { type: 'result', schemaVersion: EXEC_SCHEMA_VERSION, ...params };
|
|
39
|
+
}
|
|
40
|
+
/** Serialize one event as an NDJSON line, terminator included. */
|
|
41
|
+
export function toNdjsonLine(event) {
|
|
42
|
+
return `${JSON.stringify(event)}\n`;
|
|
43
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `aragon exec` - wiring only (cli-integration-surface section 3.3 / 6.1).
|
|
3
|
+
*
|
|
4
|
+
* ASCII ONLY - `src/exec/**` is inside the glyph scanner's scope.
|
|
5
|
+
*
|
|
6
|
+
* NO PROCESS-GLOBAL STATE, AND THAT IS A RULE RATHER THAN A HABIT (section 2.2).
|
|
7
|
+
* A programmatic Node API is the deferral most likely to be asked for first, and
|
|
8
|
+
* the only thing that makes it cheap later is `runExec()` holding nothing the
|
|
9
|
+
* process owns: the controller arrives through a factory, both streams are
|
|
10
|
+
* parameters, and the exit code is RETURNED rather than assigned.
|
|
11
|
+
*
|
|
12
|
+
* THE CONTROLLER COMES FROM A FACTORY BECAUSE `makeController` LIVES IN
|
|
13
|
+
* `cli.tsx` (see the note on `ExecControllerFactory`). Reaching for it directly
|
|
14
|
+
* would make `cli.tsx -> exec/cli-commands.ts -> exec/index.ts -> cli.tsx` a
|
|
15
|
+
* cycle, and duplicating it here would give the headless approval gates a second
|
|
16
|
+
* definition - the one thing `makeController`'s own comment says must not
|
|
17
|
+
* happen.
|
|
18
|
+
*/
|
|
19
|
+
import type { AgentController } from '../agent/controller.js';
|
|
20
|
+
import { type CliFlags } from '../config/load.js';
|
|
21
|
+
import { type RawExecOptions } from './options.js';
|
|
22
|
+
import { type ToolPermission } from './permission.js';
|
|
23
|
+
/**
|
|
24
|
+
* How `runExec` obtains a controller.
|
|
25
|
+
*
|
|
26
|
+
* `cli.tsx` supplies `(flags, deps) => makeController(flags, { interactive:
|
|
27
|
+
* false, ...deps }).controller`, already wired for headless: the deny-all
|
|
28
|
+
* approval gate, the deny-all human-input gate, the log attachments and the
|
|
29
|
+
* untrusted-skill notices. Everything this module needs and nothing it should
|
|
30
|
+
* decide for itself.
|
|
31
|
+
*/
|
|
32
|
+
export type ExecControllerFactory = (flags: CliFlags, deps: {
|
|
33
|
+
permission?: ToolPermission;
|
|
34
|
+
appendSystemPrompt?: string;
|
|
35
|
+
}) => AgentController;
|
|
36
|
+
export interface RunExecContext {
|
|
37
|
+
version: string;
|
|
38
|
+
makeController: ExecControllerFactory;
|
|
39
|
+
stdout?: NodeJS.WritableStream;
|
|
40
|
+
stderr?: NodeJS.WritableStream;
|
|
41
|
+
stdin?: NodeJS.ReadableStream;
|
|
42
|
+
/** Injected by tests so a run never touches the real clock. */
|
|
43
|
+
now?: () => number;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Run one `aragon exec` invocation and resolve with the process exit code.
|
|
47
|
+
*
|
|
48
|
+
* EXIT 2 MEANS THE RUN NEVER STARTED, AND STDOUT CARRIES NOTHING ON THAT PATH.
|
|
49
|
+
* Option errors, prompt errors and session errors are all reported on stderr
|
|
50
|
+
* alone: emitting a lone `result` line for them would break the guarantee
|
|
51
|
+
* `system/init` is the FIRST stream-json line (AC-5), and a wrapper that got a
|
|
52
|
+
* `result` without an `init` could not tell a run that failed to start from one
|
|
53
|
+
* that failed. A preflight failure is different - the format is settled and the
|
|
54
|
+
* schema has begun - so that one DOES emit a `result` with `exitCode: 2`.
|
|
55
|
+
*/
|
|
56
|
+
export declare function runExec(flags: CliFlags, raw: RawExecOptions, promptArg: string | undefined, ctx: RunExecContext): Promise<number>;
|