@xingjisoft/neutrino 0.6.0 → 0.7.0

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 (169) hide show
  1. package/README.md +6 -1
  2. package/assets/fast-planner.txt +57 -0
  3. package/assets/fast-replanner.txt +28 -0
  4. package/dist/agents.d.ts +25 -0
  5. package/dist/app.d.ts +206 -0
  6. package/dist/app.js +15 -0
  7. package/dist/background.d.ts +96 -0
  8. package/dist/bin.d.ts +2 -0
  9. package/dist/bin.js +40 -3
  10. package/dist/browser.d.ts +18 -0
  11. package/dist/clipboard.d.ts +16 -0
  12. package/dist/colors.d.ts +29 -0
  13. package/dist/compact.d.ts +52 -0
  14. package/dist/config.d.ts +221 -0
  15. package/dist/config.js +22 -7
  16. package/dist/cwd.d.ts +19 -0
  17. package/dist/fast/artifacts.d.ts +26 -0
  18. package/dist/fast/artifacts.js +109 -0
  19. package/dist/fast/engine.d.ts +78 -0
  20. package/dist/fast/engine.js +657 -0
  21. package/dist/fast/evidence.d.ts +21 -0
  22. package/dist/fast/evidence.js +68 -0
  23. package/dist/fast/planner.d.ts +10 -0
  24. package/dist/fast/planner.js +51 -0
  25. package/dist/fast/pool.d.ts +17 -0
  26. package/dist/fast/pool.js +78 -0
  27. package/dist/fast/scheduler.d.ts +54 -0
  28. package/dist/fast/scheduler.js +383 -0
  29. package/dist/fast/types.d.ts +100 -0
  30. package/dist/fast/types.js +21 -0
  31. package/dist/fast/worker.d.ts +23 -0
  32. package/dist/fast/worker.js +185 -0
  33. package/dist/header.d.ts +3 -0
  34. package/dist/index.d.ts +5 -0
  35. package/dist/llm/approval.d.ts +204 -0
  36. package/dist/llm/approval.js +14 -3
  37. package/dist/llm/client.d.ts +118 -0
  38. package/dist/llm/client.js +57 -8
  39. package/dist/llm/codeExecutor.d.ts +14 -0
  40. package/dist/llm/codemode.d.ts +15 -0
  41. package/dist/llm/context.d.ts +29 -0
  42. package/dist/llm/context.js +17 -4
  43. package/dist/llm/diagnostics.d.ts +91 -0
  44. package/dist/llm/diagnostics.js +242 -0
  45. package/dist/llm/plan.d.ts +148 -0
  46. package/dist/llm/retry.d.ts +80 -0
  47. package/dist/llm/risk.d.ts +21 -0
  48. package/dist/llm/risk.js +7 -0
  49. package/dist/llm/runtime.d.ts +189 -0
  50. package/dist/llm/runtime.js +178 -24
  51. package/dist/llm/search.d.ts +2 -0
  52. package/dist/llm/searchNetwork.d.ts +8 -0
  53. package/dist/llm/subagent.d.ts +112 -0
  54. package/dist/llm/subagent.js +25 -12
  55. package/dist/llm/tools.d.ts +20 -0
  56. package/dist/llm/tools.js +4 -1
  57. package/dist/llm/workspace.d.ts +6 -0
  58. package/dist/llm/workspace.js +271 -0
  59. package/dist/markdown.d.ts +58 -0
  60. package/dist/migration.d.ts +8 -0
  61. package/dist/persistence.d.ts +14 -0
  62. package/dist/plugins/catalog.d.ts +20 -0
  63. package/dist/plugins/catalog.js +45 -0
  64. package/dist/plugins/cli.d.ts +1 -0
  65. package/dist/plugins/cli.js +106 -0
  66. package/dist/plugins/host.d.ts +121 -0
  67. package/dist/plugins/host.js +450 -0
  68. package/dist/plugins/manager.d.ts +24 -0
  69. package/dist/plugins/manager.js +288 -0
  70. package/dist/plugins/package.d.ts +5 -0
  71. package/dist/plugins/package.js +53 -0
  72. package/dist/plugins/runner.d.ts +1 -0
  73. package/dist/plugins/runner.js +227 -0
  74. package/dist/plugins/session.d.ts +12 -0
  75. package/dist/plugins/session.js +97 -0
  76. package/dist/plugins/terminal.d.ts +22 -0
  77. package/dist/plugins/terminal.js +33 -0
  78. package/dist/plugins/types.d.ts +178 -0
  79. package/dist/plugins/types.js +6 -0
  80. package/dist/plugins/validation.d.ts +14 -0
  81. package/dist/plugins/validation.js +174 -0
  82. package/dist/plugins/web-sdk.d.ts +58 -0
  83. package/dist/plugins/web-sdk.js +1 -0
  84. package/dist/pro/agents.d.ts +34 -0
  85. package/dist/pro/agents.js +1 -1
  86. package/dist/pro/config.d.ts +75 -0
  87. package/dist/pro/config.js +3 -2
  88. package/dist/pro/preflight.d.ts +21 -0
  89. package/dist/sanitize.d.ts +34 -0
  90. package/dist/screens/agentConversation.d.ts +28 -0
  91. package/dist/screens/agentHistory.d.ts +25 -0
  92. package/dist/screens/agentSelect.d.ts +16 -0
  93. package/dist/screens/chat.d.ts +292 -0
  94. package/dist/screens/chat.js +179 -65
  95. package/dist/screens/history.d.ts +23 -0
  96. package/dist/screens/modelSelect.d.ts +29 -0
  97. package/dist/screens/plugins.d.ts +29 -0
  98. package/dist/screens/plugins.js +196 -0
  99. package/dist/screens/settings.d.ts +42 -0
  100. package/dist/screens/start.d.ts +43 -0
  101. package/dist/screens/start.js +25 -17
  102. package/dist/screens/updatePrompt.d.ts +41 -0
  103. package/dist/selection.d.ts +75 -0
  104. package/dist/state.d.ts +26 -0
  105. package/dist/terminal/buffer.d.ts +47 -0
  106. package/dist/terminal/input.d.ts +70 -0
  107. package/dist/terminal/renderer.d.ts +43 -0
  108. package/dist/terminal/restore.d.ts +41 -0
  109. package/dist/terminal/screen.d.ts +57 -0
  110. package/dist/tray.d.ts +14 -0
  111. package/dist/ui.d.ts +123 -0
  112. package/dist/update.d.ts +71 -0
  113. package/dist/updateWatch.d.ts +43 -0
  114. package/dist/web/approvalQueue.d.ts +8 -0
  115. package/dist/web/approvalQueue.js +59 -0
  116. package/dist/web/auth.d.ts +14 -0
  117. package/dist/web/clientState.d.ts +16 -0
  118. package/dist/web/folderPicker.d.ts +34 -0
  119. package/dist/web/folderPicker.js +544 -0
  120. package/dist/web/hub.d.ts +213 -0
  121. package/dist/web/hub.js +14 -2
  122. package/dist/web/localApi.d.ts +11 -0
  123. package/dist/web/localApi.js +260 -0
  124. package/dist/web/plugins.d.ts +8 -0
  125. package/dist/web/plugins.js +64 -0
  126. package/dist/web/server.d.ts +81 -0
  127. package/dist/web/server.js +127 -19
  128. package/dist/web/service.d.ts +7 -0
  129. package/dist/web/service.js +1 -0
  130. package/dist/web/session.d.ts +176 -0
  131. package/dist/web/session.js +170 -21
  132. package/dist/web/settings.d.ts +65 -0
  133. package/dist/web/terminalBridge.d.ts +15 -0
  134. package/dist/web/terminalBridge.js +8 -2
  135. package/dist/width.d.ts +6 -0
  136. package/docs/plugins/README.md +126 -0
  137. package/docs/plugins/agent-sdk.md +92 -0
  138. package/docs/plugins/architecture.md +64 -0
  139. package/docs/plugins/compatibility.md +34 -0
  140. package/docs/plugins/development.md +55 -0
  141. package/docs/plugins/manifest.md +59 -0
  142. package/docs/plugins/manifest.schema.json +286 -0
  143. package/docs/plugins/security.md +53 -0
  144. package/docs/plugins/skills-prompts.md +69 -0
  145. package/docs/plugins/ui-sdk.md +109 -0
  146. package/examples/local-api.py +105 -0
  147. package/examples/plugins/cards/card.html +6 -0
  148. package/examples/plugins/cards/neutrino.plugin.json +42 -0
  149. package/examples/plugins/composer/editor.html +10 -0
  150. package/examples/plugins/composer/neutrino.plugin.json +10 -0
  151. package/examples/plugins/function-tools/agent.js +32 -0
  152. package/examples/plugins/function-tools/neutrino.plugin.json +15 -0
  153. package/examples/plugins/menus-tabs/neutrino.plugin.json +15 -0
  154. package/examples/plugins/menus-tabs/panel.html +6 -0
  155. package/examples/plugins/skills-prompts/neutrino.plugin.json +13 -0
  156. package/examples/plugins/skills-prompts/prompts/evidence.md +1 -0
  157. package/examples/plugins/skills-prompts/prompts/reviewer.md +1 -0
  158. package/examples/plugins/skills-prompts/skills/review/SKILL.md +8 -0
  159. package/examples/plugins/theme/neutrino.plugin.json +12 -0
  160. package/package.json +66 -42
  161. package/web/LOCAL-API.md +65 -0
  162. package/web/README.md +30 -8
  163. package/web/app.js +256 -67
  164. package/web/i18n.js +18 -3
  165. package/web/index.html +3 -1
  166. package/web/plugins.css +10 -0
  167. package/web/plugins.js +230 -0
  168. package/web/style.css +12 -3
  169. package/web/turns.js +7 -8
@@ -0,0 +1,75 @@
1
+ import { type ModelInfo } from "../config.js";
2
+ /** Provider URLs and credentials stay in the shared, ordinary model catalogue. */
3
+ export declare const PRO_MODEL_FILE: string;
4
+ /** Presets the user adds or rewrites themselves; a same-named preset here wins. */
5
+ export declare const PRO_CUSTOM_MODEL_FILE: string;
6
+ /** The official presets, fetched on first use: nothing is bundled with the package. */
7
+ export declare const PRO_MODELS_URL = "https://ius.neutrino.xingjisoft.com/model.json";
8
+ export declare const PRO_ROLES: readonly ["main_model", "thinking_model", "front_output_model", "backend_output_model", "confirm_model", "genimage_model", "plan_model", "modeling_model"];
9
+ export type ProRole = (typeof PRO_ROLES)[number];
10
+ export declare const ACTIVE_PRO_ROLES: ("confirm_model" | "main_model" | "thinking_model" | "front_output_model" | "backend_output_model" | "plan_model" | "modeling_model")[];
11
+ export declare const PRO_ROLE_LABELS: Record<ProRole, string>;
12
+ export interface ProModelSetting {
13
+ type: ProRole;
14
+ provider: string;
15
+ model: string | null;
16
+ intensity: string;
17
+ context_window: number;
18
+ }
19
+ export interface ProPreset {
20
+ name: string;
21
+ chinese_name: string;
22
+ "model-setting": ProModelSetting[];
23
+ }
24
+ export interface ProModelsData {
25
+ tier: ProPreset[];
26
+ }
27
+ /** Contains credentials. Never send this shape over the public API. */
28
+ export interface ProResolvedModel {
29
+ role: ProRole;
30
+ provider: string;
31
+ model: ModelInfo;
32
+ intensity: string;
33
+ context_window: number;
34
+ tier: string;
35
+ }
36
+ export interface ProModelReference {
37
+ provider: string;
38
+ model: string;
39
+ tier: string;
40
+ }
41
+ export interface ProFallback {
42
+ role: ProRole;
43
+ requested: ProModelReference;
44
+ replacement: ProModelReference | null;
45
+ reason: string;
46
+ }
47
+ export interface ProModelSyncResult {
48
+ /** `updated`: the official copy replaced the file. `unchanged`: they agree. */
49
+ status: "updated" | "unchanged" | "kept";
50
+ /** Why the local presets were kept, when the official copy could not be used. */
51
+ detail?: string;
52
+ }
53
+ /**
54
+ * Make sure the Pro presets are on disk, downloading the official set the first
55
+ * time. A file the user already has is never touched here; a failed download
56
+ * leaves nothing behind, so the next start simply tries again.
57
+ */
58
+ export declare function ensureProModels(): Promise<void>;
59
+ /**
60
+ * Keep ~/.neutrino/pro/model.json in step with the official presets, which own
61
+ * that file: any difference is overwritten. Presets the user keeps for
62
+ * themselves belong in model-custom.json, so nothing personal is lost. When the
63
+ * official copy cannot be read, the local presets stay exactly as they are.
64
+ *
65
+ * Called once at start-up by both the terminal and the Web console.
66
+ */
67
+ export declare function syncProModels(): Promise<ProModelSyncResult>;
68
+ export declare function loadProModels(): ProModelsData;
69
+ export declare function requireProPreset(value: unknown): string;
70
+ export declare function defaultProPreset(): string;
71
+ export declare const DEFAULT_PRO_RECURSION_DEPTH = 10;
72
+ export declare const MAX_PRO_RECURSION_DEPTH = 100;
73
+ export declare function proMaxRecursionDepth(): number;
74
+ /** Every agent prompt lives in the requested assets/pro directory. */
75
+ export declare function loadProPrompt(role: ProRole): string;
@@ -1,3 +1,4 @@
1
+ import { pluginPrompt } from "../plugins/session.js";
1
2
  import fs from "node:fs";
2
3
  import path from "node:path";
3
4
  import process from "node:process";
@@ -213,6 +214,6 @@ export function proMaxRecursionDepth() {
213
214
  export function loadProPrompt(role) {
214
215
  if (!PRO_ROLES.includes(role))
215
216
  throw new Error("Unknown Pro role");
216
- return fs.readFileSync(path.join(ASSET_DIR, "common.txt"), "utf8") + "\n\n" +
217
- fs.readFileSync(path.join(ASSET_DIR, `${role}.txt`), "utf8");
217
+ return pluginPrompt(fs.readFileSync(path.join(ASSET_DIR, "common.txt"), "utf8") + "\n\n" +
218
+ fs.readFileSync(path.join(ASSET_DIR, `${role}.txt`), "utf8"), role);
218
219
  }
@@ -0,0 +1,21 @@
1
+ import { type UsageInfo } from "../llm/client.js";
2
+ import { type ProFallback, type ProResolvedModel, type ProRole } from "./config.js";
3
+ export interface ProPreflightResult {
4
+ models: Partial<Record<ProRole, ProResolvedModel>>;
5
+ fallbacks: ProFallback[];
6
+ }
7
+ export declare class ProPreflightError extends Error {
8
+ readonly fallbacks: ProFallback[];
9
+ constructor(message: string, fallbacks: ProFallback[]);
10
+ }
11
+ export interface ProPreflightOptions {
12
+ signal?: AbortSignal;
13
+ onUsage?(usage: UsageInfo): void;
14
+ /** Bounded for each actual inference, including its response body. */
15
+ timeoutMs?: number;
16
+ }
17
+ /**
18
+ * Resolve each job independently, descending only within that job. Neither the
19
+ * shared catalogue nor the Pro presets are edited by a temporary replacement.
20
+ */
21
+ export declare function resolveProTeam(presetName: string, options?: ProPreflightOptions): Promise<ProPreflightResult>;
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Text hygiene for anything that will be drawn into the terminal Buffer.
3
+ *
4
+ * The renderer copies a cell's glyph straight into the output stream, so a cell
5
+ * that somehow holds a *control* character turns into a command the terminal
6
+ * executes: an ESC sequence can move the cursor, clear the screen or leave the
7
+ * alternate buffer, and a TAB shifts the rest of the row. Tool output (ANSI
8
+ * colours from `ls --color`, `git`, `npm`, progress bars, …), file contents and
9
+ * pasted text routinely carry such bytes, so they must be neutralised before
10
+ * they can reach the screen.
11
+ *
12
+ * `sanitizeText` is the *display-side* cleanup: it removes whole escape
13
+ * sequences (not just the ESC byte, which would leave `[31m` behind as literal
14
+ * text), expands tabs so every character's measured width matches what the
15
+ * terminal will draw, and drops any remaining control code. Newlines are kept
16
+ * because the wrapping/markdown layer needs them to lay text out.
17
+ */
18
+ /** Remove ANSI/VT escape sequences from `text`. */
19
+ export declare function stripAnsi(text: string): string;
20
+ export interface SanitizeOptions {
21
+ /** How many spaces a tab expands to. Defaults to 4. */
22
+ tabWidth?: number;
23
+ /** When true, newlines are also collapsed to spaces (for single-line fields
24
+ * such as the chat input). Defaults to false. */
25
+ singleLine?: boolean;
26
+ }
27
+ /**
28
+ * Make `text` safe to render: normalise newlines, drop escape sequences, expand
29
+ * tabs and remove every other control code. The result contains no character
30
+ * the terminal would interpret as a command, so it can never corrupt the grid.
31
+ */
32
+ export declare function sanitizeText(text: string, opts?: SanitizeOptions): string;
33
+ /** True if `ch` is a character the terminal would treat as a control code. */
34
+ export declare function isControlChar(ch: string): boolean;
@@ -0,0 +1,28 @@
1
+ import type { Buffer } from "../terminal/buffer.js";
2
+ import { Screen, type ScrollbarHandle } from "../terminal/screen.js";
3
+ import type { Key, MouseEvent } from "../terminal/input.js";
4
+ import type { AgentId, AgentMessage } from "../agents.js";
5
+ interface MigrationSource {
6
+ agent: AgentId;
7
+ id: string;
8
+ cwd: string;
9
+ }
10
+ export declare class AgentConversationScreen extends Screen {
11
+ private source;
12
+ private title;
13
+ private messages;
14
+ private scrollTop;
15
+ private followBottom;
16
+ private scrollbarGeom;
17
+ private migrateButton;
18
+ private migrationError;
19
+ constructor(title: string, messages: AgentMessage[], source: MigrationSource);
20
+ onKey(key: Key): void;
21
+ onMouse(ev: MouseEvent): void;
22
+ private migrate;
23
+ alwaysRepaintRows(): number[];
24
+ scrollbar(): ScrollbarHandle | null;
25
+ private buildLines;
26
+ render(buf: Buffer): void;
27
+ }
28
+ export {};
@@ -0,0 +1,25 @@
1
+ import type { Buffer } from "../terminal/buffer.js";
2
+ import { Screen } from "../terminal/screen.js";
3
+ import type { Key, MouseEvent } from "../terminal/input.js";
4
+ import { type AgentId } from "../agents.js";
5
+ export declare class AgentHistoryScreen extends Screen {
6
+ private agent;
7
+ private label;
8
+ private sessions;
9
+ private selectedIdx;
10
+ private scrollTop;
11
+ private lastHoverX;
12
+ private lastHoverY;
13
+ private rows;
14
+ private itemBounds;
15
+ private cwd;
16
+ constructor(agent: AgentId, label: string);
17
+ onActivate(): void;
18
+ private move;
19
+ onKey(key: Key): void;
20
+ onMouse(ev: MouseEvent): void;
21
+ private itemIndexAtRow;
22
+ private loadSelected;
23
+ private buildRows;
24
+ render(buf: Buffer): void;
25
+ }
@@ -0,0 +1,16 @@
1
+ import type { Buffer } from "../terminal/buffer.js";
2
+ import { Screen } from "../terminal/screen.js";
3
+ import type { Key, MouseEvent } from "../terminal/input.js";
4
+ export declare class AgentSelectScreen extends Screen {
5
+ private selectedIdx;
6
+ private scrollBtn;
7
+ private lastHoverX;
8
+ private lastHoverY;
9
+ onActivate(): void;
10
+ private move;
11
+ onKey(key: Key): void;
12
+ onMouse(ev: MouseEvent): void;
13
+ private indexAtRow;
14
+ private confirm;
15
+ render(buf: Buffer): void;
16
+ }
@@ -0,0 +1,292 @@
1
+ import { type FastSnapshot } from "../fast/types.js";
2
+ import type { Buffer } from "../terminal/buffer.js";
3
+ import { Screen, type ScrollbarHandle } from "../terminal/screen.js";
4
+ import type { Key, MouseEvent } from "../terminal/input.js";
5
+ import { type AgentMode, type ModelInfo, type SessionMessage, type TokenUsage, type ResolvedModelSelection, type ApprovalMode } from "../config.js";
6
+ import { type TaskSnapshot } from "../llm/runtime.js";
7
+ import { type PlanState } from "../llm/plan.js";
8
+ import { type ConversationContext } from "../compact.js";
9
+ import { type LiveAgent, type LiveMeta, type LiveSnapshot, type ModelChangeResult } from "../web/hub.js";
10
+ /** A sub-agent gets the same tools minus delegation: one level, never a tree. */
11
+ /**
12
+ * A finished turn folds its *work* away — the thinking and the tool calls —
13
+ * while the full user prompt and final reply always stay on screen. Doing
14
+ * that is only worth a click when the work is substantial: four or more blocks,
15
+ * or roughly six wrapped lines of text. Short exchanges stay readable without a
16
+ * click. `web/turns.js` applies the same rule in the browser, so both UIs fold
17
+ * exactly the same turns.
18
+ */
19
+ export declare const TURN_FOLD_MIN_BLOCKS = 4;
20
+ export declare const TURN_FOLD_MIN_CHARS = 600;
21
+ export declare class ChatScreen extends Screen implements LiveAgent {
22
+ initialMessage: string;
23
+ loadedMessages: SessionMessage[] | null;
24
+ loadedCwd: string | null;
25
+ sessionId: string | null;
26
+ loadedProvider: string | null;
27
+ loadedModel: string | null;
28
+ loadedIntensity: string | null;
29
+ loadedTokens: TokenUsage | null;
30
+ loadedContext: ConversationContext | null;
31
+ loadedApprovalMode: ApprovalMode | null;
32
+ loadedPlan: PlanState | null;
33
+ loadedTask: TaskSnapshot | undefined;
34
+ loadedFast: FastSnapshot | undefined;
35
+ loadedAgentMode: AgentMode | null;
36
+ private approvalMode;
37
+ modelProvider: string;
38
+ model: ModelInfo;
39
+ intensity: string;
40
+ private tokens;
41
+ private showInfo;
42
+ /** The plan of the turn being worked on, or the last one. */
43
+ private plan;
44
+ /** True while the planner agent is writing the steps. */
45
+ private planning;
46
+ /** What the sub-agent is doing, or null when none is running. */
47
+ private subagent;
48
+ private messages;
49
+ private streamingContent;
50
+ private saveError;
51
+ /** Why a busy turn is silent: a transient network failure being retried. */
52
+ private retryNotice;
53
+ private checkpoint;
54
+ private busy;
55
+ private paused;
56
+ private queued;
57
+ private taskRuntime;
58
+ private lastTask;
59
+ private taskOutcome;
60
+ private turnToken;
61
+ private agentMode;
62
+ private activeAgentMode;
63
+ private fastState?;
64
+ private queuedAgentMode;
65
+ private turnAbort;
66
+ private inputValue;
67
+ private cursor;
68
+ private scrollTop;
69
+ private followBottom;
70
+ private scrollbarGeom;
71
+ private lastEscTime;
72
+ private initialized;
73
+ /** Prompt tokens of the most recent request — the best proxy for how large
74
+ * the current context has grown. Reset once the history is compressed. */
75
+ private lastPromptTokens;
76
+ private compressing;
77
+ private context;
78
+ private expandedContext;
79
+ private contextLines;
80
+ private contextRows;
81
+ /** Message indices whose tool output is expanded (everything starts
82
+ * collapsed). */
83
+ private expandedTools;
84
+ /** For each line produced by buildLines, the tool message index it belongs
85
+ * to, or -1 when it is not part of a tool block. */
86
+ private toolLineIndex;
87
+ /** Terminal row -> tool message index, rebuilt each render for hit-testing. */
88
+ private toolRows;
89
+ /** First message index of every turn whose reply has finished. A transcript
90
+ * loaded from disk starts finished: reopening history reviews past work. */
91
+ private finishedTurns;
92
+ /** Turns the reader opened; a finished turn stays folded unless listed here. */
93
+ private expandedTurns;
94
+ /** First message index of the turn being answered right now, if any. */
95
+ private activeTurnStart;
96
+ /** For each built line, the folded turn it belongs to (-1 = none). Only the
97
+ * header lines carry it, so clicks inside a tool block still target the tool. */
98
+ private turnLineIndex;
99
+ /** Terminal row -> folded turn start, rebuilt each render for hit-testing. */
100
+ private turnRows;
101
+ private liveKey;
102
+ private liveDir;
103
+ /** Non-null while a tool call is waiting for a human decision. */
104
+ private approvalQueue;
105
+ private pendingApproval;
106
+ private reviewing;
107
+ /** Decisions taken by the gate, keyed by the tool message (survives
108
+ * context compression, which renumbers the array). */
109
+ private approvals;
110
+ /** Hit boxes of the approval card, rebuilt on every render. */
111
+ private approvalButtons;
112
+ constructor(initialMessage?: string);
113
+ onActivate(): void;
114
+ onDeactivate(): void;
115
+ liveCwd(): string;
116
+ liveConfigure(selection: ResolvedModelSelection): ModelChangeResult;
117
+ liveMeta(): LiveMeta;
118
+ liveSnapshot(key: string): LiveSnapshot;
119
+ livePause(): void;
120
+ liveResume(): void;
121
+ /** Answer the pending call from the web UI. */
122
+ liveApprove(approved: boolean, approvalId?: string): boolean;
123
+ liveSetAgentMode(mode: AgentMode): ModelChangeResult;
124
+ liveSetApprovalMode(mode: ApprovalMode): void;
125
+ /**
126
+ * Start a fresh conversation in the same working directory. Used by Ctrl+L
127
+ * and by the browser's Clear button, so both screens behave identically. The
128
+ * previous transcript is saved first and is never overwritten.
129
+ */
130
+ liveClear(): void;
131
+ liveSend(text: string): void;
132
+ private liveTitle;
133
+ private publishLive;
134
+ private approvalToggleY;
135
+ /**
136
+ * The input row is persistent chrome: it is drawn with absolute positioning
137
+ * and must survive any terminal-side drift (ConPTY reflow, a stray scroll).
138
+ * Repainting it every frame makes the input area self-healing — the log can
139
+ * never end up "covering" it.
140
+ */
141
+ alwaysRepaintRows(): number[];
142
+ showsCursor(): boolean;
143
+ onPaste(text: string): void;
144
+ onKey(key: Key): void;
145
+ onMouse(ev: MouseEvent): void;
146
+ scrollbar(): ScrollbarHandle | null;
147
+ private togglePause;
148
+ private maybeFlushQueue;
149
+ /**
150
+ * Run the planner agent over the current request.
151
+ *
152
+ * Returns null rather than throwing in every case where there is no usable
153
+ * plan — planning switched off, a one-step request, a provider that fails, an
154
+ * answer that is not a plan. The turn then runs exactly as it did before
155
+ * plan-first existed; a plan is an improvement, never a new way to fail.
156
+ */
157
+ private makePlan;
158
+ /** Move the plan to one step and show it: the card follows every transition. */
159
+ private setStep;
160
+ /** A turn that can no longer continue must not leave a step looking alive. */
161
+ private haltPlan;
162
+ /**
163
+ * One user turn.
164
+ *
165
+ * A planned turn is answered in two passes: the planner writes the steps, then
166
+ * the worker executes them one at a time, top to bottom, each with the whole
167
+ * plan in its system prompt and the instruction to do only its own step. That
168
+ * keeps the work of a long request explicit — the card shows exactly which
169
+ * step is running and which are done — and keeps every step verifiable on its
170
+ * own. Without a plan the turn runs in one pass, as before.
171
+ */
172
+ private runTurn;
173
+ private runTaskTurn;
174
+ /**
175
+ * The transcript this turn may see: the messages it started with plus what it
176
+ * has added since — the plan message, replies, tool calls and results.
177
+ *
178
+ * A user message that arrives while the turn runs is queued for the *next*
179
+ * turn, so it is deliberately not part of this one: the model and the approval
180
+ * reviewers must always judge the same request.
181
+ */
182
+ private turnView;
183
+ private send;
184
+ private startTurn;
185
+ /**
186
+ * Ends a turn that failed before or around the agent loop.
187
+ *
188
+ * The turn body is a floating promise, so anything thrown outside the loop's
189
+ * own try/catch would otherwise surface as an unhandled rejection, which Node
190
+ * turns into a fatal error. Ending the turn here keeps the app alive and the
191
+ * failure visible in the transcript.
192
+ */
193
+ private failTurn;
194
+ private runFastTurn;
195
+ private buildApiMessages;
196
+ /**
197
+ * One agent conversation: request, tool calls, request again, until the model
198
+ * answers without asking for a tool.
199
+ *
200
+ * Returns true when the model finished on its own and false when the turn was
201
+ * cut short (paused, superseded, or failed). The caller owns the turn's end,
202
+ * because a planned turn runs this once per step.
203
+ */
204
+ private agentLoop;
205
+ /**
206
+ * Ends the turn. `finished` is false when the turn was cut short (ESC ESC,
207
+ * Ctrl+C): a paused turn is not a completed one and stays open for reading.
208
+ */
209
+ private onTurnFinished;
210
+ /** Classify a tool call and, when it is risky, run it past the gate. */
211
+ private requestApproval;
212
+ /** Park the turn until the user answers; the header turns orange meanwhile. */
213
+ private askHuman;
214
+ /** Answer the pending request (keyboard, mouse, or the web UI). */
215
+ private settleApproval;
216
+ /** Reviewer model: `approval_model` when set, otherwise the chat model. */
217
+ private reviewerModel;
218
+ /** Orange card listing the pending call and its buttons. */
219
+ private drawApprovalCard;
220
+ private runProgram;
221
+ /**
222
+ * Run one approved tool call. `delegate` is handled here rather than inside
223
+ * tools.ts: a sub-agent has to share this turn's model, approval gate, working
224
+ * directory and abort signal, and only the session knows about those.
225
+ */
226
+ private runTool;
227
+ private dispatchTool;
228
+ /**
229
+ * Run a sub-agent for one `delegate` call and return its report.
230
+ *
231
+ * The child gets its own conversation, the parent's tools (minus delegation)
232
+ * and the parent's approval gate; what it does in between is deliberately not
233
+ * part of this transcript. While it runs, its current phase is shown in the
234
+ * status line and in the tool block, so a quiet log still has an explanation.
235
+ */
236
+ private delegate;
237
+ /** First message index of every turn: a turn starts at a user message and
238
+ * ends where the next one begins. */
239
+ private userMessageIndexes;
240
+ private turnEnd;
241
+ /**
242
+ * A finished turn is only worth folding when the work it hides is substantial.
243
+ * Whether it is folded right now is a separate question (`expandedTurns`), and
244
+ * its user input and reply are never part of what it hides.
245
+ */
246
+ private turnHides;
247
+ /**
248
+ * The index of the turn's reply: its last assistant message. A fold hides the
249
+ * work that led to the answer, so this message is always rendered.
250
+ */
251
+ private turnAnswer;
252
+ /** For every message, the reply of the turn it belongs to (-1 = none). */
253
+ private turnAnswers;
254
+ /** For every message, the first index of the turn folding it (-1 = none). */
255
+ private turnMap;
256
+ /** The header standing in for a folded turn, or the way back into one. */
257
+ private pushTurnHeader;
258
+ /** Fold or unfold one turn. */
259
+ private toggleTurn;
260
+ /** Expand/collapse the tool block belonging to message `index`. */
261
+ private toggleTool;
262
+ /** Compress at 80% of the current model's context capacity. */
263
+ private compressThreshold;
264
+ /**
265
+ * Summarise only the model's history. Original messages stay in the transcript
266
+ * and on disk; the UI folds the summarised prefix until the reader expands it.
267
+ */
268
+ private autoCompress;
269
+ /**
270
+ * Summarise a transcript produced by `transcriptFor`. Split out so tests can
271
+ * stub it without touching the network.
272
+ */
273
+ protected summarizeTranscript(transcript: string, cancelled?: () => boolean): Promise<string>;
274
+ /**
275
+ * Keep the outbound payload within budget during a long single turn: once the
276
+ * context is over the threshold, blank out all but the most recent tool
277
+ * results. Their full text stays in the visible log, which is collapsible.
278
+ */
279
+ private trimApiMessages;
280
+ private retainStreamingContent;
281
+ private save;
282
+ private writeSession;
283
+ private buildLines;
284
+ render(buf: Buffer): void;
285
+ private renderInfoOverlay;
286
+ /**
287
+ * What the card shows: the plan as a vertical timeline, then the token counts.
288
+ * Without a plan it is exactly the token card it has always been. One row is
289
+ * kept for the counts, so a long plan cannot push them out of the card.
290
+ */
291
+ private infoCardRows;
292
+ }