@oh-my-pi/pi-coding-agent 17.0.0 → 17.0.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 (202) hide show
  1. package/CHANGELOG.md +128 -0
  2. package/dist/cli.js +4006 -3966
  3. package/dist/types/advisor/advise-tool.d.ts +5 -2
  4. package/dist/types/advisor/config.d.ts +14 -6
  5. package/dist/types/advisor/runtime.d.ts +20 -11
  6. package/dist/types/autolearn/controller.d.ts +1 -0
  7. package/dist/types/cli-commands.d.ts +14 -1
  8. package/dist/types/config/model-discovery.d.ts +17 -0
  9. package/dist/types/config/model-registry.d.ts +4 -0
  10. package/dist/types/config/model-resolver.d.ts +6 -2
  11. package/dist/types/config/models-config-schema.d.ts +10 -0
  12. package/dist/types/config/models-config.d.ts +6 -0
  13. package/dist/types/config/settings-schema.d.ts +32 -7
  14. package/dist/types/config/settings.d.ts +50 -0
  15. package/dist/types/cursor.d.ts +11 -0
  16. package/dist/types/discovery/helpers.d.ts +5 -2
  17. package/dist/types/discovery/substitute-plugin-root.d.ts +20 -7
  18. package/dist/types/exec/bash-executor.d.ts +2 -0
  19. package/dist/types/extensibility/extensions/managed-timers.d.ts +15 -0
  20. package/dist/types/extensibility/extensions/runner.d.ts +7 -0
  21. package/dist/types/extensibility/extensions/types.d.ts +18 -0
  22. package/dist/types/extensibility/legacy-pi-coding-agent-shim.d.ts +40 -0
  23. package/dist/types/extensibility/shared-events.d.ts +6 -0
  24. package/dist/types/extensibility/utils.d.ts +2 -2
  25. package/dist/types/internal-urls/agent-protocol.d.ts +1 -0
  26. package/dist/types/lib/xai-http.d.ts +11 -0
  27. package/dist/types/mcp/transports/stdio.d.ts +13 -1
  28. package/dist/types/modes/acp/acp-agent.d.ts +3 -0
  29. package/dist/types/modes/acp/acp-mode.d.ts +6 -2
  30. package/dist/types/modes/components/advisor-config.d.ts +8 -1
  31. package/dist/types/modes/components/assistant-message.d.ts +2 -0
  32. package/dist/types/modes/components/custom-editor-plugin-ctor.test.d.ts +1 -0
  33. package/dist/types/modes/components/custom-editor.d.ts +23 -1
  34. package/dist/types/modes/components/hook-editor.d.ts +16 -2
  35. package/dist/types/modes/components/login-dialog.test.d.ts +1 -0
  36. package/dist/types/modes/components/model-hub.d.ts +5 -2
  37. package/dist/types/modes/components/session-selector.d.ts +4 -0
  38. package/dist/types/modes/components/tool-execution.d.ts +8 -1
  39. package/dist/types/modes/components/tool-execution.test.d.ts +1 -0
  40. package/dist/types/modes/controllers/command-controller.d.ts +8 -0
  41. package/dist/types/modes/controllers/selector-controller.d.ts +3 -1
  42. package/dist/types/modes/interactive-mode.d.ts +6 -0
  43. package/dist/types/modes/noninteractive-dispose.test.d.ts +1 -0
  44. package/dist/types/modes/print-mode.d.ts +1 -1
  45. package/dist/types/modes/types.d.ts +10 -0
  46. package/dist/types/modes/utils/transcript-render-helpers.d.ts +2 -2
  47. package/dist/types/modes/warp-events.d.ts +24 -0
  48. package/dist/types/modes/warp-events.test.d.ts +1 -0
  49. package/dist/types/plan-mode/model-transition.d.ts +47 -0
  50. package/dist/types/plan-mode/model-transition.test.d.ts +1 -0
  51. package/dist/types/registry/agent-lifecycle.d.ts +26 -1
  52. package/dist/types/sdk.d.ts +13 -2
  53. package/dist/types/session/agent-session.d.ts +43 -11
  54. package/dist/types/session/session-history-format.d.ts +10 -0
  55. package/dist/types/session/session-manager.d.ts +14 -0
  56. package/dist/types/session/streaming-output.d.ts +2 -0
  57. package/dist/types/slash-commands/helpers/active-oauth-account.d.ts +9 -0
  58. package/dist/types/slash-commands/types.d.ts +4 -4
  59. package/dist/types/system-prompt.d.ts +1 -1
  60. package/dist/types/task/label.d.ts +1 -1
  61. package/dist/types/telemetry-export.d.ts +34 -9
  62. package/dist/types/tools/approval.d.ts +8 -0
  63. package/dist/types/tools/bash.d.ts +2 -0
  64. package/dist/types/tools/browser/registry.d.ts +7 -3
  65. package/dist/types/tools/browser/tab-supervisor.d.ts +2 -0
  66. package/dist/types/tools/essential-tools.d.ts +29 -0
  67. package/dist/types/tools/image-gen.d.ts +2 -1
  68. package/dist/types/tools/index.d.ts +4 -1
  69. package/dist/types/tools/manage-skill.d.ts +2 -0
  70. package/dist/types/tools/xdev.d.ts +11 -2
  71. package/dist/types/utils/title-generator.d.ts +2 -1
  72. package/dist/types/web/search/index.d.ts +2 -0
  73. package/dist/types/web/search/providers/base.d.ts +3 -0
  74. package/dist/types/web/search/providers/kimi.d.ts +4 -1
  75. package/dist/types/web/search/types.d.ts +1 -1
  76. package/package.json +21 -16
  77. package/src/advisor/__tests__/advisor.test.ts +1358 -86
  78. package/src/advisor/__tests__/config.test.ts +58 -2
  79. package/src/advisor/advise-tool.ts +7 -3
  80. package/src/advisor/config.ts +76 -24
  81. package/src/advisor/runtime.ts +445 -92
  82. package/src/autolearn/controller.ts +23 -28
  83. package/src/cli/bench-cli.ts +4 -1
  84. package/src/cli/grep-cli.ts +2 -1
  85. package/src/cli-commands.ts +57 -23
  86. package/src/cli.ts +5 -1
  87. package/src/config/model-discovery.ts +81 -21
  88. package/src/config/model-registry.ts +34 -6
  89. package/src/config/model-resolver.ts +57 -12
  90. package/src/config/models-config-schema.ts +1 -0
  91. package/src/config/settings-schema.ts +43 -6
  92. package/src/config/settings.ts +405 -25
  93. package/src/cursor.ts +20 -3
  94. package/src/debug/report-bundle.ts +40 -4
  95. package/src/discovery/codex.ts +14 -4
  96. package/src/discovery/helpers.ts +28 -5
  97. package/src/discovery/substitute-plugin-root.ts +23 -7
  98. package/src/exec/bash-executor.ts +14 -5
  99. package/src/export/html/template.js +2 -0
  100. package/src/extensibility/custom-tools/loader.ts +3 -3
  101. package/src/extensibility/custom-tools/wrapper.ts +2 -1
  102. package/src/extensibility/extensions/loader.ts +3 -3
  103. package/src/extensibility/extensions/managed-timers.ts +83 -0
  104. package/src/extensibility/extensions/runner.ts +26 -0
  105. package/src/extensibility/extensions/types.ts +18 -0
  106. package/src/extensibility/extensions/wrapper.ts +2 -1
  107. package/src/extensibility/hooks/loader.ts +3 -3
  108. package/src/extensibility/legacy-pi-coding-agent-shim.ts +96 -1
  109. package/src/extensibility/plugins/legacy-pi-compat.ts +225 -22
  110. package/src/extensibility/plugins/manager.ts +2 -2
  111. package/src/extensibility/shared-events.ts +6 -0
  112. package/src/extensibility/utils.ts +91 -25
  113. package/src/internal-urls/__tests__/agent-protocol-nested.test.ts +73 -0
  114. package/src/internal-urls/agent-protocol.ts +73 -39
  115. package/src/irc/bus.ts +22 -3
  116. package/src/launch/broker.ts +3 -2
  117. package/src/launch/client.ts +2 -2
  118. package/src/launch/presence.ts +2 -2
  119. package/src/lib/xai-http.ts +28 -2
  120. package/src/lsp/client.ts +1 -1
  121. package/src/main.ts +11 -8
  122. package/src/mcp/manager.ts +9 -3
  123. package/src/mcp/transports/stdio.ts +103 -23
  124. package/src/modes/acp/acp-agent.ts +28 -9
  125. package/src/modes/acp/acp-event-mapper.ts +8 -0
  126. package/src/modes/acp/acp-mode.ts +18 -4
  127. package/src/modes/components/advisor-config.ts +65 -3
  128. package/src/modes/components/ask-dialog.ts +1 -1
  129. package/src/modes/components/assistant-message.ts +35 -14
  130. package/src/modes/components/chat-transcript-builder.ts +2 -0
  131. package/src/modes/components/custom-editor-plugin-ctor.test.ts +36 -0
  132. package/src/modes/components/custom-editor.ts +62 -1
  133. package/src/modes/components/hook-editor.ts +35 -5
  134. package/src/modes/components/login-dialog.test.ts +56 -0
  135. package/src/modes/components/login-dialog.ts +7 -3
  136. package/src/modes/components/model-hub.ts +138 -42
  137. package/src/modes/components/plan-review-overlay.ts +51 -10
  138. package/src/modes/components/session-selector.ts +10 -0
  139. package/src/modes/components/status-line/component.test.ts +1 -0
  140. package/src/modes/components/status-line/component.ts +2 -4
  141. package/src/modes/components/status-line/segments.ts +21 -6
  142. package/src/modes/components/tool-execution.test.ts +101 -0
  143. package/src/modes/components/tool-execution.ts +117 -9
  144. package/src/modes/components/transcript-container.ts +30 -2
  145. package/src/modes/controllers/command-controller-shared.ts +1 -1
  146. package/src/modes/controllers/command-controller.ts +168 -48
  147. package/src/modes/controllers/event-controller.ts +6 -0
  148. package/src/modes/controllers/extension-ui-controller.ts +4 -22
  149. package/src/modes/controllers/input-controller.ts +12 -12
  150. package/src/modes/controllers/selector-controller.ts +208 -46
  151. package/src/modes/interactive-mode.ts +205 -65
  152. package/src/modes/noninteractive-dispose.test.ts +60 -0
  153. package/src/modes/print-mode.ts +10 -5
  154. package/src/modes/rpc/host-tools.ts +2 -1
  155. package/src/modes/rpc/rpc-mode.ts +31 -7
  156. package/src/modes/theme/theme.ts +2 -2
  157. package/src/modes/types.ts +10 -0
  158. package/src/modes/utils/interactive-context-helpers.ts +3 -1
  159. package/src/modes/utils/transcript-render-helpers.ts +3 -2
  160. package/src/modes/warp-events.test.ts +794 -0
  161. package/src/modes/warp-events.ts +232 -0
  162. package/src/plan-mode/model-transition.test.ts +60 -0
  163. package/src/plan-mode/model-transition.ts +51 -0
  164. package/src/prompts/system/system-prompt.md +1 -1
  165. package/src/registry/agent-lifecycle.ts +133 -18
  166. package/src/sdk.ts +227 -44
  167. package/src/session/agent-session.ts +1364 -382
  168. package/src/session/session-history-format.ts +20 -5
  169. package/src/session/session-listing.ts +6 -5
  170. package/src/session/session-loader.ts +9 -0
  171. package/src/session/session-manager.ts +48 -0
  172. package/src/session/session-persistence.ts +11 -0
  173. package/src/session/streaming-output.ts +3 -1
  174. package/src/slash-commands/builtin-registry.ts +9 -0
  175. package/src/slash-commands/helpers/active-oauth-account.ts +16 -0
  176. package/src/slash-commands/types.ts +4 -4
  177. package/src/system-prompt.ts +2 -2
  178. package/src/task/executor.ts +1 -1
  179. package/src/task/label.ts +2 -0
  180. package/src/telemetry-export.ts +453 -97
  181. package/src/tools/approval.ts +11 -0
  182. package/src/tools/bash.ts +71 -38
  183. package/src/tools/browser/registry.ts +9 -2
  184. package/src/tools/browser/tab-supervisor.ts +65 -10
  185. package/src/tools/browser.ts +4 -3
  186. package/src/tools/essential-tools.ts +45 -0
  187. package/src/tools/eval.ts +3 -0
  188. package/src/tools/gh.ts +169 -2
  189. package/src/tools/image-gen.ts +624 -513
  190. package/src/tools/index.ts +10 -6
  191. package/src/tools/manage-skill.ts +5 -3
  192. package/src/tools/output-meta.ts +7 -0
  193. package/src/tools/path-utils.ts +8 -5
  194. package/src/tools/read.ts +48 -3
  195. package/src/tools/write.ts +22 -4
  196. package/src/tools/xdev.ts +14 -3
  197. package/src/utils/title-generator.ts +15 -4
  198. package/src/web/search/index.ts +21 -6
  199. package/src/web/search/providers/base.ts +3 -0
  200. package/src/web/search/providers/kimi.ts +18 -12
  201. package/src/web/search/providers/xai.ts +40 -9
  202. package/src/web/search/types.ts +6 -1
@@ -304,6 +304,24 @@ export interface ExtensionContext {
304
304
  getSystemPrompt(): string[];
305
305
  /** Structured memory runtime for status/search/save across the configured backend. */
306
306
  memory?: MemoryRuntimeContext;
307
+ /**
308
+ * Schedule a repeating callback whose throws are contained. Unlike raw
309
+ * `setInterval`, a synchronous throw or rejected promise from `callback` is
310
+ * logged and surfaced through the extension error channel instead of
311
+ * escaping as a process-fatal `uncaughtException` — one misbehaving timer
312
+ * can no longer take down the whole session. The handle is `unref`'d and
313
+ * cleared automatically on `session_shutdown`. Prefer this over raw
314
+ * `setInterval` for any extension background work.
315
+ */
316
+ setInterval(callback: (...args: unknown[]) => void, ms?: number, ...args: unknown[]): Timer;
317
+ /**
318
+ * Schedule a one-shot callback whose throws are contained, mirroring
319
+ * {@link setInterval}. Cleared automatically on `session_shutdown` if it has
320
+ * not yet fired.
321
+ */
322
+ setTimeout(callback: (...args: unknown[]) => void, ms?: number, ...args: unknown[]): Timer;
323
+ /** Clear a timer scheduled via {@link setInterval} or {@link setTimeout}. */
324
+ clearTimer(timer: Timer): void;
307
325
  }
308
326
  /**
309
327
  * Extended context for command handlers.
@@ -114,6 +114,46 @@ export declare const SettingsManager: {
114
114
  readonly create: (cwd: string, agentDir?: string) => Promise<Settings>;
115
115
  readonly inMemory: () => Settings;
116
116
  };
117
+ /** Scope used by the legacy package manager for discovered resources. */
118
+ export type SourceScope = "user" | "project" | "temporary";
119
+ /** Discovery metadata exposed alongside a legacy package resource path. */
120
+ export interface PathMetadata {
121
+ source: string;
122
+ scope: SourceScope;
123
+ origin: "package" | "top-level";
124
+ baseDir?: string;
125
+ }
126
+ /** One extension, skill, prompt, or theme resolved by the legacy package manager. */
127
+ export interface ResolvedResource {
128
+ path: string;
129
+ enabled: boolean;
130
+ metadata: PathMetadata;
131
+ }
132
+ /** Resource groups returned by {@link DefaultPackageManager.resolve}. */
133
+ export interface ResolvedPaths {
134
+ extensions: ResolvedResource[];
135
+ skills: ResolvedResource[];
136
+ prompts: ResolvedResource[];
137
+ themes: ResolvedResource[];
138
+ }
139
+ /** Action a legacy caller requests when a configured package is unavailable. */
140
+ export type MissingSourceAction = "install" | "skip" | "error";
141
+ /** Construction inputs accepted by the legacy package manager. */
142
+ export interface DefaultPackageManagerOptions {
143
+ cwd: string;
144
+ agentDir: string;
145
+ settingsManager: Settings | Promise<Settings>;
146
+ }
147
+ /**
148
+ * Enumerates the extensions OMP would load through the historical package
149
+ * manager surface used by legacy extensions.
150
+ */
151
+ export declare class DefaultPackageManager {
152
+ #private;
153
+ constructor(options: DefaultPackageManagerOptions);
154
+ /** Resolve enabled extension paths with their OMP plugin provenance. */
155
+ resolve(_onMissing?: (source: string) => Promise<MissingSourceAction>): Promise<ResolvedPaths>;
156
+ }
117
157
  /**
118
158
  * Resource-loader compatibility layer for legacy pi extensions.
119
159
  *
@@ -152,6 +152,12 @@ export interface AgentStartEvent {
152
152
  export interface AgentEndEvent {
153
153
  type: "agent_end";
154
154
  messages: AgentMessage[];
155
+ /**
156
+ * When true, the session has already scheduled an automatic continuation
157
+ * (auto-retry, empty/unexpected-stop retry, etc.). Subscribers must not
158
+ * treat this as a user-visible terminal settle.
159
+ */
160
+ willContinue?: boolean;
155
161
  }
156
162
  /** Fired at the start of each turn */
157
163
  export interface TurnStartEvent {
@@ -11,7 +11,7 @@ export declare function resolvePath(filePath: string, cwd: string): string;
11
11
  */
12
12
  export declare function createNoOpUIContext(): HookUIContext;
13
13
  /**
14
- * Raised by {@link withExitGuard} when a guarded callback synchronously
14
+ * Raised by {@link withHostGuard} when a guarded callback synchronously
15
15
  * attempts to terminate the host process. Callers catch this like any other
16
16
  * load-time failure so the extension/hook is skipped with a logged error
17
17
  * instead of taking the CLI down with it.
@@ -21,4 +21,4 @@ export declare class ExtensionExitError extends Error {
21
21
  readonly code: number | string | undefined;
22
22
  constructor(code: number | string | undefined, alias?: string);
23
23
  }
24
- export declare function withExitGuard<T>(fn: () => Promise<T>): Promise<T>;
24
+ export declare function withHostGuard<T>(fn: () => Promise<T>): Promise<T>;
@@ -6,6 +6,7 @@ import type { InternalResource, InternalUrl, ProtocolHandler, UrlCompletion } fr
6
6
  * with optional JSON extraction.
7
7
  */
8
8
  export declare class AgentProtocolHandler implements ProtocolHandler {
9
+ #private;
9
10
  readonly scheme = "agent";
10
11
  readonly immutable = true;
11
12
  resolve(url: InternalUrl): Promise<InternalResource>;
@@ -5,6 +5,17 @@ interface XAICredentials {
5
5
  baseURL: string;
6
6
  }
7
7
  export declare function ohMyPiXAIUserAgent(): string;
8
+ /** xAI provider ids supported by shared HTTP tool transport resolution. */
9
+ export type XAIHttpProvider = "xai-oauth" | "xai";
10
+ /** Resolved endpoint and configured headers for an xAI HTTP tool request. */
11
+ export interface XAIHttpTransport {
12
+ baseURL: string;
13
+ headers?: Record<string, string>;
14
+ }
15
+ /**
16
+ * Resolve an xAI tool endpoint and its provider/model header overrides.
17
+ */
18
+ export declare function resolveXAIHttpTransport(modelRegistry: ModelRegistry, provider: XAIHttpProvider, modelId?: string): XAIHttpTransport;
8
19
  /**
9
20
  * Resolve xAI credentials for HTTP tool calls.
10
21
  *
@@ -37,6 +37,18 @@ export interface StdioSpawnCommand {
37
37
  * grandchildren keep stdout routed through our pipe (#3544).
38
38
  */
39
39
  detached: boolean;
40
+ /**
41
+ * Pass argv to `Bun.spawn` verbatim (Windows only), suppressing the
42
+ * default libuv backslash-quoting.
43
+ *
44
+ * Set when `cmd` already holds a `cmd.exe /d /e:ON /v:OFF /c "<line>"`
45
+ * command line escaped for `cmd.exe`'s parser (see `buildCmdExeArgv`).
46
+ * libuv's quoting targets `CommandLineToArgvW`, not `cmd.exe`, so letting
47
+ * it re-quote a batch launch would corrupt arguments and re-open the
48
+ * `%VAR%` / quote-injection holes the escaping closes (BatBadBut,
49
+ * CVE-2024-24576).
50
+ */
51
+ windowsVerbatimArguments?: boolean;
40
52
  }
41
53
  /** Inputs used to resolve platform-specific stdio spawn behavior. */
42
54
  export interface ResolveStdioSpawnOptions {
@@ -55,7 +67,7 @@ export interface ResolveStdioSpawnOptions {
55
67
  * only appends `.exe` for extensionless names — `.cmd`/`.bat` are never
56
68
  * tried, so `npx` (which exists only as `npx.cmd` on Windows) crashes the
57
69
  * subprocess immediately. When the resolver can't pin the command down,
58
- * route through `cmd.exe /d /s /c` so Windows's own PATHEXT lookup runs.
70
+ * route through `cmd.exe` so Windows's own PATHEXT lookup runs.
59
71
  */
60
72
  export declare function resolveStdioSpawnCommand(config: MCPStdioServerConfig, options: ResolveStdioSpawnOptions): Promise<StdioSpawnCommand>;
61
73
  /** Minimal write surface of `Subprocess.stdin` we need for framed sends. */
@@ -1,4 +1,5 @@
1
1
  import { type Agent, type AgentSideConnection, type AuthenticateRequest, type AuthenticateResponse, type ClientCapabilities, type CloseSessionRequest, type CloseSessionResponse, type ForkSessionRequest, type ForkSessionResponse, type InitializeRequest, type InitializeResponse, type ListSessionsRequest, type ListSessionsResponse, type LoadSessionRequest, type LoadSessionResponse, type NewSessionRequest, type NewSessionResponse, type PromptRequest, type PromptResponse, type ResumeSessionRequest, type ResumeSessionResponse, type SetSessionConfigOptionRequest, type SetSessionConfigOptionResponse, type SetSessionModeRequest, type SetSessionModeResponse } from "@agentclientprotocol/sdk";
2
+ import { type postmortem } from "@oh-my-pi/pi-utils";
2
3
  import { type ExtensionUIContext } from "../../extensibility/extensions/index.js";
3
4
  import type { AgentSession } from "../../session/agent-session.js";
4
5
  /**
@@ -56,5 +57,7 @@ export declare class AcpAgent implements Agent {
56
57
  }): Promise<void>;
57
58
  get signal(): AbortSignal;
58
59
  get closed(): Promise<void>;
60
+ /** Dispose every session owned by this ACP connection and await persisted teardown. */
61
+ dispose(reason?: postmortem.Reason): Promise<void>;
59
62
  }
60
63
  export {};
@@ -1,5 +1,9 @@
1
1
  import { AgentSideConnection, type Stream } from "@agentclientprotocol/sdk";
2
2
  import type { AgentSession } from "../../session/agent-session.js";
3
+ import { AcpAgent } from "./acp-agent.js";
4
+ /** Creates sessions requested by an ACP client. */
3
5
  export type AcpSessionFactory = (cwd: string) => Promise<AgentSession>;
4
- export declare function createAcpConnection(transport: Stream, createSession: AcpSessionFactory, initialSession?: AgentSession): AgentSideConnection;
5
- export declare function runAcpMode(createSession: AcpSessionFactory, initialSession?: AgentSession): Promise<never>;
6
+ /** Creates an ACP connection and exposes its agent when process-level teardown must own it. */
7
+ export declare function createAcpConnection(transport: Stream, createSession: AcpSessionFactory, initialSession?: AgentSession, onAgent?: (agent: AcpAgent) => void): AgentSideConnection;
8
+ /** Serves ACP over stdio until the peer disconnects, then awaits session teardown before exit. */
9
+ export declare function runAcpMode(createSession: AcpSessionFactory, initialSession?: AgentSession): Promise<void>;
@@ -16,11 +16,13 @@
16
16
  * `save` callback.
17
17
  */
18
18
  import type { ThinkingLevel } from "@oh-my-pi/pi-agent-core";
19
- import type { Model } from "@oh-my-pi/pi-ai";
19
+ import type { Model, UsageReport } from "@oh-my-pi/pi-ai";
20
20
  import { type Component, type TUI } from "@oh-my-pi/pi-tui";
21
21
  import { type AdvisorConfigScope, type WatchdogConfigDoc } from "../../advisor/index.js";
22
22
  import type { ModelRegistry } from "../../config/model-registry.js";
23
23
  import type { Settings } from "../../config/settings.js";
24
+ import type { PerAdvisorStat } from "../../session/agent-session.js";
25
+ import type { OAuthAccountIdentity } from "../../session/auth-storage.js";
24
26
  /** Host callbacks: all disk + live-runtime effects flow through these. */
25
27
  export interface AdvisorConfigCallbacks {
26
28
  /** Load a scope's `WATCHDOG.yml` into an editable doc (empty when absent). */
@@ -32,6 +34,11 @@ export interface AdvisorConfigCallbacks {
32
34
  requestRender: () => void;
33
35
  /** Surface a transient status/warning line to the user. */
34
36
  notify: (message: string) => void;
37
+ /** Live advisor usage stats; lets the preview show tokens/cost per advisor. */
38
+ getAdvisorStats?: () => PerAdvisorStat[];
39
+ getUsageReports?: () => Promise<UsageReport[] | null>;
40
+ /** Resolve the active OAuth identity for quota filtering (per-advisor account stickiness). */
41
+ resolveActiveAccount?: (provider: string, sessionId?: string) => OAuthAccountIdentity | undefined;
35
42
  }
36
43
  export interface AdvisorConfigDeps {
37
44
  modelRegistry: ModelRegistry;
@@ -51,6 +51,8 @@ export declare class AssistantMessageComponent extends Container {
51
51
  markTranscriptBlockFinalized(): void;
52
52
  applyRetryRecovery(retryRecovery: AssistantMessage["retryRecovery"]): void;
53
53
  messagePersistenceKey(): string | undefined;
54
+ /** Toggle rendering for assistant-native and tool-result images. */
55
+ setImagesVisible(visible: boolean): void;
54
56
  setToolResultImages(toolCallId: string, images: ImageContent[]): void;
55
57
  updateContent(message: AssistantMessage, opts?: {
56
58
  transient?: boolean;
@@ -1,5 +1,5 @@
1
1
  import type { ImageContent } from "@oh-my-pi/pi-ai";
2
- import { Editor, type KeyId } from "@oh-my-pi/pi-tui";
2
+ import { Editor, type KeyId, TUI } from "@oh-my-pi/pi-tui";
3
3
  import type { AppKeybinding } from "../../config/keybindings.js";
4
4
  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.retry" | "app.clipboard.pasteImage" | "app.clipboard.pasteTextRaw" | "app.clipboard.copyPrompt">;
5
5
  /** Max gap (ms) between two spaces for the later one to count as OS key auto-repeat rather than a
@@ -73,6 +73,28 @@ export declare class CustomEditor extends Editor {
73
73
  /** Per-image source links (file:// targets) parallel to {@link pendingImages};
74
74
  * `undefined` entries are images without a backing reference yet. */
75
75
  pendingImageLinks: (string | undefined)[];
76
+ /**
77
+ * The host {@link TUI}, captured when a plugin constructs this editor through
78
+ * the upstream-pi `(tui, theme, keybindings)` convention. Undefined for omp's
79
+ * own `new CustomEditor(theme)` callers (they drive repaints through the
80
+ * interactive-mode wiring instead). Plugins that call `this.tui.requestRender()`
81
+ * in their overrides read it here (issue #4766).
82
+ */
83
+ tui?: TUI;
84
+ /**
85
+ * Accept both the omp constructor convention — `new CustomEditor(theme)` —
86
+ * and the upstream-pi `Editor` convention — `new Editor(tui, theme, keybindings)`
87
+ * — that {@link ExtensionUIContext.setEditorComponent}'s factory contract
88
+ * advertises `(tui, theme, keybindings)`. Plugins written against upstream pi
89
+ * subclass `CustomEditor`/`Editor` and forward `super(tui, theme, keybindings)`;
90
+ * without this shim the `TUI` lands in the `theme` slot and every render throws
91
+ * `undefined is not an object (evaluating 'this.#theme.symbols.boxRound')`
92
+ * (issue #4766). We locate the real {@link EditorTheme} among the args by shape
93
+ * (it carries `symbols`/`borderColor`) rather than by position, and capture a
94
+ * leading {@link TUI} so plugin overrides calling `this.tui.requestRender()`
95
+ * keep working.
96
+ */
97
+ constructor(...args: readonly unknown[]);
76
98
  /** Clear the composer draft: optionally commit `historyText` to history, then
77
99
  * reset the editor text and all pending draft-image state. The shared tail of
78
100
  * every "message submitted" path; pass no argument for a plain discard. */
@@ -7,14 +7,28 @@
7
7
  * (Ctrl+Q / Ctrl+Enter) submits, bordered popup
8
8
  * - Prompt-style (ask): Enter submits, Shift+Enter inserts newline, legacy ask chrome
9
9
  */
10
- import { Container, type TUI } from "@oh-my-pi/pi-tui";
10
+ import { Container, type Focusable, type TUI } from "@oh-my-pi/pi-tui";
11
11
  export interface HookEditorOptions {
12
12
  /** When true, use prompt-style keybindings with the legacy ask prompt chrome. */
13
13
  promptStyle?: boolean;
14
+ /**
15
+ * Max rows the inner Editor may occupy. When omitted, the editor is
16
+ * bounded to the current terminal height minus the component's chrome
17
+ * (≈10 rows) so long content scrolls instead of pushing the submit
18
+ * hint out of view.
19
+ */
20
+ maxHeight?: number;
14
21
  }
15
- export declare class HookEditorComponent extends Container {
22
+ /** Interactive multiline dialog used by hooks and the ask tool's Other response. */
23
+ export declare class HookEditorComponent extends Container implements Focusable {
16
24
  #private;
25
+ /** Focus state mirrored to the nested editor during rendering. */
26
+ focused: boolean;
17
27
  constructor(tui: TUI, title: string, prefill: string | undefined, onSubmit: (value: string) => void, onCancel: () => void, options?: HookEditorOptions);
28
+ /** Keep the nested editor's software/hardware cursor mode aligned with the dialog focus target. */
29
+ setUseTerminalCursor(useTerminalCursor: boolean): void;
30
+ /** Render the dialog after forwarding its focus state to the nested editor. */
31
+ render(width: number): readonly string[];
18
32
  handleInput(keyData: string): void;
19
33
  /** Route non-bracketed paste transports (e.g. kitty's OSC 5522 enhanced clipboard)
20
34
  * into the inner editor, mirroring bracketed-paste semantics. Without this hook,
@@ -0,0 +1 @@
1
+ export {};
@@ -8,11 +8,12 @@ export interface ScopedModelItem {
8
8
  model: Model;
9
9
  thinkingLevel?: string;
10
10
  }
11
+ export type ModelRoleSelectionScope = "global" | "project";
11
12
  export interface ModelHubCallbacks {
12
13
  /** Persist a role assignment. */
13
- onAssign: (model: Model, role: string, thinkingLevel: ConfiguredThinkingLevel | undefined, selector: string) => void;
14
+ onAssign: (model: Model, role: string, thinkingLevel: ConfiguredThinkingLevel | undefined, selector: string, scope?: ModelRoleSelectionScope) => void;
14
15
  /** Clear a configured role back to auto-selection. */
15
- onUnassign: (role: string) => void;
16
+ onUnassign: (role: string, scope?: ModelRoleSelectionScope) => void;
16
17
  /** Persist a `retry.fallbackChains` entry — keyed by a role, `provider/model-id`, or `provider/*`; an empty chain clears the key. */
17
18
  onFallbackChainChange?: (role: string, chain: string[]) => void;
18
19
  /** Locked provider activation: forward to the /login flow. */
@@ -37,6 +38,8 @@ export declare class ModelHubComponent implements Component {
37
38
  /** Cancel pending provider refresh timers and the spinner. Host calls this on overlay close. */
38
39
  dispose(): void;
39
40
  invalidate(): void;
41
+ /** Re-sync after an asynchronous callback finishes mutating settings. */
42
+ refreshAfterExternalMutation(): void;
40
43
  handleInput(data: string): void;
41
44
  render(width: number): string[];
42
45
  }
@@ -83,6 +83,10 @@ export declare class SessionSelectorComponent extends Container {
83
83
  #private;
84
84
  constructor(sessions: SessionInfo[], onSelect: (session: SessionInfo) => void, onCancel: () => void, onExit: () => void, options?: SessionSelectorOptions);
85
85
  setOnRequestRender(callback: () => void): void;
86
+ /** Ignore input after selection while the host resumes the session. */
87
+ lockInput(): void;
88
+ /** Re-enable input after a failed resume so the user can pick again. */
89
+ unlockInput(): void;
86
90
  /**
87
91
  * Dispose the session list explicitly: while the delete-confirmation dialog
88
92
  * is mounted the list is detached from the child tree, so Container's
@@ -9,6 +9,13 @@ import { type Component, Container, type NativeScrollbackLiveRegion, type TUI }
9
9
  export interface TranscriptLiveRegionProbe {
10
10
  isBlockInLiveRegion(component: Component): boolean;
11
11
  }
12
+ /** Minimal TUI surface ToolExecutionComponent uses to schedule repaints and share image budget. */
13
+ export interface ToolExecutionUi {
14
+ requestRender(): void;
15
+ requestComponentRender(component: Component): void;
16
+ resetDisplay(): void;
17
+ imageBudget?: TUI["imageBudget"];
18
+ }
12
19
  export interface ToolExecutionOptions {
13
20
  snapshots?: SnapshotStore;
14
21
  showImages?: boolean;
@@ -52,7 +59,7 @@ export declare function sharedSpinnerFrame(frameCount: number, now?: number): nu
52
59
  */
53
60
  export declare class ToolExecutionComponent extends Container implements NativeScrollbackLiveRegion {
54
61
  #private;
55
- constructor(toolName: string, args: any, options: ToolExecutionOptions | undefined, tool: AgentTool | undefined, ui: TUI, cwd?: string, _toolCallId?: string);
62
+ constructor(toolName: string, args: any, options: ToolExecutionOptions | undefined, tool: AgentTool | undefined, ui: ToolExecutionUi, cwd?: string, _toolCallId?: string);
56
63
  updateArgs(args: any, _toolCallId?: string): void;
57
64
  /**
58
65
  * Signal that args are complete (tool is about to execute).
@@ -52,4 +52,12 @@ export declare class CommandController {
52
52
  handleHandoffCommand(customInstructions?: string): Promise<void>;
53
53
  }
54
54
  export declare function renderProviderSection(details: ProviderDetails, uiTheme: Pick<typeof theme, "fg">): string;
55
+ /**
56
+ * Compact one-line quota summary for a single advisor's provider.
57
+ * Returns `null` when the provider has no usage data.
58
+ * When `activeAccount` is provided, only limits matching that credential
59
+ * are shown (mirrors `renderUsageReports`'s account-stickiness filtering).
60
+ * Example output: `Quota: 7d window · 67% used · resets in 3.2d`
61
+ */
62
+ export declare function formatCompactQuota(provider: string, reports: UsageReport[], nowMs: number, activeAccount?: OAuthAccountIdentity): string | null;
55
63
  export declare function renderUsageReports(reports: UsageReport[], uiTheme: typeof theme, nowMs: number, availableWidth: number, resolveActiveAccount?: (provider: string) => OAuthAccountIdentity | undefined): string;
@@ -50,7 +50,9 @@ export declare class SelectorController {
50
50
  showCopySelector(): void;
51
51
  showTreeSelector(): void;
52
52
  showSessionSelector(): Promise<void>;
53
- handleResumeSession(sessionPath: string): Promise<void>;
53
+ handleResumeSession(sessionPath: string, options?: {
54
+ settingsFlushed?: boolean;
55
+ }): Promise<boolean>;
54
56
  handleSessionDeleteCommand(): Promise<void>;
55
57
  showOAuthSelector(mode: "login" | "logout", providerId?: string): Promise<void>;
56
58
  showResetUsageSelector(): Promise<void>;
@@ -180,6 +180,8 @@ export declare class InteractiveMode implements InteractiveModeContext {
180
180
  * ({@link AgentSession.#refreshTitleAfterReplan}) share one source
181
181
  * ({@link discoverTitleSystemPromptFile}; issue #3734). */
182
182
  refreshTitleSystemPrompt(cwd?: string): Promise<void>;
183
+ /** Reload session skills and the `/skill:<name>` command list. */
184
+ refreshSkillState(): Promise<void>;
183
185
  /** Reload slash commands and autocomplete for the provided working directory. */
184
186
  refreshSlashCommandState(cwd?: string): Promise<void>;
185
187
  /** Stack extension autocomplete behavior on top of the built-in editor provider (#4919). */
@@ -270,6 +272,10 @@ export declare class InteractiveMode implements InteractiveModeContext {
270
272
  initializeHookRunner(uiContext: ExtensionUIContext, hasUI: boolean): void;
271
273
  setEditorComponent(factory: ((tui: TUI, theme: EditorTheme, keybindings: KeybindingsManager) => CustomEditor) | undefined): void;
272
274
  present(content: Component | readonly Component[]): void;
275
+ /** Defer transcript command panels until the active turn can no longer grow above them. */
276
+ presentCommandOutput(content: Component | readonly Component[]): void;
277
+ /** Mount every command panel queued for the current session while the agent was streaming. */
278
+ flushPendingCommandOutput(): void;
273
279
  resetTranscript(): void;
274
280
  showStatus(message: string, options?: {
275
281
  dim?: boolean;
@@ -0,0 +1 @@
1
+ export {};
@@ -1,5 +1,5 @@
1
1
  import type { ImageContent } from "@oh-my-pi/pi-ai";
2
- import type { AgentSession, AgentSessionEvent } from "../session/agent-session.js";
2
+ import { type AgentSession, type AgentSessionEvent } from "../session/agent-session.js";
3
3
  /**
4
4
  * Options for print mode.
5
5
  */
@@ -209,6 +209,14 @@ export interface InteractiveModeContext {
209
209
  * runs) so their timers/subscriptions start.
210
210
  */
211
211
  present(content: Component | readonly Component[]): void;
212
+ /**
213
+ * Mount command output immediately while idle, or defer it until the active
214
+ * agent turn ends so a growing live block cannot push duplicate rows into
215
+ * native scrollback.
216
+ */
217
+ presentCommandOutput(content: Component | readonly Component[]): void;
218
+ /** Mount command output deferred by {@link presentCommandOutput}. */
219
+ flushPendingCommandOutput(): void;
212
220
  /**
213
221
  * Dispose every live block in the transcript (stopping timers/subscriptions)
214
222
  * and clear it. Used before a full rebuild so animated/streaming blocks do not
@@ -322,6 +330,8 @@ export interface InteractiveModeContext {
322
330
  executeCompaction(customInstructionsOrOptions?: string | CompactOptions, isAuto?: boolean): Promise<CompactionOutcome>;
323
331
  openInBrowser(urlOrPath: string): void;
324
332
  refreshSlashCommandState(cwd?: string): Promise<void>;
333
+ /** Reload session skills and derived `/skill:<name>` commands. */
334
+ refreshSkillState(): Promise<void>;
325
335
  applyCwdChange(newCwd: string): Promise<void>;
326
336
  showSettingsSelector(): void;
327
337
  showAdvisorConfigure(): void;
@@ -34,8 +34,8 @@ export declare function buildIrcMessageCard(message: CustomOrHookMessage, getExp
34
34
  */
35
35
  export declare function buildFileMentionBlock(files: FileMentionMessage["files"], indent: number): TranscriptBlock;
36
36
  /**
37
- * Whether an assistant turn has visible text or thinking content (after
38
- * canonicalization) — i.e. content that closes the current read-tool run.
37
+ * Whether an assistant turn has visible text, thinking, or image content — i.e.
38
+ * content that closes the current read-tool run.
39
39
  */
40
40
  export declare function assistantHasVisibleContent(message: AssistantAgentMessage): boolean;
41
41
  /**
@@ -0,0 +1,24 @@
1
+ import type { ExtensionFactory } from "../extensibility/extensions/types.js";
2
+ /** True when Warp has negotiated the structured CLI-agent OSC protocol. */
3
+ export declare function isWarpCliAgentProtocolActive(): boolean;
4
+ export type WarpEventValue = string | number | boolean | null | readonly WarpEventValue[] | {
5
+ readonly [key: string]: WarpEventValue | undefined;
6
+ };
7
+ /** Fields added to the Warp CLI-agent event envelope by the event bridge. */
8
+ export type WarpEvent = Readonly<Record<string, WarpEventValue | undefined>>;
9
+ export interface WarpEventEmitterOptions {
10
+ sessionId: string;
11
+ getCwd?: () => string;
12
+ }
13
+ export interface WarpEventEmitter {
14
+ emit(event: WarpEvent): void;
15
+ }
16
+ /**
17
+ * Creates the Warp event transport for a top-level interactive TUI session.
18
+ * The caller MUST enforce that install-site invariant; the sole production
19
+ * caller is gated by `isInteractive`, so ACP, RPC, print, headless, and
20
+ * subagent sessions never construct an emitter.
21
+ */
22
+ export declare function createWarpEventEmitter(options: WarpEventEmitterOptions): WarpEventEmitter | undefined;
23
+ /** Internal event bridge installed only by the top-level interactive TUI runner. */
24
+ export declare function createWarpEventBridgeExtension(): ExtensionFactory;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Plan-mode model transition policy.
3
+ *
4
+ * Plan mode drives the active session model from the `plan` role: it switches
5
+ * to the plan model on entry and restores the pre-plan model on exit. The same
6
+ * policy also runs when the `plan` role is reassigned mid-planning, so a
7
+ * correction to the wrong plan model takes effect at the next turn boundary
8
+ * (issue #5657).
9
+ *
10
+ * This module holds only the pure decision — what transition a given
11
+ * (current model, resolved role, streaming) triple implies — so the branching
12
+ * is testable without a live session or TUI. The interactive mode performs the
13
+ * resulting side effect.
14
+ */
15
+ import type { Model } from "@oh-my-pi/pi-ai";
16
+ import type { ResolvedModelRoleValue } from "../config/model-resolver.js";
17
+ import type { ConfiguredThinkingLevel } from "../thinking.js";
18
+ /** The action implied by resolving the `plan` role against the active model. */
19
+ export type PlanModelTransition =
20
+ /** Already on the plan model with no thinking-level change to apply. */
21
+ {
22
+ kind: "none";
23
+ }
24
+ /** Same model; only the plan role's explicit thinking level differs. */
25
+ | {
26
+ kind: "thinking";
27
+ thinkingLevel: ConfiguredThinkingLevel;
28
+ }
29
+ /**
30
+ * Switch to `model`. `deferred` is set when the session is mid-stream: the
31
+ * switch must wait for the current turn to end (a live `setModelTemporary`
32
+ * resets the provider session), so the caller queues it instead.
33
+ */
34
+ | {
35
+ kind: "apply";
36
+ model: Model;
37
+ thinkingLevel: ConfiguredThinkingLevel | undefined;
38
+ deferred: boolean;
39
+ };
40
+ /**
41
+ * Decide how to reconcile the active model with the resolved `plan` role.
42
+ *
43
+ * @param currentModel - The session's active model, or `undefined` before one is set.
44
+ * @param resolved - The `plan` role resolved against the available models.
45
+ * @param isStreaming - Whether the session is mid-turn (forces a deferred switch).
46
+ */
47
+ export declare function resolvePlanModelTransition(currentModel: Model | undefined, resolved: ResolvedModelRoleValue, isStreaming: boolean): PlanModelTransition;
@@ -0,0 +1 @@
1
+ export {};
@@ -8,6 +8,12 @@
8
8
  * sessionFile), and revives it on demand through
9
9
  * {@link AgentLifecycleManager.ensureLive}. Only this manager flips
10
10
  * `parked` ↔ `idle`.
11
+ *
12
+ * Park/dispose is gated against concurrent ensureLive/hub-send:
13
+ * - A disposing session is never handed out.
14
+ * - ensureLive during an in-flight park either cancels the park (session still
15
+ * live) or waits for detach+park and then revives.
16
+ * - Concurrent ensureLive/park operations coalesce per id.
11
17
  */
12
18
  import type { AgentSession } from "../session/agent-session.js";
13
19
  import { type AgentRef, AgentRegistry } from "./agent-registry.js";
@@ -46,17 +52,36 @@ export declare class AgentLifecycleManager {
46
52
  adopt(id: string, opts: AdoptOptions): void;
47
53
  /** True if the id is adopted (parked or live). */
48
54
  has(id: string): boolean;
49
- /** True while {@link park} is disposing this agent's session (lets dispose hooks distinguish park from teardown). */
55
+ /**
56
+ * True when this manager owns `registry` — i.e. its adopt/park/revive state
57
+ * describes that registry's refs. Lets a caller holding a specific registry
58
+ * (e.g. a custom-registry {@link IrcBus} that fell back to the global
59
+ * manager) skip lifecycle gating that would consult unrelated park state.
60
+ */
61
+ manages(registry: AgentRegistry): boolean;
62
+ /**
63
+ * True while {@link park} is disposing this agent's session (lets dispose
64
+ * hooks distinguish park from teardown). False once the park is cancelled
65
+ * by ensureLive or after detach+dispose completes.
66
+ */
50
67
  isParking(id: string): boolean;
51
68
  /**
52
69
  * Dispose the live session, detach it from the registry, and mark the
53
70
  * agent `parked`. No-op unless the id is adopted and live.
71
+ *
72
+ * The session is detached (and status flipped to `parked`) *before*
73
+ * `session.dispose()` so concurrent {@link ensureLive}/hub-send never
74
+ * observe or inject into a disposing session. A concurrent ensureLive that
75
+ * arrives before detach cancels the park and keeps the live session.
54
76
  */
55
77
  park(id: string): Promise<void>;
56
78
  /**
57
79
  * Return the live session, reviving from the sessionFile if parked.
58
80
  * Throws a plain Error if the id is unknown or parked without a reviver.
59
81
  * Concurrent calls share one in-flight revive.
82
+ *
83
+ * Never returns a session that is mid-dispose: an in-flight park is either
84
+ * cancelled (session still live) or awaited to completion before revive.
60
85
  */
61
86
  ensureLive(id: string): Promise<AgentSession>;
62
87
  /** Hard removal: dispose if live, unregister from registry, drop timers. */
@@ -1,5 +1,5 @@
1
- import { type AgentTelemetryConfig, type ThinkingLevel } from "@oh-my-pi/pi-agent-core";
2
- import type { Model } from "@oh-my-pi/pi-ai";
1
+ import { Agent, type AgentOptions, type AgentTelemetryConfig, type AgentTool, type ThinkingLevel } from "@oh-my-pi/pi-agent-core";
2
+ import type { Model, SimpleStreamOptions } from "@oh-my-pi/pi-ai";
3
3
  import type { Dialect } from "@oh-my-pi/pi-ai/dialect";
4
4
  import { type Rule } from "./capability/rule.js";
5
5
  import { ModelRegistry } from "./config/model-registry.js";
@@ -346,6 +346,17 @@ export interface BuildSystemPromptOptions {
346
346
  * as separate entries so providers can cache prompt prefixes without concatenating blocks.
347
347
  */
348
348
  export declare function buildSystemPrompt(options?: BuildSystemPromptOptions): Promise<BuildSystemPromptResult>;
349
+ /** Dependencies used to construct an isolated auto-learn capture agent. */
350
+ export interface AutoLearnCaptureRunnerOptions {
351
+ sourceAgent: Agent;
352
+ captureTools: AgentTool[];
353
+ createAgent: (options: AgentOptions) => Agent;
354
+ onPayload?: SimpleStreamOptions["onPayload"];
355
+ onResponse?: SimpleStreamOptions["onResponse"];
356
+ createSessionId?: () => string;
357
+ }
358
+ /** Build a private capture runner over a detached message snapshot and provider session. */
359
+ export declare function createAutoLearnCaptureRunner(options: AutoLearnCaptureRunnerOptions): (content: string, signal?: AbortSignal) => Promise<void>;
349
360
  /**
350
361
  * Create an AgentSession with the specified options.
351
362
  *