@oh-my-pi/pi-coding-agent 17.0.0 → 17.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. package/CHANGELOG.md +56 -0
  2. package/dist/cli.js +3305 -3302
  3. package/dist/types/advisor/advise-tool.d.ts +5 -2
  4. package/dist/types/cli-commands.d.ts +14 -1
  5. package/dist/types/config/model-registry.d.ts +4 -0
  6. package/dist/types/config/models-config-schema.d.ts +10 -0
  7. package/dist/types/config/models-config.d.ts +6 -0
  8. package/dist/types/config/settings-schema.d.ts +1 -1
  9. package/dist/types/discovery/substitute-plugin-root.d.ts +20 -7
  10. package/dist/types/internal-urls/agent-protocol.d.ts +1 -0
  11. package/dist/types/lib/xai-http.d.ts +11 -0
  12. package/dist/types/modes/acp/acp-agent.d.ts +3 -0
  13. package/dist/types/modes/acp/acp-mode.d.ts +6 -2
  14. package/dist/types/modes/components/assistant-message.d.ts +2 -0
  15. package/dist/types/modes/components/custom-editor-plugin-ctor.test.d.ts +1 -0
  16. package/dist/types/modes/components/custom-editor.d.ts +23 -1
  17. package/dist/types/modes/components/hook-editor.d.ts +9 -2
  18. package/dist/types/modes/components/login-dialog.test.d.ts +1 -0
  19. package/dist/types/modes/components/session-selector.d.ts +2 -0
  20. package/dist/types/modes/components/tool-execution.d.ts +8 -1
  21. package/dist/types/modes/components/tool-execution.test.d.ts +1 -0
  22. package/dist/types/modes/interactive-mode.d.ts +6 -0
  23. package/dist/types/modes/noninteractive-dispose.test.d.ts +1 -0
  24. package/dist/types/modes/types.d.ts +10 -0
  25. package/dist/types/modes/utils/transcript-render-helpers.d.ts +2 -2
  26. package/dist/types/session/agent-session.d.ts +9 -1
  27. package/dist/types/session/streaming-output.d.ts +2 -0
  28. package/dist/types/slash-commands/types.d.ts +4 -4
  29. package/dist/types/system-prompt.d.ts +1 -1
  30. package/dist/types/tools/browser/registry.d.ts +7 -3
  31. package/dist/types/tools/browser/tab-supervisor.d.ts +2 -0
  32. package/dist/types/tools/index.d.ts +3 -1
  33. package/dist/types/tools/manage-skill.d.ts +2 -0
  34. package/dist/types/web/search/index.d.ts +2 -0
  35. package/dist/types/web/search/providers/base.d.ts +3 -0
  36. package/package.json +12 -12
  37. package/src/advisor/__tests__/advisor.test.ts +22 -12
  38. package/src/advisor/advise-tool.ts +7 -3
  39. package/src/cli/bench-cli.ts +4 -1
  40. package/src/cli/grep-cli.ts +2 -1
  41. package/src/cli-commands.ts +57 -23
  42. package/src/config/model-registry.ts +9 -0
  43. package/src/config/model-resolver.ts +43 -5
  44. package/src/config/models-config-schema.ts +1 -0
  45. package/src/config/settings-schema.ts +2 -1
  46. package/src/discovery/codex.ts +14 -4
  47. package/src/discovery/substitute-plugin-root.ts +23 -7
  48. package/src/export/html/template.js +2 -0
  49. package/src/internal-urls/__tests__/agent-protocol-nested.test.ts +73 -0
  50. package/src/internal-urls/agent-protocol.ts +73 -39
  51. package/src/lib/xai-http.ts +28 -2
  52. package/src/modes/acp/acp-agent.ts +28 -9
  53. package/src/modes/acp/acp-event-mapper.ts +8 -0
  54. package/src/modes/acp/acp-mode.ts +18 -4
  55. package/src/modes/components/assistant-message.ts +35 -14
  56. package/src/modes/components/chat-transcript-builder.ts +2 -0
  57. package/src/modes/components/custom-editor-plugin-ctor.test.ts +36 -0
  58. package/src/modes/components/custom-editor.ts +62 -1
  59. package/src/modes/components/hook-editor.ts +17 -2
  60. package/src/modes/components/login-dialog.test.ts +56 -0
  61. package/src/modes/components/login-dialog.ts +7 -3
  62. package/src/modes/components/plan-review-overlay.ts +51 -10
  63. package/src/modes/components/session-selector.ts +6 -0
  64. package/src/modes/components/status-line/component.ts +2 -4
  65. package/src/modes/components/tool-execution.test.ts +101 -0
  66. package/src/modes/components/tool-execution.ts +117 -9
  67. package/src/modes/components/transcript-container.ts +30 -2
  68. package/src/modes/controllers/command-controller-shared.ts +1 -1
  69. package/src/modes/controllers/command-controller.ts +1 -1
  70. package/src/modes/controllers/event-controller.ts +1 -0
  71. package/src/modes/controllers/selector-controller.ts +19 -17
  72. package/src/modes/interactive-mode.ts +66 -11
  73. package/src/modes/noninteractive-dispose.test.ts +60 -0
  74. package/src/modes/print-mode.ts +8 -3
  75. package/src/modes/rpc/rpc-mode.ts +12 -3
  76. package/src/modes/theme/theme.ts +2 -2
  77. package/src/modes/types.ts +10 -0
  78. package/src/modes/utils/interactive-context-helpers.ts +3 -1
  79. package/src/modes/utils/transcript-render-helpers.ts +3 -2
  80. package/src/prompts/system/system-prompt.md +1 -1
  81. package/src/sdk.ts +6 -2
  82. package/src/session/agent-session.ts +79 -34
  83. package/src/session/session-listing.ts +6 -5
  84. package/src/session/session-loader.ts +9 -0
  85. package/src/session/session-persistence.ts +11 -0
  86. package/src/session/streaming-output.ts +3 -1
  87. package/src/slash-commands/builtin-registry.ts +2 -0
  88. package/src/slash-commands/types.ts +4 -4
  89. package/src/system-prompt.ts +2 -2
  90. package/src/tools/browser/registry.ts +9 -2
  91. package/src/tools/browser/tab-supervisor.ts +65 -10
  92. package/src/tools/browser.ts +4 -3
  93. package/src/tools/eval.ts +3 -0
  94. package/src/tools/image-gen.ts +561 -512
  95. package/src/tools/index.ts +3 -1
  96. package/src/tools/manage-skill.ts +5 -3
  97. package/src/tools/output-meta.ts +7 -0
  98. package/src/tools/path-utils.ts +8 -5
  99. package/src/web/search/index.ts +21 -6
  100. package/src/web/search/providers/base.ts +3 -0
  101. package/src/web/search/providers/xai.ts +40 -9
@@ -59,8 +59,11 @@ export declare function isAdvisorInterruptImmuneTurnActive(opts: {
59
59
  * the live turn while one is streaming, or (when idle) a triggered turn so the
60
60
  * advice is acted on immediately.
61
61
  * - If the primary tail is already a terminal text answer and there is no queued
62
- * work, late interrupting advice is preserved as a visible card instead of
63
- * waking the primary to restate completion.
62
+ * work, a late `concern` is preserved as a visible card instead of waking the
63
+ * primary to restate completion. A `blocker` is the exception: it means the
64
+ * agent handed off broken or unexercised work, so it still steers a triggered
65
+ * turn to force the primary to acknowledge and continue before the turn is
66
+ * considered done (#5628) — deferring it to the next user turn is the bug.
64
67
  * - After a deliberate user interrupt (`autoResumeSuppressed`) the advisor must
65
68
  * not auto-resume the stopped run. While the agent is idle — or still tearing
66
69
  * the interrupted turn down (`aborting`) — the note is preserved as a visible
@@ -10,7 +10,20 @@
10
10
  */
11
11
  import type { CommandEntry } from "@oh-my-pi/pi-utils/cli";
12
12
  export declare const commands: CommandEntry[];
13
- export declare function reservedTopLevelWordMessage(first: string | undefined, argc?: number): string | undefined;
13
+ /**
14
+ * Hint for a reserved plugin/marketplace verb used as a top-level command, or
15
+ * `undefined` when the argv should fall through to `launch`.
16
+ *
17
+ * A bare verb (`omp marketplace`) always hints. A multi-word invocation only
18
+ * hints when the arguments follow the documented plugin grammar — a marketplace
19
+ * sub-action (`omp marketplace add …`) or a `name@marketplace` plugin id
20
+ * (`omp uninstall foo@bar`) — so genuine prompts that merely begin with one of
21
+ * these words (`omp list all my files`, `omp upgrade the deps`) still launch.
22
+ *
23
+ * Flags (`-…`) and `@file` arguments in the verb slot are never management
24
+ * commands; those fall through to the default `launch` command.
25
+ */
26
+ export declare function reservedTopLevelWordMessage(argv: readonly string[]): string | undefined;
14
27
  /**
15
28
  * Return true when `first` matches a registered subcommand name or alias.
16
29
  *
@@ -134,6 +134,10 @@ export declare class ModelRegistry {
134
134
  * Get the base URL associated with a provider, if any model defines one.
135
135
  */
136
136
  getProviderBaseUrl(provider: string): string | undefined;
137
+ /**
138
+ * Get provider-level headers without including per-model overrides.
139
+ */
140
+ getProviderHeaders(provider: string): Record<string, string> | undefined;
137
141
  /**
138
142
  * Get API key for a model.
139
143
  */
@@ -46,6 +46,7 @@ export declare const OpenAICompatSchema: import("arktype/internal/variants/objec
46
46
  alwaysSendMaxTokens?: boolean | undefined;
47
47
  strictResponsesPairing?: boolean | undefined;
48
48
  supportsImageDetailOriginal?: boolean | undefined;
49
+ supportsEagerToolInputStreaming?: boolean | undefined;
49
50
  requiresToolResultId?: boolean | undefined;
50
51
  replayUnsignedThinking?: boolean | undefined;
51
52
  whenThinking?: {
@@ -96,6 +97,7 @@ export declare const OpenAICompatSchema: import("arktype/internal/variants/objec
96
97
  alwaysSendMaxTokens?: boolean | undefined;
97
98
  strictResponsesPairing?: boolean | undefined;
98
99
  supportsImageDetailOriginal?: boolean | undefined;
100
+ supportsEagerToolInputStreaming?: boolean | undefined;
99
101
  requiresToolResultId?: boolean | undefined;
100
102
  replayUnsignedThinking?: boolean | undefined;
101
103
  } | undefined;
@@ -189,6 +191,7 @@ export declare const ModelOverrideSchema: import("arktype/internal/variants/obje
189
191
  alwaysSendMaxTokens?: boolean | undefined;
190
192
  strictResponsesPairing?: boolean | undefined;
191
193
  supportsImageDetailOriginal?: boolean | undefined;
194
+ supportsEagerToolInputStreaming?: boolean | undefined;
192
195
  requiresToolResultId?: boolean | undefined;
193
196
  replayUnsignedThinking?: boolean | undefined;
194
197
  whenThinking?: {
@@ -239,6 +242,7 @@ export declare const ModelOverrideSchema: import("arktype/internal/variants/obje
239
242
  alwaysSendMaxTokens?: boolean | undefined;
240
243
  strictResponsesPairing?: boolean | undefined;
241
244
  supportsImageDetailOriginal?: boolean | undefined;
245
+ supportsEagerToolInputStreaming?: boolean | undefined;
242
246
  requiresToolResultId?: boolean | undefined;
243
247
  replayUnsignedThinking?: boolean | undefined;
244
248
  } | undefined;
@@ -319,6 +323,7 @@ export declare const ModelsConfigSchema: import("arktype/internal/variants/objec
319
323
  alwaysSendMaxTokens?: boolean | undefined;
320
324
  strictResponsesPairing?: boolean | undefined;
321
325
  supportsImageDetailOriginal?: boolean | undefined;
326
+ supportsEagerToolInputStreaming?: boolean | undefined;
322
327
  requiresToolResultId?: boolean | undefined;
323
328
  replayUnsignedThinking?: boolean | undefined;
324
329
  whenThinking?: {
@@ -369,6 +374,7 @@ export declare const ModelsConfigSchema: import("arktype/internal/variants/objec
369
374
  alwaysSendMaxTokens?: boolean | undefined;
370
375
  strictResponsesPairing?: boolean | undefined;
371
376
  supportsImageDetailOriginal?: boolean | undefined;
377
+ supportsEagerToolInputStreaming?: boolean | undefined;
372
378
  requiresToolResultId?: boolean | undefined;
373
379
  replayUnsignedThinking?: boolean | undefined;
374
380
  } | undefined;
@@ -479,6 +485,7 @@ export declare const ModelsConfigSchema: import("arktype/internal/variants/objec
479
485
  alwaysSendMaxTokens?: boolean | undefined;
480
486
  strictResponsesPairing?: boolean | undefined;
481
487
  supportsImageDetailOriginal?: boolean | undefined;
488
+ supportsEagerToolInputStreaming?: boolean | undefined;
482
489
  requiresToolResultId?: boolean | undefined;
483
490
  replayUnsignedThinking?: boolean | undefined;
484
491
  whenThinking?: {
@@ -529,6 +536,7 @@ export declare const ModelsConfigSchema: import("arktype/internal/variants/objec
529
536
  alwaysSendMaxTokens?: boolean | undefined;
530
537
  strictResponsesPairing?: boolean | undefined;
531
538
  supportsImageDetailOriginal?: boolean | undefined;
539
+ supportsEagerToolInputStreaming?: boolean | undefined;
532
540
  requiresToolResultId?: boolean | undefined;
533
541
  replayUnsignedThinking?: boolean | undefined;
534
542
  } | undefined;
@@ -635,6 +643,7 @@ export declare const ModelsConfigSchema: import("arktype/internal/variants/objec
635
643
  alwaysSendMaxTokens?: boolean | undefined;
636
644
  strictResponsesPairing?: boolean | undefined;
637
645
  supportsImageDetailOriginal?: boolean | undefined;
646
+ supportsEagerToolInputStreaming?: boolean | undefined;
638
647
  requiresToolResultId?: boolean | undefined;
639
648
  replayUnsignedThinking?: boolean | undefined;
640
649
  whenThinking?: {
@@ -685,6 +694,7 @@ export declare const ModelsConfigSchema: import("arktype/internal/variants/objec
685
694
  alwaysSendMaxTokens?: boolean | undefined;
686
695
  strictResponsesPairing?: boolean | undefined;
687
696
  supportsImageDetailOriginal?: boolean | undefined;
697
+ supportsEagerToolInputStreaming?: boolean | undefined;
688
698
  requiresToolResultId?: boolean | undefined;
689
699
  replayUnsignedThinking?: boolean | undefined;
690
700
  } | undefined;
@@ -84,6 +84,7 @@ export declare const ModelsConfigFile: ConfigFile<{
84
84
  alwaysSendMaxTokens?: boolean | undefined;
85
85
  strictResponsesPairing?: boolean | undefined;
86
86
  supportsImageDetailOriginal?: boolean | undefined;
87
+ supportsEagerToolInputStreaming?: boolean | undefined;
87
88
  requiresToolResultId?: boolean | undefined;
88
89
  replayUnsignedThinking?: boolean | undefined;
89
90
  whenThinking?: {
@@ -134,6 +135,7 @@ export declare const ModelsConfigFile: ConfigFile<{
134
135
  alwaysSendMaxTokens?: boolean | undefined;
135
136
  strictResponsesPairing?: boolean | undefined;
136
137
  supportsImageDetailOriginal?: boolean | undefined;
138
+ supportsEagerToolInputStreaming?: boolean | undefined;
137
139
  requiresToolResultId?: boolean | undefined;
138
140
  replayUnsignedThinking?: boolean | undefined;
139
141
  } | undefined;
@@ -228,6 +230,7 @@ export declare const ModelsConfigFile: ConfigFile<{
228
230
  alwaysSendMaxTokens?: boolean | undefined;
229
231
  strictResponsesPairing?: boolean | undefined;
230
232
  supportsImageDetailOriginal?: boolean | undefined;
233
+ supportsEagerToolInputStreaming?: boolean | undefined;
231
234
  requiresToolResultId?: boolean | undefined;
232
235
  replayUnsignedThinking?: boolean | undefined;
233
236
  whenThinking?: {
@@ -278,6 +281,7 @@ export declare const ModelsConfigFile: ConfigFile<{
278
281
  alwaysSendMaxTokens?: boolean | undefined;
279
282
  strictResponsesPairing?: boolean | undefined;
280
283
  supportsImageDetailOriginal?: boolean | undefined;
284
+ supportsEagerToolInputStreaming?: boolean | undefined;
281
285
  requiresToolResultId?: boolean | undefined;
282
286
  replayUnsignedThinking?: boolean | undefined;
283
287
  } | undefined;
@@ -368,6 +372,7 @@ export declare const ModelsConfigFile: ConfigFile<{
368
372
  alwaysSendMaxTokens?: boolean | undefined;
369
373
  strictResponsesPairing?: boolean | undefined;
370
374
  supportsImageDetailOriginal?: boolean | undefined;
375
+ supportsEagerToolInputStreaming?: boolean | undefined;
371
376
  requiresToolResultId?: boolean | undefined;
372
377
  replayUnsignedThinking?: boolean | undefined;
373
378
  whenThinking?: {
@@ -418,6 +423,7 @@ export declare const ModelsConfigFile: ConfigFile<{
418
423
  alwaysSendMaxTokens?: boolean | undefined;
419
424
  strictResponsesPairing?: boolean | undefined;
420
425
  supportsImageDetailOriginal?: boolean | undefined;
426
+ supportsEagerToolInputStreaming?: boolean | undefined;
421
427
  requiresToolResultId?: boolean | undefined;
422
428
  replayUnsignedThinking?: boolean | undefined;
423
429
  } | undefined;
@@ -4715,7 +4715,7 @@ export declare const SETTINGS_SCHEMA: {
4715
4715
  readonly options: readonly [{
4716
4716
  readonly value: "auto";
4717
4717
  readonly label: "Auto";
4718
- readonly description: "Priority: GPT model image tool > Antigravity > xAI > OpenRouter > Gemini";
4718
+ readonly description: "Priority: active session provider > GPT model image tool > Antigravity > xAI > OpenRouter > Gemini";
4719
4719
  }, {
4720
4720
  readonly value: "openai";
4721
4721
  readonly label: "OpenAI";
@@ -1,23 +1,36 @@
1
1
  export declare function substitutePluginRoot<T>(value: T, rootPath: string): T;
2
2
  /**
3
- * Rebase relative filesystem values in a discovered plugin stdio config against
4
- * the directory of the `.mcp.json` that declared them.
3
+ * Where a relative, path-like `command` is rooted by {@link resolvePluginStdioPaths}.
5
4
  *
6
- * External plugin configs (bundled ChatGPT/Codex plugins, Claude marketplace
7
- * plugins) express `command`/`cwd` relative to their own config file, but MCP
8
- * stdio spawning roots relative values at the session cwd — so a plugin shipping
5
+ * - `"config-dir"` (default): the directory of the config file that declared the
6
+ * server the plugin package root for `.mcp.json`. A plugin can ship its
7
+ * executable at the package root (`command: "./bin/server"`) yet run from a
8
+ * data subdir (`cwd: "work"`); the command stays `<pkg>/bin/server`.
9
+ * - `"cwd"`: the rooted `cwd`, falling back to the config dir when no `cwd` is
10
+ * set. This matches how the OS resolves a relative command against the
11
+ * subprocess's working directory, which is the Codex `config.toml` contract:
12
+ * `cwd = "server"`, `command = "./bin/mcp"` → `<configDir>/server/bin/mcp`.
13
+ */
14
+ export type StdioCommandBase = "config-dir" | "cwd";
15
+ /**
16
+ * Rebase relative filesystem values in a discovered stdio server config against
17
+ * the directory of the config file (`.mcp.json`/`config.toml`) that declared them.
18
+ *
19
+ * External configs (bundled ChatGPT/Codex plugins, Claude marketplace plugins)
20
+ * express `command`/`cwd` relative to their own config file, but MCP stdio
21
+ * spawning roots relative values at the session cwd — so a server shipping
9
22
  * `command: "./bin/server"`, `cwd: "."` launches from the wrong directory and
10
23
  * fails with ENOENT. This resolves those against `configDir` instead:
11
24
  *
12
25
  * - relative `cwd` → resolved against `configDir`;
13
26
  * - path-like `command` (`./`, `../`, or the Windows `.\`/`..\` forms) →
14
- * resolved against `configDir`;
27
+ * resolved against the base selected by `commandBase` (see {@link StdioCommandBase});
15
28
  * - bare executables (`npx`, `uvx`, …) and absolute paths are left untouched.
16
29
  */
17
30
  export declare function resolvePluginStdioPaths(config: {
18
31
  command?: string;
19
32
  cwd?: string;
20
- }, configDir: string): {
33
+ }, configDir: string, commandBase?: StdioCommandBase): {
21
34
  command?: string;
22
35
  cwd?: string;
23
36
  };
@@ -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
  *
@@ -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>;
@@ -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,21 @@
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
14
  }
15
- export declare class HookEditorComponent extends Container {
15
+ /** Interactive multiline dialog used by hooks and the ask tool's Other response. */
16
+ export declare class HookEditorComponent extends Container implements Focusable {
16
17
  #private;
18
+ /** Focus state mirrored to the nested editor during rendering. */
19
+ focused: boolean;
17
20
  constructor(tui: TUI, title: string, prefill: string | undefined, onSubmit: (value: string) => void, onCancel: () => void, options?: HookEditorOptions);
21
+ /** Keep the nested editor's software/hardware cursor mode aligned with the dialog focus target. */
22
+ setUseTerminalCursor(useTerminalCursor: boolean): void;
23
+ /** Render the dialog after forwarding its focus state to the nested editor. */
24
+ render(width: number): readonly string[];
18
25
  handleInput(keyData: string): void;
19
26
  /** Route non-bracketed paste transports (e.g. kitty's OSC 5522 enhanced clipboard)
20
27
  * into the inner editor, mirroring bracketed-paste semantics. Without this hook,
@@ -0,0 +1 @@
1
+ export {};
@@ -83,6 +83,8 @@ 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;
86
88
  /**
87
89
  * Dispose the session list explicitly: while the delete-confirmation dialog
88
90
  * 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).
@@ -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 {};
@@ -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
  /**
@@ -34,7 +34,7 @@ import type { CustomTool } from "../extensibility/custom-tools/types.js";
34
34
  import type { ExtensionRunner } from "../extensibility/extensions/index.js";
35
35
  import type { CompactOptions, ContextUsage } from "../extensibility/extensions/types.js";
36
36
  import type { RecoveredRetryError } from "../extensibility/shared-events.js";
37
- import type { Skill, SkillWarning } from "../extensibility/skills.js";
37
+ import { type Skill, type SkillWarning } from "../extensibility/skills.js";
38
38
  import { type FileSlashCommand } from "../extensibility/slash-commands.js";
39
39
  import { GoalRuntime } from "../goals/runtime.js";
40
40
  import type { Goal, GoalModeState } from "../goals/state.js";
@@ -209,6 +209,8 @@ export interface AgentSessionConfig {
209
209
  skills?: Skill[];
210
210
  /** Skill loading warnings (already captured by SDK) */
211
211
  skillWarnings?: SkillWarning[];
212
+ /** Whether runtime reloads may rediscover disk-backed skills for this session. */
213
+ skillsReloadable?: boolean;
212
214
  /** Custom commands (TypeScript slash commands) */
213
215
  customCommands?: LoadedCustomCommand[];
214
216
  skillsSettings?: SkillsSettings;
@@ -689,6 +691,12 @@ export declare class AgentSession {
689
691
  /** Removes tools installed by {@link activateVibeTools} and activates `nextToolNames`. */
690
692
  deactivateVibeTools(nextToolNames: string[]): Promise<void>;
691
693
  getSelectedMCPToolNames(): string[];
694
+ /**
695
+ * Rediscover disk-backed skills and rebuild prompt-facing state without
696
+ * recreating the session. Explicit skill snapshots (`--no-skills`,
697
+ * SDK-provided `skills`) remain fixed for the lifetime of the session.
698
+ */
699
+ refreshSkills(): Promise<void>;
692
700
  /**
693
701
  * Set active tools by name.
694
702
  * Only tools in the registry can be enabled. Unknown tool names are ignored.
@@ -26,6 +26,8 @@ export interface OutputSummary {
26
26
  columnDroppedBytes?: number;
27
27
  /** Number of distinct lines that hit the per-line column cap. */
28
28
  columnTruncatedLines?: number;
29
+ /** Configured per-line column cap in effect (chars), when > 0. */
30
+ columnMax?: number;
29
31
  /** Artifact ID for internal URL access (artifact://<id>) when truncated */
30
32
  artifactId?: string;
31
33
  }
@@ -63,10 +63,10 @@ export interface SlashCommandRuntime {
63
63
  /** Re-advertise the available command list (no-op outside ACP). */
64
64
  refreshCommands: () => Promise<void> | void;
65
65
  /**
66
- * Reload plugin state (caches, slash command registry, project registries)
67
- * and re-emit available commands. Used by `/reload-plugins`, `/move`, and
68
- * `/marketplace`/`/plugins` mutations so the session sees a consistent view
69
- * after plugin or project-scope changes.
66
+ * Reload plugin state (caches, skills, slash command registry, project
67
+ * registries) and re-emit available commands. Used by `/reload-plugins`,
68
+ * `/move`, and `/marketplace`/`/plugins` mutations so the session sees a
69
+ * consistent view after plugin or project-scope changes.
70
70
  */
71
71
  reloadPlugins: () => Promise<void>;
72
72
  notifyTitleChanged?: () => Promise<void> | void;
@@ -79,7 +79,7 @@ export interface BuildSystemPromptOptions {
79
79
  depth?: number;
80
80
  }>;
81
81
  /** Skills provided directly to system prompt construction. */
82
- skills?: Skill[];
82
+ skills?: readonly Skill[];
83
83
  /** Pre-loaded rulebook rules (descriptions, excluding TTSR and always-apply). */
84
84
  rules?: Array<{
85
85
  name: string;
@@ -37,6 +37,12 @@ export interface CmuxBrowserHandle extends BrowserHandleCommon {
37
37
  surface?: string;
38
38
  }
39
39
  export type BrowserHandle = PuppeteerBrowserHandle | CmuxBrowserHandle;
40
+ /** Controls bounded browser-handle teardown and identifies the owning resource in timeout diagnostics. */
41
+ export interface ReleaseBrowserOptions {
42
+ kill: boolean;
43
+ timeoutMs?: number;
44
+ resource?: string;
45
+ }
40
46
  export interface AcquireBrowserOptions {
41
47
  cwd: string;
42
48
  viewport?: {
@@ -50,9 +56,7 @@ export interface AcquireBrowserOptions {
50
56
  export declare function acquireBrowser(kind: BrowserKind, opts: AcquireBrowserOptions): Promise<BrowserHandle>;
51
57
  export declare function normalizeConnectedCdpUrl(rawCdpUrl: string): string;
52
58
  export declare function holdBrowser(handle: BrowserHandle): void;
53
- export declare function releaseBrowser(handle: BrowserHandle, opts: {
54
- kill: boolean;
55
- }): Promise<void>;
59
+ export declare function releaseBrowser(handle: BrowserHandle, opts: ReleaseBrowserOptions): Promise<void>;
56
60
  /** Test-only accessor for the module-global browsers map. */
57
61
  export declare function getBrowsersMapForTest(): ReadonlyMap<string, BrowserHandle>;
58
62
  export {};
@@ -87,6 +87,8 @@ export interface RunInTabOptions {
87
87
  }
88
88
  export interface ReleaseTabOptions {
89
89
  kill?: boolean;
90
+ /** Maximum time for each asynchronous cleanup resource before close fails with diagnostics. */
91
+ timeoutMs?: number;
90
92
  }
91
93
  export declare function getTab(name: string): TabSession | undefined;
92
94
  export declare function acquireTab(name: string, browser: BrowserHandle, opts: AcquireTabOptions): Promise<AcquireTabResult>;
@@ -121,7 +121,9 @@ export interface ToolSession {
121
121
  /** Pre-loaded workspace tree (forwarded to subagents to skip re-scanning) */
122
122
  workspaceTree?: WorkspaceTree;
123
123
  /** Pre-loaded skills */
124
- skills?: Skill[];
124
+ skills?: readonly Skill[];
125
+ /** Rediscover live session skills after a tool mutates their backing files. */
126
+ refreshSkills?: () => Promise<void>;
125
127
  /** Pre-loaded prompt templates */
126
128
  promptTemplates?: PromptTemplate[];
127
129
  /** Pre-loaded rules (forwarded to subagents to skip re-discovery). */
@@ -12,6 +12,7 @@ export type ManageSkillParams = typeof manageSkillSchema.infer;
12
12
  * `autolearn.enabled`; backend-independent (the skill side is standalone).
13
13
  */
14
14
  export declare class ManageSkillTool implements AgentTool<typeof manageSkillSchema> {
15
+ private readonly refreshSkills?;
15
16
  readonly name = "manage_skill";
16
17
  readonly approval: "write";
17
18
  readonly label = "Manage Skill";
@@ -25,6 +26,7 @@ export declare class ManageSkillTool implements AgentTool<typeof manageSkillSche
25
26
  readonly strict = true;
26
27
  readonly loadMode: "essential";
27
28
  readonly summary = "Create, update, or delete an isolated managed skill";
29
+ constructor(refreshSkills?: (() => Promise<void>) | undefined);
28
30
  static createIf(session: ToolSession): ManageSkillTool | null;
29
31
  execute(_id: string, params: ManageSkillParams): Promise<AgentToolResult>;
30
32
  }
@@ -6,6 +6,7 @@
6
6
  */
7
7
  import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
8
8
  import type { AuthStorage } from "@oh-my-pi/pi-ai";
9
+ import { ModelRegistry } from "../../config/model-registry.js";
9
10
  import type { CustomTool } from "../../extensibility/custom-tools/types.js";
10
11
  import type { ToolSession } from "../../tools/index.js";
11
12
  import { type SearchRenderDetails } from "./render.js";
@@ -32,6 +33,7 @@ export interface SearchQueryParams extends SearchToolParams {
32
33
  */
33
34
  export declare function runSearchQuery(params: SearchQueryParams, options?: {
34
35
  authStorage?: AuthStorage;
36
+ modelRegistry?: ModelRegistry;
35
37
  sessionId?: string;
36
38
  signal?: AbortSignal;
37
39
  }): Promise<{
@@ -1,4 +1,5 @@
1
1
  import type { AuthStorage, FetchImpl } from "@oh-my-pi/pi-ai";
2
+ import type { ModelRegistry } from "../../../config/model-registry.js";
2
3
  import type { SearchProviderId, SearchResponse } from "../types.js";
3
4
  /**
4
5
  * Shared web search parameters passed to providers.
@@ -44,6 +45,8 @@ export interface SearchParams {
44
45
  * the per-credential single-flight refresh.
45
46
  */
46
47
  authStorage: AuthStorage;
48
+ /** Provider/model transport settings used by native search endpoints. */
49
+ modelRegistry?: ModelRegistry;
47
50
  /**
48
51
  * Optional session id used as the round-robin / sticky key when selecting
49
52
  * among multiple credentials for the same provider. Pass through from the