eve 0.27.3 → 0.27.5

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.
Files changed (52) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/dist/src/channel/reset-session.d.ts +8 -0
  3. package/dist/src/channel/reset-session.js +1 -0
  4. package/dist/src/channel/routes.d.ts +24 -1
  5. package/dist/src/channel/send.js +1 -1
  6. package/dist/src/channel/types.d.ts +14 -0
  7. package/dist/src/chunks/{use-eve-agent-CbF0l_Fp.js → use-eve-agent-BtkhbY2I.js} +53 -4
  8. package/dist/src/chunks/{use-eve-agent-CgxB9WQv.js → use-eve-agent-NUjD28Iu.js} +53 -4
  9. package/dist/src/cli/dev/tui/blocks.d.ts +7 -0
  10. package/dist/src/cli/dev/tui/blocks.js +3 -3
  11. package/dist/src/cli/dev/tui/message-queue.d.ts +88 -0
  12. package/dist/src/cli/dev/tui/message-queue.js +1 -0
  13. package/dist/src/cli/dev/tui/runner.d.ts +33 -0
  14. package/dist/src/cli/dev/tui/runner.js +1 -1
  15. package/dist/src/cli/dev/tui/subagent-pump.d.ts +9 -0
  16. package/dist/src/cli/dev/tui/subagent-pump.js +1 -1
  17. package/dist/src/cli/dev/tui/terminal-renderer.d.ts +9 -0
  18. package/dist/src/cli/dev/tui/terminal-renderer.js +13 -11
  19. package/dist/src/client/index.d.ts +1 -1
  20. package/dist/src/client/session.d.ts +13 -1
  21. package/dist/src/client/session.js +1 -1
  22. package/dist/src/client/types.d.ts +10 -0
  23. package/dist/src/execution/workflow-runtime.js +1 -1
  24. package/dist/src/internal/application/package.js +1 -1
  25. package/dist/src/internal/nitro/dev-runtime-source-snapshot.js +1 -1
  26. package/dist/src/internal/nitro/routes/channel-dispatch.js +1 -1
  27. package/dist/src/protocol/reset-session.d.ts +14 -0
  28. package/dist/src/protocol/reset-session.js +1 -0
  29. package/dist/src/protocol/routes.d.ts +5 -0
  30. package/dist/src/protocol/routes.js +1 -1
  31. package/dist/src/public/channels/eve.d.ts +2 -2
  32. package/dist/src/public/channels/eve.js +1 -1
  33. package/dist/src/public/channels/index.d.ts +1 -1
  34. package/dist/src/public/channels/slack/index.d.ts +1 -1
  35. package/dist/src/public/channels/slack/interactions.d.ts +2 -1
  36. package/dist/src/public/channels/slack/interactions.js +1 -1
  37. package/dist/src/public/channels/slack/slackChannel.d.ts +24 -1
  38. package/dist/src/public/channels/slack/slackChannel.js +1 -1
  39. package/dist/src/public/definitions/channel.d.ts +1 -1
  40. package/dist/src/setup/scaffold/create/project.js +1 -1
  41. package/dist/src/setup/vercel-project-api.d.ts +1 -1
  42. package/dist/src/setup/vercel-project-api.js +1 -1
  43. package/dist/src/svelte/index.js +1 -1
  44. package/dist/src/svelte/use-eve-agent.js +1 -1
  45. package/dist/src/vue/index.js +1 -1
  46. package/dist/src/vue/use-eve-agent.js +1 -1
  47. package/docs/channels/custom.mdx +38 -1
  48. package/docs/channels/slack.mdx +21 -2
  49. package/docs/extensions.md +98 -18
  50. package/docs/guides/dev-tui.md +9 -2
  51. package/docs/reference/cli.md +1 -1
  52. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # eve
2
2
 
3
+ ## 0.27.5
4
+
5
+ ### Patch Changes
6
+
7
+ - 1987e12: Add thread-bound session reset helpers to Slack message and interaction contexts, plus targeted reset support for generic Slack event handlers.
8
+
9
+ ## 0.27.4
10
+
11
+ ### Patch Changes
12
+
13
+ - 5d961f3: Request Vercel CLI's maximum 100-team page instead of following its broken default pagination path.
14
+ - 04d5814: `eve dev` no longer fails at boot with `UNRESOLVED_IMPORT` when a mounted extension (or any dependency) resolves through a `node_modules` above the app root — npm/yarn workspace hoisting, intermediate monorepo levels, and bare `withEve` agent directories whose host app owns the install now materialize in the dev-runtime snapshot.
15
+ - bbba073: The dev TUI supports queueing, steering, and cooperative turn cancellation. Pressing Enter while a turn is running queues the message (up to 5) in a pinned panel directly above the input — one line per message — and the queue coalesces into the next turn's message when the turn ends. Esc steers: it pops the oldest queued message, cancels the running turn cooperatively (`turn.cancelled` → `session.waiting`, keeping the session's context), and submits the popped message as the replacement turn. With nothing queued, Esc twice cancels the turn. Cancellation requests retry while the turn is live, so an Esc that lands in the turn-dispatch window (before the server has armed the turn's cancel hook) is no longer silently lost. Cancelling a turn mid-delegation settles its subagent sections and stops their child streams, so stale subagent output cannot paint into the steered turn. Messages still queued when a turn is interrupted or fails restore into the next prompt's input, and a turn cancelled from outside the prompt (a stale cancel or another client's `/cancel`) restores its submitted message the same way. On exit, the parting line names the server session id (`☰eve v0.27.0 · session ses_…`) so the conversation can be found again.
16
+ - dfd360f: Custom channel routes can now call `reset()` and `ClientSession` can reset the session that owns a stable continuation token. The next `send()` starts a fresh workflow session and lazily initializes a new session-scoped sandbox instead of reusing prior history or workspace state, and the `eve dev` TUI's `/new` performs that durable reset before clearing its transcript.
17
+
3
18
  ## 0.27.3
4
19
 
5
20
  ### Patch Changes
@@ -0,0 +1,8 @@
1
+ import type { ResetFn } from "#channel/routes.js";
2
+ import type { Runtime } from "#channel/types.js";
3
+ /**
4
+ * Builds a channel-scoped session reset helper. It resolves an owner once and
5
+ * retires that observed session id, so it can never cancel a later owner that
6
+ * claimed the same continuation token.
7
+ */
8
+ export declare function createResetFn(runtime: Runtime, channelName: string): ResetFn;
@@ -0,0 +1 @@
1
+ function createResetFn(e,t){return async n=>{let r=`${t}:${n.continuationToken}`,i=await e.resolveSession(r);return i===void 0?{status:`no_active_session`}:(await e.terminateSession({reason:n.reason,sessionId:i.sessionId}),{status:`reset`,previousSessionId:i.sessionId})}}export{createResetFn};
@@ -10,7 +10,8 @@ type WebSocketHeaders = Headers | readonly (readonly [string, string])[] | Recor
10
10
  /**
11
11
  * Second argument passed to every route handler. `send` starts or continues a
12
12
  * session on this channel; `cancel` stops the active turn on a session
13
- * addressed by continuation token; `getSession` looks one up by id; `receive`
13
+ * addressed by continuation token; `reset` retires a session so its
14
+ * token can start a fresh session; `getSession` looks one up by id; `receive`
14
15
  * hands inbound work to a different channel; `params` contains the matched
15
16
  * path parameters; `waitUntil` keeps background work alive past the response;
16
17
  * `requestIp` is the client IP, or `null` when the host cannot provide it.
@@ -23,6 +24,7 @@ export interface RouteHandlerArgs<TState = undefined> {
23
24
  */
24
25
  resolveActiveSession: ResolveActiveSessionFn;
25
26
  cancel: CancelFn;
27
+ reset: ResetFn;
26
28
  getSession: GetSessionFn;
27
29
  /**
28
30
  * Starts a session on a different channel to hand off inbound work (e.g. an
@@ -110,6 +112,27 @@ export interface CancelOptions {
110
112
  * on the event stream.
111
113
  */
112
114
  export type CancelFn = (options: CancelOptions) => Promise<CancelTurnResult>;
115
+ /** Options for {@link ResetFn}. */
116
+ export interface ResetOptions {
117
+ /** Channel-local raw token, in the same format accepted by {@link SendFn}. */
118
+ readonly continuationToken: string;
119
+ /** Human-readable terminal reason. Do not include credentials or message contents. */
120
+ readonly reason?: string;
121
+ }
122
+ /** Result of resetting the session that owned a continuation token. */
123
+ export type ResetResult = {
124
+ readonly status: "reset";
125
+ readonly previousSessionId: string;
126
+ } | {
127
+ readonly status: "no_active_session";
128
+ };
129
+ /**
130
+ * Terminally retires the session currently owning a continuation token.
131
+ * The token is available for the next {@link SendFn} after this resolves;
132
+ * that send starts with fresh history and state, and initializes a new
133
+ * session-scoped sandbox on first sandbox use.
134
+ */
135
+ export type ResetFn = (options: ResetOptions) => Promise<ResetResult>;
113
136
  export type RouteHandler<TState = undefined> = (req: Request, args: RouteHandlerArgs<TState>) => Promise<Response>;
114
137
  /**
115
138
  * A connected WebSocket peer passed to every {@link WebSocketRouteHooks}
@@ -1 +1 @@
1
- import{createSession}from"#channel/session.js";import{createLogger}from"#internal/logging.js";import{isRuntimeNoActiveSessionError}from"#execution/runtime-errors.js";import{serializeUrlFilePart}from"#internal/attachments/url-refs.js";const log=createLogger(`channel.send`);function createSendFn(t,r,i,a={}){return async(o,s)=>{let c=s.auth,l=s.callback,u=s.mode??`conversation`,d=s.state,f=s.title,p=s.continuationToken,m=`${i}:${p}`,{message:h,inputResponses:g,context:_,outputSchema:v}=normalizeSendInput(o),y=serializeUrlFilePartsInMessage(h);try{let n={auth:c,continuationToken:m,requestId:a.requestId,payload:{inputResponses:g,message:y,context:_,outputSchema:v}},{sessionId:r}=await t.deliver(n);return createSession(r,p,t)}catch(e){isRuntimeNoActiveSessionError(e)||log.warn(`deliver failed, falling back to starting a new session`,{continuationToken:m})}if(g&&g.length>0)throw Error(`Cannot deliver inputResponses — the target session was not found via continuation token.`);let b={adapter:d?{...r,state:{...r.state,...d}}:r,auth:c,capabilities:u===`conversation`?{requestInput:!0}:void 0,channelName:i,callback:l,continuationToken:m,input:{message:y??``,context:_,outputSchema:v},mode:u,requestId:a.requestId,title:f};return createSession((await t.run(b)).sessionId,p,t)}}function serializeUrlFilePartsInMessage(e){if(e===void 0||typeof e==`string`)return e;let t=!1,n=e.map(e=>e.type===`file`&&e.data instanceof URL&&e.data.protocol!==`data:`?(t=!0,{...e,data:serializeUrlFilePart(e.data)}):e);return t?n:e}function normalizeSendInput(e){return typeof e==`string`||Array.isArray(e)?{message:e}:e}export{createSendFn};
1
+ import{createSession}from"#channel/session.js";import{isRuntimeNoActiveSessionError}from"#execution/runtime-errors.js";import{serializeUrlFilePart}from"#internal/attachments/url-refs.js";function createSendFn(n,r,i,a={}){return async(o,s)=>{let c=s.auth,l=s.callback,u=s.mode??`conversation`,d=s.state,f=s.title,p=s.continuationToken,m=`${i}:${p}`,{message:h,inputResponses:g,context:_,outputSchema:v}=normalizeSendInput(o),y=serializeUrlFilePartsInMessage(h);try{let t={auth:c,continuationToken:m,requestId:a.requestId,payload:{inputResponses:g,message:y,context:_,outputSchema:v}},{sessionId:r}=await n.deliver(t);return createSession(r,p,n)}catch(e){if(!isRuntimeNoActiveSessionError(e))throw e}if(g&&g.length>0)throw Error(`Cannot deliver inputResponses — the target session was not found via continuation token.`);let b={adapter:d?{...r,state:{...r.state,...d}}:r,auth:c,capabilities:u===`conversation`?{requestInput:!0}:void 0,channelName:i,callback:l,continuationToken:m,input:{message:y??``,context:_,outputSchema:v},mode:u,requestId:a.requestId,title:f};return createSession((await n.run(b)).sessionId,p,n)}}function serializeUrlFilePartsInMessage(e){if(e===void 0||typeof e==`string`)return e;let t=!1,r=e.map(e=>e.type===`file`&&e.data instanceof URL&&e.data.protocol!==`data:`?(t=!0,{...e,data:serializeUrlFilePart(e.data)}):e);return t?r:e}function normalizeSendInput(e){return typeof e==`string`||Array.isArray(e)?{message:e}:e}export{createSendFn};
@@ -21,6 +21,18 @@ export interface CancelTurnInput {
21
21
  export interface CancelTurnResult {
22
22
  readonly status: CancelTurnStatus;
23
23
  }
24
+ /** Identifies a session to transition permanently to a terminal state. */
25
+ export interface TerminateSessionInput {
26
+ /** Human-readable reason recorded on the terminal workflow transition. */
27
+ readonly reason?: string;
28
+ readonly sessionId: string;
29
+ }
30
+ /** Result of attempting to terminally retire a session. */
31
+ export type TerminateSessionResult = {
32
+ readonly status: "terminated";
33
+ } | {
34
+ readonly status: "already_terminal";
35
+ };
24
36
  /**
25
37
  * Identifies one turn within a session.
26
38
  *
@@ -327,6 +339,8 @@ export interface Runtime {
327
339
  run(input: RunInput): Promise<RunHandle>;
328
340
  /** Requests cancellation of a session's in-flight turn. */
329
341
  cancelTurn(input: CancelTurnInput): Promise<CancelTurnResult>;
342
+ /** Terminally retires a session and releases its non-retained continuation hooks. */
343
+ terminateSession(input: TerminateSessionInput): Promise<TerminateSessionResult>;
330
344
  /**
331
345
  * Delivers a follow-up message to a parked session.
332
346
  */
@@ -6,6 +6,7 @@ const EVE_ROUTE_PREFIX = "/eve/v1";
6
6
  const EVE_HEALTH_ROUTE_PATH = `${EVE_ROUTE_PREFIX}/health`;
7
7
  const EVE_INFO_ROUTE_PATH = `${EVE_ROUTE_PREFIX}/info`;
8
8
  const EVE_CREATE_SESSION_ROUTE_PATH = `${EVE_ROUTE_PREFIX}/session`;
9
+ const EVE_RESET_SESSION_ROUTE_PATH = `${EVE_ROUTE_PREFIX}/session/reset`;
9
10
  const EVE_CONTINUE_SESSION_ROUTE_PATTERN = `${EVE_ROUTE_PREFIX}/session/:sessionId`;
10
11
  const EVE_MESSAGE_STREAM_ROUTE_PATTERN = `${EVE_ROUTE_PREFIX}/session/:sessionId/stream`;
11
12
  const EVE_CANCEL_TURN_ROUTE_PATTERN = `${EVE_ROUTE_PREFIX}/session/:sessionId/cancel`;
@@ -311,6 +312,17 @@ const CancelTurnResponseSchema = z.object({
311
312
  status: z.enum(["accepted", "no_active_turn"])
312
313
  });
313
314
 
315
+ //#endregion
316
+ //#region src/protocol/reset-session.ts
317
+ const ResetResponseSchema = z.discriminatedUnion("status", [z.object({
318
+ ok: z.literal(true),
319
+ previousSessionId: z.string().min(1),
320
+ status: z.literal("reset")
321
+ }), z.object({
322
+ ok: z.literal(true),
323
+ status: z.literal("no_active_session")
324
+ })]);
325
+
314
326
  //#endregion
315
327
  //#region src/client/output-schema.ts
316
328
  function extractCompletedResult(events) {
@@ -696,10 +708,14 @@ var ClientSession = class {
696
708
  const payload = normalizeSendTurnInput(input);
697
709
  const state = this.#state;
698
710
  const { continuationToken, sessionId } = await this.#postTurn(payload, state);
699
- if (this.#state === state) this.#state = {
700
- ...state,
701
- sessionId
702
- };
711
+ if (this.#state === state) {
712
+ const nextState = {
713
+ ...state,
714
+ sessionId
715
+ };
716
+ if (continuationToken !== void 0) nextState.continuationToken = continuationToken;
717
+ this.#state = nextState;
718
+ }
703
719
  return new MessageResponse({
704
720
  continuationToken,
705
721
  createStream: () => this.#createEventStream(sessionId, continuationToken, state, payload),
@@ -732,6 +748,39 @@ var ClientSession = class {
732
748
  status: result.data.status
733
749
  };
734
750
  }
751
+ async reset() {
752
+ const state = this.#state;
753
+ const continuationToken = state.continuationToken;
754
+ if (continuationToken === void 0) {
755
+ if (state.sessionId !== void 0) throw new Error("Session has no continuation token. Consume its event stream before resetting.");
756
+ this.#state = createInitialSessionState();
757
+ return { status: "no_active_session" };
758
+ }
759
+ const url = createClientUrl(this.#context.host, EVE_RESET_SESSION_ROUTE_PATH);
760
+ const headers = await this.#context.resolveHeaders();
761
+ headers.set("content-type", "application/json");
762
+ const response = await fetch(url, withRedirectPolicy$1({
763
+ body: JSON.stringify({ continuationToken }),
764
+ headers,
765
+ method: "POST"
766
+ }, this.#context.redirect));
767
+ const body = await response.text();
768
+ if (!response.ok) throw new ClientError(response.status, body, response.headers);
769
+ let payload;
770
+ try {
771
+ payload = JSON.parse(body);
772
+ } catch {
773
+ throw new Error(`Reset route returned invalid JSON (${response.status}).`);
774
+ }
775
+ const result = ResetResponseSchema.safeParse(payload);
776
+ if (!result.success) throw new Error(`Reset route returned an invalid response (${response.status}).`);
777
+ if (result.data.status === "reset" && state.sessionId !== void 0 && result.data.previousSessionId !== state.sessionId) throw new Error(`Reset route returned an invalid response (${response.status}).`);
778
+ if (this.#state === state) this.#state = createInitialSessionState();
779
+ return result.data.status === "reset" ? {
780
+ previousSessionId: result.data.previousSessionId,
781
+ status: "reset"
782
+ } : { status: "no_active_session" };
783
+ }
735
784
  stream(options) {
736
785
  const sessionId = this.#state.sessionId;
737
786
  if (!sessionId) throw new Error("Session has no session ID. Send a message first.");
@@ -6,6 +6,7 @@ const EVE_ROUTE_PREFIX = "/eve/v1";
6
6
  const EVE_HEALTH_ROUTE_PATH = `${EVE_ROUTE_PREFIX}/health`;
7
7
  const EVE_INFO_ROUTE_PATH = `${EVE_ROUTE_PREFIX}/info`;
8
8
  const EVE_CREATE_SESSION_ROUTE_PATH = `${EVE_ROUTE_PREFIX}/session`;
9
+ const EVE_RESET_SESSION_ROUTE_PATH = `${EVE_ROUTE_PREFIX}/session/reset`;
9
10
  const EVE_CONTINUE_SESSION_ROUTE_PATTERN = `${EVE_ROUTE_PREFIX}/session/:sessionId`;
10
11
  const EVE_MESSAGE_STREAM_ROUTE_PATTERN = `${EVE_ROUTE_PREFIX}/session/:sessionId/stream`;
11
12
  const EVE_CANCEL_TURN_ROUTE_PATTERN = `${EVE_ROUTE_PREFIX}/session/:sessionId/cancel`;
@@ -311,6 +312,17 @@ const CancelTurnResponseSchema = z.object({
311
312
  status: z.enum(["accepted", "no_active_turn"])
312
313
  });
313
314
 
315
+ //#endregion
316
+ //#region src/protocol/reset-session.ts
317
+ const ResetResponseSchema = z.discriminatedUnion("status", [z.object({
318
+ ok: z.literal(true),
319
+ previousSessionId: z.string().min(1),
320
+ status: z.literal("reset")
321
+ }), z.object({
322
+ ok: z.literal(true),
323
+ status: z.literal("no_active_session")
324
+ })]);
325
+
314
326
  //#endregion
315
327
  //#region src/client/output-schema.ts
316
328
  function extractCompletedResult(events) {
@@ -696,10 +708,14 @@ var ClientSession = class {
696
708
  const payload = normalizeSendTurnInput(input);
697
709
  const state = this.#state;
698
710
  const { continuationToken, sessionId } = await this.#postTurn(payload, state);
699
- if (this.#state === state) this.#state = {
700
- ...state,
701
- sessionId
702
- };
711
+ if (this.#state === state) {
712
+ const nextState = {
713
+ ...state,
714
+ sessionId
715
+ };
716
+ if (continuationToken !== void 0) nextState.continuationToken = continuationToken;
717
+ this.#state = nextState;
718
+ }
703
719
  return new MessageResponse({
704
720
  continuationToken,
705
721
  createStream: () => this.#createEventStream(sessionId, continuationToken, state, payload),
@@ -732,6 +748,39 @@ var ClientSession = class {
732
748
  status: result.data.status
733
749
  };
734
750
  }
751
+ async reset() {
752
+ const state = this.#state;
753
+ const continuationToken = state.continuationToken;
754
+ if (continuationToken === void 0) {
755
+ if (state.sessionId !== void 0) throw new Error("Session has no continuation token. Consume its event stream before resetting.");
756
+ this.#state = createInitialSessionState();
757
+ return { status: "no_active_session" };
758
+ }
759
+ const url = createClientUrl(this.#context.host, EVE_RESET_SESSION_ROUTE_PATH);
760
+ const headers = await this.#context.resolveHeaders();
761
+ headers.set("content-type", "application/json");
762
+ const response = await fetch(url, withRedirectPolicy$1({
763
+ body: JSON.stringify({ continuationToken }),
764
+ headers,
765
+ method: "POST"
766
+ }, this.#context.redirect));
767
+ const body = await response.text();
768
+ if (!response.ok) throw new ClientError(response.status, body, response.headers);
769
+ let payload;
770
+ try {
771
+ payload = JSON.parse(body);
772
+ } catch {
773
+ throw new Error(`Reset route returned invalid JSON (${response.status}).`);
774
+ }
775
+ const result = ResetResponseSchema.safeParse(payload);
776
+ if (!result.success) throw new Error(`Reset route returned an invalid response (${response.status}).`);
777
+ if (result.data.status === "reset" && state.sessionId !== void 0 && result.data.previousSessionId !== state.sessionId) throw new Error(`Reset route returned an invalid response (${response.status}).`);
778
+ if (this.#state === state) this.#state = createInitialSessionState();
779
+ return result.data.status === "reset" ? {
780
+ previousSessionId: result.data.previousSessionId,
781
+ status: "reset"
782
+ } : { status: "no_active_session" };
783
+ }
735
784
  stream(options) {
736
785
  const sessionId = this.#state.sessionId;
737
786
  if (!sessionId) throw new Error("Session has no session ID. Send a message first.");
@@ -34,6 +34,13 @@ export interface Block {
34
34
  subtitle?: string;
35
35
  /** Main multi-line content (markdown for prose, plain for logs). */
36
36
  body?: string;
37
+ /**
38
+ * User blocks only: how a mid-turn message reached the transcript. A
39
+ * steered message (Esc pop, displacing the running turn) marks itself
40
+ * with the accent arrow above its bar; a queued one (drained at the turn
41
+ * boundary) carries the arrow below. Absent for ordinary typed prompts.
42
+ */
43
+ promptOrigin?: "steer" | "queue";
37
44
  /** Reasoning trace shown above `body` (subagent steps). */
38
45
  reasoning?: string;
39
46
  /** One-line summarized result shown after a tool resolves. */
@@ -1,8 +1,8 @@
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(`
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,o);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),i=wrap(e.body??``,t-2).map(e=>`${r} ${e}`),a=n.colors.cyan(n.glyph.arrowUp);return e.promptOrigin===`steer`?[a,...i]:e.promptOrigin===`queue`?[...i,a]:i}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
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
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
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
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(`
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,r){let i=truncatePlain(e.title===void 0||e.title===`agent`?`self`:e.title,Math.max(8,t-16)),a=e.subtitle!==void 0&&e.subtitle.startsWith(`#`),o=a?`:${e.subtitle.slice(1)}`:``,s=` ${e.status===`done`?n.colors.green(n.glyph.subagent):r.activityPulse.trim().length>0?n.colors.orange(n.glyph.subagent):n.colors.dim(n.glyph.subagent)} subagent(${i}${o})`;return!a&&e.subtitle!==void 0&&e.subtitle.length>0&&(s+=` ${n.colors.dim(e.subtitle)}`),[s]}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};
@@ -0,0 +1,88 @@
1
+ /**
2
+ * The pinned message-queue panel: client-side state and pure rendering for
3
+ * messages submitted while a turn is still streaming.
4
+ *
5
+ * Enter queues the draft (up to {@link MESSAGE_QUEUE_LIMIT}); each queued
6
+ * message waits for the turn to end, where the whole queue coalesces into
7
+ * the next turn's message. Esc pops the oldest message to steer the
8
+ * conversation instead of waiting: the renderer requests cooperative turn
9
+ * cancellation and the runner submits the popped message as the next turn.
10
+ * Esc on an empty queue arms cancellation; a second Esc cancels the turn
11
+ * without a replacement message.
12
+ *
13
+ * The renderer owns lifecycle (keys, cancel requests, when the runner drains
14
+ * the queue); this module only holds the queue state machine and paints rows.
15
+ */
16
+ import type { Theme } from "./theme.js";
17
+ /** Most messages the queue holds; Enter on a full queue keeps the draft. */
18
+ export declare const MESSAGE_QUEUE_LIMIT = 5;
19
+ /** What one Esc press did to the queue state. */
20
+ export type MessageQueueEscapeOutcome =
21
+ /**
22
+ * A message is (now) staged for steering — the caller should request
23
+ * cooperative turn cancellation. Repeated presses pop further messages
24
+ * into the same staged steer payload and re-request cancellation.
25
+ */
26
+ "steer"
27
+ /** Queue empty: cancellation armed; the next Esc cancels. */
28
+ | "armed"
29
+ /** Second Esc on an empty queue — the caller should cancel the turn. */
30
+ | "cancel";
31
+ /** Read-only projection consumed by {@link renderMessageQueueRows}. */
32
+ export interface MessageQueueView {
33
+ readonly messages: readonly string[];
34
+ readonly full: boolean;
35
+ /** A popped message is staged and turn cancellation was requested. */
36
+ readonly steering: boolean;
37
+ /** First Esc on an empty queue landed; the next one cancels. */
38
+ readonly armed: boolean;
39
+ /** Esc Esc on an empty queue landed; cancellation was requested. */
40
+ readonly cancelling: boolean;
41
+ }
42
+ export declare class MessageQueue {
43
+ #private;
44
+ get size(): number;
45
+ get full(): boolean;
46
+ /** True when nothing is queued, staged, armed, or cancelling. */
47
+ get idle(): boolean;
48
+ /** Queues one message; returns false (draft stays put) when full. */
49
+ enqueue(message: string): boolean;
50
+ /**
51
+ * Applies one Esc press. Pops the oldest queued message into the staged
52
+ * steer payload while any remain; with an empty queue, arms and then
53
+ * requests cancellation.
54
+ */
55
+ handleEscape(): MessageQueueEscapeOutcome;
56
+ /** Any non-Esc activity backs out of the armed press-again state. */
57
+ disarm(): void;
58
+ /** Clears per-turn Esc state when a new stream starts rendering. */
59
+ beginTurn(): void;
60
+ /**
61
+ * The next prompt to submit after a turn boundary: the staged steer
62
+ * message when one exists (remaining queued messages stay queued for the
63
+ * steered turn), otherwise the whole queue coalesced into one message.
64
+ */
65
+ takePrompt(): string | undefined;
66
+ /**
67
+ * Everything still held — staged steer payload plus queued messages —
68
+ * coalesced for restoring into the prompt editor when a turn ends without
69
+ * a clean boundary (interrupt, transport failure). Clears the queue.
70
+ */
71
+ restoreDraft(): string | undefined;
72
+ reset(): void;
73
+ view(): MessageQueueView;
74
+ }
75
+ export interface MessageQueuePanelRowsInput {
76
+ readonly view: MessageQueueView;
77
+ readonly width: number;
78
+ readonly theme: Theme;
79
+ /** True while a turn streams — the only state in which Esc steers. */
80
+ readonly working: boolean;
81
+ }
82
+ /**
83
+ * Paints the pinned queue panel, indented so its marks share the tool
84
+ * column. Queued messages ride a `│` rail under the header (one clipped
85
+ * line each) and the last closes it with `└`. The header carries the Esc
86
+ * affordance — the panel is where steering and cancellation are taught.
87
+ */
88
+ export declare function renderMessageQueueRows(input: MessageQueuePanelRowsInput): string[];
@@ -0,0 +1 @@
1
+ import"./rail.js";import{clipVisible,stripTerminalControls}from"#cli/ui/terminal-text.js";const MESSAGE_QUEUE_LIMIT=5;var MessageQueue=class{#e=[];#t;#n=!1;#r=!1;get size(){return this.#e.length}get full(){return this.#e.length>=5}get idle(){return this.#e.length===0&&this.#t===void 0&&!this.#n&&!this.#r}enqueue(e){return this.full?!1:(this.#e.push(e),this.#n=!1,!0)}handleEscape(){let e=this.#e.shift();return e===void 0?this.#t===void 0?this.#n?(this.#r=!0,`cancel`):(this.#n=!0,`armed`):`steer`:(this.#t=joinMessages(this.#t,e),`steer`)}disarm(){this.#n=!1}beginTurn(){this.#n=!1,this.#r=!1}takePrompt(){this.#n=!1,this.#r=!1;let e=this.#t;return e===void 0?this.#i():(this.#t=void 0,e)}restoreDraft(){this.#n=!1,this.#r=!1;let e=this.#t;return this.#t=void 0,joinOptionalMessages(e,this.#i())}reset(){this.#e=[],this.#t=void 0,this.#n=!1,this.#r=!1}view(){return{messages:[...this.#e],full:this.full,steering:this.#t!==void 0,armed:this.#n,cancelling:this.#r}}#i(){if(this.#e.length===0)return;let e=this.#e.reduce(joinOptionalMessages,void 0);return this.#e=[],e}};function joinMessages(e,t){return e===void 0?t:`${e}\n\n${t}`}function joinOptionalMessages(e,t){return t===void 0?e:joinMessages(e,t)}function renderMessageQueueRows(n){let{view:r,width:i,theme:a,working:o}=n,s=a.colors,c=a.glyph;if(r.messages.length===0&&!r.steering)return o?r.cancelling?[clipVisible(` ${s.yellow(c.dotActive)} ${s.dim(`Cancelling turn…`)}`,i)]:r.armed?[clipVisible(` ${s.yellow(c.dotActive)} ${s.dim(`Press esc again to cancel the turn`)}`,i)]:[]:[];let l=[clipVisible(` ${s.gray(c.arrowUp)} ${headerBody(r,o,a)}`,i)];for(let[n,a]of r.messages.entries()){let o=n===r.messages.length-1?c.corner:c.rule,u=firstLine(stripTerminalControls(a));l.push(clipVisible(` ${s.dim(o)} ${s.dim(u)}`,i))}return l}function headerBody(e,t,n){let r=n.colors,i=` ${n.glyph.dot} `,a=`${String(e.messages.length)}/5`;if(e.steering){let t=e.messages.length>0?`${i}${a} still queued`:``;return r.dim(`Steering — cancelling the running turn…${t}`)}let o=e.full?`${i}queue full`:``,s=t?`${i}esc steers with the next message`:``;return`${r.bold(`Queue`)} ${r.dim(`${a}${o}${s}`)}`}function firstLine(e){return e.split(/\r?\n/u,1)[0]??``}export{MESSAGE_QUEUE_LIMIT,MessageQueue,renderMessageQueueRows};
@@ -19,6 +19,15 @@ export { parsePromptCommand, type PromptCommand } from "./prompt-commands.js";
19
19
  export type AgentTUIStreamResult = {
20
20
  events: AsyncIterable<AgentTUIStreamEvent> | ReadableStream<AgentTUIStreamEvent>;
21
21
  abort?: () => void;
22
+ /**
23
+ * Requests cooperative server-side cancellation of the streaming turn
24
+ * (Esc Esc, or an Esc steer pop). Unlike {@link abort} — which drops the
25
+ * client stream and forces a fresh session — the server settles the turn
26
+ * as `turn.cancelled` → `session.waiting`, so the stream reaches its
27
+ * boundary normally and the session keeps its context. Best-effort and
28
+ * idempotent; scoped to the turn the user observed when its id is known.
29
+ */
30
+ cancel?: () => void;
22
31
  turnState?: AgentTUITurnState;
23
32
  };
24
33
  export type AgentTUIStreamUsage = {
@@ -75,6 +84,8 @@ export type AgentTUIStreamEvent = {
75
84
  errorText: string;
76
85
  hint?: string;
77
86
  detail?: string;
87
+ } | {
88
+ type: "turn-cancelled";
78
89
  } | {
79
90
  type: "finish";
80
91
  usage?: AgentTUIStreamUsage;
@@ -85,6 +96,10 @@ export type AgentTUITurnState = {
85
96
  pendingApprovals: AgentTUIToolApprovalRequest[];
86
97
  pendingQuestions: InputRequest[];
87
98
  sawSessionFailure: boolean;
99
+ /** Id of the streaming turn, once `turn.started` names it. Scopes cancels. */
100
+ turnId?: string;
101
+ /** True while a cooperative-cancel request loop is running for this turn. */
102
+ cancelInFlight?: boolean;
88
103
  };
89
104
  export type AgentTUISessionOptions = {
90
105
  title?: string;
@@ -169,6 +184,24 @@ export type AgentTUIRenderer = {
169
184
  renderCommandResult?(text: string): void;
170
185
  readonly setupFlow?: SetupFlowRenderer;
171
186
  readPrompt?(options?: AgentTUISessionOptions): Promise<string | undefined>;
187
+ /**
188
+ * Consumes the next prompt produced by mid-turn input: the Esc-popped
189
+ * steering message when one is staged, otherwise every message queued
190
+ * during the turn coalesced into one. The runner calls this at a clean
191
+ * turn boundary and submits the result as the next turn without reading
192
+ * the prompt. Optional — renderers without mid-turn input never queue.
193
+ */
194
+ takeQueuedPrompt?(): string | undefined;
195
+ /**
196
+ * Reports the server session id backing the conversation — pushed by the
197
+ * runner once a send is accepted, and overwritten when a later session's
198
+ * turn is accepted. Deliberately sticky across `/new` and interrupt
199
+ * recovery: the terminal renderer echoes the LAST session this TUI talked
200
+ * to in the parting line on exit, so an interrupted conversation (whose
201
+ * replacement session never ran a turn) can still be found again
202
+ * (`eve logs`, the session store). Optional.
203
+ */
204
+ setSessionId?(sessionId: string): void;
172
205
  readToolApproval?(request: AgentTUIToolApprovalRequest, options?: AgentTUISessionOptions): Promise<AgentTUIToolApprovalResponse>;
173
206
  readInputQuestion?(question: AgentTUIInputQuestion, options?: AgentTUISessionOptions): Promise<AgentTUIInputQuestionResponse | undefined>;
174
207
  renderStream(result: AgentTUIStreamResult, options?: AgentTUISessionOptions): Promise<void>;
@@ -1 +1 @@
1
- import{PROMPT_COMMANDS,formatPromptCommandHelp,parsePromptCommand}from"./prompt-commands.js";import{pickAgentHeaderTip}from"./agent-header.js";import{probeAgentInfo}from"./agent-info-probe.js";import{failureKey,formatFailureDetail,formatFailureHint,formatFailureMessage,isInterruptedError,localFailureHint}from"./errors.js";import{parseLogDisplayMode}from"./log-display-mode.js";import{createMcpConnectionStatusTracker}from"./mcp-connection-status.js";import{createRemoteConnectionController}from"./remote-connection.js";import{SubagentPump}from"./subagent-pump.js";import{BOOT_DETECTIONS,CLI_MISSING_SETUP_ISSUE,LOGIN_SETUP_ISSUE,detectSetupIssues,formatSetupIssuesLine,orderedSetupIssues,resolveModelProviderState}from"./setup-issues.js";import{TerminalRenderer}from"./terminal-renderer.js";import{createVercelStatusTracker}from"./vercel-status.js";import"#client/index.js";import{toErrorMessage}from"#shared/errors.js";import{getVercelAuthStatus}from"#setup/vercel-project.js";import{loadDevelopmentEnvironmentFiles}from"#cli/dev/environment.js";import{subscribeDevelopmentSandboxPrewarmLogs}from"#execution/sandbox/development-prewarm.js";import{createDevelopmentRuntimeArtifactRefresher}from"#services/dev-client.js";import{devBootPhase}from"#internal/dev-boot-progress.js";function authIssueForStatus(e){if(e===`logged-out`)return LOGIN_SETUP_ISSUE;if(e===`cli-missing`)return CLI_MISSING_SETUP_ISSUE}var EveTUIRunner=class{#e;#t;#n;#r;#i;#a;#o;#s;#c;#l;#u;#d;#f;#p;#m;#h;#g;#_;#v;#y;#b;#x=!1;#S=new AbortController;#C=!1;#w=[];#T;#E;#D;#O=pickAgentHeaderTip();#k;#A=new Map;#j;#M=new Map;#N=new Set;#P=!1;#F;constructor(t){this.#e=t.session,t.client!==void 0&&(this.#t=t.client),this.#n=createRenderer(t);let n={formatActionResultError};if(this.#t!==void 0&&(n.client=this.#t),this.#n.subagents!==void 0&&(n.view=this.#n.subagents),this.#j=new SubagentPump(n),this.#r=t.name??`eve`,this.#i=t.tools??`full`,this.#a=t.reasoning??`full`,this.#o=t.subagents??`full`,this.#s=t.connectionAuth??`full`,this.#c=t.assistantResponseStats??`tokensPerSecond`,this.#l=t.contextSize,this.#u=t.formatTransportError??toErrorMessage,t.initialInput!==void 0&&(this.#m=t.initialInput),t.appRoot!==void 0){this.#p=t.appRoot;let e={appRoot:t.appRoot,onChange:e=>this.#n.setVercelStatus?.(e)};t.detectProjectIdentity!==void 0&&(e.detectIdentity=t.detectProjectIdentity),this.#E=createVercelStatusTracker(e),t.probeMcpConnection!==void 0&&(this.#D=createMcpConnectionStatusTracker({onChange:()=>{},probe:t.probeMcpConnection}))}if(t.promptCommandHandler!==void 0&&(this.#h=t.promptCommandHandler),this.#g=t.availablePromptCommands??PROMPT_COMMANDS,t.remote!==void 0){if(this.#t===void 0)throw Error(`A remote TUI requires a configured development client.`);this.#_=createRemoteConnectionController({client:this.#t,credentials:t.remote.credentials,target:t.remote.target,onChange:e=>this.#n.setRemoteConnectionStatus?.(e),resolveOidcToken:t.remote.resolveOidcToken,resolveDeployment:t.remote.resolveDeployment})}this.#v=t.bootDetections??BOOT_DETECTIONS,this.#y=t.getVercelAuthStatus??getVercelAuthStatus,t.onBootProgress!==void 0&&(this.#b=t.onBootProgress),t.serverUrl!==void 0&&(this.#f=t.serverUrl),t.serverUrl!==void 0&&t.remote===void 0&&(this.#d=createDevelopmentRuntimeArtifactRefresher({serverUrl:t.serverUrl}))}async#I(){if(this.#f===void 0){this.#R(),await this.#G(void 0);return}let e;if(this.#_!==void 0){let t=await this.#_.check();t.state===`ready`&&(e=t.info)}else{let t=this.#t;if(t!==void 0)try{let n=await devBootPhase(`connecting to agent`,()=>probeAgentInfo({client:t}),this.#b);n.kind===`ready`&&(e=n.info)}catch{e=void 0}}this.#R();let t=this.#L(e);await this.#G(t)}#L(e){let t=this.#p===void 0?e:resolveModelProviderState(e,process.env);this.#k=t;let n=this.#f;if(n===void 0)return t;let r={name:this.#r,serverUrl:n};return t!==void 0&&(r.info=t),this.#p!==void 0&&(r.tip=this.#O),this.#n.renderAgentHeader?.(r),t}#R(){let e=this.#b;this.#b=void 0,e?.({type:`before-first-paint`})}async run(){try{await this.#z()}finally{this.#x=!0,this.#S.abort(),this.#j.abortAll(),this.#F?.(),this.#F=void 0,this.#n.shutdown?.(),this.#E?.dispose(),this.#D?.dispose(),this.#_?.dispose()}}async#z(){let e=this.#r,r,i,a=!1,o=!1,s=this.#m;await this.#I(),this.#_?.current().connection.state===`auth-required`&&await this.#te({type:`extension`,name:`vc:login`,argument:``},e,{trigger:`startup`}),this.#Y(),this.#E?.refreshIdentity(),this.#D?.refresh();let c=this.#m===void 0?void 0:parsePromptCommand(this.#m);for(c?.type===`extension`&&c.name===`model`&&c.argument===``&&this.#p!==void 0&&this.#h!==void 0&&this.#n.setupFlow!==void 0&&(s=void 0,await this.#ne(e));;){if(!o){if(r==null){if(!this.#n.readPrompt){if(a)return;throw Error(`No prompt was provided and the renderer does not support prompt input.`)}let t={title:e};s!==void 0&&(t.initialDraft=s,s=void 0);try{r=await this.#V(t)}catch(e){if(isInterruptedError(e))return;throw e}if(r==null)return}let c=parsePromptCommand(r);if(c?.type===`exit`)return;if(c?.type===`new`){this.#B(),i=void 0,o=!1,r=void 0,this.#n.reset?.();continue}if(c?.type===`help`){this.#X(formatPromptCommandHelp(this.#g)),i=void 0,o=!1,r=void 0;continue}if(c?.type===`loglevel`){this.#X(this.#ie(c.argument)),i=void 0,o=!1,r=void 0;continue}if(c?.type===`extension`){try{await this.#te(c,e,{trigger:`command`})}catch(e){if(isInterruptedError(e))return;throw e}i=void 0,r=void 0,o=!1;continue}a=!0}let c=await this.#H({prompt:o?void 0:r,inputResponses:i}),u=r,d=!1;try{for(;;){await this.#n.renderStream(c,{title:e,submittedPrompt:u,continueSession:!!this.#n.readPrompt,tools:this.#i,reasoning:this.#a,subagents:this.#o,connectionAuth:this.#s,assistantResponseStats:this.#c,contextSize:this.#l});let t=c.turnState?.pendingApprovals??[],n=c.turnState?.pendingQuestions??[];if(t.length>0||n.length>0){let a=[];if(t.length>0){if(!this.#n.readToolApproval)throw Error(`Tool approval was requested, but the renderer does not support tool approval input.`);for(let n of t){let t=await this.#n.readToolApproval(n,{title:e});a.push({requestId:n.approvalId,optionId:t.approved?`approve`:`deny`}),this.#A.delete(n.approvalId)}}if(n.length>0){if(!this.#n.readInputQuestion)throw Error(`An interactive question was requested, but the renderer does not support input questions.`);for(let t of n){let n=toAgentTUIInputQuestion(t),r=await this.#n.readInputQuestion(n,{title:e});if(r===void 0)continue;let i={requestId:t.requestId};r.optionId!==void 0&&(i.optionId=r.optionId),r.text!==void 0&&(i.text=r.text),a.push(i),this.#A.delete(t.requestId)}}if(a.length===0)break;o=!0,i=a,r=void 0,d=!0;break}if(this.#le(c)){c=this.#U(),u=void 0;continue}if(c.turnState&&c.turnState.boundaryEvent===void 0)if(c.turnState.aborted)this.#P=!0;else{let e=this.#e.state.sessionId;this.#n.renderNotice?.(e?`Lost the event stream — the turn may still be running on the server (session ${e}). Your next message resumes this session; use /cancel to stop the turn.`:`Lost the connection to the running turn.`)}break}}catch(e){if(isInterruptedError(e))return;throw e}d||(o=!1,i=void 0,r=void 0,this.#P&&(this.#P=!1,this.#B(),c.turnState?.aborted?this.#n.renderNotice?.(`Stopped following the turn and started a new session. Earlier context was cleared; the interrupted turn may still be running on the server.`):this.#n.renderSessionBoundary===void 0?this.#n.renderNotice?.(`Session ended — started a new session. Earlier context was cleared.`):this.#n.renderSessionBoundary()))}}#B(){this.#j.abortAll(),this.#A.clear(),this.#M.clear(),this.#N.clear(),this.#n.setConnectionAuthPendingCount?.(0),this.#t&&(this.#e=this.#t.session()),this.#d?.clear()}async#V(e){if(!this.#n.readPrompt)return;let t=this.#n.readPrompt(e),n=this.#d;if(n===void 0)return await t;let r=!1,i=!1,a,refresh=async()=>{if(!(r||i)){i=!0;try{await n.refreshIdle({onRuntimeArtifactsChanged:()=>this.#se()})}finally{i=!1}}},startRefresh=()=>{if(r||i)return;let e=refresh().finally(()=>{a===e&&(a=void 0)});a=e};startRefresh();let o=setInterval(()=>{startRefresh()},500);o.unref?.();try{return await t}finally{r=!0,clearInterval(o),await a}}async#H(e){let t=new AbortController,n={signal:t.signal};e.prompt!==void 0&&(n.message=e.prompt),e.inputResponses!==void 0&&e.inputResponses.length>0&&(n.inputResponses=e.inputResponses);let r;try{this.#d!==void 0&&await this.#d.refresh({inputResponses:n.inputResponses,message:n.message,onRuntimeArtifactsChanged:()=>this.#se()}),n.message!==void 0&&(n.inputResponses?.length??0)===0&&this.#n.flushDelayedDevBuildErrors?.(),r=await this.#e.send(n)}catch(e){if(isInterruptedError(e))throw e;return this.#_?.reportFailure(e),this.#P=!0,{events:errorOnlyTUIStream({errorText:this.#u(e)}),turnState:createTurnState()}}return this.#W(r,()=>t.abort())}#U(){let e=new AbortController;return this.#W(this.#e.stream({signal:e.signal}),()=>e.abort())}#W(e,t){let n=createTurnState();return{abort:()=>{n.aborted=!0,t()},events:eveEventsToTUIStream({events:e,pendingInputRequests:this.#A,turnState:n,onSubagentCalled:e=>this.#j.begin(e),onSubagentCompleted:e=>this.#j.settle(e),onConnectionAuthRequired:e=>this.#ce(e),onConnectionAuthCompleted:e=>this.#ue(e),onTerminalFailure:()=>{this.#P=!0},failureHintOverride:this.#p===void 0?void 0:localFailureHint}),turnState:n}}async#G(e){if(this.#p===void 0)return;let t={appRoot:this.#p,env:process.env};e!==void 0&&(t.info=e),this.#w=await detectSetupIssues(t,this.#v),this.#n.renderSetupWarning!==void 0&&(this.#K(),this.#q())}#K(){let e=orderedSetupIssues(this.#w,this.#T);e.length>0?this.#n.renderSetupWarning?.(formatSetupIssuesLine(e)):this.#n.clearSetupWarning?.()}async#q(){let e=this.#p;if(e===void 0)return;let t;try{t=await this.#y(e,{signal:this.#S.signal})}catch{return}this.#x||this.#C||(this.#T=authIssueForStatus(t),this.#K())}async#J(e){let t=this.#p;if(t===void 0||this.#n.renderSetupWarning===void 0)return;let n={appRoot:t,env:process.env};e!==void 0&&(n.info=e);try{this.#w=await detectSetupIssues(n,this.#v);let e=await this.#y(t,{signal:this.#S.signal});this.#T=authIssueForStatus(e)}catch{return}this.#x||this.#K()}#Y(){this.#p===void 0||this.#n.renderSandboxLog===void 0||this.#F===void 0&&(this.#F=subscribeDevelopmentSandboxPrewarmLogs({appRoot:this.#p,log:e=>this.#n.renderSandboxLog?.(e)}))}#X(e){if(e!==void 0){if(this.#n.renderCommandResult!==void 0){this.#n.renderCommandResult(e);return}this.#n.renderNotice?.(e)}}async#Z(e,t){let n=this.#h;if(n===void 0)return{message:`/${e.name} is not available in this session.`};let r={renderer:this.#n,title:t.title,initialModelStep:t.initialModelStep,remoteConnection:this.#_},i=this.#D?.current(),a=i!==void 0&&Object.keys(i).length>0?{...r,disabledConnectionReasons:i}:r;return t.keepSetupFlowOpen===!0?await n.handle(e,{...a,keepSetupFlowOpen:!0}):await n.handle(e,a)}#Q(e,t){if(t!==`startup`)return;let n=this.#_?.current().connection.state,r=n===`auth-failed`||n===`unavailable`?`failed`:void 0,i=e.argument.length===0?``:` ${e.argument}`;this.#n.renderCommandInvocation?.(`/${e.name}${i}`,r)}async#$(e){if(e?.kind===`connection-added`){this.#E?.applyEffect({kind:`refresh-identity`}),this.#C=!0,await this.#ee(),await this.#ae();return}if(e?.kind===`model-access-changed`){this.#E?.applyEffect({kind:`refresh-identity`}),this.#C=!0,await this.#ae();return}e!==void 0&&(this.#E?.applyEffect(e),this.#C=!0,this.#J(this.#k))}async#ee(){let e=this.#d;e!==void 0&&await e.refreshAfterSourceChange({onRuntimeArtifactsChanged:()=>this.#se()})}async#te(e,t,n){let r=await this.#Z(e,{initialModelStep:n.initialModelStep,keepSetupFlowOpen:n.keepSetupFlowOpen,title:t});this.#Q(e,n.trigger),this.#X(r?.message),await this.#$(r?.effect),this.#re()}async#ne(e){let t=this.#p;if(t===void 0)return;let authStatus=async()=>{try{return await this.#y(t,{signal:this.#S.signal})}catch{return}},n=await authStatus();if(n===`cli-missing`&&(await this.#te({type:`extension`,name:`vc:install`,argument:``},e,{trigger:`startup`,keepSetupFlowOpen:!0}),n=await authStatus(),n===`cli-missing`)){this.#n.setupFlow?.end();return}if(n===`logged-out`&&(await this.#te({type:`extension`,name:`vc:login`,argument:``},e,{trigger:`startup`,keepSetupFlowOpen:!0}),n=await authStatus(),n===`cli-missing`||n===`logged-out`)){this.#n.setupFlow?.end();return}await this.#te({type:`extension`,name:`model`,argument:``},e,{trigger:`startup`,initialModelStep:`provider`})}#re(){let e=this.#_?.current().connection;e?.state!==`ready`||e.info===this.#k||(this.#k=e.info,this.#f!==void 0&&this.#n.renderAgentHeader?.({info:e.info,name:this.#r,serverUrl:this.#f}))}#ie(e){let t=this.#n;if(t.logDisplayMode===void 0||t.setLogDisplayMode===void 0)return`/loglevel is not available in this session.`;if(e===``)return`Logs: ${t.logDisplayMode()}. Use /loglevel all|stderr|sandbox|none — logs stay buffered, so switching also hides or restores past lines.`;let n=parseLogDisplayMode(e);if(n===void 0)return`Unknown log level "${e}". Use all, stderr, sandbox, or none.`;if(n===t.logDisplayMode())return`Logs already set to ${n}.`;switch(t.setLogDisplayMode(n),n){case`none`:return`Logs hidden. Output stays buffered — /loglevel all restores it.`;case`stderr`:return`Showing stderr logs only.`;case`sandbox`:return`Showing sandbox logs only.`;case`all`:return`Showing all logs.`}}async#ae(){let e=this.#p;if(e===void 0)return;loadDevelopmentEnvironmentFiles(e);let t=this.#L(await this.#oe());this.#J(t)}async#oe(){let e=this.#t;if(e===void 0)return;let t=await probeAgentInfo({client:e});return t.kind===`ready`?t.info:void 0}async#se(){let e=this.#k,t=await this.#oe();t!==void 0&&this.#L(t),(!this.#n.renderAgentHeader||t===void 0)&&this.#n.renderNotice?.(formatAgentUpdateNotice(e,t))}#ce(e){let t={name:e.data.name,description:e.data.description,state:`required`};e.data.authorization!==void 0&&(t.challenge=e.data.authorization),e.data.webhookUrl!==void 0&&(t.webhookUrl=e.data.webhookUrl),this.#M.set(e.data.name,t),this.#de(t)}#le(e){if(e.turnState?.boundaryEvent!==`session.waiting`)return!1;let t=!1;for(let e of this.#M.values())e.state!==`required`||e.webhookUrl===void 0||(e.state=`pending`,this.#N.add(e.name),this.#de(e),t=!0);return t&&this.#n.setConnectionAuthPendingCount?.(this.#N.size),this.#N.size>0}#ue(e){let t=this.#M.get(e.data.name)??{name:e.data.name,description:``,state:e.data.outcome};t.state=e.data.outcome,e.data.reason!==void 0&&(t.reason=e.data.reason),this.#M.set(e.data.name,t),this.#N.delete(e.data.name),this.#de(t),this.#n.setConnectionAuthPendingCount?.(this.#N.size)}#de(e){let t={name:e.name,description:e.description,state:e.state};e.challenge!==void 0&&(t.challenge=e.challenge),e.reason!==void 0&&(t.reason=e.reason),this.#n.upsertConnectionAuth?.(t)}};function createRenderer(e){return e.renderer?e.renderer:new TerminalRenderer({tools:e.tools,reasoning:e.reasoning,subagents:e.subagents,connectionAuth:e.connectionAuth,assistantResponseStats:e.assistantResponseStats,contextSize:e.contextSize,logs:e.logs,availablePromptCommands:e.availablePromptCommands,input:e.userInput,output:e.screen,diagnostics:e.diagnostics})}function formatAgentUpdateNotice(e,t){let n=e?.agent.model.id,r=t?.agent.model.id;return n!==void 0&&r!==void 0&&n!==r?`Agent updated: Model ${n} -> ${r}`:`Agent updated.`}async function*eveEventsToTUIStream(e){let{events:t,pendingInputRequests:n,turnState:r,onSubagentCalled:i,onSubagentCompleted:a,onConnectionAuthRequired:o,onConnectionAuthCompleted:s,onTerminalFailure:c,failureHintOverride:l}=e,u=new Map,d=new Map,f=0,p=new Set,m=new Set,h=new Set,g=!1,_=!1,v;for await(let e of t)if(!(_&&isPostTurnVisibleEvent(e)))switch(e.type){case`session.started`:case`turn.started`:case`message.received`:break;case`step.started`:f+=1,yield{type:`step-start`};break;case`step.completed`:{let t=e;v=t.data.usage,yield*closeOpenParts(u,`assistant-complete`,f),yield*closeOpenParts(d,`reasoning-complete`,f),yield{type:`step-finish`,usage:t.data.usage};break}case`message.appended`:{let t=e,n=textPartId(t.data.turnId,t.data.stepIndex),r=partStateFor(u,n),i=t.data.messageSoFar;if(r.completed){if(r.text.startsWith(i)||f<=r.completedEpoch)break;r.generation+=1,r.text=``,r.completed=!1}if(!i.startsWith(r.text)||i.length<=r.text.length)break;let a=i.slice(r.text.length);r.text=i,yield{type:`assistant-delta`,id:partGenerationId(n,r.generation),delta:a};break}case`message.completed`:{let t=textPartId(e.data.turnId,e.data.stepIndex),n=partStateFor(u,t),r=e.data.message;if(n.completed){if(r===null||r===n.text||f<=n.completedEpoch)break;n.generation+=1,n.text=r,n.completedEpoch=f,yield{type:`assistant-complete`,id:partGenerationId(t,n.generation),text:r};break}let i=partGenerationId(t,n.generation);if(r!==null){if(n.text.length===0)n.text=r,n.completed=!0,n.completedEpoch=f,yield{type:`assistant-complete`,id:i,text:r};else if(r.startsWith(n.text)){let e=r.slice(n.text.length);e.length>0&&(yield{type:`assistant-delta`,id:i,delta:e}),n.text=r,n.completed=!0,n.completedEpoch=f,yield{type:`assistant-complete`,id:i}}}else n.text.length>0&&(n.completed=!0,n.completedEpoch=f,yield{type:`assistant-complete`,id:i});break}case`reasoning.appended`:{let t=e,n=reasoningPartId(t.data.turnId,t.data.stepIndex),r=partStateFor(d,n),i=t.data.reasoningSoFar;if(r.completed){if(r.text.startsWith(i)||f<=r.completedEpoch)break;r.generation+=1,r.text=``,r.completed=!1}if(!i.startsWith(r.text)||i.length<=r.text.length)break;let a=i.slice(r.text.length);r.text=i,yield{type:`reasoning-delta`,id:partGenerationId(n,r.generation),delta:a};break}case`reasoning.completed`:{let t=reasoningPartId(e.data.turnId,e.data.stepIndex),n=partStateFor(d,t),r=e.data.reasoning;if(n.completed){if(r.length===0||r===n.text||n.text.startsWith(r)||f<=n.completedEpoch)break;n.generation+=1,n.text=r,n.completedEpoch=f;let e=partGenerationId(t,n.generation);yield{type:`reasoning-delta`,id:e,delta:r},yield{type:`reasoning-complete`,id:e};break}let i=partGenerationId(t,n.generation);if(n.text.length===0&&r.length>0)n.text=r,yield{type:`reasoning-delta`,id:i,delta:r};else if(r.length>0&&!r.startsWith(n.text))break;n.completed=!0,n.completedEpoch=f,yield{type:`reasoning-complete`,id:i};break}case`actions.requested`:{let t=e.data.actions.filter(e=>e.kind===`tool-call`);if(t.length===0)break;for(let e of t)p.has(e.callId)||(p.add(e.callId),yield{type:`tool-call`,toolCallId:e.callId,toolName:e.toolName,input:e.input});break}case`input.requested`:{let t=e.data.requests.filter(e=>e.action.kind===`tool-call`);if(t.length===0)break;for(let e of t){let t=e.action.callId;if(p.has(t)||(p.add(t),yield{type:`tool-call`,toolCallId:t,toolName:e.action.toolName,input:e.action.input}),!m.has(e.requestId)){if(m.add(e.requestId),n.set(e.requestId,e),isQuestionRequest(e)){upsertPendingQuestion(r,e);continue}upsertPendingApproval(r,e),yield{type:`tool-approval-request`,approvalId:e.requestId,toolCallId:t}}}break}case`action.result`:{let t=e;if(t.data.result.kind!==`tool-result`)break;let n=t.data.result.callId;if(!p.has(n))break;switch(t.data.status){case`completed`:yield{type:`tool-result`,toolCallId:n,output:t.data.result.output};break;case`failed`:yield{type:`tool-error`,toolCallId:n,errorText:formatActionResultError(t)};break;case`rejected`:yield{type:`tool-rejected`,toolCallId:n,reason:formatActionResultError(t)};break}break}case`step.failed`:case`turn.failed`:{let t=toFailureEvent(e,h,l);t&&(yield t);break}case`session.failed`:{r.sawSessionFailure=!0,c?.(e);let t=toFailureEvent(e,h,l);t&&(yield t),r.boundaryEvent=e.type,yield*closeOpenParts(u,`assistant-complete`,f),yield*closeOpenParts(d,`reasoning-complete`,f),yield{type:`finish`,usage:v},g=!0;return}case`session.waiting`:case`session.completed`:r.boundaryEvent=e.type,yield*closeOpenParts(u,`assistant-complete`,f),yield*closeOpenParts(d,`reasoning-complete`,f),yield{type:`finish`,usage:v},g=!0;return;case`turn.completed`:_=!0,yield*closeOpenParts(u,`assistant-complete`,f),yield*closeOpenParts(d,`reasoning-complete`,f);break;case`subagent.called`:i?.(e);break;case`subagent.started`:case`subagent.event`:break;case`subagent.completed`:a?.(e.data.callId);break;case`authorization.required`:o?.(e);break;case`authorization.completed`:s?.(e);break;default:break}g||(yield*closeOpenParts(u,`assistant-complete`,f),yield*closeOpenParts(d,`reasoning-complete`,f),yield{type:`finish`,usage:v})}async function*errorOnlyTUIStream(e){yield{type:`error`,errorText:e.errorText},yield{type:`finish`}}function createTurnState(){return{aborted:!1,pendingApprovals:[],pendingQuestions:[],sawSessionFailure:!1}}function upsertPendingApproval(e,t){let n=toAgentTUIToolApprovalRequest(t),r=e.pendingApprovals.findIndex(e=>e.approvalId===n.approvalId);r===-1?e.pendingApprovals.push(n):e.pendingApprovals[r]=n}function toAgentTUIToolApprovalRequest(e){return{approvalId:e.requestId,toolCallId:e.action.callId,toolName:e.action.toolName,input:e.action.input}}function upsertPendingQuestion(e,t){let n=e.pendingQuestions.findIndex(e=>e.requestId===t.requestId);n===-1?e.pendingQuestions.push(t):e.pendingQuestions[n]=t}function textPartId(e,t){return`text:${e}:${t}`}function reasoningPartId(e,t){return`reasoning:${e}:${t}`}function partStateFor(e,t){let n=e.get(t);return n===void 0&&(n={generation:0,text:``,completed:!1,completedEpoch:0},e.set(t,n)),n}function partGenerationId(e,t){return t===0?e:`${e}#${t}`}function*closeOpenParts(e,t,n){for(let[r,i]of e)i.completed||i.text.length===0||(i.completed=!0,i.completedEpoch=n,yield{type:t,id:partGenerationId(r,i.generation)})}function isPostTurnVisibleEvent(e){switch(e.type){case`actions.requested`:case`authorization.completed`:case`authorization.required`:case`input.requested`:case`message.appended`:case`message.completed`:case`reasoning.appended`:case`reasoning.completed`:case`result.completed`:case`step.completed`:case`step.failed`:case`step.started`:case`subagent.called`:case`subagent.completed`:case`subagent.event`:case`subagent.started`:case`turn.completed`:case`turn.failed`:return!0;default:return!1}}function formatActionResultError(e){if(e.data.error?.message)return e.data.error.message;let t=e.data.result.output;if(typeof t==`string`)return t;try{return JSON.stringify(t)}catch{return`Tool execution failed.`}}function toFailureEvent(e,t,n){let r=failureKey(e);if(t.has(r))return;t.add(r);let i={type:`error`,errorText:formatFailureMessage(e)},l=n?.(e)??formatFailureHint(e);l!==void 0&&(i.hint=l);let u=formatFailureDetail(e);return u!==void 0&&(i.detail=u),i}function isQuestionRequest(e){return e.display===`select`||e.display===`text`?!0:e.display===`confirmation`?!1:e.options!==void 0&&e.options.length>0}function toAgentTUIInputQuestion(e){let t=e.display===`text`?`text`:e.display===`select`||e.options!==void 0&&e.options.length>0?`select`:`text`,n={requestId:e.requestId,prompt:e.prompt,display:t};return e.options!==void 0&&(n.options=e.options.map(e=>{let t={id:e.id,label:e.label};return e.description!==void 0&&(t.description=e.description),e.style!==void 0&&(t.style=e.style),t})),e.allowFreeform!==void 0&&(n.allowFreeform=e.allowFreeform),n}export{EveTUIRunner,parsePromptCommand};
1
+ import{PROMPT_COMMANDS,formatPromptCommandHelp,parsePromptCommand}from"./prompt-commands.js";import{pickAgentHeaderTip}from"./agent-header.js";import{probeAgentInfo}from"./agent-info-probe.js";import{failureKey,formatFailureDetail,formatFailureHint,formatFailureMessage,isInterruptedError,localFailureHint}from"./errors.js";import{parseLogDisplayMode}from"./log-display-mode.js";import{createMcpConnectionStatusTracker}from"./mcp-connection-status.js";import{createRemoteConnectionController}from"./remote-connection.js";import{SubagentPump}from"./subagent-pump.js";import{BOOT_DETECTIONS,CLI_MISSING_SETUP_ISSUE,LOGIN_SETUP_ISSUE,detectSetupIssues,formatSetupIssuesLine,orderedSetupIssues,resolveModelProviderState}from"./setup-issues.js";import{TerminalRenderer}from"./terminal-renderer.js";import{createVercelStatusTracker}from"./vercel-status.js";import"#client/index.js";import{toErrorMessage}from"#shared/errors.js";import{getVercelAuthStatus}from"#setup/vercel-project.js";import{loadDevelopmentEnvironmentFiles}from"#cli/dev/environment.js";import{subscribeDevelopmentSandboxPrewarmLogs}from"#execution/sandbox/development-prewarm.js";import{createDevelopmentRuntimeArtifactRefresher}from"#services/dev-client.js";import{devBootPhase}from"#internal/dev-boot-progress.js";async function delayMs(e){await new Promise(t=>{setTimeout(t,e).unref?.()})}function authIssueForStatus(e){if(e===`logged-out`)return LOGIN_SETUP_ISSUE;if(e===`cli-missing`)return CLI_MISSING_SETUP_ISSUE}var EveTUIRunner=class{#e;#t;#n;#r;#i;#a;#o;#s;#c;#l;#u;#d;#f;#p;#m;#h;#g;#_;#v;#y;#b;#x=!1;#S=new AbortController;#C=!1;#w=[];#T;#E;#D;#O=pickAgentHeaderTip();#k;#A=new Map;#j;#M=new Map;#N=new Set;#P=!1;#F;constructor(t){this.#e=t.session,t.client!==void 0&&(this.#t=t.client),this.#n=createRenderer(t);let n={formatActionResultError};if(this.#t!==void 0&&(n.client=this.#t),this.#n.subagents!==void 0&&(n.view=this.#n.subagents),this.#j=new SubagentPump(n),this.#r=t.name??`eve`,this.#i=t.tools??`full`,this.#a=t.reasoning??`full`,this.#o=t.subagents??`full`,this.#s=t.connectionAuth??`full`,this.#c=t.assistantResponseStats??`tokensPerSecond`,this.#l=t.contextSize,this.#u=t.formatTransportError??toErrorMessage,t.initialInput!==void 0&&(this.#m=t.initialInput),t.appRoot!==void 0){this.#p=t.appRoot;let e={appRoot:t.appRoot,onChange:e=>this.#n.setVercelStatus?.(e)};t.detectProjectIdentity!==void 0&&(e.detectIdentity=t.detectProjectIdentity),this.#E=createVercelStatusTracker(e),t.probeMcpConnection!==void 0&&(this.#D=createMcpConnectionStatusTracker({onChange:()=>{},probe:t.probeMcpConnection}))}if(t.promptCommandHandler!==void 0&&(this.#h=t.promptCommandHandler),this.#g=t.availablePromptCommands??PROMPT_COMMANDS,t.remote!==void 0){if(this.#t===void 0)throw Error(`A remote TUI requires a configured development client.`);this.#_=createRemoteConnectionController({client:this.#t,credentials:t.remote.credentials,target:t.remote.target,onChange:e=>this.#n.setRemoteConnectionStatus?.(e),resolveOidcToken:t.remote.resolveOidcToken,resolveDeployment:t.remote.resolveDeployment})}this.#v=t.bootDetections??BOOT_DETECTIONS,this.#y=t.getVercelAuthStatus??getVercelAuthStatus,t.onBootProgress!==void 0&&(this.#b=t.onBootProgress),t.serverUrl!==void 0&&(this.#f=t.serverUrl),t.serverUrl!==void 0&&t.remote===void 0&&(this.#d=createDevelopmentRuntimeArtifactRefresher({serverUrl:t.serverUrl}))}async#I(){if(this.#f===void 0){this.#R(),await this.#q(void 0);return}let e;if(this.#_!==void 0){let t=await this.#_.check();t.state===`ready`&&(e=t.info)}else{let t=this.#t;if(t!==void 0)try{let n=await devBootPhase(`connecting to agent`,()=>probeAgentInfo({client:t}),this.#b);n.kind===`ready`&&(e=n.info)}catch{e=void 0}}this.#R();let t=this.#L(e);await this.#q(t)}#L(e){let t=this.#p===void 0?e:resolveModelProviderState(e,process.env);this.#k=t;let n=this.#f;if(n===void 0)return t;let r={name:this.#r,serverUrl:n};return t!==void 0&&(r.info=t),this.#p!==void 0&&(r.tip=this.#O),this.#n.renderAgentHeader?.(r),t}#R(){let e=this.#b;this.#b=void 0,e?.({type:`before-first-paint`})}async run(){try{await this.#z()}finally{this.#x=!0,this.#S.abort(),this.#j.abortAll(),this.#F?.(),this.#F=void 0,this.#n.shutdown?.(),this.#E?.dispose(),this.#D?.dispose(),this.#_?.dispose()}}async#z(){let e=this.#r,r,i,a=!1,o=!1,s=this.#m;await this.#I(),this.#_?.current().connection.state===`auth-required`&&await this.#re({type:`extension`,name:`vc:login`,argument:``},e,{trigger:`startup`}),this.#Z(),this.#E?.refreshIdentity(),this.#D?.refresh();let c=this.#m===void 0?void 0:parsePromptCommand(this.#m);for(c?.type===`extension`&&c.name===`model`&&c.argument===``&&this.#p!==void 0&&this.#h!==void 0&&this.#n.setupFlow!==void 0&&(s=void 0,await this.#ie(e));;){if(!o){if(r==null){if(!this.#n.readPrompt){if(a)return;throw Error(`No prompt was provided and the renderer does not support prompt input.`)}let t={title:e};s!==void 0&&(t.initialDraft=s,s=void 0);try{r=await this.#H(t)}catch(e){if(isInterruptedError(e))return;throw e}if(r==null)return}let c=parsePromptCommand(r);if(c?.type===`exit`)return;if(c?.type===`new`){if(!await this.#V()){i=void 0,o=!1,r=void 0;continue}i=void 0,o=!1,r=void 0;continue}if(c?.type===`help`){this.#Q(formatPromptCommandHelp(this.#g)),i=void 0,o=!1,r=void 0;continue}if(c?.type===`loglevel`){this.#Q(this.#oe(c.argument)),i=void 0,o=!1,r=void 0;continue}if(c?.type===`extension`){try{await this.#re(c,e,{trigger:`command`})}catch(e){if(isInterruptedError(e))return;throw e}i=void 0,r=void 0,o=!1;continue}a=!0}let c=await this.#U({prompt:o?void 0:r,inputResponses:i}),u=this.#e.state.sessionId;u!==void 0&&this.#n.setSessionId?.(u);let d=r,f=!1;try{for(;;){await this.#n.renderStream(c,{title:e,submittedPrompt:d,continueSession:!!this.#n.readPrompt,tools:this.#i,reasoning:this.#a,subagents:this.#o,connectionAuth:this.#s,assistantResponseStats:this.#c,contextSize:this.#l});let t=c.turnState?.pendingApprovals??[],n=c.turnState?.pendingQuestions??[];if(t.length>0||n.length>0){let a=[];if(t.length>0){if(!this.#n.readToolApproval)throw Error(`Tool approval was requested, but the renderer does not support tool approval input.`);for(let n of t){let t=await this.#n.readToolApproval(n,{title:e});a.push({requestId:n.approvalId,optionId:t.approved?`approve`:`deny`}),this.#A.delete(n.approvalId)}}if(n.length>0){if(!this.#n.readInputQuestion)throw Error(`An interactive question was requested, but the renderer does not support input questions.`);for(let t of n){let n=toAgentTUIInputQuestion(t),r=await this.#n.readInputQuestion(n,{title:e});if(r===void 0)continue;let i={requestId:t.requestId};r.optionId!==void 0&&(i.optionId=r.optionId),r.text!==void 0&&(i.text=r.text),a.push(i),this.#A.delete(t.requestId)}}if(a.length===0)break;o=!0,i=a,r=void 0,f=!0;break}if(this.#de(c)){c=this.#G(),d=void 0;continue}if(c.turnState&&c.turnState.boundaryEvent===void 0)if(c.turnState.aborted)this.#P=!0;else{let e=this.#e.state.sessionId;this.#n.renderNotice?.(e?`Lost the event stream — the turn may still be running on the server (session ${e}). Your next message resumes this session; use /cancel to stop the turn.`:`Lost the connection to the running turn.`)}break}}catch(e){if(isInterruptedError(e))return;throw e}if(f)continue;o=!1,i=void 0,r=void 0;let p=c.turnState?.boundaryEvent;!this.#P&&(p===`session.waiting`||p===`session.completed`)&&(r=this.#n.takeQueuedPrompt?.()),this.#P&&(this.#P=!1,this.#B(),c.turnState?.aborted?this.#n.renderNotice?.(`Stopped following the turn and started a new session. Earlier context was cleared; the interrupted turn may still be running on the server.`):this.#n.renderSessionBoundary===void 0?this.#n.renderNotice?.(`Session ended — started a new session. Earlier context was cleared.`):this.#n.renderSessionBoundary())}}#B(){this.#j.abortAll(),this.#A.clear(),this.#M.clear(),this.#N.clear(),this.#n.setConnectionAuthPendingCount?.(0),this.#t&&(this.#e=this.#t.session()),this.#d?.clear()}async#V(){try{await this.#e.reset()}catch(e){return this.#n.renderNotice?.(`Couldn't reset the session: ${toErrorMessage(e)}`),!1}return this.#B(),this.#n.reset?.(),!0}async#H(e){if(!this.#n.readPrompt)return;let t=this.#n.readPrompt(e),n=this.#d;if(n===void 0)return await t;let r=!1,i=!1,a,refresh=async()=>{if(!(r||i)){i=!0;try{await n.refreshIdle({onRuntimeArtifactsChanged:()=>this.#le()})}finally{i=!1}}},startRefresh=()=>{if(r||i)return;let e=refresh().finally(()=>{a===e&&(a=void 0)});a=e};startRefresh();let o=setInterval(()=>{startRefresh()},500);o.unref?.();try{return await t}finally{r=!0,clearInterval(o),await a}}async#U(e){let t=new AbortController,n={signal:t.signal};e.prompt!==void 0&&(n.message=e.prompt),e.inputResponses!==void 0&&e.inputResponses.length>0&&(n.inputResponses=e.inputResponses);let r;try{this.#d!==void 0&&await this.#d.refresh({inputResponses:n.inputResponses,message:n.message,onRuntimeArtifactsChanged:()=>this.#le()}),n.message!==void 0&&(n.inputResponses?.length??0)===0&&this.#n.flushDelayedDevBuildErrors?.(),r=await this.#e.send(n)}catch(e){if(isInterruptedError(e))throw e;return this.#_?.reportFailure(e),this.#P=!0,{events:errorOnlyTUIStream({errorText:this.#u(e)}),turnState:createTurnState()}}return this.#K(r,()=>t.abort())}async#W(e){if(e.cancelInFlight!==!0){e.cancelInFlight=!0;try{for(let t=0;t<8;t+=1){if(e.boundaryEvent!==void 0||e.aborted===!0)return;let t=e.turnId;try{if((await this.#e.cancel(t===void 0?void 0:{turnId:t})).status===`accepted`)return}catch{}await delayMs(250)}}finally{e.cancelInFlight=!1}}}#G(){let e=new AbortController;return this.#K(this.#e.stream({signal:e.signal}),()=>e.abort())}#K(e,t){let n=createTurnState();return{abort:()=>{n.aborted=!0,t()},cancel:()=>{this.#W(n)},events:eveEventsToTUIStream({events:e,pendingInputRequests:this.#A,turnState:n,onSubagentCalled:e=>this.#j.begin(e),onSubagentCompleted:e=>this.#j.settle(e),onTurnCancelled:()=>this.#j.settleAll(),onConnectionAuthRequired:e=>this.#ue(e),onConnectionAuthCompleted:e=>this.#fe(e),onTerminalFailure:()=>{this.#P=!0},failureHintOverride:this.#p===void 0?void 0:localFailureHint}),turnState:n}}async#q(e){if(this.#p===void 0)return;let t={appRoot:this.#p,env:process.env};e!==void 0&&(t.info=e),this.#w=await detectSetupIssues(t,this.#v),this.#n.renderSetupWarning!==void 0&&(this.#J(),this.#Y())}#J(){let e=orderedSetupIssues(this.#w,this.#T);e.length>0?this.#n.renderSetupWarning?.(formatSetupIssuesLine(e)):this.#n.clearSetupWarning?.()}async#Y(){let e=this.#p;if(e===void 0)return;let t;try{t=await this.#y(e,{signal:this.#S.signal})}catch{return}this.#x||this.#C||(this.#T=authIssueForStatus(t),this.#J())}async#X(e){let t=this.#p;if(t===void 0||this.#n.renderSetupWarning===void 0)return;let n={appRoot:t,env:process.env};e!==void 0&&(n.info=e);try{this.#w=await detectSetupIssues(n,this.#v);let e=await this.#y(t,{signal:this.#S.signal});this.#T=authIssueForStatus(e)}catch{return}this.#x||this.#J()}#Z(){this.#p===void 0||this.#n.renderSandboxLog===void 0||this.#F===void 0&&(this.#F=subscribeDevelopmentSandboxPrewarmLogs({appRoot:this.#p,log:e=>this.#n.renderSandboxLog?.(e)}))}#Q(e){if(e!==void 0){if(this.#n.renderCommandResult!==void 0){this.#n.renderCommandResult(e);return}this.#n.renderNotice?.(e)}}async#$(e,t){let n=this.#h;if(n===void 0)return{message:`/${e.name} is not available in this session.`};let r={renderer:this.#n,title:t.title,initialModelStep:t.initialModelStep,remoteConnection:this.#_},i=this.#D?.current(),a=i!==void 0&&Object.keys(i).length>0?{...r,disabledConnectionReasons:i}:r;return t.keepSetupFlowOpen===!0?await n.handle(e,{...a,keepSetupFlowOpen:!0}):await n.handle(e,a)}#ee(e,t){if(t!==`startup`)return;let n=this.#_?.current().connection.state,r=n===`auth-failed`||n===`unavailable`?`failed`:void 0,i=e.argument.length===0?``:` ${e.argument}`;this.#n.renderCommandInvocation?.(`/${e.name}${i}`,r)}async#te(e){if(e?.kind===`connection-added`){this.#E?.applyEffect({kind:`refresh-identity`}),this.#C=!0,await this.#ne(),await this.#se();return}if(e?.kind===`model-access-changed`){this.#E?.applyEffect({kind:`refresh-identity`}),this.#C=!0,await this.#se();return}e!==void 0&&(this.#E?.applyEffect(e),this.#C=!0,this.#X(this.#k))}async#ne(){let e=this.#d;e!==void 0&&await e.refreshAfterSourceChange({onRuntimeArtifactsChanged:()=>this.#le()})}async#re(e,t,n){let r=await this.#$(e,{initialModelStep:n.initialModelStep,keepSetupFlowOpen:n.keepSetupFlowOpen,title:t});this.#ee(e,n.trigger),this.#Q(r?.message),await this.#te(r?.effect),this.#ae()}async#ie(e){let t=this.#p;if(t===void 0)return;let authStatus=async()=>{try{return await this.#y(t,{signal:this.#S.signal})}catch{return}},n=await authStatus();if(n===`cli-missing`&&(await this.#re({type:`extension`,name:`vc:install`,argument:``},e,{trigger:`startup`,keepSetupFlowOpen:!0}),n=await authStatus(),n===`cli-missing`)){this.#n.setupFlow?.end();return}if(n===`logged-out`&&(await this.#re({type:`extension`,name:`vc:login`,argument:``},e,{trigger:`startup`,keepSetupFlowOpen:!0}),n=await authStatus(),n===`cli-missing`||n===`logged-out`)){this.#n.setupFlow?.end();return}await this.#re({type:`extension`,name:`model`,argument:``},e,{trigger:`startup`,initialModelStep:`provider`})}#ae(){let e=this.#_?.current().connection;e?.state!==`ready`||e.info===this.#k||(this.#k=e.info,this.#f!==void 0&&this.#n.renderAgentHeader?.({info:e.info,name:this.#r,serverUrl:this.#f}))}#oe(e){let t=this.#n;if(t.logDisplayMode===void 0||t.setLogDisplayMode===void 0)return`/loglevel is not available in this session.`;if(e===``)return`Logs: ${t.logDisplayMode()}. Use /loglevel all|stderr|sandbox|none — logs stay buffered, so switching also hides or restores past lines.`;let n=parseLogDisplayMode(e);if(n===void 0)return`Unknown log level "${e}". Use all, stderr, sandbox, or none.`;if(n===t.logDisplayMode())return`Logs already set to ${n}.`;switch(t.setLogDisplayMode(n),n){case`none`:return`Logs hidden. Output stays buffered — /loglevel all restores it.`;case`stderr`:return`Showing stderr logs only.`;case`sandbox`:return`Showing sandbox logs only.`;case`all`:return`Showing all logs.`}}async#se(){let e=this.#p;if(e===void 0)return;loadDevelopmentEnvironmentFiles(e);let t=this.#L(await this.#ce());this.#X(t)}async#ce(){let e=this.#t;if(e===void 0)return;let t=await probeAgentInfo({client:e});return t.kind===`ready`?t.info:void 0}async#le(){let e=this.#k,t=await this.#ce();t!==void 0&&this.#L(t),(!this.#n.renderAgentHeader||t===void 0)&&this.#n.renderNotice?.(formatAgentUpdateNotice(e,t))}#ue(e){let t={name:e.data.name,description:e.data.description,state:`required`};e.data.authorization!==void 0&&(t.challenge=e.data.authorization),e.data.webhookUrl!==void 0&&(t.webhookUrl=e.data.webhookUrl),this.#M.set(e.data.name,t),this.#pe(t)}#de(e){if(e.turnState?.boundaryEvent!==`session.waiting`)return!1;let t=!1;for(let e of this.#M.values())e.state!==`required`||e.webhookUrl===void 0||(e.state=`pending`,this.#N.add(e.name),this.#pe(e),t=!0);return t&&this.#n.setConnectionAuthPendingCount?.(this.#N.size),this.#N.size>0}#fe(e){let t=this.#M.get(e.data.name)??{name:e.data.name,description:``,state:e.data.outcome};t.state=e.data.outcome,e.data.reason!==void 0&&(t.reason=e.data.reason),this.#M.set(e.data.name,t),this.#N.delete(e.data.name),this.#pe(t),this.#n.setConnectionAuthPendingCount?.(this.#N.size)}#pe(e){let t={name:e.name,description:e.description,state:e.state};e.challenge!==void 0&&(t.challenge=e.challenge),e.reason!==void 0&&(t.reason=e.reason),this.#n.upsertConnectionAuth?.(t)}};function createRenderer(e){return e.renderer?e.renderer:new TerminalRenderer({tools:e.tools,reasoning:e.reasoning,subagents:e.subagents,connectionAuth:e.connectionAuth,assistantResponseStats:e.assistantResponseStats,contextSize:e.contextSize,logs:e.logs,availablePromptCommands:e.availablePromptCommands,input:e.userInput,output:e.screen,diagnostics:e.diagnostics})}function formatAgentUpdateNotice(e,t){let n=e?.agent.model.id,r=t?.agent.model.id;return n!==void 0&&r!==void 0&&n!==r?`Agent updated: Model ${n} -> ${r}`:`Agent updated.`}async function*eveEventsToTUIStream(e){let{events:t,pendingInputRequests:n,turnState:r,onSubagentCalled:i,onSubagentCompleted:a,onTurnCancelled:o,onConnectionAuthRequired:s,onConnectionAuthCompleted:c,onTerminalFailure:l,failureHintOverride:u}=e,d=new Map,f=new Map,p=0,m=new Set,h=new Set,g=new Set,_=!1,v=!1,y;for await(let e of t)if(!(v&&isPostTurnVisibleEvent(e)))switch(e.type){case`session.started`:case`message.received`:break;case`turn.started`:r.turnId=e.data.turnId;break;case`step.started`:p+=1,yield{type:`step-start`};break;case`step.completed`:{let t=e;y=t.data.usage,yield*closeOpenParts(d,`assistant-complete`,p),yield*closeOpenParts(f,`reasoning-complete`,p),yield{type:`step-finish`,usage:t.data.usage};break}case`message.appended`:{let t=e,n=textPartId(t.data.turnId,t.data.stepIndex),r=partStateFor(d,n),i=t.data.messageSoFar;if(r.completed){if(r.text.startsWith(i)||p<=r.completedEpoch)break;r.generation+=1,r.text=``,r.completed=!1}if(!i.startsWith(r.text)||i.length<=r.text.length)break;let a=i.slice(r.text.length);r.text=i,yield{type:`assistant-delta`,id:partGenerationId(n,r.generation),delta:a};break}case`message.completed`:{let t=textPartId(e.data.turnId,e.data.stepIndex),n=partStateFor(d,t),r=e.data.message;if(n.completed){if(r===null||r===n.text||p<=n.completedEpoch)break;n.generation+=1,n.text=r,n.completedEpoch=p,yield{type:`assistant-complete`,id:partGenerationId(t,n.generation),text:r};break}let i=partGenerationId(t,n.generation);if(r!==null){if(n.text.length===0)n.text=r,n.completed=!0,n.completedEpoch=p,yield{type:`assistant-complete`,id:i,text:r};else if(r.startsWith(n.text)){let e=r.slice(n.text.length);e.length>0&&(yield{type:`assistant-delta`,id:i,delta:e}),n.text=r,n.completed=!0,n.completedEpoch=p,yield{type:`assistant-complete`,id:i}}}else n.text.length>0&&(n.completed=!0,n.completedEpoch=p,yield{type:`assistant-complete`,id:i});break}case`reasoning.appended`:{let t=e,n=reasoningPartId(t.data.turnId,t.data.stepIndex),r=partStateFor(f,n),i=t.data.reasoningSoFar;if(r.completed){if(r.text.startsWith(i)||p<=r.completedEpoch)break;r.generation+=1,r.text=``,r.completed=!1}if(!i.startsWith(r.text)||i.length<=r.text.length)break;let a=i.slice(r.text.length);r.text=i,yield{type:`reasoning-delta`,id:partGenerationId(n,r.generation),delta:a};break}case`reasoning.completed`:{let t=reasoningPartId(e.data.turnId,e.data.stepIndex),n=partStateFor(f,t),r=e.data.reasoning;if(n.completed){if(r.length===0||r===n.text||n.text.startsWith(r)||p<=n.completedEpoch)break;n.generation+=1,n.text=r,n.completedEpoch=p;let e=partGenerationId(t,n.generation);yield{type:`reasoning-delta`,id:e,delta:r},yield{type:`reasoning-complete`,id:e};break}let i=partGenerationId(t,n.generation);if(n.text.length===0&&r.length>0)n.text=r,yield{type:`reasoning-delta`,id:i,delta:r};else if(r.length>0&&!r.startsWith(n.text))break;n.completed=!0,n.completedEpoch=p,yield{type:`reasoning-complete`,id:i};break}case`actions.requested`:{let t=e.data.actions.filter(e=>e.kind===`tool-call`);if(t.length===0)break;for(let e of t)m.has(e.callId)||(m.add(e.callId),yield{type:`tool-call`,toolCallId:e.callId,toolName:e.toolName,input:e.input});break}case`input.requested`:{let t=e.data.requests.filter(e=>e.action.kind===`tool-call`);if(t.length===0)break;for(let e of t){let t=e.action.callId;if(m.has(t)||(m.add(t),yield{type:`tool-call`,toolCallId:t,toolName:e.action.toolName,input:e.action.input}),!h.has(e.requestId)){if(h.add(e.requestId),n.set(e.requestId,e),isQuestionRequest(e)){upsertPendingQuestion(r,e);continue}upsertPendingApproval(r,e),yield{type:`tool-approval-request`,approvalId:e.requestId,toolCallId:t}}}break}case`action.result`:{let t=e;if(t.data.result.kind!==`tool-result`)break;let n=t.data.result.callId;if(!m.has(n))break;switch(t.data.status){case`completed`:yield{type:`tool-result`,toolCallId:n,output:t.data.result.output};break;case`failed`:yield{type:`tool-error`,toolCallId:n,errorText:formatActionResultError(t)};break;case`rejected`:yield{type:`tool-rejected`,toolCallId:n,reason:formatActionResultError(t)};break}break}case`step.failed`:case`turn.failed`:{let t=toFailureEvent(e,g,u);t&&(yield t);break}case`session.failed`:{r.sawSessionFailure=!0,l?.(e);let t=toFailureEvent(e,g,u);t&&(yield t),r.boundaryEvent=e.type,yield*closeOpenParts(d,`assistant-complete`,p),yield*closeOpenParts(f,`reasoning-complete`,p),yield{type:`finish`,usage:y},_=!0;return}case`session.waiting`:case`session.completed`:r.boundaryEvent=e.type,yield*closeOpenParts(d,`assistant-complete`,p),yield*closeOpenParts(f,`reasoning-complete`,p),yield{type:`finish`,usage:y},_=!0;return;case`turn.completed`:v=!0,yield*closeOpenParts(d,`assistant-complete`,p),yield*closeOpenParts(f,`reasoning-complete`,p);break;case`turn.cancelled`:o?.(),yield*closeOpenParts(d,`assistant-complete`,p),yield*closeOpenParts(f,`reasoning-complete`,p),yield{type:`turn-cancelled`};break;case`subagent.called`:i?.(e);break;case`subagent.started`:case`subagent.event`:break;case`subagent.completed`:a?.(e.data.callId);break;case`authorization.required`:s?.(e);break;case`authorization.completed`:c?.(e);break;default:break}_||(yield*closeOpenParts(d,`assistant-complete`,p),yield*closeOpenParts(f,`reasoning-complete`,p),yield{type:`finish`,usage:y})}async function*errorOnlyTUIStream(e){yield{type:`error`,errorText:e.errorText},yield{type:`finish`}}function createTurnState(){return{aborted:!1,pendingApprovals:[],pendingQuestions:[],sawSessionFailure:!1}}function upsertPendingApproval(e,t){let n=toAgentTUIToolApprovalRequest(t),r=e.pendingApprovals.findIndex(e=>e.approvalId===n.approvalId);r===-1?e.pendingApprovals.push(n):e.pendingApprovals[r]=n}function toAgentTUIToolApprovalRequest(e){return{approvalId:e.requestId,toolCallId:e.action.callId,toolName:e.action.toolName,input:e.action.input}}function upsertPendingQuestion(e,t){let n=e.pendingQuestions.findIndex(e=>e.requestId===t.requestId);n===-1?e.pendingQuestions.push(t):e.pendingQuestions[n]=t}function textPartId(e,t){return`text:${e}:${t}`}function reasoningPartId(e,t){return`reasoning:${e}:${t}`}function partStateFor(e,t){let n=e.get(t);return n===void 0&&(n={generation:0,text:``,completed:!1,completedEpoch:0},e.set(t,n)),n}function partGenerationId(e,t){return t===0?e:`${e}#${t}`}function*closeOpenParts(e,t,n){for(let[r,i]of e)i.completed||i.text.length===0||(i.completed=!0,i.completedEpoch=n,yield{type:t,id:partGenerationId(r,i.generation)})}function isPostTurnVisibleEvent(e){switch(e.type){case`actions.requested`:case`authorization.completed`:case`authorization.required`:case`input.requested`:case`message.appended`:case`message.completed`:case`reasoning.appended`:case`reasoning.completed`:case`result.completed`:case`step.completed`:case`step.failed`:case`step.started`:case`subagent.called`:case`subagent.completed`:case`subagent.event`:case`subagent.started`:case`turn.completed`:case`turn.failed`:return!0;default:return!1}}function formatActionResultError(e){if(e.data.error?.message)return e.data.error.message;let t=e.data.result.output;if(typeof t==`string`)return t;try{return JSON.stringify(t)}catch{return`Tool execution failed.`}}function toFailureEvent(e,t,n){let r=failureKey(e);if(t.has(r))return;t.add(r);let i={type:`error`,errorText:formatFailureMessage(e)},l=n?.(e)??formatFailureHint(e);l!==void 0&&(i.hint=l);let u=formatFailureDetail(e);return u!==void 0&&(i.detail=u),i}function isQuestionRequest(e){return e.display===`select`||e.display===`text`?!0:e.display===`confirmation`?!1:e.options!==void 0&&e.options.length>0}function toAgentTUIInputQuestion(e){let t=e.display===`text`?`text`:e.display===`select`||e.options!==void 0&&e.options.length>0?`select`:`text`,n={requestId:e.requestId,prompt:e.prompt,display:t};return e.options!==void 0&&(n.options=e.options.map(e=>{let t={id:e.id,label:e.label};return e.description!==void 0&&(t.description=e.description),e.style!==void 0&&(t.style=e.style),t})),e.allowFreeform!==void 0&&(n.allowFreeform=e.allowFreeform),n}export{EveTUIRunner,parsePromptCommand};
@@ -123,5 +123,14 @@ export declare class SubagentPump {
123
123
  */
124
124
  settle(callId: string): void;
125
125
  abortAll(): void;
126
+ /**
127
+ * Settles every live run and stops its child stream. Called when the
128
+ * parent turn is cancelled (an Esc steer or Esc Esc): the server cancels
129
+ * the pending descendants, so their sections must close now — a child
130
+ * still flushing reasoning would otherwise keep painting stale sections
131
+ * into the next (steered) turn's transcript. Runs stay registered so a
132
+ * late parent `subagent.completed` settles as a no-op.
133
+ */
134
+ settleAll(): void;
126
135
  }
127
136
  export {};