@aragon-agent/cli 0.6.31 → 0.6.32
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 +2957 -2826
- package/dist/agent/controller.d.ts +46 -0
- package/dist/agent/controller.js +175 -7
- package/dist/agent/job-notices.d.ts +143 -0
- package/dist/agent/job-notices.js +182 -0
- package/dist/agent/reducer.d.ts +21 -1
- package/dist/agent/reducer.js +7 -0
- package/dist/agent/system-prompt.d.ts +12 -0
- package/dist/agent/system-prompt.js +2 -0
- package/dist/cli.js +232 -8
- package/dist/commands/builtins.js +23 -8
- package/dist/commands/perf.d.ts +54 -1
- package/dist/commands/perf.js +28 -4
- package/dist/config/cli-commands.d.ts +27 -0
- package/dist/config/cli-commands.js +54 -1
- package/dist/config/env.js +38 -0
- package/dist/config/load.js +50 -1
- package/dist/config/schema.d.ts +73 -0
- package/dist/config/schema.js +34 -0
- package/dist/config/store.js +14 -1
- package/dist/exec/events.d.ts +29 -3
- package/dist/exec/events.js +3 -12
- package/dist/exec/runner.d.ts +24 -0
- package/dist/exec/runner.js +79 -0
- package/dist/input/cursor-report.d.ts +61 -0
- package/dist/input/cursor-report.js +97 -0
- package/dist/input/stdin-filter.d.ts +22 -0
- package/dist/input/stdin-filter.js +48 -3
- package/dist/proc/limits.d.ts +76 -2
- package/dist/proc/limits.js +83 -2
- package/dist/proc/log-mirror.d.ts +59 -0
- package/dist/proc/log-mirror.js +203 -0
- package/dist/proc/log-ring.d.ts +22 -0
- package/dist/proc/log-ring.js +20 -1
- package/dist/proc/notices.d.ts +57 -0
- package/dist/proc/notices.js +101 -0
- package/dist/proc/progress.d.ts +40 -0
- package/dist/proc/progress.js +135 -0
- package/dist/proc/prompt.d.ts +24 -2
- package/dist/proc/prompt.js +51 -2
- package/dist/proc/supervisor.d.ts +35 -2
- package/dist/proc/supervisor.js +142 -43
- package/dist/proc/types.d.ts +89 -1
- package/dist/proc/wait.d.ts +57 -0
- package/dist/proc/wait.js +133 -0
- package/dist/session/persist.js +3 -1
- package/dist/session/validate-session.js +17 -0
- package/dist/tools/bash-tool.d.ts +12 -1
- package/dist/tools/bash-tool.js +100 -13
- package/dist/tools/index.d.ts +26 -2
- package/dist/tools/index.js +43 -2
- package/dist/tools/job-tools.d.ts +54 -0
- package/dist/tools/job-tools.js +329 -0
- package/dist/tools/proc-tools.d.ts +1 -1
- package/dist/tools/proc-tools.js +49 -17
- package/dist/ui/ActivityLine.js +7 -0
- package/dist/ui/App.js +64 -6
- package/dist/ui/ScrollbackShell.d.ts +30 -4
- package/dist/ui/ScrollbackShell.js +8 -3
- package/dist/ui/StatusBar.d.ts +5 -0
- package/dist/ui/StatusBar.js +1 -0
- package/dist/ui/Transcript.d.ts +14 -0
- package/dist/ui/Transcript.js +14 -2
- package/dist/ui/entries/ServiceCard.d.ts +17 -1
- package/dist/ui/entries/ServiceCard.js +39 -4
- package/dist/ui/layout/status-layout.d.ts +13 -1
- package/dist/ui/layout/status-layout.js +10 -0
- package/dist/ui/layout/virtual-window.js +14 -1
- package/dist/ui/run-status-row.d.ts +12 -0
- package/dist/ui/screen.d.ts +17 -4
- package/dist/ui/screen.js +14 -6
- package/dist/ui/scrollback/LiveTail.d.ts +64 -0
- package/dist/ui/scrollback/LiveTail.js +27 -0
- package/dist/ui/scrollback/band.d.ts +105 -0
- package/dist/ui/scrollback/band.js +109 -0
- package/dist/ui/scrollback/budget.d.ts +32 -3
- package/dist/ui/scrollback/budget.js +43 -6
- package/dist/ui/scrollback/canvas.d.ts +99 -0
- package/dist/ui/scrollback/canvas.js +113 -0
- package/dist/ui/scrollback/cursor-probe.d.ts +71 -0
- package/dist/ui/scrollback/cursor-probe.js +133 -0
- package/dist/ui/scrollback/limits.d.ts +49 -0
- package/dist/ui/scrollback/limits.js +49 -0
- package/dist/ui/scrollback/scrollback-writer.d.ts +104 -16
- package/dist/ui/scrollback/scrollback-writer.js +368 -82
- package/dist/ui/scrollback/use-scrollback-view.d.ts +11 -0
- package/dist/ui/scrollback/use-scrollback-view.js +37 -6
- package/dist/ui/scrollback/writer-shapes.d.ts +68 -2
- package/dist/ui/scrollback/writer-shapes.js +53 -8
- package/package.json +3 -3
|
@@ -64,7 +64,7 @@ function pruneEntryIds(printed, entries) {
|
|
|
64
64
|
printed.delete(id);
|
|
65
65
|
}
|
|
66
66
|
export function useScrollbackView(args) {
|
|
67
|
-
const { enabled, bridge, entries, runActive, theme, caps, density, thinkingVisible, reducedMotion, rows, cols, headerNode, openerNode, overlayOpen, draftRows, popupRows, statusExpanded, forceInactive = false, } = args;
|
|
67
|
+
const { enabled, bridge, entries, runActive, theme, caps, density, thinkingVisible, reducedMotion, rows, cols, headerNode, openerNode, overlayOpen, draftRows, popupRows, statusExpanded, forceInactive = false, itemCount, panelEnabled, teamRowsNatural, } = args;
|
|
68
68
|
const contentCols = Math.max(1, cols - 1);
|
|
69
69
|
const startedRef = useRef(false);
|
|
70
70
|
// Everything the asynchronous pass reads travels here, refreshed on every render.
|
|
@@ -86,6 +86,12 @@ export function useScrollbackView(args) {
|
|
|
86
86
|
const cursorRef = useRef(null);
|
|
87
87
|
const pendingReset = useRef(null);
|
|
88
88
|
const heldTailRows = useRef(0);
|
|
89
|
+
// Band hysteresis (release-gate-and-native-panels §6.7). Same lifecycle and same
|
|
90
|
+
// reason as `heldTailRows`: the writer re-lays out the canvas on every batch, so a
|
|
91
|
+
// band that shrank for two frames would make everything above the composer jump.
|
|
92
|
+
const heldRailRows = useRef(0);
|
|
93
|
+
const heldTeamRows = useRef(0);
|
|
94
|
+
const heldGeometry = useRef({ rows, cols });
|
|
89
95
|
const pumpQueued = useRef(false);
|
|
90
96
|
const mountedRef = useRef(true);
|
|
91
97
|
const ensureRenderer = useCallback(() => {
|
|
@@ -227,19 +233,44 @@ export function useScrollbackView(args) {
|
|
|
227
233
|
: 0;
|
|
228
234
|
// D11 · the preview height only grows while anything is unsettled, then resets.
|
|
229
235
|
heldTailRows.current = unsettled.length === 0 ? 0 : Math.max(heldTailRows.current, wanted);
|
|
236
|
+
// The band's hysteresis has exactly THREE reset points and no others: the plan
|
|
237
|
+
// emptied, the dispatch finished, or the geometry changed (a new size is a new
|
|
238
|
+
// measurement - the same treatment `App` gives `guardTripped`).
|
|
239
|
+
if (heldGeometry.current.rows !== rows || heldGeometry.current.cols !== cols) {
|
|
240
|
+
heldGeometry.current = { rows, cols };
|
|
241
|
+
heldRailRows.current = 0;
|
|
242
|
+
heldTeamRows.current = 0;
|
|
243
|
+
}
|
|
244
|
+
if (itemCount === 0)
|
|
245
|
+
heldRailRows.current = 0;
|
|
246
|
+
if (teamRowsNatural === 0)
|
|
247
|
+
heldTeamRows.current = 0;
|
|
230
248
|
const budget = useMemo(() => enabled
|
|
231
249
|
? buildScrollbackBudget({
|
|
232
250
|
rows, cols, draftRows, popupRows, statusExpanded, overlayOpen,
|
|
233
251
|
liveTailWanted: heldTailRows.current, forceInactive,
|
|
252
|
+
band: {
|
|
253
|
+
itemCount, panelEnabled, teamRowsNatural,
|
|
254
|
+
heldRailRows: heldRailRows.current, heldTeamRows: heldTeamRows.current,
|
|
255
|
+
},
|
|
234
256
|
})
|
|
235
257
|
: null,
|
|
236
|
-
// `heldTailRows.current`
|
|
258
|
+
// `heldTailRows.current` and the two band refs are read at memo time; `wanted`,
|
|
259
|
+
// `itemCount` and `teamRowsNatural` are what move them. ONE memo, deliberately:
|
|
260
|
+
// a second one depending on the first would render the previous frame's band.
|
|
237
261
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
238
262
|
[enabled, rows, cols, draftRows, popupRows, statusExpanded, overlayOpen, wanted,
|
|
239
|
-
unsettled.length, forceInactive]);
|
|
263
|
+
unsettled.length, forceInactive, itemCount, panelEnabled, teamRowsNatural]);
|
|
264
|
+
if (budget) {
|
|
265
|
+
// Monotone memory, fed back into the memo above on the next frame.
|
|
266
|
+
heldRailRows.current = budget.band.heldRailRows;
|
|
267
|
+
heldTeamRows.current = budget.band.heldTeamRows;
|
|
268
|
+
}
|
|
269
|
+
// Print keeps `contentCols`; only the live preview gives up the rail's columns (I-5).
|
|
270
|
+
const previewCols = budget ? budget.previewCols : contentCols;
|
|
240
271
|
const liveTailLines = useMemo(() => enabled && budget && budget.liveTailRows > 0
|
|
241
|
-
? buildLivePreview({ unsettled, cols:
|
|
242
|
-
: [], [enabled, budget, unsettled,
|
|
272
|
+
? buildLivePreview({ unsettled, cols: previewCols, rows: budget.liveTailRows, thinkingVisible })
|
|
273
|
+
: [], [enabled, budget, unsettled, previewCols, thinkingVisible]);
|
|
243
274
|
const reprintExpanded = useCallback((entryId) => {
|
|
244
275
|
if (!enabled || !bridge)
|
|
245
276
|
return false;
|
|
@@ -259,5 +290,5 @@ export function useScrollbackView(args) {
|
|
|
259
290
|
return;
|
|
260
291
|
pendingReset.current = { kind, captured: latest.current.entries };
|
|
261
292
|
}, [enabled]);
|
|
262
|
-
return { budget, liveTailLines, reprintExpanded, settleAll, notifyReset };
|
|
293
|
+
return { budget, liveTailLines, unsettledEntries: unsettled, reprintExpanded, settleAll, notifyReset };
|
|
263
294
|
}
|
|
@@ -21,6 +21,60 @@ export declare function seedBytes(input: {
|
|
|
21
21
|
/** After a foreign write the cursor may sit mid-line; start on a new one (RV-11). */
|
|
22
22
|
reseed: boolean;
|
|
23
23
|
}): string;
|
|
24
|
+
/**
|
|
25
|
+
* CUD(n): move down n rows WITHOUT writing a single cell.
|
|
26
|
+
*
|
|
27
|
+
* This is how the canvas spends its `gap` (D3). A blank row that is never written
|
|
28
|
+
* cannot be pushed into the scrollback by a later overflow, which is the whole
|
|
29
|
+
* reason the gap is not a run of `\r\n` (I-B3). The sequence is already whitelisted
|
|
30
|
+
* (`diffBytes` uses it to step between changed rows); this is the same CUD used to
|
|
31
|
+
* skip empty space instead.
|
|
32
|
+
*/
|
|
33
|
+
export declare function skipRows(rows: number): string;
|
|
34
|
+
/**
|
|
35
|
+
* First canvas batch (or the first one after a reset): the screen below the cursor
|
|
36
|
+
* is assumed empty, so there is nothing to erase — only `[gap][content][region]` to
|
|
37
|
+
* write, ending with the cursor parked on the last row.
|
|
38
|
+
*/
|
|
39
|
+
export declare function canvasSeedBytes(input: {
|
|
40
|
+
/**
|
|
41
|
+
* Rows to descend from the cursor to the canvas top, when the canvas is shorter
|
|
42
|
+
* than the space measured below the cursor.
|
|
43
|
+
*
|
|
44
|
+
* Non-zero only on a terminal taller than the start-of-canvas cap: the canvas then
|
|
45
|
+
* begins BELOW the cursor, and a seed that started writing at the cursor would park
|
|
46
|
+
* the region low and leave the top of the canvas empty for the whole session.
|
|
47
|
+
*/
|
|
48
|
+
downToTop: number;
|
|
49
|
+
/** Blank rows to skip before the first content row. */
|
|
50
|
+
gap: number;
|
|
51
|
+
/** Content rows, already clipped, oldest first. */
|
|
52
|
+
held: readonly string[];
|
|
53
|
+
/** The live region. */
|
|
54
|
+
lines: readonly string[];
|
|
55
|
+
sync: boolean;
|
|
56
|
+
/** After a foreign write the cursor may sit mid-line; start on a new one. */
|
|
57
|
+
reseed: boolean;
|
|
58
|
+
}): string;
|
|
59
|
+
/**
|
|
60
|
+
* Redraw the whole canvas: erase the previous one, then write `[gap][content][region]`.
|
|
61
|
+
*
|
|
62
|
+
* ORDER IS SEMANTICS: `ED0`, then the gap, then the content, then the region. Moving
|
|
63
|
+
* the gap after the content puts the blank space back between the reply and the
|
|
64
|
+
* composer, which is the exact defect this feature fixes (M1 in the spec).
|
|
65
|
+
*
|
|
66
|
+
* `held` is the FULL content sequence, not the part that will still be on screen: the
|
|
67
|
+
* rows that do not fit are supposed to leave through the bottom, and the terminal can
|
|
68
|
+
* only scroll away what it was given.
|
|
69
|
+
*/
|
|
70
|
+
export declare function canvasBytes(input: {
|
|
71
|
+
/** Previous canvas height: the erase distance. */
|
|
72
|
+
eraseUp: number;
|
|
73
|
+
gap: number;
|
|
74
|
+
held: readonly string[];
|
|
75
|
+
lines: readonly string[];
|
|
76
|
+
sync: boolean;
|
|
77
|
+
}): string;
|
|
24
78
|
/** Erase exactly the previous live region, print static rows, redraw the region. */
|
|
25
79
|
export declare function fullBytes(input: {
|
|
26
80
|
lines: readonly string[];
|
|
@@ -29,6 +83,20 @@ export declare function fullBytes(input: {
|
|
|
29
83
|
eraseUp: number;
|
|
30
84
|
sync: boolean;
|
|
31
85
|
}): string;
|
|
86
|
+
/**
|
|
87
|
+
* Fill the screen down to the LAST row before the first batch (D4 rung 2 / §4.3).
|
|
88
|
+
*
|
|
89
|
+
* This is the fallback for a terminal that never answers `ESC[6n`: from any row, a
|
|
90
|
+
* run of `rows - 1` line feeds is guaranteed to leave the cursor on the bottom row
|
|
91
|
+
* (extra feeds only scroll, which is why the count is the caller's business). It is
|
|
92
|
+
* written ONCE, before anything else, so the rows it scrolls away are the host's old
|
|
93
|
+
* output — which is still in the scrollback — and never this session's content.
|
|
94
|
+
*
|
|
95
|
+
* The argument is the NUMBER OF LINE FEEDS, not the terminal height: `cli.tsx` passes
|
|
96
|
+
* `rows - 1`. Naming it after the height instead made the caller subtract twice and
|
|
97
|
+
* left the cursor one row short of the bottom.
|
|
98
|
+
*/
|
|
99
|
+
export declare function fillBytes(count: number): string;
|
|
32
100
|
/** Same height, no static rows: rewrite only the rows that changed. `''` if none did. */
|
|
33
101
|
export declare function diffBytes(input: {
|
|
34
102
|
lines: readonly string[];
|
|
@@ -57,5 +125,3 @@ export declare function clipLine(line: string, maxCols: number): {
|
|
|
57
125
|
text: string;
|
|
58
126
|
clipped: boolean;
|
|
59
127
|
};
|
|
60
|
-
/** Rows the previous region occupies after the terminal re-flowed it to `cols` (§4.10). */
|
|
61
|
-
export declare function estimateReflowRows(lines: readonly string[], cols: number): number;
|
|
@@ -32,10 +32,63 @@ export function seedBytes(input) {
|
|
|
32
32
|
const lead = input.reseed ? '\r\n' : '';
|
|
33
33
|
return wrapSync(lead + '\r' + SGR0 + rows(input.statics) + rows(input.lines), input.sync);
|
|
34
34
|
}
|
|
35
|
+
/**
|
|
36
|
+
* CUD(n): move down n rows WITHOUT writing a single cell.
|
|
37
|
+
*
|
|
38
|
+
* This is how the canvas spends its `gap` (D3). A blank row that is never written
|
|
39
|
+
* cannot be pushed into the scrollback by a later overflow, which is the whole
|
|
40
|
+
* reason the gap is not a run of `\r\n` (I-B3). The sequence is already whitelisted
|
|
41
|
+
* (`diffBytes` uses it to step between changed rows); this is the same CUD used to
|
|
42
|
+
* skip empty space instead.
|
|
43
|
+
*/
|
|
44
|
+
export function skipRows(rows) {
|
|
45
|
+
return down(Math.max(0, Math.floor(Number.isFinite(rows) ? rows : 0)));
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* First canvas batch (or the first one after a reset): the screen below the cursor
|
|
49
|
+
* is assumed empty, so there is nothing to erase — only `[gap][content][region]` to
|
|
50
|
+
* write, ending with the cursor parked on the last row.
|
|
51
|
+
*/
|
|
52
|
+
export function canvasSeedBytes(input) {
|
|
53
|
+
const lead = input.reseed ? '\r\n' : '';
|
|
54
|
+
const skip = skipRows(input.downToTop) + skipRows(input.gap);
|
|
55
|
+
return wrapSync(lead + '\r' + SGR0 + skip + rows(input.held) + rows(input.lines), input.sync);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Redraw the whole canvas: erase the previous one, then write `[gap][content][region]`.
|
|
59
|
+
*
|
|
60
|
+
* ORDER IS SEMANTICS: `ED0`, then the gap, then the content, then the region. Moving
|
|
61
|
+
* the gap after the content puts the blank space back between the reply and the
|
|
62
|
+
* composer, which is the exact defect this feature fixes (M1 in the spec).
|
|
63
|
+
*
|
|
64
|
+
* `held` is the FULL content sequence, not the part that will still be on screen: the
|
|
65
|
+
* rows that do not fit are supposed to leave through the bottom, and the terminal can
|
|
66
|
+
* only scroll away what it was given.
|
|
67
|
+
*/
|
|
68
|
+
export function canvasBytes(input) {
|
|
69
|
+
return wrapSync(up(input.eraseUp) + '\r' + SGR0 + ED0 + skipRows(input.gap) +
|
|
70
|
+
rows(input.held) + rows(input.lines), input.sync);
|
|
71
|
+
}
|
|
35
72
|
/** Erase exactly the previous live region, print static rows, redraw the region. */
|
|
36
73
|
export function fullBytes(input) {
|
|
37
74
|
return wrapSync(up(input.eraseUp) + '\r' + SGR0 + ED0 + rows(input.statics) + rows(input.lines), input.sync);
|
|
38
75
|
}
|
|
76
|
+
/**
|
|
77
|
+
* Fill the screen down to the LAST row before the first batch (D4 rung 2 / §4.3).
|
|
78
|
+
*
|
|
79
|
+
* This is the fallback for a terminal that never answers `ESC[6n`: from any row, a
|
|
80
|
+
* run of `rows - 1` line feeds is guaranteed to leave the cursor on the bottom row
|
|
81
|
+
* (extra feeds only scroll, which is why the count is the caller's business). It is
|
|
82
|
+
* written ONCE, before anything else, so the rows it scrolls away are the host's old
|
|
83
|
+
* output — which is still in the scrollback — and never this session's content.
|
|
84
|
+
*
|
|
85
|
+
* The argument is the NUMBER OF LINE FEEDS, not the terminal height: `cli.tsx` passes
|
|
86
|
+
* `rows - 1`. Naming it after the height instead made the caller subtract twice and
|
|
87
|
+
* left the cursor one row short of the bottom.
|
|
88
|
+
*/
|
|
89
|
+
export function fillBytes(count) {
|
|
90
|
+
return '\r\n'.repeat(Math.max(0, Math.floor(count)));
|
|
91
|
+
}
|
|
39
92
|
/** Same height, no static rows: rewrite only the rows that changed. `''` if none did. */
|
|
40
93
|
export function diffBytes(input) {
|
|
41
94
|
const { lines, prev } = input;
|
|
@@ -104,11 +157,3 @@ export function clipLine(line, maxCols) {
|
|
|
104
157
|
}
|
|
105
158
|
return { text: out, clipped: false };
|
|
106
159
|
}
|
|
107
|
-
/** Rows the previous region occupies after the terminal re-flowed it to `cols` (§4.10). */
|
|
108
|
-
export function estimateReflowRows(lines, cols) {
|
|
109
|
-
const width = Math.max(1, cols);
|
|
110
|
-
let total = 0;
|
|
111
|
-
for (const line of lines)
|
|
112
|
-
total += Math.max(1, Math.ceil(stringWidth(stripAnsi(line)) / width));
|
|
113
|
-
return total;
|
|
114
|
-
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aragon-agent/cli",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.32",
|
|
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.44",
|
|
60
60
|
"chalk": "^5.6.2",
|
|
61
61
|
"cli-highlight": "^2.0.0",
|
|
62
62
|
"commander": "^12.1.0",
|
|
@@ -76,6 +76,6 @@
|
|
|
76
76
|
"@types/react": "^18.3.0",
|
|
77
77
|
"ink-testing-library": "^4.0.0",
|
|
78
78
|
"typescript": "^5.9.3",
|
|
79
|
-
"vitest": "
|
|
79
|
+
"vitest": "4.1.9"
|
|
80
80
|
}
|
|
81
81
|
}
|