@oh-my-pi/pi-coding-agent 15.8.3 → 15.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (172) hide show
  1. package/CHANGELOG.md +113 -31
  2. package/dist/types/capability/skill.d.ts +7 -0
  3. package/dist/types/cli/update-cli.d.ts +15 -1
  4. package/dist/types/config/append-only-context-mode.d.ts +8 -0
  5. package/dist/types/config/model-registry.d.ts +3 -0
  6. package/dist/types/config/models-config-schema.d.ts +15 -0
  7. package/dist/types/config/settings-schema.d.ts +38 -24
  8. package/dist/types/debug/protocol-probe.d.ts +38 -0
  9. package/dist/types/debug/terminal-info.d.ts +34 -0
  10. package/dist/types/exa/mcp-client.d.ts +2 -1
  11. package/dist/types/export/html/template.generated.d.ts +1 -1
  12. package/dist/types/extensibility/custom-tools/types.d.ts +1 -1
  13. package/dist/types/extensibility/extensions/types.d.ts +11 -0
  14. package/dist/types/extensibility/shared-events.d.ts +1 -1
  15. package/dist/types/index.d.ts +1 -0
  16. package/dist/types/mcp/json-rpc.d.ts +6 -1
  17. package/dist/types/mcp/tool-bridge.d.ts +4 -0
  18. package/dist/types/mcp/transports/stdio.d.ts +16 -7
  19. package/dist/types/mnemopi/state.d.ts +2 -2
  20. package/dist/types/modes/components/agent-dashboard.d.ts +1 -0
  21. package/dist/types/modes/components/assistant-message.d.ts +3 -2
  22. package/dist/types/modes/components/extensions/extension-dashboard.d.ts +1 -0
  23. package/dist/types/modes/components/hook-selector.d.ts +11 -0
  24. package/dist/types/modes/components/plugin-settings.d.ts +40 -8
  25. package/dist/types/modes/components/session-selector.d.ts +8 -3
  26. package/dist/types/modes/components/settings-selector.d.ts +1 -1
  27. package/dist/types/modes/components/todo-reminder.d.ts +1 -1
  28. package/dist/types/modes/components/transcript-container.d.ts +36 -0
  29. package/dist/types/modes/interactive-mode.d.ts +2 -1
  30. package/dist/types/modes/rpc/rpc-types.d.ts +1 -1
  31. package/dist/types/modes/theme/theme.d.ts +20 -1
  32. package/dist/types/modes/utils/keybinding-matchers.d.ts +4 -0
  33. package/dist/types/plan-mode/plan-handoff.d.ts +20 -0
  34. package/dist/types/session/agent-session.d.ts +5 -2
  35. package/dist/types/session/history-storage.d.ts +3 -4
  36. package/dist/types/session/indexed-session-storage.d.ts +59 -0
  37. package/dist/types/session/messages.d.ts +1 -0
  38. package/dist/types/session/redis-session-storage.d.ts +12 -85
  39. package/dist/types/session/session-manager.d.ts +21 -0
  40. package/dist/types/session/session-storage.d.ts +5 -7
  41. package/dist/types/session/sql-session-storage.d.ts +16 -85
  42. package/dist/types/slash-commands/types.d.ts +17 -4
  43. package/dist/types/task/executor.d.ts +9 -0
  44. package/dist/types/task/index.d.ts +3 -1
  45. package/dist/types/telemetry-export.d.ts +19 -0
  46. package/dist/types/tiny/compiled-runtime.d.ts +35 -0
  47. package/dist/types/tiny/text.d.ts +17 -0
  48. package/dist/types/tools/ask.d.ts +1 -0
  49. package/dist/types/tools/index.d.ts +4 -2
  50. package/dist/types/tools/path-utils.d.ts +1 -1
  51. package/dist/types/tools/search.d.ts +2 -2
  52. package/dist/types/tools/{todo-write.d.ts → todo.d.ts} +18 -18
  53. package/dist/types/utils/session-color.d.ts +7 -2
  54. package/dist/types/web/search/index.d.ts +1 -1
  55. package/dist/types/web/search/provider.d.ts +2 -2
  56. package/dist/types/web/search/providers/base.d.ts +14 -0
  57. package/dist/types/web/search/providers/exa.d.ts +9 -0
  58. package/dist/types/web/search/providers/perplexity.d.ts +2 -2
  59. package/dist/types/web/search/types.d.ts +66 -1
  60. package/package.json +15 -9
  61. package/scripts/build-binary.ts +12 -0
  62. package/src/capability/skill.ts +7 -0
  63. package/src/cli/args.ts +1 -1
  64. package/src/cli/session-picker.ts +1 -0
  65. package/src/cli/update-cli.ts +54 -2
  66. package/src/commands/completions.ts +1 -1
  67. package/src/config/append-only-context-mode.ts +37 -0
  68. package/src/config/models-config-schema.ts +1 -0
  69. package/src/config/settings-schema.ts +24 -57
  70. package/src/debug/index.ts +67 -1
  71. package/src/debug/protocol-probe.ts +267 -0
  72. package/src/debug/terminal-info.ts +127 -0
  73. package/src/exa/mcp-client.ts +11 -5
  74. package/src/export/html/template.generated.ts +1 -1
  75. package/src/export/html/template.js +3 -3
  76. package/src/extensibility/custom-tools/types.ts +1 -1
  77. package/src/extensibility/extensions/types.ts +11 -0
  78. package/src/extensibility/shared-events.ts +1 -1
  79. package/src/extensibility/skills.ts +3 -3
  80. package/src/index.ts +1 -0
  81. package/src/internal-urls/docs-index.generated.ts +7 -7
  82. package/src/main.ts +16 -2
  83. package/src/mcp/json-rpc.ts +8 -0
  84. package/src/mcp/render.ts +3 -0
  85. package/src/mcp/tool-bridge.ts +10 -2
  86. package/src/mcp/transports/http.ts +33 -16
  87. package/src/mcp/transports/stdio.ts +37 -12
  88. package/src/mnemopi/state.ts +4 -4
  89. package/src/modes/acp/acp-agent.ts +168 -3
  90. package/src/modes/acp/acp-event-mapper.ts +7 -7
  91. package/src/modes/components/agent-dashboard.ts +103 -31
  92. package/src/modes/components/assistant-message.ts +3 -2
  93. package/src/modes/components/extensions/extension-dashboard.ts +56 -10
  94. package/src/modes/components/history-search.ts +128 -14
  95. package/src/modes/components/hook-selector.ts +149 -14
  96. package/src/modes/components/plugin-settings.ts +270 -36
  97. package/src/modes/components/session-selector.ts +81 -19
  98. package/src/modes/components/settings-selector.ts +1 -1
  99. package/src/modes/components/status-line/segments.ts +2 -1
  100. package/src/modes/components/status-line.ts +1 -1
  101. package/src/modes/components/tips.txt +6 -2
  102. package/src/modes/components/todo-reminder.ts +1 -1
  103. package/src/modes/components/tool-execution.ts +9 -4
  104. package/src/modes/components/transcript-container.ts +109 -0
  105. package/src/modes/controllers/command-controller.ts +4 -3
  106. package/src/modes/controllers/event-controller.ts +12 -7
  107. package/src/modes/controllers/extension-ui-controller.ts +3 -0
  108. package/src/modes/controllers/input-controller.ts +10 -5
  109. package/src/modes/controllers/selector-controller.ts +30 -19
  110. package/src/modes/controllers/todo-command-controller.ts +1 -1
  111. package/src/modes/interactive-mode.ts +56 -9
  112. package/src/modes/print-mode.ts +5 -0
  113. package/src/modes/rpc/rpc-types.ts +1 -1
  114. package/src/modes/theme/theme.ts +48 -8
  115. package/src/modes/utils/keybinding-matchers.ts +10 -0
  116. package/src/modes/utils/ui-helpers.ts +1 -0
  117. package/src/plan-mode/plan-handoff.ts +37 -0
  118. package/src/priority.json +4 -0
  119. package/src/prompts/goals/goal-continuation.md +1 -1
  120. package/src/prompts/steering/user-interjection.md +10 -0
  121. package/src/prompts/system/agent-creation-architect.md +1 -26
  122. package/src/prompts/system/eager-todo.md +3 -3
  123. package/src/prompts/system/orchestrate-notice.md +5 -5
  124. package/src/prompts/system/plan-mode-approved.md +14 -17
  125. package/src/prompts/system/plan-mode-reference.md +3 -6
  126. package/src/prompts/system/subagent-system-prompt.md +11 -0
  127. package/src/prompts/system/system-prompt.md +143 -145
  128. package/src/prompts/system/title-system.md +3 -2
  129. package/src/prompts/system/workflow-notice.md +1 -1
  130. package/src/prompts/tools/browser.md +33 -30
  131. package/src/prompts/tools/render-mermaid.md +2 -2
  132. package/src/prompts/tools/search.md +1 -1
  133. package/src/prompts/tools/task.md +3 -1
  134. package/src/prompts/tools/{todo-write.md → todo.md} +5 -5
  135. package/src/sdk.ts +6 -21
  136. package/src/session/agent-session.ts +44 -21
  137. package/src/session/history-storage.ts +11 -18
  138. package/src/session/indexed-session-storage.ts +430 -0
  139. package/src/session/messages.ts +80 -0
  140. package/src/session/redis-session-storage.ts +66 -377
  141. package/src/session/session-manager.ts +109 -23
  142. package/src/session/session-storage.ts +148 -68
  143. package/src/session/sql-session-storage.ts +131 -382
  144. package/src/slash-commands/helpers/todo.ts +2 -2
  145. package/src/slash-commands/types.ts +27 -10
  146. package/src/task/executor.ts +9 -1
  147. package/src/task/index.ts +51 -1
  148. package/src/telemetry-export.ts +126 -0
  149. package/src/tiny/compiled-runtime.ts +179 -0
  150. package/src/tiny/text.ts +112 -1
  151. package/src/tiny/worker.ts +24 -2
  152. package/src/tools/ask.ts +133 -87
  153. package/src/tools/fetch.ts +17 -4
  154. package/src/tools/find.ts +2 -2
  155. package/src/tools/index.ts +6 -4
  156. package/src/tools/memory-recall.ts +1 -1
  157. package/src/tools/memory-reflect.ts +1 -1
  158. package/src/tools/path-utils.ts +16 -7
  159. package/src/tools/renderers.ts +2 -2
  160. package/src/tools/search.ts +6 -3
  161. package/src/tools/ssh.ts +26 -10
  162. package/src/tools/{todo-write.ts → todo.ts} +32 -35
  163. package/src/tools/write.ts +14 -2
  164. package/src/tui/status-line.ts +15 -4
  165. package/src/utils/session-color.ts +39 -14
  166. package/src/utils/title-generator.ts +9 -2
  167. package/src/web/search/index.ts +4 -2
  168. package/src/web/search/provider.ts +19 -35
  169. package/src/web/search/providers/base.ts +17 -0
  170. package/src/web/search/providers/exa.ts +111 -7
  171. package/src/web/search/providers/perplexity.ts +8 -4
  172. package/src/web/search/types.ts +74 -32
@@ -15,7 +15,7 @@ import type { ExecOptions, ExecResult } from "../../exec/exec";
15
15
  import type { HookUIContext } from "../../extensibility/hooks/types";
16
16
  import type { Theme } from "../../modes/theme/theme";
17
17
  import type { ReadonlySessionManager } from "../../session/session-manager";
18
- import type { TodoItem } from "../../tools/todo-write";
18
+ import type { TodoItem } from "../../tools/todo";
19
19
  /** Alias for clarity */
20
20
  export type CustomToolUIContext = HookUIContext;
21
21
  export type { ExecOptions, ExecResult } from "../../exec/exec";
@@ -59,6 +59,17 @@ export interface ExtensionUIDialogOptions {
59
59
  onExternalEditor?: () => void;
60
60
  /** Optional footer hint text rendered by interactive selector */
61
61
  helpText?: string;
62
+ /** Render a leading radio/checkbox marker before each markable option in
63
+ * select dialogs (matches the ask transcript). "radio" fills the cursor row
64
+ * for single-choice; "checkbox" reflects `checkedIndices` per row for
65
+ * multi-select. Options beyond `markableCount` keep the plain cursor. */
66
+ selectionMarker?: "radio" | "checkbox";
67
+ /** For `selectionMarker: "checkbox"`: option indices currently checked. */
68
+ checkedIndices?: readonly number[];
69
+ /** Number of leading options that receive a selection marker; the remaining
70
+ * trailing options (e.g. "Other"/"Done" actions) keep the plain cursor.
71
+ * Defaults to all options when `selectionMarker` is set. */
72
+ markableCount?: number;
62
73
  }
63
74
  /** Raw terminal input listener for extensions. */
64
75
  export type TerminalInputHandler = (data: string) => {
@@ -18,7 +18,7 @@ import type { ImageContent, TextContent, ToolResultMessage } from "@oh-my-pi/pi-
18
18
  import type { Rule } from "../capability/rule";
19
19
  import type { Goal, GoalModeState } from "../goals/state";
20
20
  import type { BranchSummaryEntry, CompactionEntry, SessionEntry } from "../session/session-manager";
21
- import type { TodoItem } from "../tools/todo-write";
21
+ import type { TodoItem } from "../tools/todo";
22
22
  /** Fired on initial session load */
23
23
  export interface SessionStartEvent {
24
24
  type: "session_start";
@@ -22,6 +22,7 @@ export * from "./modes/theme/theme";
22
22
  export * from "./sdk";
23
23
  export * from "./session/agent-session";
24
24
  export * from "./session/auth-storage";
25
+ export * from "./session/indexed-session-storage";
25
26
  export * from "./session/messages";
26
27
  export * from "./session/redis-session-storage";
27
28
  export * from "./session/session-dump-format";
@@ -11,12 +11,17 @@ export interface JsonRpcResponse<T = unknown> {
11
11
  data?: unknown;
12
12
  };
13
13
  }
14
+ /** Options controlling a single MCP JSON-RPC HTTP request. */
15
+ export interface CallMcpOptions {
16
+ signal?: AbortSignal;
17
+ }
14
18
  /**
15
19
  * Call an MCP server with JSON-RPC 2.0 over HTTPS.
16
20
  *
17
21
  * @param url - Full MCP server URL (including any query parameters)
18
22
  * @param method - JSON-RPC method name (e.g., "tools/list", "tools/call")
19
23
  * @param params - Method parameters
24
+ * @param options - Optional transport controls such as cancellation.
20
25
  * @returns Parsed JSON-RPC response
21
26
  */
22
- export declare function callMCP<T = unknown>(url: string, method: string, params?: Record<string, unknown>): Promise<JsonRpcResponse<T>>;
27
+ export declare function callMCP<T = unknown>(url: string, method: string, params?: Record<string, unknown>, options?: CallMcpOptions): Promise<JsonRpcResponse<T>>;
@@ -53,6 +53,8 @@ export declare class MCPTool implements CustomTool<TSchema, MCPToolDetails> {
53
53
  readonly mcpToolName: string;
54
54
  /** Server name */
55
55
  readonly mcpServerName: string;
56
+ /** Render completed MCP calls with the result header replacing the pending call header. */
57
+ readonly mergeCallAndResult = true;
56
58
  /** Create MCPTool instances for all tools from an MCP server connection */
57
59
  static fromTools(connection: MCPServerConnection, tools: MCPToolDefinition[], reconnect?: MCPReconnect): MCPTool[];
58
60
  constructor(connection: MCPServerConnection, tool: MCPToolDefinition, reconnect?: MCPReconnect | undefined);
@@ -77,6 +79,8 @@ export declare class DeferredMCPTool implements CustomTool<TSchema, MCPToolDetai
77
79
  readonly mcpToolName: string;
78
80
  /** Server name */
79
81
  readonly mcpServerName: string;
82
+ /** Render completed MCP calls with the result header replacing the pending call header. */
83
+ readonly mergeCallAndResult = true;
80
84
  /** Create DeferredMCPTool instances for all tools from an MCP server */
81
85
  static fromTools(serverName: string, tools: MCPToolDefinition[], getConnection: () => Promise<MCPServerConnection>, source?: SourceMeta, reconnect?: MCPReconnect): DeferredMCPTool[];
82
86
  constructor(serverName: string, tool: MCPToolDefinition, getConnection: () => Promise<MCPServerConnection>, source?: SourceMeta, reconnect?: MCPReconnect | undefined);
@@ -12,15 +12,24 @@ interface FrameSink {
12
12
  }
13
13
  /**
14
14
  * Write a newline-delimited JSON-RPC frame to the subprocess's stdin sink,
15
- * swallowing synchronous errors so the caller can decide how to react.
15
+ * swallowing both synchronous throws and asynchronous rejections so the caller
16
+ * can decide how to react.
16
17
  *
17
- * Bun's `FileSink` may throw synchronously (most reliably on Windows) when
18
- * the read end of the pipe has been closed by a subprocess that exited
19
- * between read-loop ticks. Letting that throw escape an `async` method
20
- * surfaces as an unhandled promise rejection at the call site.
18
+ * Bun's `FileSink.write()`/`flush()` can fail two ways once the read end of the
19
+ * pipe has been closed by a subprocess that exited between read-loop ticks:
20
+ * - a synchronous throw (most reliably observed on Windows), and
21
+ * - a *rejected Promise* returned from `write()`/`flush()`, i.e. the EPIPE is
22
+ * surfaced asynchronously (note the `processTicksAndRejections` frame in the
23
+ * stack traces on #1710 and the follow-up report).
21
24
  *
22
- * Returns `true` when the frame was accepted by the sink, `false` when the
23
- * sink threw callers signal transport closure on `false`.
25
+ * A sibling `async` method's `try/catch` only catches the synchronous case; an
26
+ * un-awaited rejected Promise escapes as a fatal unhandled rejection. So we both
27
+ * catch the throw and neutralize any returned promise's rejection.
28
+ *
29
+ * Returns `true` when the frame was accepted synchronously, `false` when the
30
+ * sink threw — callers signal transport closure on `false`. An asynchronous
31
+ * failure cannot be reflected in the return value; it is neutralized here and
32
+ * the dead transport is detected by the read loop / request timeout instead.
24
33
  */
25
34
  export declare function writeFrame(stdin: FrameSink, frame: string): boolean;
26
35
  /**
@@ -48,8 +48,8 @@ export declare class MnemopiSessionState {
48
48
  getScopedRetainTarget(): MnemopiScopedMemory;
49
49
  editScopedMemory(op: MnemopiMemoryEditOperation, id: string, options?: MnemopiMemoryEditOptions): MnemopiMemoryEditResult;
50
50
  formatScopedRecallWithIds(results: readonly RecallResult[]): string;
51
- collectScopedRecallResults(query: string): RecallResult[];
52
- recallResultsScoped(query: string): RecallResult[];
51
+ collectScopedRecallResults(query: string): Promise<RecallResult[]>;
52
+ recallResultsScoped(query: string): Promise<RecallResult[]>;
53
53
  formatScopedRecallContext(results: readonly RecallResult[], format?: "bullet" | "json"): string | undefined;
54
54
  formatContextScoped(results: readonly RecallResult[], format?: "bullet" | "json"): string;
55
55
  rememberInScope(memory: MnemopiRememberInput, options?: MnemopiRememberOptions): string | undefined;
@@ -16,6 +16,7 @@ export declare class AgentDashboard extends Container {
16
16
  onRequestRender?: () => void;
17
17
  private constructor();
18
18
  static create(cwd: string, settings?: Settings | null, terminalHeight?: number, modelContext?: AgentDashboardModelContext): Promise<AgentDashboard>;
19
+ render(width: number): string[];
19
20
  handleInput(data: string): void;
20
21
  }
21
22
  export {};
@@ -1,5 +1,5 @@
1
1
  import type { AssistantMessage, ImageContent, Usage } from "@oh-my-pi/pi-ai";
2
- import { Container } from "@oh-my-pi/pi-tui";
2
+ import { Container, type ImageBudget } from "@oh-my-pi/pi-tui";
3
3
  import type { AssistantThinkingRenderer } from "../../extensibility/extensions/types";
4
4
  /**
5
5
  * Component that renders a complete assistant message
@@ -9,7 +9,8 @@ export declare class AssistantMessageComponent extends Container {
9
9
  private hideThinkingBlock;
10
10
  private readonly onImageUpdate?;
11
11
  private readonly thinkingRenderers;
12
- constructor(message?: AssistantMessage, hideThinkingBlock?: boolean, onImageUpdate?: (() => void) | undefined, thinkingRenderers?: readonly AssistantThinkingRenderer[]);
12
+ private readonly imageBudget?;
13
+ constructor(message?: AssistantMessage, hideThinkingBlock?: boolean, onImageUpdate?: (() => void) | undefined, thinkingRenderers?: readonly AssistantThinkingRenderer[], imageBudget?: ImageBudget | undefined);
13
14
  invalidate(): void;
14
15
  setHideThinkingBlock(hide: boolean): void;
15
16
  setToolResultImages(toolCallId: string, images: ImageContent[]): void;
@@ -22,5 +22,6 @@ export declare class ExtensionDashboard extends Container {
22
22
  onRequestRender?: () => void;
23
23
  private constructor();
24
24
  static create(cwd: string, settings?: Settings | null, terminalHeight?: number): Promise<ExtensionDashboard>;
25
+ render(width: number): string[];
25
26
  handleInput(data: string): void;
26
27
  }
@@ -44,6 +44,17 @@ export interface HookSelectorOptions {
44
44
  /** Indices into the original options that cannot be selected: they render
45
45
  * dimmed, are skipped during navigation, and reject enter/timeout. */
46
46
  disabledIndices?: readonly number[];
47
+ /** Render a leading radio/checkbox marker before each markable option,
48
+ * matching the ask transcript. "radio" fills the marker on the cursor row
49
+ * (single-choice); "checkbox" reflects {@link checkedIndices} per row
50
+ * (multi-select). Options at or beyond {@link markableCount} keep the plain
51
+ * cursor prefix — used for trailing control rows like "Other"/"Done". */
52
+ selectionMarker?: "radio" | "checkbox";
53
+ /** For `selectionMarker: "checkbox"`: original-indices currently checked. */
54
+ checkedIndices?: readonly number[];
55
+ /** Number of leading options (original order) that receive a selection
56
+ * marker. Defaults to every option when {@link selectionMarker} is set. */
57
+ markableCount?: number;
47
58
  }
48
59
  export interface HookSelectorOption {
49
60
  label: string;
@@ -2,13 +2,15 @@
2
2
  * Plugin settings UI components.
3
3
  *
4
4
  * Provides a hierarchical settings interface:
5
- * - Plugin list (shows all installed plugins)
6
- * - Plugin detail (enable/disable, features, config)
5
+ * - Plugin list (npm plugins + marketplace plugins)
6
+ * - npm plugin detail (enable/disable, features, config)
7
+ * - Marketplace plugin detail (enable/disable + read-only metadata)
7
8
  * - Feature toggles
8
9
  * - Config value editor
9
10
  */
10
11
  import { Container } from "@oh-my-pi/pi-tui";
11
12
  import { PluginManager } from "../../extensibility/plugins/manager";
13
+ import type { InstalledPluginSummary } from "../../extensibility/plugins/marketplace";
12
14
  import type { InstalledPlugin } from "../../extensibility/plugins/types";
13
15
  /**
14
16
  * Forwards a keystroke to `input`, but cancels via `onCancel` when the user presses Escape.
@@ -16,18 +18,32 @@ import type { InstalledPlugin } from "../../extensibility/plugins/types";
16
18
  export declare function handleInputOrEscape(data: string, input: {
17
19
  handleInput(data: string): void;
18
20
  }, onCancel: () => void): void;
21
+ /**
22
+ * One row in the unified plugin list. npm and marketplace plugins live in
23
+ * separate registries with different shapes, so a tagged union keeps both
24
+ * paths type-safe end-to-end (list rendering, value lookup, detail callback).
25
+ */
26
+ export type PluginListEntry = {
27
+ kind: "npm";
28
+ plugin: InstalledPlugin;
29
+ } | {
30
+ kind: "marketplace";
31
+ plugin: InstalledPluginSummary;
32
+ };
19
33
  export interface PluginListCallbacks {
20
- onPluginSelect: (plugin: InstalledPlugin) => void;
34
+ onNpmSelect: (plugin: InstalledPlugin) => void;
35
+ onMarketplaceSelect: (plugin: InstalledPluginSummary) => void;
21
36
  onCancel: () => void;
22
37
  }
23
38
  /**
24
- * Shows list of installed plugins with enable/disable status.
25
- * Selecting a plugin opens its detail view.
39
+ * Shows installed plugins from both registries (npm + marketplace) with
40
+ * enable/disable status, scope tag, and shadow indicator. Selecting an entry
41
+ * fans out to the kind-specific detail callback.
26
42
  */
27
43
  export declare class PluginListComponent extends Container {
28
44
  #private;
29
- private readonly plugins;
30
- constructor(plugins: InstalledPlugin[], callbacks: PluginListCallbacks);
45
+ private readonly entries;
46
+ constructor(entries: ReadonlyArray<PluginListEntry>, callbacks: PluginListCallbacks);
31
47
  handleInput(data: string): void;
32
48
  }
33
49
  export interface PluginDetailCallbacks {
@@ -50,9 +66,25 @@ export declare class PluginDetailComponent extends Container {
50
66
  constructor(plugin: InstalledPlugin, manager: PluginManager, callbacks: PluginDetailCallbacks);
51
67
  handleInput(data: string): void;
52
68
  }
69
+ export interface MarketplacePluginDetailCallbacks {
70
+ onEnabledChange: (enabled: boolean) => void;
71
+ onBack: () => void;
72
+ }
73
+ /**
74
+ * Detail view for a marketplace plugin. Marketplace plugins do not declare
75
+ * features or settings, so the panel exposes a single enable/disable toggle
76
+ * plus the read-only metadata from the installed-plugins registry.
77
+ */
78
+ export declare class MarketplacePluginDetailComponent extends Container {
79
+ #private;
80
+ private plugin;
81
+ private readonly callbacks;
82
+ constructor(plugin: InstalledPluginSummary, callbacks: MarketplacePluginDetailCallbacks);
83
+ handleInput(data: string): void;
84
+ }
53
85
  export interface PluginSettingsCallbacks {
54
86
  onClose: () => void;
55
- onPluginChanged: () => void;
87
+ onPluginChanged: () => void | Promise<void>;
56
88
  }
57
89
  /**
58
90
  * Top-level plugin settings component.
@@ -8,10 +8,10 @@ export type SessionHistoryMatcher = (query: string) => string[];
8
8
  *
9
9
  * - `fuzzy` is the ordered fuzzy-filter result over session metadata (best first).
10
10
  * - `historyIds` are session IDs whose recorded prompts matched the query,
11
- * ordered by history relevance (best first); duplicates are tolerated.
11
+ * ordered by prompt-history rank (typically newest matching prompt first); duplicates are tolerated.
12
12
  *
13
13
  * Ranking: sessions matched by **both** signals lead (keeping fuzzy order), then
14
- * fuzzy-only matches, then history-only matches (by history order). A fuzzy match
14
+ * fuzzy-only matches, then history-only matches (by prompt-history order). A fuzzy match
15
15
  * is never dropped, and history matches not present in `allSessions` (e.g. deleted
16
16
  * or out-of-scope sessions) are ignored since they cannot be resumed from here.
17
17
  */
@@ -26,7 +26,7 @@ declare class SessionList implements Component {
26
26
  onExit: () => void;
27
27
  onToggleScope?: () => void;
28
28
  onDeleteRequest?: (session: SessionInfo) => void;
29
- constructor(sessions: SessionInfo[], showCwd?: boolean, historyMatcher?: SessionHistoryMatcher);
29
+ constructor(sessions: SessionInfo[], showCwd?: boolean, historyMatcher?: SessionHistoryMatcher, getTerminalRows?: () => number);
30
30
  /** Replace the visible dataset, e.g. when toggling folder/all-projects scope. */
31
31
  setSessions(sessions: SessionInfo[], showCwd: boolean): void;
32
32
  removeSession(sessionPath: string): void;
@@ -43,6 +43,11 @@ export interface SessionSelectorOptions {
43
43
  allSessions?: SessionInfo[];
44
44
  /** Open directly in all-projects scope (e.g. the current folder has no sessions). */
45
45
  startInAllScope?: boolean;
46
+ /**
47
+ * Reads the live terminal height so the visible window fits the viewport.
48
+ * Omitted only in tests; defaults to a conservative 24 rows.
49
+ */
50
+ getTerminalRows?: () => number;
46
51
  }
47
52
  /**
48
53
  * Component that renders a session selector with optional confirmation dialog
@@ -36,7 +36,7 @@ export interface SettingsCallbacks {
36
36
  /** Get current rendered status line for inline preview */
37
37
  getStatusLinePreview?: () => string;
38
38
  /** Called when plugins change */
39
- onPluginsChanged?: () => void;
39
+ onPluginsChanged?: () => void | Promise<void>;
40
40
  /** Called when settings panel is closed */
41
41
  onCancel: () => void;
42
42
  }
@@ -1,5 +1,5 @@
1
1
  import { Container } from "@oh-my-pi/pi-tui";
2
- import type { TodoItem } from "../../tools/todo-write";
2
+ import type { TodoItem } from "../../tools/todo";
3
3
  /**
4
4
  * Component that renders a todo completion reminder notification.
5
5
  * Shows when the agent stops with incomplete todos.
@@ -0,0 +1,36 @@
1
+ import { Container } from "@oh-my-pi/pi-tui";
2
+ /**
3
+ * Transcript container that freezes the rendered output of every block except
4
+ * the bottom-most (live) one on terminals where committed native scrollback is
5
+ * immutable.
6
+ *
7
+ * On ED3-risk terminals with an unobservable viewport (ghostty/kitty/iTerm2/…)
8
+ * the renderer cannot clear saved lines (`\x1b[3J` may yank a reader) or query
9
+ * whether the user has scrolled, so any block that re-lays-out *after* it has
10
+ * scrolled past the viewport leaves a stale duplicate above the live region
11
+ * (a finalized assistant message re-wrapping, a tool preview collapsing to its
12
+ * compact result, a late async tool completion). The renderer's only safe move
13
+ * for such an offscreen edit is to not repaint — which is correct only if the
14
+ * committed region never changes underneath it.
15
+ *
16
+ * This container provides that guarantee: a block's render is snapshotted while
17
+ * it is the live (bottom-most) block, and once a newer block is appended it
18
+ * replays the snapshot instead of recomputing. Mutations after a block leaves
19
+ * live are intentionally deferred until the next checkpoint {@link thaw} (prompt
20
+ * submit → native-scrollback rebuild), where the whole transcript is replayed
21
+ * and any drift reconciles safely. On terminals that can rebuild history this
22
+ * freezing is unnecessary, so it renders every block live for full fidelity.
23
+ */
24
+ export declare class TranscriptContainer extends Container {
25
+ #private;
26
+ invalidate(): void;
27
+ clear(): void;
28
+ /**
29
+ * Retire all frozen snapshots so the next render reflects each block's current
30
+ * state. Call at reconciliation checkpoints (prompt submit) where the whole
31
+ * transcript is replayed into native scrollback and any drift a frozen block
32
+ * accumulated is reconciled.
33
+ */
34
+ thaw(): void;
35
+ render(width: number): string[];
36
+ }
@@ -23,6 +23,7 @@ import type { HookInputComponent } from "./components/hook-input";
23
23
  import type { HookSelectorComponent, HookSelectorSlider } from "./components/hook-selector";
24
24
  import { StatusLineComponent } from "./components/status-line";
25
25
  import type { ToolExecutionHandle } from "./components/tool-execution";
26
+ import { TranscriptContainer } from "./components/transcript-container";
26
27
  import { type LoopLimitRuntime } from "./loop-limit";
27
28
  import { OAuthManualInputManager } from "./oauth-manual-input";
28
29
  import type { Theme } from "./theme/theme";
@@ -49,7 +50,7 @@ export declare class InteractiveMode implements InteractiveModeContext {
49
50
  agent: Agent;
50
51
  historyStorage?: HistoryStorage;
51
52
  ui: TUI;
52
- chatContainer: Container;
53
+ chatContainer: TranscriptContainer;
53
54
  pendingMessagesContainer: Container;
54
55
  statusContainer: Container;
55
56
  todoContainer: Container;
@@ -10,7 +10,7 @@ import type { Effort, ImageContent, Model } from "@oh-my-pi/pi-ai";
10
10
  import type { BashResult } from "../../exec/bash-executor";
11
11
  import type { ContextUsage } from "../../extensibility/extensions/types";
12
12
  import type { SessionStats } from "../../session/agent-session";
13
- import type { TodoPhase } from "../../tools/todo-write";
13
+ import type { TodoPhase } from "../../tools/todo";
14
14
  export type RpcCommand = {
15
15
  id?: string;
16
16
  type: "prompt";
@@ -6,7 +6,7 @@ export type SymbolPreset = "unicode" | "nerd" | "ascii";
6
6
  /**
7
7
  * All available symbol keys organized by category.
8
8
  */
9
- export type SymbolKey = "status.success" | "status.error" | "status.warning" | "status.info" | "status.pending" | "status.disabled" | "status.enabled" | "status.running" | "status.shadowed" | "status.aborted" | "nav.cursor" | "nav.selected" | "nav.expand" | "nav.collapse" | "nav.back" | "tree.branch" | "tree.last" | "tree.vertical" | "tree.horizontal" | "tree.hook" | "boxRound.topLeft" | "boxRound.topRight" | "boxRound.bottomLeft" | "boxRound.bottomRight" | "boxRound.horizontal" | "boxRound.vertical" | "boxSharp.topLeft" | "boxSharp.topRight" | "boxSharp.bottomLeft" | "boxSharp.bottomRight" | "boxSharp.horizontal" | "boxSharp.vertical" | "boxSharp.cross" | "boxSharp.teeDown" | "boxSharp.teeUp" | "boxSharp.teeRight" | "boxSharp.teeLeft" | "sep.powerline" | "sep.powerlineThin" | "sep.powerlineLeft" | "sep.powerlineRight" | "sep.powerlineThinLeft" | "sep.powerlineThinRight" | "sep.block" | "sep.space" | "sep.asciiLeft" | "sep.asciiRight" | "sep.dot" | "sep.slash" | "sep.pipe" | "icon.model" | "icon.plan" | "icon.goal" | "icon.pause" | "icon.loop" | "icon.folder" | "icon.scratchFolder" | "icon.file" | "icon.git" | "icon.branch" | "icon.pr" | "icon.tokens" | "icon.context" | "icon.cost" | "icon.time" | "icon.pi" | "icon.agents" | "icon.cache" | "icon.input" | "icon.output" | "icon.host" | "icon.session" | "icon.package" | "icon.warning" | "icon.rewind" | "icon.auto" | "icon.fast" | "icon.extensionSkill" | "icon.extensionTool" | "icon.extensionSlashCommand" | "icon.extensionMcp" | "icon.extensionRule" | "icon.extensionHook" | "icon.extensionPrompt" | "icon.extensionContextFile" | "icon.extensionInstruction" | "icon.mic" | "thinking.minimal" | "thinking.low" | "thinking.medium" | "thinking.high" | "thinking.xhigh" | "thinking.autoPending" | "checkbox.checked" | "checkbox.unchecked" | "format.bullet" | "format.dash" | "format.bracketLeft" | "format.bracketRight" | "md.quoteBorder" | "md.hrChar" | "md.bullet" | "md.colorSwatch" | "lang.default" | "lang.typescript" | "lang.javascript" | "lang.python" | "lang.rust" | "lang.go" | "lang.java" | "lang.c" | "lang.cpp" | "lang.csharp" | "lang.ruby" | "lang.php" | "lang.swift" | "lang.kotlin" | "lang.shell" | "lang.html" | "lang.css" | "lang.json" | "lang.yaml" | "lang.markdown" | "lang.sql" | "lang.docker" | "lang.lua" | "lang.text" | "lang.env" | "lang.toml" | "lang.xml" | "lang.ini" | "lang.conf" | "lang.log" | "lang.csv" | "lang.tsv" | "lang.image" | "lang.pdf" | "lang.archive" | "lang.binary" | "tab.appearance" | "tab.model" | "tab.interaction" | "tab.context" | "tab.editing" | "tab.tools" | "tab.memory" | "tab.tasks" | "tab.providers";
9
+ export type SymbolKey = "status.success" | "status.error" | "status.warning" | "status.info" | "status.pending" | "status.disabled" | "status.enabled" | "status.running" | "status.shadowed" | "status.aborted" | "nav.cursor" | "nav.selected" | "nav.expand" | "nav.collapse" | "nav.back" | "tree.branch" | "tree.last" | "tree.vertical" | "tree.horizontal" | "tree.hook" | "boxRound.topLeft" | "boxRound.topRight" | "boxRound.bottomLeft" | "boxRound.bottomRight" | "boxRound.horizontal" | "boxRound.vertical" | "boxSharp.topLeft" | "boxSharp.topRight" | "boxSharp.bottomLeft" | "boxSharp.bottomRight" | "boxSharp.horizontal" | "boxSharp.vertical" | "boxSharp.cross" | "boxSharp.teeDown" | "boxSharp.teeUp" | "boxSharp.teeRight" | "boxSharp.teeLeft" | "sep.powerline" | "sep.powerlineThin" | "sep.powerlineLeft" | "sep.powerlineRight" | "sep.powerlineThinLeft" | "sep.powerlineThinRight" | "sep.block" | "sep.space" | "sep.asciiLeft" | "sep.asciiRight" | "sep.dot" | "sep.slash" | "sep.pipe" | "icon.model" | "icon.plan" | "icon.goal" | "icon.pause" | "icon.loop" | "icon.folder" | "icon.scratchFolder" | "icon.file" | "icon.git" | "icon.branch" | "icon.pr" | "icon.tokens" | "icon.context" | "icon.cost" | "icon.time" | "icon.pi" | "icon.agents" | "icon.cache" | "icon.input" | "icon.output" | "icon.host" | "icon.session" | "icon.package" | "icon.warning" | "icon.rewind" | "icon.auto" | "icon.fast" | "icon.extensionSkill" | "icon.extensionTool" | "icon.extensionSlashCommand" | "icon.extensionMcp" | "icon.extensionRule" | "icon.extensionHook" | "icon.extensionPrompt" | "icon.extensionContextFile" | "icon.extensionInstruction" | "icon.mic" | "thinking.minimal" | "thinking.low" | "thinking.medium" | "thinking.high" | "thinking.xhigh" | "thinking.autoPending" | "checkbox.checked" | "checkbox.unchecked" | "radio.selected" | "radio.unselected" | "format.bullet" | "format.dash" | "format.bracketLeft" | "format.bracketRight" | "md.quoteBorder" | "md.hrChar" | "md.bullet" | "md.colorSwatch" | "lang.default" | "lang.typescript" | "lang.javascript" | "lang.python" | "lang.rust" | "lang.go" | "lang.java" | "lang.c" | "lang.cpp" | "lang.csharp" | "lang.ruby" | "lang.php" | "lang.swift" | "lang.kotlin" | "lang.shell" | "lang.html" | "lang.css" | "lang.json" | "lang.yaml" | "lang.markdown" | "lang.sql" | "lang.docker" | "lang.lua" | "lang.text" | "lang.env" | "lang.toml" | "lang.xml" | "lang.ini" | "lang.conf" | "lang.log" | "lang.csv" | "lang.tsv" | "lang.image" | "lang.pdf" | "lang.archive" | "lang.binary" | "tab.appearance" | "tab.model" | "tab.interaction" | "tab.context" | "tab.editing" | "tab.tools" | "tab.memory" | "tab.tasks" | "tab.providers";
10
10
  export type SpinnerType = "status" | "activity";
11
11
  export type ThemeColor = "accent" | "border" | "borderAccent" | "borderMuted" | "success" | "error" | "warning" | "muted" | "dim" | "text" | "thinkingText" | "userMessageText" | "customMessageText" | "customMessageLabel" | "toolTitle" | "toolOutput" | "mdHeading" | "mdLink" | "mdLinkUrl" | "mdCode" | "mdCodeBlock" | "mdCodeBlockBorder" | "mdQuote" | "mdQuoteBorder" | "mdHr" | "mdListBullet" | "toolDiffAdded" | "toolDiffRemoved" | "toolDiffContext" | "syntaxComment" | "syntaxKeyword" | "syntaxFunction" | "syntaxVariable" | "syntaxString" | "syntaxNumber" | "syntaxType" | "syntaxOperator" | "syntaxPunctuation" | "thinkingOff" | "thinkingMinimal" | "thinkingLow" | "thinkingMedium" | "thinkingHigh" | "thinkingXhigh" | "bashMode" | "pythonMode" | "statusLineSep" | "statusLineModel" | "statusLinePath" | "statusLineGitClean" | "statusLineGitDirty" | "statusLineContext" | "statusLineSpend" | "statusLineStaged" | "statusLineDirty" | "statusLineUntracked" | "statusLineOutput" | "statusLineCost" | "statusLineSubagents";
12
12
  /** Check if a string is a valid ThemeColor value */
@@ -17,7 +17,22 @@ export declare class Theme {
17
17
  #private;
18
18
  private readonly mode;
19
19
  private readonly symbolPreset;
20
+ /**
21
+ * Perceptual luma (0..1) of the status-line background — used to classify the
22
+ * theme light/dark. Undefined when it can't be resolved. Classified against the
23
+ * status line (the surface session accents render on) rather than the chat bubble
24
+ * (`userMessageBg`), which some themes (e.g. `porcelain`) style dark on an
25
+ * otherwise-light theme.
26
+ */
27
+ readonly statusLineLuminance: number | undefined;
20
28
  constructor(fgColors: Record<ThemeColor, string | number>, bgColors: Record<ThemeBg, string | number>, mode: ColorMode, symbolPreset: SymbolPreset, symbolOverrides: Partial<Record<SymbolKey, string>>, spinnerFramesOverrides?: Partial<Record<SpinnerType, string[]>>);
29
+ /** True when the active theme has a light status-line background. */
30
+ get isLight(): boolean;
31
+ /**
32
+ * Surface luminance to size session accents against on light themes; undefined on
33
+ * dark themes so accents stay vivid. Pass straight to `getSessionAccentHex`.
34
+ */
35
+ get accentSurfaceLuminance(): number | undefined;
21
36
  fg(color: ThemeColor, text: string): string;
22
37
  bg(color: ThemeBg, text: string): string;
23
38
  bold(text: string): string;
@@ -167,6 +182,10 @@ export declare class Theme {
167
182
  checked: string;
168
183
  unchecked: string;
169
184
  };
185
+ get radio(): {
186
+ selected: string;
187
+ unselected: string;
188
+ };
170
189
  get format(): {
171
190
  bullet: string;
172
191
  dash: string;
@@ -12,4 +12,8 @@ export declare function matchesSelectCancel(data: string): boolean;
12
12
  export declare function matchesSelectUp(data: string): boolean;
13
13
  /** Match the generic selector down-navigation keybinding. */
14
14
  export declare function matchesSelectDown(data: string): boolean;
15
+ /** Match the generic selector page-up keybinding. */
16
+ export declare function matchesSelectPageUp(data: string): boolean;
17
+ /** Match the generic selector page-down keybinding. */
18
+ export declare function matchesSelectPageDown(data: string): boolean;
15
19
  export declare function matchesAppExternalEditor(data: string): boolean;
@@ -0,0 +1,20 @@
1
+ import { type LocalProtocolOptions } from "../internal-urls";
2
+ /** The session's active plan, resolved for handoff into a subagent's context. */
3
+ export interface OverallPlanReference {
4
+ /** The `local://` reference path (e.g. `local://my-feature.md`), kept for display. */
5
+ path: string;
6
+ /** The full plan markdown, as written to disk. */
7
+ content: string;
8
+ }
9
+ /**
10
+ * Load the session's active overall plan for subagent handoff.
11
+ *
12
+ * Returns the plan referenced by `planReferencePath` when it exists on disk with
13
+ * non-empty content, or `undefined` when there is no plan (the file is absent or
14
+ * empty). This mirrors `AgentSession.#buildPlanReferenceMessage`'s gating so a
15
+ * subagent sees exactly the plan the main agent treats as its active reference.
16
+ *
17
+ * Callers MUST skip this during plan mode itself — read-only plan exploration
18
+ * uses a different prompt and a draft plan should not be handed off as approved.
19
+ */
20
+ export declare function loadOverallPlanReference(planReferencePath: string, localProtocolOptions: LocalProtocolOptions): Promise<OverallPlanReference | undefined>;
@@ -43,7 +43,7 @@ import { type SecretObfuscator } from "../secrets/obfuscator";
43
43
  import { type ConfiguredThinkingLevel } from "../thinking";
44
44
  import { type DiscoverableTool, type DiscoverableToolSearchIndex } from "../tool-discovery/tool-index";
45
45
  import type { CheckpointState } from "../tools/checkpoint";
46
- import { type TodoItem, type TodoPhase } from "../tools/todo-write";
46
+ import { type TodoItem, type TodoPhase } from "../tools/todo";
47
47
  import type { ClientBridge } from "./client-bridge";
48
48
  import { type CustomMessage } from "./messages";
49
49
  import type { BranchSummaryEntry, NewSessionOptions, SessionContext, SessionManager } from "./session-manager";
@@ -313,6 +313,7 @@ export declare class AgentSession {
313
313
  peekQueueInvoker(): ((input: unknown) => Promise<unknown> | unknown) | undefined;
314
314
  peekStandingResolveHandler(): ((input: unknown) => Promise<unknown> | unknown) | undefined;
315
315
  setStandingResolveHandler(handler: ((input: unknown) => Promise<unknown> | unknown) | null): void;
316
+ setSessionSwitchReconciler(reconciler: (() => Promise<void>) | null): void;
316
317
  /** Provider-scoped mutable state store for transport/session caches. */
317
318
  get providerSessionState(): Map<string, ProviderSessionState>;
318
319
  getHindsightSessionState(): HindsightSessionState | undefined;
@@ -637,7 +638,9 @@ export declare class AgentSession {
637
638
  * Validates API key, saves to session log but NOT to settings.
638
639
  * @throws Error if no API key available for the model
639
640
  */
640
- setModelTemporary(model: Model, thinkingLevel?: ThinkingLevel): Promise<void>;
641
+ setModelTemporary(model: Model, thinkingLevel?: ThinkingLevel, options?: {
642
+ ephemeral?: boolean;
643
+ }): Promise<void>;
641
644
  /**
642
645
  * Cycle to next/previous model.
643
646
  * Uses scoped models (from --models flag) if available, otherwise all available models.
@@ -22,10 +22,9 @@ export declare class HistoryStorage {
22
22
  getRecent(limit: number): HistoryEntry[];
23
23
  search(query: string, limit: number): HistoryEntry[];
24
24
  /**
25
- * IDs of the sessions whose stored prompts match `query`, ordered by match
26
- * relevance (most relevant/recent first) and de-duplicated. Prompts with no
27
- * recorded session are skipped. Used to augment session ranking in the
28
- * resume picker with prompts that the 4KB session-list prefix never sees.
25
+ * IDs of the sessions whose stored prompts match `query`, ordered by prompt
26
+ * recency and de-duplicated. Used to augment session ranking in the resume
27
+ * picker with prompts that the 4KB session-list prefix never sees.
29
28
  */
30
29
  matchingSessionIds(query: string, limit?: number): string[];
31
30
  }
@@ -0,0 +1,59 @@
1
+ import type { SessionStorage, SessionStorageStat, SessionStorageWriter } from "./session-storage";
2
+ export interface SessionStorageIndexEntry {
3
+ path: string;
4
+ size: number;
5
+ mtimeMs: number;
6
+ }
7
+ export interface SessionStorageBackend {
8
+ init(): Promise<void>;
9
+ loadIndex(): Promise<Iterable<SessionStorageIndexEntry>>;
10
+ readFull(path: string): Promise<string | null>;
11
+ readSlices(path: string, prefixBytes: number, suffixBytes: number): Promise<[string, string]>;
12
+ writeFull(path: string, content: string, mtimeMs: number): Promise<void>;
13
+ append(path: string, line: string, mtimeMs: number): Promise<void>;
14
+ truncate(path: string, mtimeMs: number): Promise<void>;
15
+ remove(paths: string[]): Promise<void>;
16
+ move(src: string, dst: string, mtimeMs: number): Promise<void>;
17
+ }
18
+ export declare class IndexedSessionStorage implements SessionStorage {
19
+ #private;
20
+ constructor(backend: SessionStorageBackend);
21
+ initialize(): Promise<void>;
22
+ refresh(): Promise<void>;
23
+ drain(): Promise<void>;
24
+ ensureDirSync(_dir: string): void;
25
+ existsSync(path: string): boolean;
26
+ writeTextSync(path: string, content: string): void;
27
+ statSync(path: string): SessionStorageStat;
28
+ listFilesSync(dir: string, pattern: string): string[];
29
+ exists(path: string): Promise<boolean>;
30
+ readText(path: string): Promise<string>;
31
+ readTextSlices(path: string, prefixBytes: number, suffixBytes: number): Promise<[string, string]>;
32
+ writeText(path: string, content: string): Promise<void>;
33
+ rename(src: string, dst: string): Promise<void>;
34
+ unlink(path: string): Promise<void>;
35
+ deleteSessionWithArtifacts(sessionPath: string): Promise<void>;
36
+ openWriter(path: string, options?: {
37
+ flags?: "a" | "w";
38
+ onError?: (err: Error) => void;
39
+ }): SessionStorageWriter;
40
+ _writerClosed(writer: IndexedSessionStorageWriter): void;
41
+ _truncateForWriter(path: string): number;
42
+ _queueTruncate(path: string, mtimeMs: number, getError?: () => Error | undefined): Promise<void>;
43
+ _appendForWriter(path: string, line: string): number;
44
+ _queueAppend(path: string, line: string, mtimeMs: number, getError?: () => Error | undefined): Promise<void>;
45
+ }
46
+ declare class IndexedSessionStorageWriter implements SessionStorageWriter {
47
+ #private;
48
+ constructor(storage: IndexedSessionStorage, path: string, options?: {
49
+ flags?: "a" | "w";
50
+ onError?: (err: Error) => void;
51
+ });
52
+ writeLineSync(line: string): void;
53
+ writeLine(line: string): Promise<void>;
54
+ flush(): Promise<void>;
55
+ fsync(): Promise<void>;
56
+ close(): Promise<void>;
57
+ getError(): Error | undefined;
58
+ }
59
+ export {};
@@ -55,6 +55,7 @@ export declare const INTERNAL_DETAILS_FIELDS: readonly ["__pendingDisplayTag"];
55
55
  * (null/non-object, or no listed fields present) so callers don't pay a
56
56
  * clone cost on the common path. */
57
57
  export declare function stripInternalDetailsFields<T>(details: T | undefined): T | undefined;
58
+ export declare function wrapSteeringForModel(messages: AgentMessage[]): AgentMessage[];
58
59
  /**
59
60
  * Strip image content blocks from `message` in place. Returns the count of
60
61
  * images removed across `content` (every role that carries `ImageContent`) and