@oh-my-pi/pi-coding-agent 15.10.0 → 15.10.2

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 (238) hide show
  1. package/CHANGELOG.md +142 -1
  2. package/dist/types/cli/dry-balance-cli.d.ts +15 -1
  3. package/dist/types/cli/startup-cwd.d.ts +2 -0
  4. package/dist/types/commands/launch.d.ts +3 -0
  5. package/dist/types/commit/analysis/conventional.d.ts +2 -2
  6. package/dist/types/commit/analysis/summary.d.ts +2 -2
  7. package/dist/types/commit/changelog/generate.d.ts +2 -2
  8. package/dist/types/commit/changelog/index.d.ts +2 -2
  9. package/dist/types/commit/map-reduce/index.d.ts +3 -3
  10. package/dist/types/commit/map-reduce/map-phase.d.ts +2 -2
  11. package/dist/types/commit/map-reduce/reduce-phase.d.ts +2 -2
  12. package/dist/types/commit/model-selection.d.ts +10 -4
  13. package/dist/types/config/api-key-resolver.d.ts +34 -0
  14. package/dist/types/config/keybindings.d.ts +2 -2
  15. package/dist/types/config/model-provider-priority.d.ts +1 -0
  16. package/dist/types/config/model-registry.d.ts +17 -1
  17. package/dist/types/config/model-resolver.d.ts +4 -1
  18. package/dist/types/config/settings-schema.d.ts +9 -0
  19. package/dist/types/config/settings.d.ts +7 -2
  20. package/dist/types/dap/config.d.ts +14 -1
  21. package/dist/types/dap/types.d.ts +10 -0
  22. package/dist/types/debug/report-bundle.d.ts +3 -0
  23. package/dist/types/edit/file-snapshot-store.d.ts +18 -10
  24. package/dist/types/eval/py/__tests__/prelude.test.d.ts +1 -0
  25. package/dist/types/extensibility/extensions/types.d.ts +4 -1
  26. package/dist/types/lsp/client.d.ts +10 -0
  27. package/dist/types/lsp/utils.d.ts +3 -2
  28. package/dist/types/main.d.ts +3 -9
  29. package/dist/types/mcp/tool-bridge.d.ts +2 -0
  30. package/dist/types/modes/components/chat-block.d.ts +64 -0
  31. package/dist/types/modes/components/custom-editor.d.ts +4 -1
  32. package/dist/types/modes/components/overlay-box.d.ts +17 -0
  33. package/dist/types/modes/components/plan-review-overlay.d.ts +59 -0
  34. package/dist/types/modes/components/plan-toc.d.ts +41 -0
  35. package/dist/types/modes/components/read-tool-group.d.ts +2 -0
  36. package/dist/types/modes/components/status-line.d.ts +2 -0
  37. package/dist/types/modes/components/transcript-container.d.ts +11 -0
  38. package/dist/types/modes/controllers/command-controller.d.ts +1 -0
  39. package/dist/types/modes/controllers/event-controller.d.ts +17 -1
  40. package/dist/types/modes/controllers/extension-ui-controller.d.ts +0 -1
  41. package/dist/types/modes/controllers/input-controller.d.ts +1 -1
  42. package/dist/types/modes/controllers/streaming-reveal.d.ts +22 -0
  43. package/dist/types/modes/controllers/tan-command-controller.d.ts +6 -0
  44. package/dist/types/modes/interactive-mode.d.ts +16 -5
  45. package/dist/types/modes/magic-keywords.d.ts +1 -1
  46. package/dist/types/modes/markdown-prose.d.ts +1 -1
  47. package/dist/types/modes/theme/theme.d.ts +1 -1
  48. package/dist/types/modes/types.d.ts +21 -5
  49. package/dist/types/modes/utils/copy-targets.d.ts +21 -1
  50. package/dist/types/modes/workflow.d.ts +3 -3
  51. package/dist/types/plan-mode/approved-plan.d.ts +27 -8
  52. package/dist/types/plan-mode/plan-protection.d.ts +4 -4
  53. package/dist/types/sdk.d.ts +2 -0
  54. package/dist/types/session/agent-session.d.ts +21 -0
  55. package/dist/types/session/auth-storage.d.ts +1 -1
  56. package/dist/types/session/messages.d.ts +12 -0
  57. package/dist/types/session/session-manager.d.ts +8 -3
  58. package/dist/types/slash-commands/types.d.ts +4 -6
  59. package/dist/types/task/executor.d.ts +17 -0
  60. package/dist/types/task/index.d.ts +1 -0
  61. package/dist/types/task/render.d.ts +3 -2
  62. package/dist/types/tools/archive-reader.d.ts +5 -0
  63. package/dist/types/tools/ast-edit.d.ts +3 -0
  64. package/dist/types/tools/ast-grep.d.ts +3 -0
  65. package/dist/types/tools/bash.d.ts +1 -0
  66. package/dist/types/tools/eval.d.ts +8 -0
  67. package/dist/types/tools/find.d.ts +8 -4
  68. package/dist/types/tools/gh-cache-invalidation.d.ts +6 -0
  69. package/dist/types/tools/github-cache.d.ts +12 -0
  70. package/dist/types/tools/grouped-file-output.d.ts +95 -12
  71. package/dist/types/tools/memory-render.d.ts +4 -1
  72. package/dist/types/tools/path-utils.d.ts +8 -0
  73. package/dist/types/tools/plan-mode-guard.d.ts +8 -9
  74. package/dist/types/tools/render-utils.d.ts +5 -9
  75. package/dist/types/tools/search.d.ts +6 -2
  76. package/dist/types/tools/sqlite-reader.d.ts +1 -0
  77. package/dist/types/tools/todo.d.ts +3 -2
  78. package/dist/types/tools/write.d.ts +3 -0
  79. package/dist/types/tools/yield.d.ts +8 -0
  80. package/dist/types/tui/output-block.d.ts +16 -4
  81. package/dist/types/tui/status-line.d.ts +3 -0
  82. package/dist/types/utils/enhanced-paste.d.ts +20 -0
  83. package/dist/types/web/search/providers/kimi.d.ts +1 -1
  84. package/package.json +9 -9
  85. package/src/auto-thinking/classifier.ts +5 -1
  86. package/src/cli/args.ts +3 -1
  87. package/src/cli/dry-balance-cli.ts +54 -21
  88. package/src/cli/gallery-cli.ts +4 -1
  89. package/src/cli/gallery-fixtures/misc.ts +29 -0
  90. package/src/cli/startup-cwd.ts +68 -0
  91. package/src/commands/launch.ts +3 -0
  92. package/src/commit/analysis/conventional.ts +2 -2
  93. package/src/commit/analysis/summary.ts +2 -2
  94. package/src/commit/changelog/generate.ts +2 -2
  95. package/src/commit/changelog/index.ts +2 -2
  96. package/src/commit/map-reduce/index.ts +3 -3
  97. package/src/commit/map-reduce/map-phase.ts +2 -2
  98. package/src/commit/map-reduce/reduce-phase.ts +2 -2
  99. package/src/commit/model-selection.ts +36 -11
  100. package/src/commit/pipeline.ts +4 -4
  101. package/src/config/api-key-resolver.ts +58 -0
  102. package/src/config/model-provider-priority.ts +55 -0
  103. package/src/config/model-registry.ts +29 -24
  104. package/src/config/model-resolver.ts +39 -7
  105. package/src/config/settings-schema.ts +10 -0
  106. package/src/config/settings.ts +106 -43
  107. package/src/dap/config.ts +41 -2
  108. package/src/dap/defaults.json +1 -0
  109. package/src/dap/session.ts +1 -0
  110. package/src/dap/types.ts +10 -0
  111. package/src/debug/index.ts +47 -53
  112. package/src/debug/raw-sse-buffer.ts +7 -4
  113. package/src/debug/report-bundle.ts +9 -0
  114. package/src/edit/file-snapshot-store.ts +33 -1
  115. package/src/edit/hashline/filesystem.ts +2 -1
  116. package/src/edit/renderer.ts +82 -78
  117. package/src/eval/__tests__/llm-bridge.test.ts +110 -31
  118. package/src/eval/js/context-manager.ts +32 -15
  119. package/src/eval/llm-bridge.ts +22 -6
  120. package/src/eval/py/__tests__/prelude.test.ts +19 -0
  121. package/src/eval/py/executor.ts +23 -11
  122. package/src/eval/py/prelude.py +1 -1
  123. package/src/extensibility/extensions/types.ts +10 -1
  124. package/src/goals/tools/goal-tool.ts +36 -26
  125. package/src/internal-urls/docs-index.generated.ts +8 -8
  126. package/src/lsp/client.ts +23 -11
  127. package/src/lsp/config.ts +11 -1
  128. package/src/lsp/index.ts +61 -9
  129. package/src/lsp/utils.ts +3 -2
  130. package/src/main.ts +100 -72
  131. package/src/mcp/tool-bridge.ts +2 -0
  132. package/src/memories/index.ts +14 -7
  133. package/src/mnemopi/backend.ts +5 -1
  134. package/src/modes/acp/acp-agent.ts +33 -26
  135. package/src/modes/components/assistant-message.ts +2 -9
  136. package/src/modes/components/chat-block.ts +111 -0
  137. package/src/modes/components/copy-selector.ts +1 -44
  138. package/src/modes/components/custom-editor.ts +164 -109
  139. package/src/modes/components/custom-message.ts +1 -3
  140. package/src/modes/components/execution-shared.ts +1 -2
  141. package/src/modes/components/hook-message.ts +1 -3
  142. package/src/modes/components/model-selector.ts +59 -13
  143. package/src/modes/components/oauth-selector.ts +33 -7
  144. package/src/modes/components/overlay-box.ts +108 -0
  145. package/src/modes/components/plan-review-overlay.ts +799 -0
  146. package/src/modes/components/plan-toc.ts +138 -0
  147. package/src/modes/components/read-tool-group.ts +20 -4
  148. package/src/modes/components/skill-message.ts +0 -1
  149. package/src/modes/components/status-line.ts +19 -4
  150. package/src/modes/components/tips.txt +2 -1
  151. package/src/modes/components/todo-reminder.ts +0 -2
  152. package/src/modes/components/tool-execution.ts +68 -88
  153. package/src/modes/components/transcript-container.ts +84 -24
  154. package/src/modes/components/user-message.ts +2 -3
  155. package/src/modes/controllers/command-controller-shared.ts +7 -6
  156. package/src/modes/controllers/command-controller.ts +57 -55
  157. package/src/modes/controllers/event-controller.ts +67 -40
  158. package/src/modes/controllers/extension-ui-controller.ts +10 -73
  159. package/src/modes/controllers/input-controller.ts +170 -126
  160. package/src/modes/controllers/mcp-command-controller.ts +69 -60
  161. package/src/modes/controllers/selector-controller.ts +23 -25
  162. package/src/modes/controllers/streaming-reveal.ts +212 -0
  163. package/src/modes/controllers/tan-command-controller.ts +173 -0
  164. package/src/modes/interactive-mode.ts +274 -112
  165. package/src/modes/magic-keywords.ts +1 -1
  166. package/src/modes/markdown-prose.ts +1 -1
  167. package/src/modes/setup-wizard/wizard-overlay.ts +1 -1
  168. package/src/modes/theme/shimmer.ts +20 -9
  169. package/src/modes/theme/theme-schema.json +1 -1
  170. package/src/modes/theme/theme.ts +8 -4
  171. package/src/modes/types.ts +21 -7
  172. package/src/modes/utils/copy-targets.ts +133 -27
  173. package/src/modes/utils/ui-helpers.ts +44 -46
  174. package/src/modes/workflow.ts +10 -10
  175. package/src/plan-mode/approved-plan.ts +66 -43
  176. package/src/plan-mode/plan-protection.ts +4 -4
  177. package/src/prompts/system/background-tan-dispatch.md +8 -0
  178. package/src/prompts/system/plan-mode-active.md +67 -58
  179. package/src/prompts/system/plan-mode-approved.md +1 -1
  180. package/src/prompts/system/workflow-notice.md +1 -1
  181. package/src/prompts/tools/bash.md +9 -0
  182. package/src/prompts/tools/browser.md +1 -1
  183. package/src/prompts/tools/eval.md +2 -1
  184. package/src/prompts/tools/read.md +2 -2
  185. package/src/sdk.ts +37 -46
  186. package/src/session/agent-session.ts +119 -18
  187. package/src/session/auth-storage.ts +2 -0
  188. package/src/session/messages.ts +26 -0
  189. package/src/session/session-manager.ts +109 -28
  190. package/src/slash-commands/builtin-registry.ts +36 -9
  191. package/src/slash-commands/types.ts +4 -6
  192. package/src/task/executor.ts +76 -38
  193. package/src/task/index.ts +4 -0
  194. package/src/task/render.ts +211 -147
  195. package/src/tools/archive-reader.ts +64 -0
  196. package/src/tools/ask.ts +119 -164
  197. package/src/tools/ast-edit.ts +98 -71
  198. package/src/tools/ast-grep.ts +37 -43
  199. package/src/tools/bash.ts +57 -6
  200. package/src/tools/browser/tab-supervisor.ts +13 -1
  201. package/src/tools/browser/tab-worker.ts +33 -4
  202. package/src/tools/debug.ts +20 -8
  203. package/src/tools/eval.ts +13 -2
  204. package/src/tools/fetch.ts +297 -7
  205. package/src/tools/find.ts +51 -30
  206. package/src/tools/gh-cache-invalidation.ts +200 -0
  207. package/src/tools/gh-renderer.ts +81 -42
  208. package/src/tools/github-cache.ts +25 -0
  209. package/src/tools/grouped-file-output.ts +272 -48
  210. package/src/tools/image-gen.ts +150 -103
  211. package/src/tools/inspect-image-renderer.ts +63 -41
  212. package/src/tools/inspect-image.ts +10 -3
  213. package/src/tools/job.ts +3 -4
  214. package/src/tools/memory-render.ts +4 -1
  215. package/src/tools/path-utils.ts +28 -2
  216. package/src/tools/plan-mode-guard.ts +66 -39
  217. package/src/tools/read.ts +48 -28
  218. package/src/tools/render-utils.ts +21 -37
  219. package/src/tools/resolve.ts +14 -0
  220. package/src/tools/search-tool-bm25.ts +36 -23
  221. package/src/tools/search.ts +118 -81
  222. package/src/tools/sqlite-reader.ts +9 -12
  223. package/src/tools/todo.ts +118 -52
  224. package/src/tools/write.ts +83 -64
  225. package/src/tools/yield.ts +10 -1
  226. package/src/tui/output-block.ts +60 -13
  227. package/src/tui/status-line.ts +5 -1
  228. package/src/utils/commit-message-generator.ts +11 -3
  229. package/src/utils/enhanced-paste.ts +230 -0
  230. package/src/utils/title-generator.ts +2 -1
  231. package/src/web/search/providers/anthropic.ts +25 -19
  232. package/src/web/search/providers/codex.ts +37 -8
  233. package/src/web/search/providers/exa.ts +11 -3
  234. package/src/web/search/providers/kimi.ts +28 -17
  235. package/src/web/search/providers/parallel.ts +35 -24
  236. package/src/web/search/providers/synthetic.ts +8 -6
  237. package/src/web/search/providers/tavily.ts +9 -8
  238. package/src/web/search/providers/zai.ts +8 -6
@@ -1,13 +1,3 @@
1
- /**
2
- * Session-bound file snapshot store.
3
- *
4
- * Used by `read` and `search` to record exactly what the model saw, and by
5
- * the hashline patcher to verify or recover from stale section tags (file
6
- * changed externally between read and edit, or a prior in-session edit
7
- * advanced the tag). The store is the {@link InMemorySnapshotStore}
8
- * from `@oh-my-pi/hashline`; the only coding-agent-specific concern here
9
- * is wiring it onto the per-session owner object.
10
- */
11
1
  import { InMemorySnapshotStore } from "@oh-my-pi/hashline";
12
2
  /**
13
3
  * Upper bound on the file size we snapshot. A section tag is a content hash of
@@ -25,6 +15,24 @@ interface FileSnapshotStoreOwner {
25
15
  * the session itself.
26
16
  */
27
17
  export declare function getFileSnapshotStore(session: FileSnapshotStoreOwner): InMemorySnapshotStore;
18
+ /**
19
+ * Canonicalize an absolute path into the stable key the snapshot store uses.
20
+ *
21
+ * Different code paths reach the snapshot store via different path forms:
22
+ * `read local://foo.md` records under the file's `fs.realpath` (the local
23
+ * protocol handler resolves symlinks); a subsequent `edit` may address the
24
+ * same artifact via `local://foo.md`, whose resolver does NOT realpath, or
25
+ * via the absolute path returned in the `[path#tag]` header. macOS adds the
26
+ * same hazard at the working-tree level (`/tmp/...` vs `/private/tmp/...`).
27
+ * Collapsing every key through `realpath` makes those forms fuse onto one
28
+ * snapshot entry, so a freshly-minted tag is never rejected as stale just
29
+ * because the lookup spelled the same file differently.
30
+ *
31
+ * Non-existent paths (new-file writes) fall back to a realpath of the parent
32
+ * directory + basename, then to the input. This keeps creates and updates on
33
+ * the same canonical key.
34
+ */
35
+ export declare function canonicalSnapshotKey(absolutePath: string): string;
28
36
  /**
29
37
  * Read the full text of `absolutePath` (within {@link SNAPSHOT_MAX_BYTES}),
30
38
  * record it as a version snapshot, and return its content-hash tag. Returns
@@ -0,0 +1 @@
1
+ export {};
@@ -7,7 +7,7 @@
7
7
  * - Register commands, keyboard shortcuts, and CLI flags
8
8
  * - Interact with the user via UI primitives
9
9
  */
10
- import type { AgentMessage, AgentToolResult, AgentToolUpdateCallback, ThinkingLevel } from "@oh-my-pi/pi-agent-core";
10
+ import type { AgentMessage, AgentToolResult, AgentToolUpdateCallback, ThinkingLevel, ToolApproval } from "@oh-my-pi/pi-agent-core";
11
11
  import type { CompactionResult } from "@oh-my-pi/pi-agent-core/compaction";
12
12
  import type { Api, AssistantMessageEvent, AssistantMessageEventStream, Context, ImageContent, Model, ProviderResponseMetadata, SimpleStreamOptions, Static, TextContent, TSchema } from "@oh-my-pi/pi-ai";
13
13
  import type { OAuthCredentials, OAuthLoginCallbacks } from "@oh-my-pi/pi-ai/utils/oauth/types";
@@ -270,6 +270,9 @@ export interface ToolDefinition<TParams extends TSchema = TSchema, TDetails = un
270
270
  defaultInactive?: boolean;
271
271
  /** If true, tool may stage deferred changes that require explicit resolve/discard. */
272
272
  deferrable?: boolean;
273
+ /** Tool approval tier. Defaults to `"exec"` when omitted.
274
+ * `"read"`: read-only operations. `"write"`: mutations. `"exec"`: code execution. */
275
+ approval?: ToolApproval;
273
276
  /** MCP server name for discovery/search metadata when this tool fronts an MCP server. */
274
277
  mcpServerName?: string;
275
278
  /** Original MCP tool name for discovery/search metadata. */
@@ -45,6 +45,16 @@ export declare function refreshFile(client: LspClient, filePath: string, signal?
45
45
  export declare function shutdownClient(key: string): Promise<void>;
46
46
  /**
47
47
  * Send an LSP request and wait for response.
48
+ *
49
+ * Timeout policy:
50
+ * - If `timeoutMs` is explicitly provided, that value is used.
51
+ * - Else, if `signal` is provided, no internal timer is installed (the caller
52
+ * owns the deadline via the signal — typically a wall-clock `AbortSignal.timeout`
53
+ * from the LSP tool). Installing a second hard-coded 30s timer here used to
54
+ * cause "timed out after 30000ms" errors even when the caller had requested
55
+ * `timeout: 60`.
56
+ * - Else (no signal, no explicit timeout), fall back to `DEFAULT_REQUEST_TIMEOUT_MS`
57
+ * to avoid leaking pending requests forever.
48
58
  */
49
59
  export declare function sendRequest(client: LspClient, method: string, params: unknown, signal?: AbortSignal, timeoutMs?: number): Promise<unknown>;
50
60
  /**
@@ -28,9 +28,10 @@ export declare function severityToIcon(severity?: DiagnosticSeverity): string;
28
28
  */
29
29
  export declare function formatDiagnostic(diagnostic: Diagnostic, filePath: string): string;
30
30
  /**
31
- * Reformat pre-formatted diagnostic messages into grep-style directory/file groups.
31
+ * Reformat pre-formatted diagnostic messages into a multi-level, prefix-folded
32
+ * directory/file grouping (see `formatGroupedFiles`).
32
33
  * Input: ["path:line:col [sev] msg", ...]
33
- * Output: "# dir/\n## file.ts\n line:col [sev] msg"
34
+ * Output: "# pkg/src/\n## file.ts\n line:col [sev] msg"
34
35
  *
35
36
  * Messages that don't match the expected format are appended ungrouped at the end.
36
37
  */
@@ -1,9 +1,3 @@
1
- /**
2
- * Main entry point for the coding agent CLI.
3
- *
4
- * This file handles CLI argument parsing and translates them into
5
- * createAgentSession() options. The SDK does the heavy lifting.
6
- */
7
1
  import type { Args } from "./cli/args";
8
2
  import { ModelRegistry } from "./config/model-registry";
9
3
  import { Settings } from "./config/settings";
@@ -41,10 +35,10 @@ export interface AcpSessionFactoryOptions {
41
35
  * tool registry and shadow the client-supplied servers (issue #1234).
42
36
  */
43
37
  export declare function createAcpSessionFactory(args: AcpSessionFactoryOptions): AcpSessionFactory;
44
- type ForkSessionPromptResult = "accepted" | "declined" | "unavailable";
45
- type ForkSessionPrompt = (session: SessionInfo) => Promise<ForkSessionPromptResult>;
38
+ type SessionPromptResult = "accepted" | "declined" | "unavailable";
39
+ type SessionPrompt = (session: SessionInfo) => Promise<SessionPromptResult>;
46
40
  /** Resolves CLI session flags into an existing, forked, in-memory, or cancelled session manager. */
47
- export declare function createSessionManager(parsed: Args, cwd: string, activeSettings?: Settings, askToForkSession?: ForkSessionPrompt): Promise<SessionManager | undefined>;
41
+ export declare function createSessionManager(parsed: Args, cwd: string, activeSettings?: Settings, askToForkSession?: SessionPrompt, askToMoveSession?: SessionPrompt): Promise<SessionManager | undefined>;
48
42
  interface RunRootCommandDependencies {
49
43
  createAgentSession?: typeof createAgentSession;
50
44
  discoverAuthStorage?: typeof discoverAuthStorage;
@@ -53,6 +53,7 @@ export declare class MCPTool implements CustomTool<TSchema, MCPToolDetails> {
53
53
  readonly mcpToolName: string;
54
54
  /** Server name */
55
55
  readonly mcpServerName: string;
56
+ readonly approval: "write";
56
57
  /** Render completed MCP calls with the result header replacing the pending call header. */
57
58
  readonly mergeCallAndResult = true;
58
59
  /** Create MCPTool instances for all tools from an MCP server connection */
@@ -79,6 +80,7 @@ export declare class DeferredMCPTool implements CustomTool<TSchema, MCPToolDetai
79
80
  readonly mcpToolName: string;
80
81
  /** Server name */
81
82
  readonly mcpServerName: string;
83
+ readonly approval: "write";
82
84
  /** Render completed MCP calls with the result header replacing the pending call header. */
83
85
  readonly mergeCallAndResult = true;
84
86
  /** Create DeferredMCPTool instances for all tools from an MCP server */
@@ -0,0 +1,64 @@
1
+ import { Container } from "@oh-my-pi/pi-tui";
2
+ /**
3
+ * Capabilities a mounted {@link ChatBlock} may use against its host transcript.
4
+ * Kept minimal so blocks never reach into the full TUI/InteractiveMode surface.
5
+ */
6
+ export interface ChatBlockHost {
7
+ /** Schedule a repaint of the transcript. */
8
+ requestRender(): void;
9
+ }
10
+ /**
11
+ * Lifecycle-aware transcript block — the "return a block, let the host mount it"
12
+ * primitive, modelled on React/Svelte component lifecycles.
13
+ *
14
+ * Producers build and return a `ChatBlock` instead of poking `chatContainer` and
15
+ * `ui.requestRender()` directly. The host (`ctx.present`) appends it and calls
16
+ * {@link mount}, which runs {@link onMount}; effects started there register
17
+ * teardown via {@link onCleanup}. The block repaints through {@link requestRender}
18
+ * — never touching the TUI — and tears down exactly once on {@link finish}
19
+ * (self-complete: stop the animation, keep the final frame in the transcript) or
20
+ * {@link dispose} (host discards it, e.g. a transcript reset).
21
+ *
22
+ * While mounted and unfinished a block reports `isTranscriptBlockFinalized() ===
23
+ * false` so {@link "../components/transcript-container".TranscriptContainer}
24
+ * keeps it in the live, repaintable region on ED3-risk terminals; after
25
+ * `finish()`/`dispose()` it reports `true` and freezes at its final content.
26
+ */
27
+ export declare abstract class ChatBlock extends Container {
28
+ #private;
29
+ /**
30
+ * Run setup after the block is in the transcript: start timers/subscriptions
31
+ * and register their teardown with {@link onCleanup}. Default: no-op (a block
32
+ * whose content is fixed at construction needs no mount work).
33
+ */
34
+ protected onMount(): void;
35
+ /**
36
+ * Register a teardown to run on {@link finish}/{@link dispose}, à la a
37
+ * `useEffect` cleanup. If the block is already disposed the cleanup runs
38
+ * immediately so callers never leak.
39
+ */
40
+ protected onCleanup(cleanup: () => void): void;
41
+ /** Ask the host to repaint. No-op before mount or after dispose. */
42
+ protected requestRender(): void;
43
+ /** True between {@link mount} and {@link finish}/{@link dispose}. */
44
+ protected get active(): boolean;
45
+ /**
46
+ * Host-only: attach the host and run {@link onMount}. Idempotent — a second
47
+ * call (e.g. a transcript rebuild that re-presents the same instance) is a
48
+ * no-op.
49
+ */
50
+ mount(host: ChatBlockHost): void;
51
+ /**
52
+ * Self-complete: stop ongoing effects and freeze the block at its current
53
+ * content, leaving it rendered in the transcript. Use when the operation the
54
+ * block represents finishes (connection resolved, download done).
55
+ */
56
+ finish(): void;
57
+ /**
58
+ * Host-only teardown: release everything and propagate to children. Called
59
+ * when the host permanently discards the block (transcript reset). Idempotent.
60
+ */
61
+ dispose(): void;
62
+ /** Live blocks stay repaintable; finished/disposed ones may freeze. */
63
+ isTranscriptBlockFinalized(): boolean;
64
+ }
@@ -1,13 +1,14 @@
1
1
  import { Editor, type KeyId } from "@oh-my-pi/pi-tui";
2
2
  import type { AppKeybinding } from "../../config/keybindings";
3
3
  type ConfigurableEditorAction = Extract<AppKeybinding, "app.interrupt" | "app.clear" | "app.exit" | "app.suspend" | "app.display.reset" | "app.thinking.cycle" | "app.model.cycleForward" | "app.model.cycleBackward" | "app.model.select" | "app.model.selectTemporary" | "app.tools.expand" | "app.thinking.toggle" | "app.editor.external" | "app.history.search" | "app.message.dequeue" | "app.clipboard.pasteImage" | "app.clipboard.pasteTextRaw" | "app.clipboard.copyPrompt">;
4
+ export declare function extractBracketedImagePastePath(data: string): string | undefined;
4
5
  /**
5
6
  * Custom editor that handles configurable app-level shortcuts for coding-agent.
6
7
  */
7
8
  export declare class CustomEditor extends Editor {
8
9
  #private;
9
10
  imageLinks?: readonly (string | undefined)[];
10
- /** Gradient-highlight the "ultrathink" / "orchestrate" / "workflow" keywords as the user types
11
+ /** Gradient-highlight the "ultrathink" / "orchestrate" / "workflowz" keywords as the user types
11
12
  * them, skipping any occurrence inside code spans, fenced blocks, or XML sections. Also make
12
13
  * pasted image placeholders visually distinct and hyperlink them once their blob file exists. */
13
14
  decorateText: (text: string) => string;
@@ -29,6 +30,8 @@ export declare class CustomEditor extends Editor {
29
30
  onCopyPrompt?: () => void;
30
31
  /** Called when the configured image-paste shortcut is pressed. */
31
32
  onPasteImage?: () => Promise<boolean>;
33
+ /** Called when a bracketed paste contains exactly one image-file path. */
34
+ onPasteImagePath?: (path: string) => void;
32
35
  /** Called when the configured raw text-paste shortcut is pressed. */
33
36
  onPasteTextRaw?: () => void;
34
37
  /** Called when the configured dequeue shortcut is pressed. */
@@ -0,0 +1,17 @@
1
+ /** Pad or truncate a (possibly ANSI-styled) string to exactly `width` columns. */
2
+ export declare function fit(text: string, width: number): string;
3
+ /** Top border with an optional accent-colored title inset into the rule. */
4
+ export declare function topBorder(width: number, title: string): string;
5
+ /** A horizontal rule with left/right tees, splitting overlay sections. */
6
+ export declare function divider(width: number): string;
7
+ export declare function bottomBorder(width: number): string;
8
+ /** Wrap pre-styled content in vertical borders with single-column insets. */
9
+ export declare function row(content: string, width: number): string;
10
+ /** Body content width for a two-column overlay of total `width`. */
11
+ export declare function splitBodyWidth(width: number, sidebarWidth: number): number;
12
+ /** Top border carrying the title, split by a `┬` over the column divider. */
13
+ export declare function topBorderSplit(width: number, title: string, sidebarWidth: number): string;
14
+ /** Section rule that closes the sidebar column with a `┴` over the divider. */
15
+ export declare function dividerSplit(width: number, sidebarWidth: number): string;
16
+ /** A two-column content row: `│ sidebar │ body │`, each inset by one column. */
17
+ export declare function splitRow(sidebar: string, body: string, width: number, sidebarWidth: number): string;
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Fullscreen plan-review overlay. The overlay owns its entire content: the plan
3
+ * is split into sections (preamble + one per heading), each rendered through its
4
+ * own {@link Markdown} and windowed by a {@link ScrollView}, while the approval
5
+ * options (plus the optional model-tier slider) sit beneath inside the same
6
+ * outlined box — one self-contained surface in the spirit of the `/copy` picker.
7
+ *
8
+ * When the terminal is wide enough and the plan has ≥2 headings, a Contents
9
+ * sidebar appears: it tracks the scrolled section with an accent "glow", and —
10
+ * when focused — lets the operator jump between sections, delete a section
11
+ * (with undo), and annotate sections with feedback that feeds the Refine loop.
12
+ *
13
+ * Focus regions (`toc`/`body`/`actions`) cycle with Tab/Shift+Tab; arrows move
14
+ * within the focused region and step left into the sidebar. The default focus is
15
+ * `actions`, so the muscle memory of the old single-target overlay carries over:
16
+ * ↑/↓ select options, Enter confirms, ←/→ drives the slider when there is no
17
+ * sidebar, g/G + PgUp/PgDn scroll, and the external-editor key opens the plan.
18
+ */
19
+ import { type Component } from "@oh-my-pi/pi-tui";
20
+ import type { HookSelectorSlider } from "./hook-selector";
21
+ export interface PlanReviewOverlayCallbacks {
22
+ /** Invoked with the chosen option label (never a disabled one). */
23
+ onPick: (label: string) => void;
24
+ /** Invoked on Esc / cancel. */
25
+ onCancel: () => void;
26
+ /** Invoked when the external-editor key is pressed (overlay stays open). */
27
+ onExternalEditor?: () => void;
28
+ /** Invoked with the new full plan text after an in-overlay delete/undo. */
29
+ onPlanEdited?: (content: string) => void;
30
+ /** Invoked with the Refine feedback markdown whenever annotations change. */
31
+ onFeedbackChange?: (feedback: string) => void;
32
+ }
33
+ export interface PlanReviewOverlayOptions {
34
+ /** Prompt rendered above the options (e.g. "Plan mode - next step"). */
35
+ promptTitle?: string;
36
+ options: string[];
37
+ /** Indices into `options` that render dimmed and cannot be selected. */
38
+ disabledIndices?: number[];
39
+ /** Trailing footer hint (cancel hint); the overlay prepends dynamic help. */
40
+ helpText?: string;
41
+ /** Initially highlighted option index. */
42
+ initialIndex?: number;
43
+ /** Optional model-tier slider rendered between the plan body and options. */
44
+ slider?: HookSelectorSlider;
45
+ /** Display label for the external-editor key, surfaced in the footer help. */
46
+ externalEditorLabel?: string;
47
+ }
48
+ export declare class PlanReviewOverlay implements Component {
49
+ #private;
50
+ private readonly callbacks;
51
+ constructor(planContent: string, options: PlanReviewOverlayOptions, callbacks: PlanReviewOverlayCallbacks);
52
+ invalidate(): void;
53
+ /** Swap the displayed plan (e.g. after an external-editor round-trip) and
54
+ * reset scroll/focus so the operator starts at the top. Does not emit
55
+ * `onPlanEdited` (the editor round-trip already persisted the file). */
56
+ setPlanContent(planContent: string): void;
57
+ handleInput(keyData: string): void;
58
+ render(width: number): string[];
59
+ }
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Pure heading/section parser for the plan-review overlay. It splits a plan's
3
+ * markdown into a flat list of sections — a leading preamble (text before the
4
+ * first heading) followed by one entry per ATX heading — preserving the exact
5
+ * source bytes of each section so the overlay can render, reorder-free delete,
6
+ * and round-trip the document without a full markdown re-render.
7
+ *
8
+ * No TUI dependencies: this module is unit-tested in isolation.
9
+ */
10
+ export interface PlanSection {
11
+ /** `0` = preamble (no heading, no ToC entry); `1..6` = heading depth. */
12
+ level: number;
13
+ /** Plain-text heading label with inline markdown lightly stripped. */
14
+ title: string;
15
+ /** Exact source slice for this section, including its trailing newline(s). */
16
+ raw: string;
17
+ }
18
+ /**
19
+ * Collapse inline markdown emphasis/link/code syntax to readable text. This is
20
+ * a deliberately light strip (not a full markdown render) just so ToC entries
21
+ * read cleanly — `**Goal** & [docs](x)` becomes `Goal & docs`.
22
+ */
23
+ export declare function stripInlineMarkdown(text: string): string;
24
+ /**
25
+ * Split `text` into preamble + heading sections. `#` characters inside fenced
26
+ * code blocks are never treated as headings. Concatenating every section's
27
+ * `raw` reproduces the original text exactly.
28
+ */
29
+ export declare function parsePlanSections(text: string): PlanSection[];
30
+ /**
31
+ * Concatenate every section's `raw` back into a single document and guarantee a
32
+ * single trailing newline. Inverse of {@link parsePlanSections} for any input
33
+ * that already ends with a newline.
34
+ */
35
+ export declare function joinPlanSections(sections: readonly PlanSection[]): string;
36
+ /**
37
+ * Indices to remove when deleting `sections[index]`: the heading itself plus
38
+ * every following section nested deeper than it (its sub-headings). The
39
+ * preamble (level 0) is never a deletion target and yields an empty span.
40
+ */
41
+ export declare function sectionDeletionSpan(sections: readonly PlanSection[], index: number): number[];
@@ -14,6 +14,8 @@ type ReadToolGroupOptions = {
14
14
  export declare class ReadToolGroupComponent extends Container implements ToolExecutionHandle {
15
15
  #private;
16
16
  constructor(options?: ReadToolGroupOptions);
17
+ isTranscriptBlockFinalized(): boolean;
18
+ finalize(): void;
17
19
  updateArgs(args: ReadRenderArgs, toolCallId?: string): void;
18
20
  updateResult(result: {
19
21
  content: Array<{
@@ -30,11 +30,13 @@ export interface StatusLineSettings {
30
30
  showHookStatus?: boolean;
31
31
  sessionAccent?: boolean;
32
32
  }
33
+ export type EffectiveStatusLineSettings = Required<Pick<StatusLineSettings, "leftSegments" | "rightSegments" | "separator" | "segmentOptions">> & StatusLineSettings;
33
34
  export declare class StatusLineComponent implements Component {
34
35
  #private;
35
36
  private readonly session;
36
37
  constructor(session: AgentSession);
37
38
  updateSettings(settings: StatusLineSettings): void;
39
+ getEffectiveSettingsForTest(): EffectiveStatusLineSettings;
38
40
  setAutoCompactEnabled(enabled: boolean): void;
39
41
  setSubagentCount(count: number): void;
40
42
  setSessionStartTime(time: number): void;
@@ -36,3 +36,14 @@ export declare class TranscriptContainer extends Container implements NativeScro
36
36
  thaw(): void;
37
37
  render(width: number): string[];
38
38
  }
39
+ /**
40
+ * Groups a run of sibling rows (an IRC card's header + body, a file-mention
41
+ * list, a bordered command/version panel) into a single transcript child so the
42
+ * container spaces it as one block — one blank line above, none injected between
43
+ * its rows. Without this wrapper the rows would be top-level children and the
44
+ * container would put a blank line between each (and inside any border box).
45
+ * It is a plain {@link Container}; the named subclass documents intent and makes
46
+ * every manual block grouping greppable.
47
+ */
48
+ export declare class TranscriptBlock extends Container {
49
+ }
@@ -22,6 +22,7 @@ export declare class CommandController {
22
22
  handleContextCommand(): void;
23
23
  handleMemoryCommand(text: string): Promise<void>;
24
24
  handleClearCommand(): Promise<void>;
25
+ handleFreshCommand(): Promise<void>;
25
26
  handleDropCommand(): Promise<void>;
26
27
  handleForkCommand(): Promise<void>;
27
28
  handleMoveCommand(targetPath: string): Promise<void>;
@@ -1,12 +1,28 @@
1
1
  import type { InteractiveModeContext } from "../../modes/types";
2
2
  import type { AgentSessionEvent } from "../../session/agent-session";
3
+ /**
4
+ * Loader label shown the instant a user interrupt (Esc) is requested, kept until
5
+ * the agent turn fully unwinds. Esc fires the abort synchronously, but the loop
6
+ * only stops the spinner at `agent_end`, which it cannot reach until every
7
+ * in-flight tool settles its abort in `executeToolCalls` (`Promise.allSettled`).
8
+ * Swapping the steady "Working…" for this acknowledges the keypress instead of
9
+ * reading as an ignored Esc for the seconds a slow tool takes to tear down.
10
+ */
11
+ export declare const INTERRUPTING_WORKING_MESSAGE = "Interrupting\u2026";
3
12
  export declare class EventController {
4
13
  #private;
5
14
  private ctx;
6
15
  constructor(ctx: InteractiveModeContext);
7
16
  dispose(): void;
17
+ /**
18
+ * Acknowledge a user interrupt (Esc) immediately: switch the loader to
19
+ * `INTERRUPTING_WORKING_MESSAGE` and freeze intent-driven working-message
20
+ * updates for the rest of the turn so a late `tool_execution_start` intent
21
+ * cannot repaint a "Working…/<intent>" line over the acknowledgment. Reset at
22
+ * the next `agent_start`. No-op outside an active turn or if already set.
23
+ */
24
+ notifyInterrupting(): void;
8
25
  subscribeToAgent(): void;
9
26
  handleEvent(event: AgentSessionEvent): Promise<void>;
10
27
  sendCompletionNotification(): void;
11
- handleBackgroundEvent(event: AgentSessionEvent): Promise<void>;
12
28
  }
@@ -14,7 +14,6 @@ export declare class ExtensionUiController {
14
14
  initHooksAndCustomTools(): Promise<void>;
15
15
  setHookWidget(key: string, content: ExtensionWidgetContent, options?: ExtensionWidgetOptions): void;
16
16
  initializeHookRunner(uiContext: ExtensionUIContext, _hasUI: boolean): void;
17
- createBackgroundUiContext(): ExtensionUIContext;
18
17
  /**
19
18
  * Emit session event to all extension tools.
20
19
  */
@@ -16,7 +16,7 @@ export declare class InputController {
16
16
  abort?: boolean;
17
17
  currentText?: string;
18
18
  }): number;
19
- handleBackgroundCommand(): void;
19
+ handleImagePathPaste(path: string): Promise<void>;
20
20
  handleImagePaste(): Promise<boolean>;
21
21
  handleClipboardTextRawPaste(): Promise<void>;
22
22
  createAutocompleteProvider(commands: SlashCommand[], basePath: string): AutocompleteProvider;
@@ -0,0 +1,22 @@
1
+ import type { AssistantMessage } from "@oh-my-pi/pi-ai";
2
+ import type { AssistantMessageComponent } from "../components/assistant-message";
3
+ export declare const STREAMING_REVEAL_FRAME_MS: number;
4
+ export declare const MIN_STEP = 3;
5
+ export declare const CATCHUP_FRAMES = 8;
6
+ type StreamingRevealComponent = Pick<AssistantMessageComponent, "updateContent">;
7
+ type StreamingRevealControllerOptions = {
8
+ getSmoothStreaming(): boolean;
9
+ getHideThinkingBlock(): boolean;
10
+ requestRender(): void;
11
+ };
12
+ export declare function visibleUnits(message: AssistantMessage, hideThinking: boolean): number;
13
+ export declare function buildDisplayMessage(target: AssistantMessage, revealed: number, hideThinking: boolean): AssistantMessage;
14
+ export declare function nextStep(backlog: number): number;
15
+ export declare class StreamingRevealController {
16
+ #private;
17
+ constructor(options: StreamingRevealControllerOptions);
18
+ begin(component: StreamingRevealComponent, message: AssistantMessage): void;
19
+ setTarget(message: AssistantMessage): void;
20
+ stop(): void;
21
+ }
22
+ export {};
@@ -0,0 +1,6 @@
1
+ import type { InteractiveModeContext } from "../types";
2
+ export declare class TanCommandController {
3
+ private readonly ctx;
4
+ constructor(ctx: InteractiveModeContext);
5
+ start(work: string): Promise<void>;
6
+ }
@@ -8,7 +8,7 @@ import { Settings } from "../config/settings";
8
8
  import type { ExtensionUIContext, ExtensionUIDialogOptions, ExtensionUISelectItem, ExtensionWidgetContent, ExtensionWidgetOptions } from "../extensibility/extensions";
9
9
  import type { CompactOptions } from "../extensibility/extensions/types";
10
10
  import { type PlanApprovalDetails } from "../plan-mode/approved-plan";
11
- import type { AgentSession, AgentSessionEvent } from "../session/agent-session";
11
+ import type { AgentSession } from "../session/agent-session";
12
12
  import { HistoryStorage } from "../session/history-storage";
13
13
  import type { SessionContext, SessionManager } from "../session/session-manager";
14
14
  import type { ShakeMode } from "../session/shake-types";
@@ -63,7 +63,6 @@ export declare class InteractiveMode implements InteractiveModeContext {
63
63
  hookWidgetContainerBelow: Container;
64
64
  statusLine: StatusLineComponent;
65
65
  isInitialized: boolean;
66
- isBackgrounded: boolean;
67
66
  isBashMode: boolean;
68
67
  toolOutputExpanded: boolean;
69
68
  todoExpanded: boolean;
@@ -150,6 +149,16 @@ export declare class InteractiveMode implements InteractiveModeContext {
150
149
  rebuildChatFromMessages(): void;
151
150
  /** Apply any deferred model switch after the current stream ends. */
152
151
  flushPendingModelSwitch(): Promise<void>;
152
+ showPlanReview(planContent: string, title: string, options: string[], dialogOptions?: {
153
+ helpText?: string;
154
+ disabledIndices?: number[];
155
+ onExternalEditor?: () => void;
156
+ onPlanEdited?: (content: string) => void;
157
+ onFeedbackChange?: (feedback: string) => void;
158
+ initialIndex?: number;
159
+ }, extra?: {
160
+ slider?: HookSelectorSlider;
161
+ }): Promise<string | undefined>;
153
162
  handlePlanModeCommand(initialPrompt?: string): Promise<void>;
154
163
  handleGoalModeCommand(rest?: string): Promise<void>;
155
164
  handlePlanApproval(details: PlanApprovalDetails): Promise<void>;
@@ -158,9 +167,9 @@ export declare class InteractiveMode implements InteractiveModeContext {
158
167
  checkShutdownRequested(): Promise<void>;
159
168
  setToolUIContext(uiContext: ExtensionUIContext, hasUI: boolean): void;
160
169
  initializeHookRunner(uiContext: ExtensionUIContext, hasUI: boolean): void;
161
- createBackgroundUiContext(): ExtensionUIContext;
162
170
  setEditorComponent(factory: ((tui: TUI, theme: EditorTheme, keybindings: KeybindingsManager) => CustomEditor) | undefined): void;
163
- handleBackgroundEvent(event: AgentSessionEvent): Promise<void>;
171
+ present(content: Component | readonly Component[]): void;
172
+ resetTranscript(): void;
164
173
  showStatus(message: string, options?: {
165
174
  dim?: boolean;
166
175
  }): void;
@@ -171,6 +180,7 @@ export declare class InteractiveMode implements InteractiveModeContext {
171
180
  ensureLoadingAnimation(): void;
172
181
  setWorkingMessage(message?: string): void;
173
182
  applyPendingWorkingMessage(): void;
183
+ notifyInterrupting(): void;
174
184
  showNewVersionNotification(newVersion: string): void;
175
185
  clearEditor(): void;
176
186
  updatePendingMessagesDisplay(): void;
@@ -208,6 +218,7 @@ export declare class InteractiveMode implements InteractiveModeContext {
208
218
  handleToolsCommand(): void;
209
219
  handleContextCommand(): void;
210
220
  handleClearCommand(): Promise<void>;
221
+ handleFreshCommand(): Promise<void>;
211
222
  handleDropCommand(): Promise<void>;
212
223
  handleForkCommand(): Promise<void>;
213
224
  handleMoveCommand(targetPath: string): Promise<void>;
@@ -246,9 +257,9 @@ export declare class InteractiveMode implements InteractiveModeContext {
246
257
  handleCtrlD(): void;
247
258
  handleCtrlZ(): void;
248
259
  handleDequeue(): void;
249
- handleBackgroundCommand(): void;
250
260
  handleImagePaste(): Promise<boolean>;
251
261
  handleBtwCommand(question: string): Promise<void>;
262
+ handleTanCommand(work: string): Promise<void>;
252
263
  hasActiveBtw(): boolean;
253
264
  handleBtwEscape(): boolean;
254
265
  handleOmfgCommand(complaint: string): Promise<void>;
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Gradient-highlight every magic keyword ("ultrathink", "orchestrate",
3
- * "workflow") that appears as standalone prose, skipping any occurrence inside a
3
+ * "workflowz") that appears as standalone prose, skipping any occurrence inside a
4
4
  * code block, inline code span, or XML/HTML section. Each highlighter paints its
5
5
  * own keyword with its own gradient, so chaining is order-independent — the
6
6
  * earlier passes only inject zero-width SGR escapes (no backticks or angle
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Markdown structure awareness for the magic-keyword affordances
3
- * ("ultrathink"/"orchestrate"/"workflow").
3
+ * ("ultrathink"/"orchestrate"/"workflowz").
4
4
  *
5
5
  * Keyword detection and editor/transcript highlighting must fire only on prose
6
6
  * the user is actually addressing to the model — never on a word that happens to
@@ -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" | "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";
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.search" | "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 */