eve 0.26.0 → 0.26.1
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 +6 -0
- package/dist/src/cli/banner.d.ts +5 -0
- package/dist/src/cli/banner.js +1 -1
- package/dist/src/cli/dev/tui/blocks.d.ts +56 -8
- package/dist/src/cli/dev/tui/blocks.js +7 -7
- package/dist/src/cli/dev/tui/diagnostic-presentation.d.ts +2 -0
- package/dist/src/cli/dev/tui/diagnostic-presentation.js +3 -2
- package/dist/src/cli/dev/tui/file-content-cache.d.ts +35 -0
- package/dist/src/cli/dev/tui/file-content-cache.js +3 -0
- package/dist/src/cli/dev/tui/line-diff.d.ts +24 -0
- package/dist/src/cli/dev/tui/line-diff.js +1 -0
- package/dist/src/cli/dev/tui/markdown.d.ts +2 -1
- package/dist/src/cli/dev/tui/markdown.js +7 -3
- package/dist/src/cli/dev/tui/prompt-placeholder.d.ts +12 -0
- package/dist/src/cli/dev/tui/prompt-placeholder.js +1 -0
- package/dist/src/cli/dev/tui/question-panel.d.ts +24 -0
- package/dist/src/cli/dev/tui/question-panel.js +1 -0
- package/dist/src/cli/dev/tui/rail.d.ts +15 -0
- package/dist/src/cli/dev/tui/rail.js +1 -0
- package/dist/src/cli/dev/tui/runner.d.ts +22 -65
- package/dist/src/cli/dev/tui/runner.js +1 -1
- package/dist/src/cli/dev/tui/setup-commands.js +1 -1
- package/dist/src/cli/dev/tui/setup-issues.js +1 -1
- package/dist/src/cli/dev/tui/status-line.js +1 -1
- package/dist/src/cli/dev/tui/stream-format.d.ts +16 -3
- package/dist/src/cli/dev/tui/stream-format.js +1 -1
- package/dist/src/cli/dev/tui/subagent-pump.d.ts +127 -0
- package/dist/src/cli/dev/tui/subagent-pump.js +1 -0
- package/dist/src/cli/dev/tui/terminal-renderer.d.ts +34 -1
- package/dist/src/cli/dev/tui/terminal-renderer.js +11 -10
- package/dist/src/cli/dev/tui/test/mock-terminal.d.ts +7 -0
- package/dist/src/cli/dev/tui/test/mock-terminal.js +1 -1
- package/dist/src/cli/dev/tui/theme.d.ts +16 -2
- package/dist/src/cli/dev/tui/theme.js +1 -1
- package/dist/src/cli/dev/tui/todo-panel.d.ts +44 -0
- package/dist/src/cli/dev/tui/todo-panel.js +1 -0
- package/dist/src/cli/dev/tui/tool-block-groups.d.ts +40 -0
- package/dist/src/cli/dev/tui/tool-block-groups.js +1 -0
- package/dist/src/cli/dev/tui/tool-presentation.d.ts +67 -0
- package/dist/src/cli/dev/tui/tool-presentation.js +1 -0
- package/dist/src/cli/dev/tui/tool-rows.d.ts +15 -0
- package/dist/src/cli/dev/tui/tool-rows.js +2 -0
- package/dist/src/cli/dev/tui/turn-clock.d.ts +36 -0
- package/dist/src/cli/dev/tui/turn-clock.js +1 -0
- package/dist/src/cli/dev/tui/types.d.ts +2 -2
- package/dist/src/cli/dev/ui-options.js +1 -1
- package/dist/src/client/index.js +1 -1
- package/dist/src/client/session.js +1 -1
- package/dist/src/compiled/.vendor-stamp.json +2 -1
- package/dist/src/compiled/marked/LICENSE.md +44 -0
- package/dist/src/compiled/marked/index.d.ts +24 -0
- package/dist/src/compiled/marked/index.js +59 -0
- package/dist/src/evals/session.js +1 -1
- package/dist/src/execution/terminal-session-failure-step.js +1 -1
- package/dist/src/harness/tool-loop.js +2 -2
- package/dist/src/internal/application/package.js +1 -1
- package/dist/src/internal/nitro/routes/agent-info/build-agent-info-response-from-manifest.js +1 -1
- package/dist/src/internal/nitro/routes/info.js +1 -1
- package/dist/src/internal/resolve-model-endpoint-status.d.ts +46 -3
- package/dist/src/internal/resolve-model-endpoint-status.js +1 -1
- package/dist/src/setup/flows/link.d.ts +13 -3
- package/dist/src/setup/flows/link.js +1 -1
- package/dist/src/setup/flows/model.d.ts +4 -3
- package/dist/src/setup/flows/model.js +1 -1
- package/dist/src/setup/flows/provider.d.ts +3 -1
- package/dist/src/setup/flows/provider.js +2 -2
- package/dist/src/setup/scaffold/create/project.js +1 -1
- package/package.json +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# eve
|
|
2
2
|
|
|
3
|
+
## 0.26.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 1f04ff7: The dev TUI renders Markdown through a real GFM parser (width-fitted tables, code blocks, task lists, links), presents every builtin tool with semantic activity copy (`Fetch <url>`, `Run <command>`, `Search <query>` — including `web_search` across provider input shapes, `todo`, `ask_question`, `agent`, and `connection_search`), and shows rejected tool approvals as denied instead of successful. Tool activity now accumulates in place: an in-flight batch renders as one counted header with its newest calls listed first behind a `│` rail and a `… (N more)` elision, then collapses to a single past-tense line (`▪ Fetched 30 URLs`) once every call settles — failures keep their itemized per-call error rail — and each `write_file` keeps its own block rendering a real line diff (`+`/`-` rows with context, computed from content the session has already seen — prior writes and full-file reads; new files show all additions). `ask_question` prompts open as a numbered overlay panel above the input (number keys select directly, the "Type your own answer" row focuses its inline editor on reach, Esc dismisses to plain text input), committing as `? question ⎿ answer` in the transcript. The `todo` tool no longer emits transcript blocks; it drives a pinned panel above the input showing per-task state, which commits as a completed block once every task settles. An empty prompt now shows a quiet `›` mark with a rotating placeholder of things to try, switching to the active `❯` once typing starts. Reasoning defaults to a fixed one-line thinking indicator that updates in place (persisting as `○ Thought for 12s` only for long thoughts; `--reasoning full` restores the streaming trace), the prompt stays anchored during a turn with Enter inert (the draft carries into the next prompt), and completed turns close with a `└ Done in <duration>` stats coda (per-turn token flow, context fill) when the turn was long or expensive. Subagent calls render as individual `※ subagent(<name>) #N` sections in the tool column whose child rows window to the three most recently active (failures stay itemized while settled work condenses to one counted row) and close on a corner that reports `Done` once the call's final message arrives; captured server output renders as one open-railed `○ stderr` / `○ stdout` stream section per source (streams are continuous — no closing corner, and interleaved activity never fragments them): the section sits at its newest write's position — everything that happened after the last error displays after it — and shows only that newest write, with earlier ones behind an `… (N more)` count (the stored-diagnostics pointer carries the history); the status bar names the model's actual routing and credential (`via ai-gateway(oidc:<project>)`, `via ai-gateway(api-key)`, or `via <provider>⌝` for a directly-authored endpoint); an empty prompt no longer submits; and a mid-conversation session replacement marks the context cut with a `┌── Session restarted, clear context.` boundary line.
|
|
8
|
+
|
|
3
9
|
## 0.26.0
|
|
4
10
|
|
|
5
11
|
### Minor Changes
|
package/dist/src/cli/banner.d.ts
CHANGED
|
@@ -5,3 +5,8 @@ export declare const EVE_WORDMARK = "eve";
|
|
|
5
5
|
* pre-action hook so commands never compose their own variant.
|
|
6
6
|
*/
|
|
7
7
|
export declare function eveCliBanner(): string;
|
|
8
|
+
/**
|
|
9
|
+
* The unstyled wordmark-and-version tag (`☰eve v0.24.5`) — the boot banner's
|
|
10
|
+
* plain-text form. The dev TUI dims it as its parting line on teardown.
|
|
11
|
+
*/
|
|
12
|
+
export declare function eveVersionTag(): string;
|
package/dist/src/cli/banner.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{__toESM}from"../_virtual/_rolldown/runtime.js";import{require_picocolors}from"../node_modules/.pnpm/picocolors@1.1.1/node_modules/picocolors/picocolors.js";import{resolveInstalledPackageInfo}from"#internal/application/package.js";var import_picocolors=__toESM(require_picocolors(),1);const EVE_WORDMARK=`eve`;function eveCliBanner(){let{version:e}=resolveInstalledPackageInfo();return`${import_picocolors.default.bgBlack(import_picocolors.default.white(`☰eve `))} ${import_picocolors.default.dim(`v${e}`)}`}export{EVE_WORDMARK,eveCliBanner};
|
|
1
|
+
import{__toESM}from"../_virtual/_rolldown/runtime.js";import{require_picocolors}from"../node_modules/.pnpm/picocolors@1.1.1/node_modules/picocolors/picocolors.js";import{resolveInstalledPackageInfo}from"#internal/application/package.js";var import_picocolors=__toESM(require_picocolors(),1);const EVE_WORDMARK=`eve`;function eveCliBanner(){let{version:e}=resolveInstalledPackageInfo();return`${import_picocolors.default.bgBlack(import_picocolors.default.white(`☰eve `))} ${import_picocolors.default.dim(`v${e}`)}`}function eveVersionTag(){let{version:e}=resolveInstalledPackageInfo();return`☰eve v${e}`}export{EVE_WORDMARK,eveCliBanner,eveVersionTag};
|
|
@@ -9,9 +9,11 @@
|
|
|
9
9
|
* boxes anywhere. Every returned row is already styled and fits within the
|
|
10
10
|
* given width, so the live region can place rows verbatim.
|
|
11
11
|
*/
|
|
12
|
+
import type { ToolDetailLine } from "./line-diff.js";
|
|
12
13
|
import type { Theme } from "./theme.js";
|
|
14
|
+
import type { ToolGroupPresentation } from "./tool-presentation.js";
|
|
13
15
|
export type ToolStatus = "running" | "done" | "error" | "denied" | "approval";
|
|
14
|
-
export type BlockKind = "user" | "assistant" | "reasoning" | "tool" | "error" | "notice" | "warning" | "result" | "flow" | "command" | "question" | "subagent" | "subagent-step" | "subagent-tool" | "connection-auth" | "sandbox" | "log" | "agent-header";
|
|
16
|
+
export type BlockKind = "user" | "assistant" | "reasoning" | "tool" | "error" | "notice" | "warning" | "result" | "flow" | "command" | "question" | "subagent" | "subagent-step" | "subagent-tool" | "subagent-close" | "connection-auth" | "sandbox" | "log" | "turn-stats" | "session-boundary" | "todo-list" | "agent-header";
|
|
15
17
|
/**
|
|
16
18
|
* One renderable transcript unit. Fields are interpreted per `kind`; unset
|
|
17
19
|
* fields are simply omitted from the rendered output.
|
|
@@ -22,10 +24,12 @@ export interface Block {
|
|
|
22
24
|
id?: string;
|
|
23
25
|
/** Nesting depth: 0 = top level, 1 = inside a subagent, etc. */
|
|
24
26
|
depth?: number;
|
|
25
|
-
/** Whether the block is still streaming / mutating (drives the
|
|
27
|
+
/** Whether the block is still streaming / mutating (drives the activity pulse). */
|
|
26
28
|
live?: boolean;
|
|
27
29
|
/** Primary label — tool name, subagent name, log source, error title. */
|
|
28
30
|
title?: string;
|
|
31
|
+
/** Past-tense tool label swapped in once the call settles successfully. */
|
|
32
|
+
doneTitle?: string;
|
|
29
33
|
/** Compact secondary text — summarized tool args. */
|
|
30
34
|
subtitle?: string;
|
|
31
35
|
/** Main multi-line content (markdown for prose, plain for logs). */
|
|
@@ -54,15 +58,59 @@ export interface Block {
|
|
|
54
58
|
/** Raw tool input / output for the expanded view. */
|
|
55
59
|
toolInput?: unknown;
|
|
56
60
|
toolOutput?: unknown;
|
|
61
|
+
/** Original execution name, kept separate from a semantic display title. */
|
|
62
|
+
toolName?: string;
|
|
63
|
+
/** Optional aggregation metadata; execution state remains on this call's block. */
|
|
64
|
+
toolGroup?: ToolGroupPresentation;
|
|
65
|
+
/** Salient body lines rendered behind the `│` rail under the tool header. */
|
|
66
|
+
detailLines?: readonly ToolDetailLine[];
|
|
67
|
+
/** When true, `detailLines` stay visible after the call settles (writes). */
|
|
68
|
+
keepDetailWhenDone?: boolean;
|
|
69
|
+
/** Links a subagent section's header and children so calls can coalesce. */
|
|
70
|
+
subagentCallId?: string;
|
|
71
|
+
/**
|
|
72
|
+
* Monotonic activity stamp, bumped on every push and in-place update.
|
|
73
|
+
* Recency windows key on it so a parallel-announced call that just
|
|
74
|
+
* settled counts as newer than a later-announced one still idle.
|
|
75
|
+
*/
|
|
76
|
+
updateSeq?: number;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* What the renderers actually draw: an execution {@link Block} plus the
|
|
80
|
+
* synthesized presentation the display grouping may attach. Only the
|
|
81
|
+
* grouping layer creates these fields, so an execution block can never
|
|
82
|
+
* smuggle display state — the type boundary enforces what used to be a
|
|
83
|
+
* comment.
|
|
84
|
+
*/
|
|
85
|
+
export interface DisplayBlock extends Block {
|
|
86
|
+
/** Items listed when equivalent tool calls are coalesced into one row. */
|
|
87
|
+
toolGroupItems?: readonly ToolGroupItem[];
|
|
88
|
+
/**
|
|
89
|
+
* Stand-in for this many earlier sibling rows elided from a capped
|
|
90
|
+
* subagent run; renders as a single dim `… +N more` line.
|
|
91
|
+
*/
|
|
92
|
+
elided?: number;
|
|
93
|
+
/**
|
|
94
|
+
* This block is the last of its section, so its final row swaps the
|
|
95
|
+
* nesting rule for the closing `└` — the rail ends on the newest child
|
|
96
|
+
* instead of a bare corner row.
|
|
97
|
+
*/
|
|
98
|
+
closesRail?: boolean;
|
|
99
|
+
}
|
|
100
|
+
/** One coalesced call's row beneath an aggregated tool header. */
|
|
101
|
+
export interface ToolGroupItem {
|
|
102
|
+
readonly text: string;
|
|
103
|
+
/** Per-call failure summary, present when a failed batch is aggregated. */
|
|
104
|
+
readonly result?: string;
|
|
57
105
|
}
|
|
58
106
|
export interface RenderBlockContext {
|
|
59
|
-
/** Current
|
|
60
|
-
|
|
107
|
+
/** Current shared square-pulse frame for live activity blocks. */
|
|
108
|
+
activityPulse: string;
|
|
61
109
|
/**
|
|
62
110
|
* Kind and title of the block rendered immediately above this one. Lets a
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
111
|
+
* sandbox block detect that it continues a run (label suppressed, lines
|
|
112
|
+
* hang under the previous block's label) without any mutable run state —
|
|
113
|
+
* each captured write stays its own immediately-committed block.
|
|
66
114
|
*/
|
|
67
115
|
previous?: {
|
|
68
116
|
kind: BlockKind;
|
|
@@ -73,7 +121,7 @@ export interface RenderBlockContext {
|
|
|
73
121
|
* Renders a block to its terminal rows. Each row is fully styled and clipped
|
|
74
122
|
* to `width` visible columns.
|
|
75
123
|
*/
|
|
76
|
-
export declare function renderBlockLines(block:
|
|
124
|
+
export declare function renderBlockLines(block: DisplayBlock, width: number, theme: Theme, context: RenderBlockContext): string[];
|
|
77
125
|
/**
|
|
78
126
|
* The setup attention line (`⚠ 1 setup issue: … · /model`): yellow glyph, body
|
|
79
127
|
* at full intensity, slash commands painted blue so the fix reads as actionable
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import{isPromptControlCommand}from"./prompt-commands.js";import{
|
|
2
|
-
`)}}function renderUser(e,t,n){let r=n.colors.cyan(n.glyph.user);return wrap(e.body??``,t-2).map(e=>`${r} ${e}`)}function renderProse(e,
|
|
3
|
-
`).flatMap(e=>wrapVisibleLine(e,
|
|
4
|
-
`),i=r.slice(0,12),a=i.map(e=>` ${n.colors.dim(truncatePlain(e,Math.max(1,t-2)))}`),o=r.length-i.length;return o>0&&a.push(` ${n.colors.dim(`${n.glyph.ellipsis} +${o} more line${o===1?``:`s`}`)}`),a}const URL_PATTERN=/(https?:\/\/\S+)/u;function colorizeError(e,t){return URL_PATTERN.test(e)?e.split(URL_PATTERN).map((e,n)=>n%2==1?t.colors.cyan(e):t.colors.red(e)).join(``):t.colors.red(e)}function renderNotice(e,t,n){let r=n.colors.dim(n.glyph.dot),i=wrap(e.body??``,t-2);return i.length===0?[r]:i.map(e=>`${r} ${n.colors.dim(e)}`)}function renderAttentionRows(e,t,n){let r=n.colors.yellow(n.glyph.warning);return wrap(e,t-2).map((e,t)=>`${t===0?r:` `} ${paintCommands(e,n)}`)}function renderWarning(e,t,n){return renderAttentionRows(e.body??``,t,n)}function paintCommands(t,n){return t.replace(/\/[a-z:-]+/g,t=>isPromptControlCommand(t)?n.colors.blue(t):t)}function renderCommand(e,t){let n=t.colors,r=e.status===`error`?`${n.red(t.glyph.error)} `:``;return[`${n.cyan(t.glyph.user)} ${r}${n.blue(e.body??``)}`]}function renderFlow(e,t,n){let r=n.colors,i=e.title??`info`,a=i===`success`?r.green(n.glyph.success):i===`warning`?r.yellow(n.glyph.warning):i===`error`?r.red(n.glyph.error):r.dim(n.glyph.dot),o=wrap(e.body??``,t-2),paint=e=>i===`info`?r.dim(e):e;return o.map((e,t)=>`${t===0?a:` `} ${paint(e)}`)}function renderResult(e,t,n){let r=n.colors.dim(n.glyph.elbow),i=wrap(e.body??``,t-7);if(i.length===0)return[` ${r}`];let dim=e=>n.colors.dim(e.replaceAll(`\x1B[22m`,`\x1B[22m\x1B[2m`));return i.map((e,t)=>t===0?` ${r} ${dim(e)}`:` ${dim(e)}`)}function renderPreformatted(e,t,n){let r=e.kind===`connection-auth`?n.colors.yellow(n.glyph.connection):n.colors.yellow(n.colors.bold(n.glyph.question)),i=wrap(e.title??``,t-2),a
|
|
5
|
-
`))for(let e of wrapVisibleLine(n,t-
|
|
6
|
-
`),f=[];for(let e of d){let r=wrapVisibleLine(e,Math.max(1,t-2-c));for(let e of r){let t=f.length===0&&!u?
|
|
7
|
-
`)
|
|
1
|
+
import{isPromptControlCommand}from"./prompt-commands.js";import{renderMarkdown}from"./markdown.js";import{elisionText}from"./rail.js";import{renderTool}from"./tool-rows.js";import{clipVisible,sliceVisible,visibleLength,wrapVisibleLine}from"#cli/ui/terminal-text.js";function renderBlockLines(e,t,n,r){let i=e.depth??0,a=nestingPrefix(i,n),s=renderBody(e,Math.max(8,t-visibleLength(a)),n,r);if(e.closesRail===!0&&i>0){let e=closingPrefix(i,n);return s.map((t,n)=>`${n===s.length-1?e:a}${t}`)}return s.map(e=>`${a}${e}`)}function nestingPrefix(e,t){return e<=0?``:` ${`${t.colors.dim(t.glyph.rule)} `.repeat(e)}`}function closingPrefix(e,t){return` ${`${t.colors.dim(t.glyph.rule)} `.repeat(e-1)}${t.colors.dim(t.glyph.corner)} `}function renderBody(e,t,a,o){if(e.elided!==void 0&&e.kind===`subagent-step`)return[` ${elisionText(e.elided,a)}`];switch(e.kind){case`user`:return renderUser(e,t,a);case`assistant`:case`subagent-step`:return renderProse(e,t,a);case`reasoning`:return renderReasoning(e,t,a);case`tool`:case`subagent-tool`:return renderTool(e,t,a,o);case`error`:return renderError(e,t,a);case`notice`:return renderNotice(e,t,a);case`warning`:return renderWarning(e,t,a);case`result`:return renderResult(e,t,a);case`flow`:return renderFlow(e,t,a);case`command`:return renderCommand(e,a);case`question`:case`connection-auth`:return renderPreformatted(e,t,a);case`sandbox`:return renderSandbox(e,t,a,o);case`log`:return renderLog(e,t,a);case`subagent`:return renderSubagentHeader(e,t,a);case`subagent-close`:{let n=` ${a.colors.dim(a.glyph.corner)}`;return e.body!==void 0&&e.body.length>0?[clipVisible(`${n} ${a.colors.dim(e.body)}`,Math.max(1,t))]:[n]}case`turn-stats`:return renderTurnStats(e,t,a);case`session-boundary`:case`todo-list`:case`agent-header`:return(e.body??``).split(`
|
|
2
|
+
`)}}function renderUser(e,t,n){let r=n.colors.cyan(n.glyph.user);return wrap(e.body??``,t-2).map(e=>`${r} ${e}`)}function renderProse(e,n,r){let i=[],o=e.kind===`subagent-step`;if(o&&e.collapsed===!0){let t=firstNonEmptyLine(e.body)??(e.reasoning===void 0?void 0:firstNonEmptyLine(e.reasoning));return t===void 0?[]:[r.colors.dim(sliceVisible(t,Math.max(1,n)))]}let c=o?``:`${r.colors.bold(r.glyph.brand)} `,l=o?``:` `;e.reasoning&&e.reasoning.trim().length>0&&i.push(...renderReasoningLines(e.reasoning,n,r));let u=(e.body??``).trim();return u.length===0&&i.length===0?[`${c}${r.colors.dim(`thinking${r.glyph.ellipsis}`)}`]:(u.length>0&&renderMarkdown(u,n-l.length).split(`
|
|
3
|
+
`).flatMap(e=>wrapVisibleLine(e,n-l.length)).forEach((e,t)=>{t===0&&!o&&i.length===0?i.push(`${c}${e}`):i.push(`${l}${e}`)}),i.length>0?i:[`${c}`])}function renderReasoning(e,t,n){return e.collapsed?[`${n.colors.gray(n.glyph.reasoning)} ${n.colors.dim(e.title??`thinking`)}`]:renderReasoningLines(e.body??``,t,n,n.glyph.reasoning)}function renderReasoningLines(e,t,n,r){let i=r?2:0,a=wrap(e.trim(),t-i);return a.length===0?[]:a.map((e,t)=>`${r?t===0?`${n.colors.gray(r)} `:` `:``}${n.colors.dim(n.colors.italic(e))}`)}function renderError(e,t,n){let r=n.colors.red(n.colors.bold(n.glyph.error)),i=e.title??`Error`,a=[`${r} ${n.colors.red(n.colors.bold(i))}`];for(let r of wrap(e.body??``,t-2))a.push(` ${colorizeError(r,n)}`);if(e.hint!==void 0&&e.hint.trim().length>0)for(let[r,i]of wrap(e.hint,t-4).entries()){let e=r===0?`${n.glyph.arrow} `:` `;a.push(` ${n.colors.cyan(`${e}${i}`)}`)}return a.push(...renderErrorDetail(e.detail,t,n)),a}function renderErrorDetail(e,t,n){if(e===void 0||e.trim().length===0)return[];let r=e.split(`
|
|
4
|
+
`),i=r.slice(0,12),a=i.map(e=>` ${n.colors.dim(truncatePlain(e,Math.max(1,t-2)))}`),o=r.length-i.length;return o>0&&a.push(` ${n.colors.dim(`${n.glyph.ellipsis} +${o} more line${o===1?``:`s`}`)}`),a}const URL_PATTERN=/(https?:\/\/\S+)/u;function colorizeError(e,t){return URL_PATTERN.test(e)?e.split(URL_PATTERN).map((e,n)=>n%2==1?t.colors.cyan(e):t.colors.red(e)).join(``):t.colors.red(e)}function renderNotice(e,t,n){let r=n.colors.dim(n.glyph.dot),i=wrap(e.body??``,t-2);return i.length===0?[r]:i.map(e=>`${r} ${n.colors.dim(e)}`)}function renderAttentionRows(e,t,n){let r=n.colors.yellow(n.glyph.warning);return wrap(e,t-2).map((e,t)=>`${t===0?r:` `} ${paintCommands(e,n)}`)}function renderWarning(e,t,n){return renderAttentionRows(e.body??``,t,n)}function paintCommands(t,n){return t.replace(/\/[a-z:-]+/g,t=>isPromptControlCommand(t)?n.colors.blue(t):t)}function renderCommand(e,t){let n=t.colors,r=e.status===`error`?`${n.red(t.glyph.error)} `:``;return[`${n.cyan(t.glyph.user)} ${r}${n.blue(e.body??``)}`]}function renderFlow(e,t,n){let r=n.colors,i=e.title??`info`,a=i===`success`?r.green(n.glyph.success):i===`warning`?r.yellow(n.glyph.warning):i===`error`?r.red(n.glyph.error):r.dim(n.glyph.dot),o=wrap(e.body??``,t-2),paint=e=>i===`info`?r.dim(e):e;return o.map((e,t)=>`${t===0?a:` `} ${paint(e)}`)}function renderResult(e,t,n){let r=n.colors.dim(n.glyph.elbow),i=wrap(e.body??``,t-7);if(i.length===0)return[` ${r}`];let dim=e=>n.colors.dim(e.replaceAll(`\x1B[22m`,`\x1B[22m\x1B[2m`));return i.map((e,t)=>t===0?` ${r} ${dim(e)}`:` ${dim(e)}`)}function renderPreformatted(e,t,n){let r=e.kind===`connection-auth`?n.colors.yellow(n.glyph.connection):n.colors.yellow(n.colors.bold(n.glyph.question)),i=e.kind===`question`?` `:` `,a=wrap(e.title??``,t-2),o=a.length===0?[`${r} `]:a.map((e,t)=>t===0?`${r} ${n.colors.bold(e)}`:` ${n.colors.bold(e)}`);for(let n of(e.body??``).split(`
|
|
5
|
+
`))for(let e of wrapVisibleLine(n,Math.max(1,t-i.length)))o.push(`${i}${e}`);return o}function renderSandbox(e,t,n,r){let i=n.colors.cyan(n.glyph.rule),a=n.colors.dim(`sandbox ${n.glyph.dot} `),c=visibleLength(a),l=` `.repeat(c),u=r.previous?.kind===`sandbox`,d=(e.body??``).split(`
|
|
6
|
+
`),f=[];for(let e of d){let r=wrapVisibleLine(e,Math.max(1,t-2-c));for(let e of r){let t=f.length===0&&!u?a:l;f.push(`${i} ${t}${n.colors.gray(e)}`)}}return f.length>0?f:[`${i}`]}function renderLog(e,t,r){let i=e.title===`stderr`,a=i?r.colors.red:r.colors.gray,o=r.colors.dim(r.glyph.rule),c=i?`stderr`:`stdout`,l=[`${r.colors.dim(r.glyph.reasoning)} ${r.colors.dim(c)}`];e.elided!==void 0&&e.elided>0&&l.push(`${o} ${elisionText(e.elided,r)}`);for(let n of(e.body??``).split(`
|
|
7
|
+
`))for(let e of wrapVisibleLine(n,Math.max(1,t-2)))l.push(`${o} ${r.colors.dim(a(e))}`);return l}function renderTurnStats(e,t,n){let r=`${n.glyph.corner} ${e.body??``}`;return[n.colors.dim(truncatePlain(r,Math.max(1,t)))]}function renderSubagentHeader(e,t,n){let r=truncatePlain(e.title===void 0||e.title===`agent`?`self`:e.title,Math.max(8,t-16)),i=e.subtitle!==void 0&&e.subtitle.startsWith(`#`),a=i?`:${e.subtitle.slice(1)}`:``,o=` ${e.status===`done`?n.colors.green(n.glyph.subagent):n.colors.orange(n.glyph.subagent)} ${n.colors.bold(`subagent(${r}${a})`)}`;return!i&&e.subtitle!==void 0&&e.subtitle.length>0&&(o+=` ${n.colors.dim(e.subtitle)}`),[o]}function firstNonEmptyLine(e){return e===void 0?void 0:e.split(/\r?\n/u).find(e=>e.trim().length>0)?.trim()}function wrap(e,t){return e.trim().length===0?[]:e.split(`
|
|
8
8
|
`).flatMap(e=>wrapVisibleLine(e,Math.max(1,t)))}function truncatePlain(e,t){return visibleLength(e)<=t?e:sliceVisible(e,t)}export{renderAttentionRows,renderBlockLines};
|
|
@@ -4,6 +4,8 @@ export type DiagnosticPresentation = {
|
|
|
4
4
|
} | {
|
|
5
5
|
readonly kind: "stored";
|
|
6
6
|
readonly summary: string;
|
|
7
|
+
/** First error-naming line of the collapsed body, when one exists. */
|
|
8
|
+
readonly headline?: string;
|
|
7
9
|
readonly omittedLines: number;
|
|
8
10
|
readonly path: string;
|
|
9
11
|
};
|
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
function presentDiagnostic(
|
|
2
|
-
`);if(
|
|
1
|
+
const ERROR_HEADLINE_PATTERN=/^\s*(?:message|name):\s*\S|^\s*[A-Z][\w$]*Error\b/u;function presentDiagnostic(t,n){let r=t.split(`
|
|
2
|
+
`);if(r.length<=4&&t.length<=600)return{kind:`inline`,text:t};let i=r.findIndex(e=>e.trim().length>0),a=i===-1?`Diagnostic output`:r[i].trim(),o=r.slice(i+1).find(t=>ERROR_HEADLINE_PATTERN.test(t))?.trim(),s=1+(o===void 0?0:1),c={kind:`stored`,summary:clip(a),omittedLines:Math.max(0,r.length-s),path:n};return o===void 0?c:{...c,headline:clip(o)}}function formatStoredDiagnostic(e){let t=e.omittedLines,n=t===0?`diagnostic details`:`${t} diagnostic line${t===1?``:`s`}`,r=[e.summary];return e.headline!==void 0&&r.push(e.headline),r.push(`… ${n} · details: ${e.path}`),r.join(`
|
|
3
|
+
`)}function clip(e){return e.length<=240?e:`${e.slice(0,239)}…`}export{formatStoredDiagnostic,presentDiagnostic};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session-local knowledge of file contents, so the write block can show a
|
|
3
|
+
* real diff without any protocol addition. Two feeds keep it current: every
|
|
4
|
+
* `write_file` input is a full replacement (exact), and every full-file
|
|
5
|
+
* `read_file` result reconstructs to the file's exact lines. Files touched
|
|
6
|
+
* outside these two paths (e.g. by `bash`) are invisible here — a write over
|
|
7
|
+
* unknown prior content renders plain rather than pretending to be a diff.
|
|
8
|
+
*/
|
|
9
|
+
export declare class FileContentCache {
|
|
10
|
+
#private;
|
|
11
|
+
/**
|
|
12
|
+
* Records one write and returns the content it replaced. Tool blocks
|
|
13
|
+
* re-render on every lifecycle event of the same call, so a repeated
|
|
14
|
+
* observation of `callId` keeps returning the original previous content
|
|
15
|
+
* instead of diffing the write against itself.
|
|
16
|
+
*/
|
|
17
|
+
observeWrite(input: {
|
|
18
|
+
path: string;
|
|
19
|
+
content: string;
|
|
20
|
+
callId: string;
|
|
21
|
+
}): string | undefined;
|
|
22
|
+
/**
|
|
23
|
+
* Forgets everything. A new conversation runs against a fresh session —
|
|
24
|
+
* possibly a fresh sandbox — so stale bases would produce confidently
|
|
25
|
+
* wrong diffs.
|
|
26
|
+
*/
|
|
27
|
+
clear(): void;
|
|
28
|
+
/**
|
|
29
|
+
* Records a read result when it provably covers the whole file: not
|
|
30
|
+
* truncated, starting at line 1, with exactly `totalLines` numbered lines.
|
|
31
|
+
* Partial or truncated reads are ignored — caching them would produce
|
|
32
|
+
* confidently wrong diffs later.
|
|
33
|
+
*/
|
|
34
|
+
observeRead(output: unknown): void;
|
|
35
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
const MAX_CACHED_CONTENT_CHARS=2e5;var FileContentCache=class{#e=new Map;observeWrite(t){let n=this.#e.get(t.path);if(n?.writerCallId===t.callId)return n.previous;if(t.content.length>MAX_CACHED_CONTENT_CHARS){this.#e.delete(t.path);return}let r=n?.content,i={content:t.content,writerCallId:t.callId};return r!==void 0&&(i.previous=r),this.#e.set(t.path,i),r}clear(){this.#e.clear()}observeRead(t){let n=readFileResultShape(t);if(n===void 0||n.truncated||n.content.length>MAX_CACHED_CONTENT_CHARS)return;let r=reconstructNumberedLines(n.content);r===void 0||r.length!==n.totalLines||this.#e.set(n.path,{content:r.join(`
|
|
2
|
+
`)})}};function readFileResultShape(e){if(typeof e!=`object`||!e||Array.isArray(e))return;let{content:t,path:n,totalLines:r,truncated:i}=e;if(!(typeof t!=`string`||typeof n!=`string`)&&!(typeof r!=`number`||typeof i!=`boolean`))return{content:t,path:n,totalLines:r,truncated:i}}function reconstructNumberedLines(e){if(e===``)return[];let t=[];for(let[n,r]of e.split(`
|
|
3
|
+
`).entries()){let e=/^(\d+): (.*)$/su.exec(r);if(e===null||Number(e[1])!==n+1)return;t.push(e[2])}return t}export{FileContentCache};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure line diffing for the write block's rail. The TUI computes diffs
|
|
3
|
+
* client-side from content it has already seen (write inputs, full-file read
|
|
4
|
+
* results) — putting prior content into the tool's output would feed it
|
|
5
|
+
* straight back into model context, paying tokens for something only the
|
|
6
|
+
* terminal needs.
|
|
7
|
+
*/
|
|
8
|
+
/** One rail row under a tool header. `kind` is unset for plain/context text. */
|
|
9
|
+
export interface ToolDetailLine {
|
|
10
|
+
readonly text: string;
|
|
11
|
+
readonly kind?: "added" | "removed" | "gap";
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Builds the write rail for `content` against what it replaced.
|
|
15
|
+
*
|
|
16
|
+
* - `previous` known → a windowed line diff (changes with two context lines,
|
|
17
|
+
* unchanged stretches collapsed behind `gap` rows); identical content
|
|
18
|
+
* yields no rows.
|
|
19
|
+
* - `previous` unknown but the file provably did not exist → every line is
|
|
20
|
+
* an addition.
|
|
21
|
+
* - otherwise → plain content rows, because inventing `+` markers for an
|
|
22
|
+
* overwrite would misread as "everything changed".
|
|
23
|
+
*/
|
|
24
|
+
export declare function diffWriteDetail(previous: string | undefined, content: string, existed?: boolean): ToolDetailLine[];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function diffWriteDetail(e,t,n){let r=splitContentLines(t);if(e===void 0)return n===!1?r.map(e=>({text:e,kind:`added`})):r.map(e=>({text:e}));let i=splitContentLines(e);return(i.length+1)*(r.length+1)>25e4?r.map(e=>({text:e})):windowHunks(lcsDiff(i,r))}function splitContentLines(e){let t=e.split(/\r?\n/u);for(;t.length>0&&t.at(-1)?.trim()===``;)t.pop();return t}function lcsDiff(e,t){let n=t.length+1,r=new Uint32Array((e.length+1)*n);for(let i=e.length-1;i>=0;--i)for(let a=t.length-1;a>=0;--a)r[i*n+a]=e[i]===t[a]?r[(i+1)*n+a+1]+1:Math.max(r[(i+1)*n+a],r[i*n+a+1]);let i=[],a=0,o=0;for(;a<e.length&&o<t.length;)e[a]===t[o]?(i.push({text:e[a]}),a+=1,o+=1):r[(a+1)*n+o]>=r[a*n+o+1]?(i.push({text:e[a],kind:`removed`}),a+=1):(i.push({text:t[o],kind:`added`}),o+=1);for(;a<e.length;a+=1)i.push({text:e[a],kind:`removed`});for(;o<t.length;o+=1)i.push({text:t[o],kind:`added`});return i}function windowHunks(e){let t=e.map(e=>e.kind===`added`||e.kind===`removed`);if(!t.includes(!0))return[];let n=e.map((n,r)=>{for(let n=Math.max(0,r-2);n<=Math.min(e.length-1,r+2);n+=1)if(t[n])return!0;return!1}),r=[];for(let[t,i]of e.entries())n[t]?r.push(i):r.at(-1)?.kind!==`gap`&&r.push({text:``,kind:`gap`});return r}export{diffWriteDetail};
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
/** Renders parsed GFM blocks to terminal text, fitting tables to `width`. */
|
|
2
|
+
export declare function renderMarkdown(input: string, width?: number): string;
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
-
import{visibleLength}from"#cli/ui/terminal-text.js";const ansi={bold:`\x1B[1m`,boldOff:`\x1B[22m`,italic:`\x1B[3m`,italicOff:`\x1B[23m`};function renderMarkdown(e){
|
|
2
|
-
`),n=[];for(let e
|
|
3
|
-
`)
|
|
1
|
+
import{sliceVisible,visibleLength}from"#cli/ui/terminal-text.js";import{lexer}from"#compiled/marked/index.js";const ansi={bold:`\x1B[1m`,boldOff:`\x1B[22m`,cyan:`\x1B[36m`,cyanOff:`\x1B[39m`,dim:`\x1B[2m`,dimOff:`\x1B[22m`,italic:`\x1B[3m`,italicOff:`\x1B[23m`,strike:`\x1B[9m`,strikeOff:`\x1B[29m`};function renderMarkdown(e,t=1/0){return trimTrailingBlankRows(renderBlocks(lexer(e),t)).join(`
|
|
2
|
+
`)}function renderBlocks(e,t){let n=[];for(let i of e)switch(i.type){case`space`:pushBlankRow(n);break;case`heading`:{let e=i.depth===1?`█`:i.depth===2?`■`:`▶`;n.push(`${e} ${ansi.bold}${renderInline(i.tokens)}${ansi.boldOff}`);break}case`paragraph`:case`text`:n.push(...renderInline(i.tokens,i.text).split(`
|
|
3
|
+
`));break;case`code`:n.push(...renderCodeBlock(i));break;case`blockquote`:n.push(...renderBlocks(i.tokens??[],Math.max(8,t-2)).map(e=>`${ansi.dim}│${ansi.dimOff} ${e}`));break;case`list`:n.push(...renderList(i,t));break;case`table`:n.push(...renderTable(i,t));break;case`hr`:n.push(ansi.dim+`─`.repeat(horizontalRuleWidth(t))+ansi.dimOff);break;case`html`:n.push(...(i.text??i.raw??``).split(`
|
|
4
|
+
`));break;case`def`:break;default:i.tokens===void 0?i.text!==void 0&&n.push(i.text):n.push(...renderBlocks(i.tokens,t));break}return n}function renderCodeBlock(e){let t=[];e.lang?.trim()&&t.push(` ${ansi.dim}${e.lang.trim()}${ansi.dimOff}`);let n=(e.text??``).replace(/\n$/u,``).split(`
|
|
5
|
+
`);for(let e of n)t.push(`${ansi.dim}│${ansi.dimOff} ${ansi.cyan}${e}${ansi.cyanOff}`);return t}function renderList(e,t){let n=[],r=typeof e.start==`number`?e.start:1;for(let i of e.items??[]){let a=e.ordered?`${r}.`:`•`,o=i.checked===!0?`☑ `:i.checked===!1?`☐ `:``,s=renderBlocks(i.tokens??[],Math.max(8,t-a.length-1));(s.length===0?[``]:s).forEach((e,t)=>{n.push(t===0?`${a} ${o}${e}`:`${` `.repeat(a.length+1)}${e}`)}),r+=1}return n}function renderInline(e,t=``){return e===void 0?t:e.map(renderInlineToken).join(``)}function renderInlineToken(e){switch(e.type){case`text`:return renderInline(e.tokens,e.text??``);case`strong`:return`${ansi.bold}${renderInline(e.tokens,e.text)}${ansi.boldOff}`;case`em`:return`${ansi.italic}${renderInline(e.tokens,e.text)}${ansi.italicOff}`;case`del`:return`${ansi.strike}${renderInline(e.tokens,e.text)}${ansi.strikeOff}`;case`codespan`:return`${ansi.cyan}${e.text??``}${ansi.cyanOff}`;case`link`:{let t=renderInline(e.tokens,e.text),n=e.href??``;return n.length===0||t===n?`${ansi.cyan}${t}${ansi.cyanOff}`:`${t} (${ansi.cyan}${n}${ansi.cyanOff})`}case`image`:{let t=e.text?.trim()||`image`,n=e.href??``;return n.length===0?`[${t}]`:`[${t}] (${ansi.cyan}${n}${ansi.cyanOff})`}case`br`:return`
|
|
6
|
+
`;case`checkbox`:return e.checked?`☑ `:`☐ `;case`escape`:return e.text??``;case`html`:return e.text??e.raw??``;default:return renderInline(e.tokens,e.text??e.raw??``)}}function renderTable(e,n){let i=e.header??[];if(i.length===0)return[];let a=i.map((t,n)=>normalizeAlignment(e.align?.[n])),o=i.map(renderTableCell),s=(e.rows??[]).map(e=>normalizeTableRow(e,i.length).map(renderTableCell)),c=[o,...s],l=a.map((e,n)=>Math.max(3,...c.map(e=>visibleLength(e[n]??``))));return fitTableWidths(l,n),[formatTableRow(o.map(e=>`${ansi.bold}${e}${ansi.boldOff}`),l,a),l.map(e=>`─`.repeat(e)).join(` `),...s.map(e=>formatTableRow(e,l,a))]}function renderTableCell(e){return renderInline(e.tokens,e.text).replaceAll(`
|
|
7
|
+
`,` `)}function normalizeTableRow(e,t){return Array.from({length:t},(t,n)=>e[n]??{text:``,tokens:[]})}function normalizeAlignment(e){return e??`left`}function fitTableWidths(e,t){if(!Number.isFinite(t))return;let n=Math.max(0,e.length-1)*2,r=Math.max(e.length*3,Math.floor(t)-n);for(;e.reduce((e,t)=>e+t,0)>r;){let t=Math.max(...e),n=e.findIndex(e=>e===t&&e>3);if(n===-1)return;e[n]=t-1}}function formatTableRow(e,t,n){return e.map((e,r)=>alignTableCell(fitTableCell(e,t[r]??3),t[r]??3,n[r]??`left`)).join(` `)}function fitTableCell(n,r){return visibleLength(n)<=r?n:`${sliceVisible(n,Math.max(1,r-1))}…`}function alignTableCell(e,n,r){let i=Math.max(0,n-visibleLength(e));if(r===`right`)return`${` `.repeat(i)}${e}`;if(r===`center`){let t=Math.floor(i/2);return`${` `.repeat(t)}${e}${` `.repeat(i-t)}`}return`${e}${` `.repeat(i)}`}function horizontalRuleWidth(e){return Number.isFinite(e)?Math.max(3,Math.min(40,Math.floor(e))):40}function pushBlankRow(e){e.length>0&&e.at(-1)!==``&&e.push(``)}function trimTrailingBlankRows(e){for(;e.at(-1)===``;)e.pop();return e}export{renderMarkdown};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The empty prompt's rotating invitation, written in the agent's own voice
|
|
3
|
+
* ("my capabilities") since the prompt is a message to it. Messages point at
|
|
4
|
+
* things an eve agent can actually do out of the box, so an idle prompt
|
|
5
|
+
* doubles as a hint surface. The caret-blink repaint keeps the rotation
|
|
6
|
+
* moving without its own timer.
|
|
7
|
+
*/
|
|
8
|
+
export declare const PROMPT_PLACEHOLDER_MESSAGES: readonly string[];
|
|
9
|
+
/** How long each message holds before the rotation advances. */
|
|
10
|
+
export declare const promptPlaceholderCycleMs = 6000;
|
|
11
|
+
/** Picks the message for the given time since the renderer started. */
|
|
12
|
+
export declare function promptPlaceholder(elapsedMs: number): string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const PROMPT_PLACEHOLDER_MESSAGES=[`Ask about my capabilities`,`Have me explore the workspace`,`Refine my instructions`],promptPlaceholderCycleMs=6e3;function promptPlaceholder(e){return PROMPT_PLACEHOLDER_MESSAGES[Math.floor(Math.max(0,e)/promptPlaceholderCycleMs)%PROMPT_PLACEHOLDER_MESSAGES.length]}export{PROMPT_PLACEHOLDER_MESSAGES,promptPlaceholder,promptPlaceholderCycleMs};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure rendering for the HITL question panel — the overlay the agent's
|
|
3
|
+
* `ask_question` tool opens above the input area. A full-width rule separates
|
|
4
|
+
* it from the transcript, options render as numbered rows with their
|
|
5
|
+
* descriptions always visible, and the trailing "Type your own answer" row
|
|
6
|
+
* carries an inline elbow editor that receives focus the moment the cursor
|
|
7
|
+
* rests on it (the provider-key grammar from the setup panel). The renderer
|
|
8
|
+
* hosts lifecycle and keys; this module only paints rows.
|
|
9
|
+
*/
|
|
10
|
+
import type { AgentTUIInputOption } from "./runner.js";
|
|
11
|
+
import { type LineState } from "./line-editor.js";
|
|
12
|
+
import type { Theme } from "./theme.js";
|
|
13
|
+
export interface QuestionPanelState {
|
|
14
|
+
readonly prompt: string;
|
|
15
|
+
readonly options: readonly AgentTUIInputOption[];
|
|
16
|
+
/** Row index under the cursor; `options.length` is the freeform row. */
|
|
17
|
+
readonly cursor: number;
|
|
18
|
+
/** Whether the trailing freeform row exists. */
|
|
19
|
+
readonly allowFreeform: boolean;
|
|
20
|
+
/** The freeform row's inline editor; focused while the cursor rests on it. */
|
|
21
|
+
readonly editor: LineState;
|
|
22
|
+
readonly caretVisible: boolean;
|
|
23
|
+
}
|
|
24
|
+
export declare function renderQuestionPanel(state: QuestionPanelState, theme: Theme, width: number): string[];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{visibleLine}from"./line-editor.js";import{clipVisible,renderInputWithBlockCursor,wrapVisibleLine}from"#cli/ui/terminal-text.js";function selectedRow(e,t){let n=t.colors;return`${n.inverse(n.blue(` ${t.glyph.selectedPointer} ${e} `))} ${n.dim(`↵`)}`}function renderQuestionPanel(e,n,i){let a=n.colors,o=n.glyph,s=[a.dim(o.hrule.repeat(Math.max(1,i)))];for(let t of e.prompt.split(/\r?\n/u))for(let e of wrapVisibleLine(t,Math.max(8,i-2)))s.push(` ${a.bold(e)}`);s.push(``);for(let[t,r]of e.options.entries())s.push(...optionRows(r.label,r.description,t,e,n));if(e.allowFreeform){let t=e.options.length,r=e.cursor===t;s.push(...optionRows(`Type your own answer`,void 0,t,e,n)),(r||e.editor.text.length>0)&&s.push(` ${a.dim(o.elbow)} ${freeformEditorBody(e,r,n,i)}`)}return s.push(``,` ${a.dim(`Esc to dismiss`)}`),s.map(e=>clipVisible(e,i))}function optionRows(e,t,n,r,i){let a=i.colors,o=`${n+1}. ${e}`,s=[r.cursor===n?` ${selectedRow(o,i)}`:` ${a.dim(`${n+1}.`)} ${e}`];return t!==void 0&&t.length>0&&s.push(` ${a.dim(t)}`),s}function freeformEditorBody(t,r,i,a){let o=i.colors,s=Math.max(4,a-12);if(!r){let n=visibleLine(t.editor,s,i.glyph.ellipsis);return o.dim(`${n.before}${n.under}${n.after}`)}return renderInputWithBlockCursor({...visibleLine(t.editor,s,i.glyph.ellipsis),visible:t.caretVisible,inverse:o.inverse})}export{renderQuestionPanel};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The shared atoms of the transcript's rail grammar. Persistent sections
|
|
3
|
+
* (tool rows, subagent sections, the todo panel) all hang their marks at the
|
|
4
|
+
* same two-cell tool column and elide overflow with the same counted row —
|
|
5
|
+
* one definition keeps the alignment a checked fact instead of a set of
|
|
6
|
+
* parallel comments.
|
|
7
|
+
*/
|
|
8
|
+
import type { Theme } from "./theme.js";
|
|
9
|
+
/**
|
|
10
|
+
* The two-cell indent that puts a section's mark at the prose text column
|
|
11
|
+
* (the character after the `│`/`▲` gutter marks).
|
|
12
|
+
*/
|
|
13
|
+
export declare const TOOL_COLUMN_LEAD = " ";
|
|
14
|
+
/** The dim `… (N more)` elision label used by every capped region. */
|
|
15
|
+
export declare function elisionText(hidden: number, theme: Theme): string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const TOOL_COLUMN_LEAD=` `;function elisionText(e,t){return t.colors.dim(`${t.glyph.ellipsis} (${e} more)`)}export{TOOL_COLUMN_LEAD,elisionText};
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { type AgentInfoResult, type ConnectionAuthorizationOutcome, type InputRequest, Client, ClientSession } from "#client/index.js";
|
|
2
|
+
import { type SubagentView } from "./subagent-pump.js";
|
|
3
|
+
export type { SubagentRun, SubagentStepUpdate, SubagentToolUpdate, SubagentView, } from "./subagent-pump.js";
|
|
2
4
|
import { type DevBootProgressReporter } from "#internal/dev-boot-progress.js";
|
|
3
5
|
import { type PromptCommand, type PromptCommandSpec } from "./prompt-commands.js";
|
|
4
6
|
import { type RemoteConnectionController, type RemoteConnectionControllerOptions, type RemoteConnectionSnapshot } from "./remote-connection.js";
|
|
@@ -43,6 +45,10 @@ export type AgentTUIStreamEvent = {
|
|
|
43
45
|
} | {
|
|
44
46
|
type: "reasoning-complete";
|
|
45
47
|
id: string;
|
|
48
|
+
} | {
|
|
49
|
+
type: "tool-call-preparing";
|
|
50
|
+
toolCallId: string;
|
|
51
|
+
toolName: string;
|
|
46
52
|
} | {
|
|
47
53
|
type: "tool-call";
|
|
48
54
|
toolCallId: string;
|
|
@@ -60,6 +66,10 @@ export type AgentTUIStreamEvent = {
|
|
|
60
66
|
type: "tool-error";
|
|
61
67
|
toolCallId: string;
|
|
62
68
|
errorText: string;
|
|
69
|
+
} | {
|
|
70
|
+
type: "tool-rejected";
|
|
71
|
+
toolCallId: string;
|
|
72
|
+
reason: string;
|
|
63
73
|
} | {
|
|
64
74
|
type: "error";
|
|
65
75
|
errorText: string;
|
|
@@ -140,6 +150,12 @@ export type AgentTUIRenderer = {
|
|
|
140
150
|
* recovery and slash-command results. Optional.
|
|
141
151
|
*/
|
|
142
152
|
renderNotice?(text: string): void;
|
|
153
|
+
/**
|
|
154
|
+
* Commits the session boundary (`┌── Session restarted, clear context.`)
|
|
155
|
+
* when a dead session is replaced mid-conversation. Optional; renderers
|
|
156
|
+
* without it get the plain notice.
|
|
157
|
+
*/
|
|
158
|
+
renderSessionBoundary?(): void;
|
|
143
159
|
/**
|
|
144
160
|
* Commits one development sandbox lifecycle line to the transcript.
|
|
145
161
|
* Optional so non-terminal renderers can ignore local prewarm progress.
|
|
@@ -157,22 +173,13 @@ export type AgentTUIRenderer = {
|
|
|
157
173
|
readInputQuestion?(question: AgentTUIInputQuestion, options?: AgentTUISessionOptions): Promise<AgentTUIInputQuestionResponse | undefined>;
|
|
158
174
|
renderStream(result: AgentTUIStreamResult, options?: AgentTUISessionOptions): Promise<void>;
|
|
159
175
|
/**
|
|
160
|
-
*
|
|
161
|
-
*
|
|
162
|
-
*
|
|
163
|
-
*
|
|
176
|
+
* The renderer's whole subagent surface — sections, nested steps and
|
|
177
|
+
* tools, ghost sweeps, completion. One optional capability with required
|
|
178
|
+
* members: a renderer either has a subagent view or it doesn't, and a
|
|
179
|
+
* type-legal partial implementation (which would ghost placeholders or
|
|
180
|
+
* duplicate parent tool rows) cannot exist.
|
|
164
181
|
*/
|
|
165
|
-
|
|
166
|
-
/**
|
|
167
|
-
* Out-of-band update for one child tool call of a subagent dispatch.
|
|
168
|
-
*/
|
|
169
|
-
upsertSubagentTool?(update: SubagentToolUpdate): void;
|
|
170
|
-
/**
|
|
171
|
-
* Registers a tool call id as originating from a subagent's child
|
|
172
|
-
* session. The renderer must skip or remove parent-level tool blocks for
|
|
173
|
-
* these ids — they are surfaced via {@link upsertSubagentTool} instead.
|
|
174
|
-
*/
|
|
175
|
-
markChildToolCallId?(callId: string): void;
|
|
182
|
+
readonly subagents?: SubagentView;
|
|
176
183
|
/**
|
|
177
184
|
* Out-of-band update for one MCP connection authorization lifecycle.
|
|
178
185
|
* Called by the runner as `authorization.*` events arrive.
|
|
@@ -322,56 +329,6 @@ export declare class EveTUIRunner {
|
|
|
322
329
|
constructor(options: EveTUIRunnerOptions);
|
|
323
330
|
run(): Promise<void>;
|
|
324
331
|
}
|
|
325
|
-
type SubagentChildStep = {
|
|
326
|
-
reasoning: string;
|
|
327
|
-
message: string;
|
|
328
|
-
finalized: boolean;
|
|
329
|
-
};
|
|
330
|
-
type SubagentToolState = {
|
|
331
|
-
toolName: string;
|
|
332
|
-
input: unknown;
|
|
333
|
-
status: "approval-requested" | "executing" | "done" | "failed";
|
|
334
|
-
output?: unknown;
|
|
335
|
-
errorText?: string;
|
|
336
|
-
};
|
|
337
|
-
export type SubagentRun = {
|
|
338
|
-
name: string;
|
|
339
|
-
/**
|
|
340
|
-
* One entry per logical "child message" — independent of the child's
|
|
341
|
-
* `stepIndex` field, which the harness can reuse across multiple
|
|
342
|
-
* assistant messages within a turn (e.g. a message before a tool call
|
|
343
|
-
* and another message after the tool result both arrive under
|
|
344
|
-
* `stepIndex: 0`). The key is a monotonic counter so each
|
|
345
|
-
* `message.completed` opens a new box on the next inbound delta.
|
|
346
|
-
*/
|
|
347
|
-
steps: Map<number, SubagentChildStep>;
|
|
348
|
-
/**
|
|
349
|
-
* Section currently accepting reasoning/message deltas. `null` means
|
|
350
|
-
* the next delta opens a new section.
|
|
351
|
-
*/
|
|
352
|
-
currentSectionKey: number | null;
|
|
353
|
-
/** Monotonic counter for new section keys. */
|
|
354
|
-
nextSectionKey: number;
|
|
355
|
-
tools: Map<string, SubagentToolState>;
|
|
356
|
-
};
|
|
357
|
-
export type SubagentStepUpdate = {
|
|
358
|
-
callId: string;
|
|
359
|
-
subagentName: string;
|
|
360
|
-
sectionKey: number;
|
|
361
|
-
reasoning: string;
|
|
362
|
-
message: string;
|
|
363
|
-
finalized: boolean;
|
|
364
|
-
};
|
|
365
|
-
export type SubagentToolUpdate = {
|
|
366
|
-
callId: string;
|
|
367
|
-
subagentName: string;
|
|
368
|
-
childCallId: string;
|
|
369
|
-
toolName: string;
|
|
370
|
-
input: unknown;
|
|
371
|
-
status: "approval-requested" | "executing" | "done" | "failed";
|
|
372
|
-
output?: unknown;
|
|
373
|
-
errorText?: string;
|
|
374
|
-
};
|
|
375
332
|
export type ConnectionAuthChallenge = {
|
|
376
333
|
url?: string;
|
|
377
334
|
userCode?: string;
|