@aragon-agent/cli 0.5.8 → 0.5.9
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 +279 -0
- package/README.md +1429 -1163
- package/dist/agent/coalesce.d.ts +13 -0
- package/dist/agent/coalesce.js +50 -11
- package/dist/agent/controller.d.ts +141 -2
- package/dist/agent/controller.js +396 -4
- package/dist/agent/headless.d.ts +8 -0
- package/dist/agent/headless.js +40 -0
- package/dist/agent/reducer.d.ts +245 -3
- package/dist/agent/reducer.js +490 -17
- package/dist/agent/retry-view.d.ts +68 -0
- package/dist/agent/retry-view.js +95 -0
- package/dist/agent/system-prompt.d.ts +11 -0
- package/dist/agent/system-prompt.js +2 -0
- package/dist/cli.js +86 -2
- package/dist/commands/builtins.d.ts +1 -1
- package/dist/commands/builtins.js +308 -2
- package/dist/config/cli-commands.d.ts +53 -2
- package/dist/config/cli-commands.js +136 -3
- package/dist/config/env.d.ts +6 -3
- package/dist/config/env.js +103 -3
- package/dist/config/load.d.ts +49 -0
- package/dist/config/load.js +83 -1
- package/dist/config/schema.d.ts +212 -2
- package/dist/config/schema.js +207 -1
- package/dist/config/store.js +20 -1
- package/dist/fast/critique.d.ts +43 -0
- package/dist/fast/critique.js +62 -0
- package/dist/fast/digest.d.ts +42 -0
- package/dist/fast/digest.js +85 -0
- package/dist/fast/frames.d.ts +99 -0
- package/dist/fast/frames.js +180 -0
- package/dist/fast/limits.d.ts +98 -0
- package/dist/fast/limits.js +98 -0
- package/dist/fast/prompt.d.ts +72 -0
- package/dist/fast/prompt.js +94 -0
- package/dist/fast/resolve.d.ts +43 -0
- package/dist/fast/resolve.js +105 -0
- package/dist/fast/review-call.d.ts +99 -0
- package/dist/fast/review-call.js +130 -0
- package/dist/fast/reviewer.d.ts +248 -0
- package/dist/fast/reviewer.js +664 -0
- package/dist/fast/types.d.ts +128 -0
- package/dist/fast/types.js +14 -0
- package/dist/fast/wiring.d.ts +170 -0
- package/dist/fast/wiring.js +316 -0
- package/dist/logging/install.d.ts +15 -1
- package/dist/logging/install.js +37 -4
- package/dist/logging/logger.d.ts +1 -1
- package/dist/session/persist.js +57 -1
- package/dist/team/normalize.d.ts +26 -1
- package/dist/team/normalize.js +23 -3
- package/dist/team/prompt.d.ts +11 -0
- package/dist/team/prompt.js +10 -0
- package/dist/team/report.d.ts +18 -0
- package/dist/team/report.js +27 -1
- package/dist/team/runtime.d.ts +13 -2
- package/dist/team/runtime.js +33 -6
- package/dist/team/subagent.d.ts +19 -1
- package/dist/team/subagent.js +72 -10
- package/dist/team/task-tool.d.ts +26 -0
- package/dist/team/task-tool.js +48 -4
- package/dist/team/types.d.ts +80 -1
- package/dist/tools/bash-tool.js +19 -3
- package/dist/tools/diff.d.ts +25 -5
- package/dist/tools/diff.js +72 -41
- package/dist/tools/file-change-store.d.ts +34 -0
- package/dist/tools/file-change-store.js +57 -0
- package/dist/tools/fs-tools.d.ts +26 -0
- package/dist/tools/fs-tools.js +62 -5
- package/dist/tools/index.d.ts +31 -0
- package/dist/tools/index.js +7 -1
- package/dist/tools/patch.d.ts +115 -0
- package/dist/tools/patch.js +453 -0
- package/dist/tools/terminal-output.d.ts +107 -0
- package/dist/tools/terminal-output.js +198 -0
- package/dist/tools/tool-output-store.d.ts +68 -0
- package/dist/tools/tool-output-store.js +102 -0
- package/dist/ui/ActivityLine.d.ts +48 -0
- package/dist/ui/ActivityLine.js +22 -0
- package/dist/ui/App.d.ts +1 -4
- package/dist/ui/App.js +273 -37
- package/dist/ui/BottomStatusRow.d.ts +43 -0
- package/dist/ui/BottomStatusRow.js +14 -0
- package/dist/ui/Composer.d.ts +1 -6
- package/dist/ui/Composer.js +2 -2
- package/dist/ui/PromptInput.d.ts +1 -15
- package/dist/ui/PromptInput.js +1 -38
- package/dist/ui/StatusBar.d.ts +37 -0
- package/dist/ui/StatusBar.js +5 -3
- package/dist/ui/TeamPanel.d.ts +5 -4
- package/dist/ui/TeamPanel.js +1 -1
- package/dist/ui/TodoPanel.d.ts +5 -4
- package/dist/ui/Transcript.d.ts +26 -3
- package/dist/ui/Transcript.js +76 -10
- package/dist/ui/activity-phrases.d.ts +33 -0
- package/dist/ui/activity-phrases.js +50 -0
- package/dist/ui/entries/AssistantEntry.d.ts +20 -0
- package/dist/ui/entries/AssistantEntry.js +3 -2
- package/dist/ui/entries/DiffView.d.ts +67 -0
- package/dist/ui/entries/DiffView.js +103 -0
- package/dist/ui/entries/FastCard.d.ts +53 -0
- package/dist/ui/entries/FastCard.js +87 -0
- package/dist/ui/entries/RetryCard.d.ts +56 -0
- package/dist/ui/entries/RetryCard.js +60 -0
- package/dist/ui/entries/TeamCard.js +6 -1
- package/dist/ui/entries/ToolCard.d.ts +38 -1
- package/dist/ui/entries/ToolCard.js +68 -5
- package/dist/ui/glyphs.d.ts +9 -0
- package/dist/ui/glyphs.js +2 -0
- package/dist/ui/layout/AppShell.d.ts +13 -22
- package/dist/ui/layout/AppShell.js +3 -38
- package/dist/ui/layout/virtual-window.d.ts +1 -1
- package/dist/ui/layout/virtual-window.js +109 -5
- package/dist/ui/overlays/HelpOverlay.js +16 -2
- package/dist/ui/overlays/SettingsScreen.d.ts +82 -1
- package/dist/ui/overlays/SettingsScreen.js +147 -1
- package/dist/ui/transcript-text.js +27 -0
- package/dist/ui/use-wheel-routing.d.ts +16 -32
- package/dist/ui/use-wheel-routing.js +21 -38
- package/package.json +2 -2
- package/dist/ui/layout/regions.d.ts +0 -55
- package/dist/ui/layout/regions.js +0 -52
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* simply print everything twice.
|
|
8
8
|
*/
|
|
9
9
|
import { formatCost, formatDuration, formatTokens } from '../agent/usage.js';
|
|
10
|
+
import { formatRetryLine } from '../agent/retry-view.js';
|
|
10
11
|
const DEFAULT_MAX_ENTRIES = 200;
|
|
11
12
|
const CONTINUATION_INDENT = ' ';
|
|
12
13
|
const TOOL_INDENT = ' ';
|
|
@@ -84,6 +85,32 @@ function renderEntry(entry, glyphs) {
|
|
|
84
85
|
];
|
|
85
86
|
return lines;
|
|
86
87
|
}
|
|
88
|
+
case 'retry': {
|
|
89
|
+
// A turn that spent three minutes retrying is exactly the kind of cost an
|
|
90
|
+
// exported transcript is supposed to account for — the same argument the
|
|
91
|
+
// `team` case above makes in its own words. This file's `default: return []`
|
|
92
|
+
// means the addition is a CHOICE rather than a compile requirement, and it is
|
|
93
|
+
// worth making: without it a replay of a session that lost two minutes to a
|
|
94
|
+
// 529 shows a gap and no reason for it.
|
|
95
|
+
const glyph = entry.phase === 'exhausted' ? glyphs.error : glyphs.retry;
|
|
96
|
+
return [
|
|
97
|
+
`${TOOL_INDENT}${glyph} ${formatRetryLine(entry, glyphs, Date.now())}`,
|
|
98
|
+
];
|
|
99
|
+
}
|
|
100
|
+
case 'fast': {
|
|
101
|
+
// Reviews are real spend and real advice, and an exported transcript that
|
|
102
|
+
// omitted them would be unaccountable for both — the argument the `team`
|
|
103
|
+
// and `retry` cases above each make in their own words.
|
|
104
|
+
const glyph = entry.status === 'failed' ? glyphs.toolError : glyphs.toolDone;
|
|
105
|
+
const duration = entry.durationMs === undefined ? '' : ` (${entry.durationMs}ms)`;
|
|
106
|
+
const head = `${TOOL_INDENT}${glyph} fast review #${entry.reviewIndex} ${entry.model} ` +
|
|
107
|
+
`turn ${entry.turn}${duration}`;
|
|
108
|
+
if (entry.status === 'advice' && entry.text) {
|
|
109
|
+
return [head, ...entry.text.split('\n').map((l) => `${TOOL_INDENT}${CONTINUATION_INDENT}${l}`)];
|
|
110
|
+
}
|
|
111
|
+
const detail = entry.detail ? `: ${entry.detail}` : '';
|
|
112
|
+
return [`${head} ${entry.status}${detail}`];
|
|
113
|
+
}
|
|
87
114
|
case 'notice': {
|
|
88
115
|
const glyph = entry.level === 'error'
|
|
89
116
|
? glyphs.error
|
|
@@ -1,31 +1,26 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Wheel routing (
|
|
2
|
+
* Wheel routing (wheel-scrolls-transcript-only §4.1).
|
|
3
3
|
*
|
|
4
|
-
* Subscribes to the mouse source
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* 1000-line component (D-13).
|
|
4
|
+
* Subscribes to the mouse source and dispatches every notch to THE ONE
|
|
5
|
+
* SCROLLABLE REGION ON SCREEN — the transcript, or the controlled overlay
|
|
6
|
+
* covering it. Lives outside `App.tsx` because the routing table is the most
|
|
7
|
+
* testable part of this feature and a table wants to be readable on its own,
|
|
8
|
+
* away from a large component (D-13).
|
|
10
9
|
*
|
|
11
|
-
* THE
|
|
12
|
-
*
|
|
13
|
-
*
|
|
10
|
+
* THE POINTER ROW IS NOT CONSULTED, and that is the requirement rather than a
|
|
11
|
+
* simplification (§1). A wheel notch is a VIEWPORT gesture: the pointer in a
|
|
12
|
+
* TUI rests wherever the user last left it — in a chat-shaped app, next to the
|
|
13
|
+
* thing they type into — so routing by row meant the ordinary "scroll back to
|
|
14
|
+
* see what the agent just did" gesture landed on the composer and replaced the
|
|
15
|
+
* draft with an old prompt. Prompt history belongs to `↑` / `↓` alone (G1 / G3),
|
|
16
|
+
* which is the contract Claude Code, Codex and every full-screen terminal app
|
|
17
|
+
* the user brings muscle memory from already follow.
|
|
14
18
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* - composer: exactly ONE history step per notch. Multiplying here would make
|
|
18
|
-
* a single flick jump three prompts back — unusable, and destructive when a
|
|
19
|
-
* draft is in play.
|
|
20
|
-
*
|
|
21
|
-
* Bursts are handled differently for the same reason: transcript events are
|
|
22
|
-
* coalesced into one intent carrying `repeat`, composer events never are (they
|
|
23
|
-
* are rate-limited by the human, and each must produce its own visible step).
|
|
19
|
+
* Every notch is coalesced into one intent carrying `repeat`, no matter how fast
|
|
20
|
+
* the wheel spins: one gesture, one `setState`, one render.
|
|
24
21
|
*/
|
|
25
|
-
import { type MutableRefObject } from 'react';
|
|
26
22
|
import type { Overlay } from '../agent/reducer.js';
|
|
27
23
|
import type { MouseSource } from '../input/stdin-mouse-filter.js';
|
|
28
|
-
import { type FrameGeometry } from './layout/regions.js';
|
|
29
24
|
import type { ScrollIntent } from './layout/scroll.js';
|
|
30
25
|
/**
|
|
31
26
|
* Rows a PgUp/PgDn — and a Shift+wheel notch — moves inside a controlled
|
|
@@ -37,22 +32,11 @@ export declare const OVERLAY_PAGE = 8;
|
|
|
37
32
|
export interface WheelRoutingOptions {
|
|
38
33
|
/** Absent when mouse support is off, in inline mode, or on a non-TTY. */
|
|
39
34
|
mouseSource?: MouseSource;
|
|
40
|
-
/** Live frame geometry, written by `AppShell`'s layout effect (§4.5). */
|
|
41
|
-
geometryRef: MutableRefObject<FrameGeometry>;
|
|
42
|
-
/**
|
|
43
|
-
* Test-only seam (§8.2): when set, the router reads this instead of the
|
|
44
|
-
* measured ref, so a routing test never depends on `measureElement` working
|
|
45
|
-
* under `ink-testing-library` — a dependency no other test in this package
|
|
46
|
-
* exercises, and one that would make a routing regression present as a
|
|
47
|
-
* measurement flake.
|
|
48
|
-
*/
|
|
49
|
-
geometryOverride?: FrameGeometry;
|
|
50
35
|
/** Read at EVENT time for the routing branch, and again at FLUSH time (P1-3). */
|
|
51
36
|
getOverlay: () => Overlay | null;
|
|
52
37
|
onScroll: (kind: ScrollIntent, repeat: number) => void;
|
|
53
38
|
/** Signed row delta; the caller clamps at 0 the way the keyboard branch does. */
|
|
54
39
|
onOverlayScroll: (delta: number) => void;
|
|
55
|
-
onHistoryStep: (dir: 'up' | 'down') => void;
|
|
56
40
|
}
|
|
57
41
|
export interface WheelRouting {
|
|
58
42
|
/**
|
|
@@ -1,29 +1,25 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Wheel routing (
|
|
2
|
+
* Wheel routing (wheel-scrolls-transcript-only §4.1).
|
|
3
3
|
*
|
|
4
|
-
* Subscribes to the mouse source
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* 1000-line component (D-13).
|
|
4
|
+
* Subscribes to the mouse source and dispatches every notch to THE ONE
|
|
5
|
+
* SCROLLABLE REGION ON SCREEN — the transcript, or the controlled overlay
|
|
6
|
+
* covering it. Lives outside `App.tsx` because the routing table is the most
|
|
7
|
+
* testable part of this feature and a table wants to be readable on its own,
|
|
8
|
+
* away from a large component (D-13).
|
|
10
9
|
*
|
|
11
|
-
* THE
|
|
12
|
-
*
|
|
13
|
-
*
|
|
10
|
+
* THE POINTER ROW IS NOT CONSULTED, and that is the requirement rather than a
|
|
11
|
+
* simplification (§1). A wheel notch is a VIEWPORT gesture: the pointer in a
|
|
12
|
+
* TUI rests wherever the user last left it — in a chat-shaped app, next to the
|
|
13
|
+
* thing they type into — so routing by row meant the ordinary "scroll back to
|
|
14
|
+
* see what the agent just did" gesture landed on the composer and replaced the
|
|
15
|
+
* draft with an old prompt. Prompt history belongs to `↑` / `↓` alone (G1 / G3),
|
|
16
|
+
* which is the contract Claude Code, Codex and every full-screen terminal app
|
|
17
|
+
* the user brings muscle memory from already follow.
|
|
14
18
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* - composer: exactly ONE history step per notch. Multiplying here would make
|
|
18
|
-
* a single flick jump three prompts back — unusable, and destructive when a
|
|
19
|
-
* draft is in play.
|
|
20
|
-
*
|
|
21
|
-
* Bursts are handled differently for the same reason: transcript events are
|
|
22
|
-
* coalesced into one intent carrying `repeat`, composer events never are (they
|
|
23
|
-
* are rate-limited by the human, and each must produce its own visible step).
|
|
19
|
+
* Every notch is coalesced into one intent carrying `repeat`, no matter how fast
|
|
20
|
+
* the wheel spins: one gesture, one `setState`, one render.
|
|
24
21
|
*/
|
|
25
22
|
import { useCallback, useEffect, useRef } from 'react';
|
|
26
|
-
import { hitTestWheel } from './layout/regions.js';
|
|
27
23
|
/**
|
|
28
24
|
* Rows a PgUp/PgDn — and a Shift+wheel notch — moves inside a controlled
|
|
29
25
|
* overlay. Declared here rather than in `App.tsx` because both the keyboard
|
|
@@ -89,42 +85,29 @@ export function useWheelRouting(options) {
|
|
|
89
85
|
}, [flush]);
|
|
90
86
|
const route = useCallback((event) => {
|
|
91
87
|
const current = optionsRef.current;
|
|
92
|
-
const geometry = current.geometryOverride ?? current.geometryRef.current;
|
|
93
|
-
const band = hitTestWheel(event.y, geometry);
|
|
94
88
|
const overlay = current.getOverlay();
|
|
95
|
-
// THE OVERLAY BRANCH IS EVALUATED FIRST AND RETURNS FOR EVERY
|
|
89
|
+
// THE OVERLAY BRANCH IS EVALUATED FIRST AND RETURNS FOR EVERY OVERLAY IT
|
|
96
90
|
// RECOGNIZES — the same two ordering rules the keyboard handler follows,
|
|
97
91
|
// and for the same reason (R-P1-7).
|
|
98
92
|
if (overlay) {
|
|
99
|
-
// The composer is inactive behind an overlay; stepping a hidden draft
|
|
100
|
-
// is worse than doing nothing.
|
|
101
|
-
if (band !== 'content')
|
|
102
|
-
return;
|
|
103
93
|
// Modes A only. `model` / `confirm` / `question` own their own keys and
|
|
104
94
|
// scrolling them would leave an inconsistent cursor (R-11).
|
|
105
95
|
const controlled = overlay === 'help' || overlay === 'settings' || overlay === 'plan';
|
|
106
96
|
if (!controlled)
|
|
107
97
|
return;
|
|
98
|
+
// D-3: the row is not consulted here either. Behind an overlay the
|
|
99
|
+
// composer is inactive and the overlay is the only scrollable thing on
|
|
100
|
+
// screen, so a notch anywhere scrolls it.
|
|
108
101
|
const step = event.shift ? OVERLAY_PAGE : OVERLAY_LINES_PER_NOTCH;
|
|
109
102
|
current.onOverlayScroll(event.dir === 'up' ? -step : step);
|
|
110
103
|
return;
|
|
111
104
|
}
|
|
112
|
-
if (band === 'composer') {
|
|
113
|
-
// §4.7: the accumulator flushes when the BAND changes, not only when
|
|
114
|
-
// the direction does. The composer path is never coalesced, so without
|
|
115
|
-
// this the transcript scroll that preceded the pointer moving down
|
|
116
|
-
// lands ~16 ms AFTER the history step it happened before — the two
|
|
117
|
-
// halves of one gesture, applied out of order.
|
|
118
|
-
flush();
|
|
119
|
-
current.onHistoryStep(event.dir);
|
|
120
|
-
return;
|
|
121
|
-
}
|
|
122
105
|
if (event.shift) {
|
|
123
106
|
accumulate(event.dir === 'up' ? 'pageUp' : 'pageDown', 1);
|
|
124
107
|
return;
|
|
125
108
|
}
|
|
126
109
|
accumulate(event.dir === 'up' ? 'lineUp' : 'lineDown', CONTENT_LINES_PER_NOTCH);
|
|
127
|
-
}, [accumulate
|
|
110
|
+
}, [accumulate]);
|
|
128
111
|
const { mouseSource } = options;
|
|
129
112
|
useEffect(() => {
|
|
130
113
|
if (!mouseSource)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aragon-agent/cli",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.9",
|
|
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",
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"prepublishOnly": "npm run build"
|
|
53
53
|
},
|
|
54
54
|
"dependencies": {
|
|
55
|
-
"@aragon-agent/core": "^0.2.
|
|
55
|
+
"@aragon-agent/core": "^0.2.9",
|
|
56
56
|
"chalk": "^5.6.2",
|
|
57
57
|
"cli-highlight": "^2.0.0",
|
|
58
58
|
"commander": "^12.1.0",
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Wheel band hit-testing (mouse-wheel-region-routing §4.5) — pure, React-free.
|
|
3
|
-
*
|
|
4
|
-
* The requirement is stated in terms of REGIONS ("scrolling over the agent area
|
|
5
|
-
* scrolls the transcript; scrolling over the input box steps prompt history"),
|
|
6
|
-
* so the router needs to turn a reported terminal row into one of two bands.
|
|
7
|
-
*
|
|
8
|
-
* The boundary is MEASURED, never computed from `budget.ts`. That arithmetic
|
|
9
|
-
* describes the PLANNED chrome, but the real bottom chrome grows and shrinks at
|
|
10
|
-
* run time: the toast row comes and goes, the hint row is dropped below
|
|
11
|
-
* `HINT_MIN_ROWS`, and the autocomplete popup adds up to nine rows. Routing off
|
|
12
|
-
* the plan would put the boundary in the wrong place exactly when the popup is
|
|
13
|
-
* open — the moment precision matters most (D-5 / D-16).
|
|
14
|
-
*/
|
|
15
|
-
export type WheelBand = 'content' | 'composer';
|
|
16
|
-
export interface FrameGeometry {
|
|
17
|
-
/**
|
|
18
|
-
* 1-based row of the frame's first row. 1 in the alternate screen.
|
|
19
|
-
*
|
|
20
|
-
* This is DERIVED, not assumed, and it has a named dependency: it holds
|
|
21
|
-
* because the full-screen transcript renders no `<Static>`
|
|
22
|
-
* (`Transcript.tsx`), so Ink's `log-update` writes `frameHeight(rows) = rows-1`
|
|
23
|
-
* lines plus a newline into a `rows`-row buffer — nothing scrolls, and the
|
|
24
|
-
* frame sits at rows `1 … rows-1` with the cursor parked on the undrawn last
|
|
25
|
-
* row. Reintroducing `<Static>` into the full-screen path pushes the frame
|
|
26
|
-
* down the screen and silently biases every hit test; whoever does that has
|
|
27
|
-
* to change `top` here at the same time.
|
|
28
|
-
*/
|
|
29
|
-
top: number;
|
|
30
|
-
/** Rows the frame occupies — `frameHeight(rows)`. */
|
|
31
|
-
height: number;
|
|
32
|
-
/** Measured rows of the bottom chrome (toast + composer + status). */
|
|
33
|
-
bottom: number;
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* The "I do not know where the frame is" value.
|
|
37
|
-
*
|
|
38
|
-
* `App` writes it into the geometry ref on every render path that does NOT
|
|
39
|
-
* render the full-screen `AppShell` — the terminal-too-small placeholder and
|
|
40
|
-
* inline mode — so a stale measurement can never outlive the frame it
|
|
41
|
-
* described. There is deliberately no arithmetic fallback: an unmeasured frame
|
|
42
|
-
* routes to `'content'`, which is the band that cannot destroy anything, and
|
|
43
|
-
* one invisible frame after a resize is a better failure than a wrong band
|
|
44
|
-
* (§4.5, P1-5 / D-16).
|
|
45
|
-
*/
|
|
46
|
-
export declare const UNMEASURED_GEOMETRY: FrameGeometry;
|
|
47
|
-
/**
|
|
48
|
-
* Which band does terminal row `y` belong to?
|
|
49
|
-
*
|
|
50
|
-
* Fails toward `'content'`: the whole point of this feature is that a wheel
|
|
51
|
-
* notch must never edit the user's draft (I-3), so every degenerate input —
|
|
52
|
-
* nothing measured yet, a row outside the frame, a chrome measurement that
|
|
53
|
-
* swallowed the screen — resolves to the harmless direction.
|
|
54
|
-
*/
|
|
55
|
-
export declare function hitTestWheel(y: number, geometry: FrameGeometry): WheelBand;
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Wheel band hit-testing (mouse-wheel-region-routing §4.5) — pure, React-free.
|
|
3
|
-
*
|
|
4
|
-
* The requirement is stated in terms of REGIONS ("scrolling over the agent area
|
|
5
|
-
* scrolls the transcript; scrolling over the input box steps prompt history"),
|
|
6
|
-
* so the router needs to turn a reported terminal row into one of two bands.
|
|
7
|
-
*
|
|
8
|
-
* The boundary is MEASURED, never computed from `budget.ts`. That arithmetic
|
|
9
|
-
* describes the PLANNED chrome, but the real bottom chrome grows and shrinks at
|
|
10
|
-
* run time: the toast row comes and goes, the hint row is dropped below
|
|
11
|
-
* `HINT_MIN_ROWS`, and the autocomplete popup adds up to nine rows. Routing off
|
|
12
|
-
* the plan would put the boundary in the wrong place exactly when the popup is
|
|
13
|
-
* open — the moment precision matters most (D-5 / D-16).
|
|
14
|
-
*/
|
|
15
|
-
/**
|
|
16
|
-
* The "I do not know where the frame is" value.
|
|
17
|
-
*
|
|
18
|
-
* `App` writes it into the geometry ref on every render path that does NOT
|
|
19
|
-
* render the full-screen `AppShell` — the terminal-too-small placeholder and
|
|
20
|
-
* inline mode — so a stale measurement can never outlive the frame it
|
|
21
|
-
* described. There is deliberately no arithmetic fallback: an unmeasured frame
|
|
22
|
-
* routes to `'content'`, which is the band that cannot destroy anything, and
|
|
23
|
-
* one invisible frame after a resize is a better failure than a wrong band
|
|
24
|
-
* (§4.5, P1-5 / D-16).
|
|
25
|
-
*/
|
|
26
|
-
export const UNMEASURED_GEOMETRY = { top: 1, height: 0, bottom: 0 };
|
|
27
|
-
/**
|
|
28
|
-
* Which band does terminal row `y` belong to?
|
|
29
|
-
*
|
|
30
|
-
* Fails toward `'content'`: the whole point of this feature is that a wheel
|
|
31
|
-
* notch must never edit the user's draft (I-3), so every degenerate input —
|
|
32
|
-
* nothing measured yet, a row outside the frame, a chrome measurement that
|
|
33
|
-
* swallowed the screen — resolves to the harmless direction.
|
|
34
|
-
*/
|
|
35
|
-
export function hitTestWheel(y, geometry) {
|
|
36
|
-
const { top, height } = geometry;
|
|
37
|
-
if (!Number.isFinite(height) || height <= 0)
|
|
38
|
-
return 'content';
|
|
39
|
-
if (!Number.isFinite(y))
|
|
40
|
-
return 'content';
|
|
41
|
-
// Clamp into the frame so the one undrawn bottom row — and any off-by-one
|
|
42
|
-
// from a terminal that reports 0-based rows — lands on a real band instead of
|
|
43
|
-
// being dropped.
|
|
44
|
-
const row = Math.min(Math.max(Math.floor(y), top), top + height - 1);
|
|
45
|
-
// I-6: at least one content row always survives. This clamp is a backstop
|
|
46
|
-
// that should never fire, and that is checkable rather than hopeful: the
|
|
47
|
-
// completion popup is capped at `viewportRows(rows) - 4`, so the measured
|
|
48
|
-
// chrome tops out at `rows - 6` against a frame of `rows - 1` — five content
|
|
49
|
-
// rows survive the worst case the layout can produce.
|
|
50
|
-
const bottom = Math.min(Math.max(Math.floor(geometry.bottom) || 0, 0), height - 1);
|
|
51
|
-
return row >= top + height - bottom ? 'composer' : 'content';
|
|
52
|
-
}
|