@oh-my-pi/pi-coding-agent 16.5.0 → 16.5.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 (198) hide show
  1. package/CHANGELOG.md +91 -0
  2. package/dist/cli.js +3556 -3504
  3. package/dist/types/advisor/advise-tool.d.ts +12 -1
  4. package/dist/types/advisor/runtime.d.ts +41 -1
  5. package/dist/types/cli/args.d.ts +2 -0
  6. package/dist/types/cli/update-cli.d.ts +4 -1
  7. package/dist/types/cli/usage-cli.d.ts +3 -0
  8. package/dist/types/cli/usage-error.d.ts +4 -0
  9. package/dist/types/config/api-key-resolver.d.ts +2 -2
  10. package/dist/types/config/model-registry.d.ts +3 -3
  11. package/dist/types/config/model-resolver.d.ts +8 -1
  12. package/dist/types/config/models-config.d.ts +1 -1
  13. package/dist/types/config/settings-schema.d.ts +10 -0
  14. package/dist/types/discovery/substitute-plugin-root.d.ts +22 -0
  15. package/dist/types/eval/__tests__/process-entry-import.test.d.ts +1 -0
  16. package/dist/types/eval/backend.d.ts +3 -3
  17. package/dist/types/eval/bridge-timeout.d.ts +9 -1
  18. package/dist/types/eval/js/context-manager.d.ts +5 -3
  19. package/dist/types/eval/js/process-entry.d.ts +6 -0
  20. package/dist/types/eval/js/worker-core.d.ts +15 -1
  21. package/dist/types/eval/py/spawn-options.d.ts +10 -0
  22. package/dist/types/eval/py/tool-bridge.d.ts +1 -0
  23. package/dist/types/extensibility/custom-tools/types.d.ts +3 -0
  24. package/dist/types/extensibility/extensions/runner.d.ts +3 -1
  25. package/dist/types/extensibility/extensions/types.d.ts +3 -0
  26. package/dist/types/extensibility/extensions/wrapper.d.ts +3 -6
  27. package/dist/types/extensibility/plugins/bun-git-cache.d.ts +3 -0
  28. package/dist/types/goals/guided-setup.d.ts +12 -0
  29. package/dist/types/internal-urls/history-protocol.d.ts +3 -2
  30. package/dist/types/internal-urls/memory-protocol.d.ts +6 -7
  31. package/dist/types/internal-urls/registry-helpers.d.ts +19 -0
  32. package/dist/types/main.d.ts +1 -0
  33. package/dist/types/mcp/oauth-discovery.d.ts +2 -0
  34. package/dist/types/mcp/oauth-flow.d.ts +2 -0
  35. package/dist/types/modes/components/__tests__/dynamic-border.test.d.ts +1 -0
  36. package/dist/types/modes/components/agent-hub.d.ts +10 -0
  37. package/dist/types/modes/components/dynamic-border.d.ts +5 -3
  38. package/dist/types/modes/components/login-dialog.d.ts +2 -0
  39. package/dist/types/modes/components/mcp-add-wizard.d.ts +1 -0
  40. package/dist/types/modes/components/read-tool-group.d.ts +0 -2
  41. package/dist/types/modes/components/transcript-container.d.ts +3 -2
  42. package/dist/types/modes/controllers/selector-controller.d.ts +1 -0
  43. package/dist/types/modes/interactive-mode.d.ts +1 -0
  44. package/dist/types/modes/magic-keyword-boundary.d.ts +9 -0
  45. package/dist/types/modes/orchestrate.d.ts +1 -1
  46. package/dist/types/modes/rpc/host-tools.d.ts +2 -0
  47. package/dist/types/modes/rpc/rpc-mode.d.ts +26 -6
  48. package/dist/types/modes/types.d.ts +1 -0
  49. package/dist/types/modes/ultrathink.d.ts +1 -1
  50. package/dist/types/modes/utils/transcript-render-helpers.d.ts +12 -0
  51. package/dist/types/modes/workflow.d.ts +1 -1
  52. package/dist/types/session/agent-session.d.ts +6 -0
  53. package/dist/types/session/exit-diagnostics.d.ts +11 -0
  54. package/dist/types/session/messages.d.ts +15 -0
  55. package/dist/types/slash-commands/helpers/active-oauth-account.d.ts +11 -0
  56. package/dist/types/subprocess/worker-client.d.ts +6 -0
  57. package/dist/types/tools/bash-skill-urls.d.ts +1 -0
  58. package/dist/types/tools/grep.d.ts +0 -2
  59. package/dist/types/tools/read.d.ts +0 -4
  60. package/dist/types/web/search/provider.d.ts +10 -3
  61. package/dist/types/web/search/providers/codex.d.ts +5 -4
  62. package/package.json +12 -12
  63. package/src/advisor/__tests__/advisor.test.ts +917 -42
  64. package/src/advisor/advise-tool.ts +17 -1
  65. package/src/advisor/runtime.ts +270 -67
  66. package/src/autolearn/controller.ts +15 -3
  67. package/src/autoresearch/dashboard.ts +2 -2
  68. package/src/cli/args.ts +12 -0
  69. package/src/cli/auth-broker-cli.ts +30 -11
  70. package/src/cli/auth-gateway-cli.ts +5 -1
  71. package/src/cli/config-cli.ts +15 -3
  72. package/src/cli/dry-balance-cli.ts +14 -4
  73. package/src/cli/flag-tables.ts +21 -7
  74. package/src/cli/update-cli.ts +62 -11
  75. package/src/cli/usage-cli.ts +58 -5
  76. package/src/cli/usage-error.ts +7 -0
  77. package/src/cli.ts +23 -1
  78. package/src/commands/acp.ts +11 -2
  79. package/src/commands/launch.ts +12 -3
  80. package/src/commands/token.ts +3 -1
  81. package/src/config/api-key-resolver.ts +12 -3
  82. package/src/config/config-file.ts +30 -12
  83. package/src/config/model-registry.ts +7 -7
  84. package/src/config/model-resolver.ts +21 -7
  85. package/src/config/models-config.ts +1 -1
  86. package/src/config/settings-schema.ts +10 -0
  87. package/src/cursor.ts +2 -0
  88. package/src/discovery/claude-plugins.ts +9 -3
  89. package/src/discovery/omp-plugins.ts +6 -2
  90. package/src/discovery/substitute-plugin-root.ts +32 -0
  91. package/src/eval/__tests__/agent-bridge.test.ts +19 -14
  92. package/src/eval/__tests__/bridge-timeout.test.ts +106 -0
  93. package/src/eval/__tests__/js-context-manager.test.ts +158 -1
  94. package/src/eval/__tests__/kernel-spawn.test.ts +12 -0
  95. package/src/eval/__tests__/prelude-agent.test.ts +20 -0
  96. package/src/eval/__tests__/process-entry-import.test.ts +27 -0
  97. package/src/eval/agent-bridge.ts +121 -116
  98. package/src/eval/backend.ts +3 -3
  99. package/src/eval/bridge-timeout.ts +20 -2
  100. package/src/eval/executor-base.ts +85 -7
  101. package/src/eval/jl/kernel.ts +2 -1
  102. package/src/eval/js/context-manager.ts +109 -32
  103. package/src/eval/js/process-entry.ts +27 -0
  104. package/src/eval/js/shared/runtime.ts +1 -1
  105. package/src/eval/js/worker-core.ts +70 -9
  106. package/src/eval/js/worker-entry.ts +1 -1
  107. package/src/eval/py/__tests__/prelude.test.ts +72 -0
  108. package/src/eval/py/kernel.ts +2 -1
  109. package/src/eval/py/prelude.py +28 -1
  110. package/src/eval/py/spawn-options.ts +13 -0
  111. package/src/eval/py/tool-bridge.ts +13 -14
  112. package/src/eval/rb/kernel.ts +2 -1
  113. package/src/exec/bash-executor.ts +30 -43
  114. package/src/extensibility/custom-tools/types.ts +3 -0
  115. package/src/extensibility/extensions/runner.ts +3 -0
  116. package/src/extensibility/extensions/types.ts +3 -0
  117. package/src/extensibility/extensions/wrapper.ts +18 -18
  118. package/src/extensibility/plugins/bun-git-cache.ts +91 -0
  119. package/src/extensibility/plugins/legacy-pi-compat.ts +32 -16
  120. package/src/extensibility/plugins/manager.ts +28 -7
  121. package/src/goals/guided-setup.ts +29 -1
  122. package/src/internal-urls/history-protocol.ts +95 -15
  123. package/src/internal-urls/memory-protocol.ts +13 -9
  124. package/src/internal-urls/registry-helpers.ts +50 -1
  125. package/src/launch/broker.ts +38 -25
  126. package/src/lsp/client.ts +7 -1
  127. package/src/main.ts +29 -0
  128. package/src/mcp/oauth-discovery.ts +20 -1
  129. package/src/mcp/oauth-flow.ts +3 -1
  130. package/src/mcp/tool-bridge.ts +57 -6
  131. package/src/modes/components/__tests__/dynamic-border.test.ts +55 -0
  132. package/src/modes/components/agent-dashboard.ts +2 -2
  133. package/src/modes/components/agent-hub.ts +15 -2
  134. package/src/modes/components/agent-transcript-viewer.ts +2 -2
  135. package/src/modes/components/chat-transcript-builder.ts +26 -4
  136. package/src/modes/components/dynamic-border.ts +9 -6
  137. package/src/modes/components/extensions/extension-list.ts +2 -2
  138. package/src/modes/components/hook-selector.ts +10 -4
  139. package/src/modes/components/login-dialog.ts +5 -0
  140. package/src/modes/components/mcp-add-wizard.ts +5 -0
  141. package/src/modes/components/plan-review-overlay.ts +11 -11
  142. package/src/modes/components/read-tool-group.ts +1 -8
  143. package/src/modes/components/status-line/component.ts +10 -1
  144. package/src/modes/components/transcript-container.ts +110 -7
  145. package/src/modes/controllers/command-controller.ts +12 -4
  146. package/src/modes/controllers/event-controller.ts +80 -15
  147. package/src/modes/controllers/input-controller.ts +4 -2
  148. package/src/modes/controllers/mcp-command-controller.ts +6 -7
  149. package/src/modes/controllers/selector-controller.ts +24 -5
  150. package/src/modes/controllers/todo-command-controller.ts +18 -14
  151. package/src/modes/interactive-mode.ts +7 -3
  152. package/src/modes/magic-keyword-boundary.ts +23 -0
  153. package/src/modes/orchestrate.ts +6 -5
  154. package/src/modes/print-mode.ts +9 -0
  155. package/src/modes/prompt-action-autocomplete.ts +6 -1
  156. package/src/modes/rpc/host-tools.ts +15 -0
  157. package/src/modes/rpc/rpc-mode.ts +123 -48
  158. package/src/modes/types.ts +1 -1
  159. package/src/modes/ultrathink.ts +6 -5
  160. package/src/modes/utils/transcript-render-helpers.ts +54 -0
  161. package/src/modes/utils/ui-helpers.ts +27 -1
  162. package/src/modes/workflow.ts +6 -5
  163. package/src/prompts/advisor/system.md +1 -0
  164. package/src/prompts/system/system-prompt.md +1 -0
  165. package/src/prompts/tools/eval.md +2 -2
  166. package/src/prompts/tools/grep.md +1 -2
  167. package/src/prompts/tools/read.md +2 -4
  168. package/src/sdk.ts +61 -34
  169. package/src/session/agent-session.ts +283 -39
  170. package/src/session/exit-diagnostics.ts +108 -0
  171. package/src/session/messages.test.ts +66 -0
  172. package/src/session/messages.ts +37 -0
  173. package/src/session/streaming-output.ts +40 -12
  174. package/src/slash-commands/helpers/active-oauth-account.ts +22 -2
  175. package/src/slash-commands/helpers/logout.ts +23 -3
  176. package/src/slash-commands/helpers/usage-report.ts +14 -2
  177. package/src/subprocess/worker-client.ts +9 -2
  178. package/src/system-prompt.test.ts +36 -0
  179. package/src/system-prompt.ts +1 -1
  180. package/src/task/executor.ts +8 -0
  181. package/src/task/render.test.ts +36 -0
  182. package/src/task/render.ts +55 -43
  183. package/src/tools/bash-skill-urls.ts +4 -1
  184. package/src/tools/bash.ts +1 -0
  185. package/src/tools/browser/registry.ts +17 -3
  186. package/src/tools/eval.ts +14 -9
  187. package/src/tools/gh.ts +3 -1
  188. package/src/tools/grep.ts +5 -45
  189. package/src/tools/path-utils.ts +7 -1
  190. package/src/tools/read.ts +23 -74
  191. package/src/tools/write.ts +82 -9
  192. package/src/tools/yield.ts +29 -1
  193. package/src/utils/title-generator.ts +10 -6
  194. package/src/web/search/index.ts +39 -22
  195. package/src/web/search/provider.ts +33 -16
  196. package/src/web/search/providers/codex.ts +68 -21
  197. package/src/web/search/providers/perplexity-auth.ts +20 -11
  198. package/src/web/search/providers/perplexity.ts +14 -2
@@ -36,6 +36,13 @@ export declare function formatAdvisorBatchContent(notes: readonly AdvisorNote[])
36
36
  * and `blocker` interrupt; a plain `nit` queues.
37
37
  */
38
38
  export declare function isInterruptingSeverity(severity: AdvisorSeverity | undefined): boolean;
39
+ /**
40
+ * Append a staleness caveat to an advisor note when newer primary turns arrived
41
+ * after the reviewed transcript window (i.e. `hasFreshBacklog` is true on the
42
+ * advisor runtime at delivery time). Pure function — no session coupling — so it
43
+ * can be unit-tested in isolation and called from `AgentSession#routeAdvice`.
44
+ */
45
+ export declare function annotateForStaleness(note: string, hasFreshBacklog: boolean): string;
39
46
  /** How an advisor note is routed to the primary. */
40
47
  export type AdvisorDeliveryChannel = "aside" | "steer" | "preserve";
41
48
  /** Half-open turn-count fence for the post-interrupt cooldown. */
@@ -51,6 +58,9 @@ export declare function isAdvisorInterruptImmuneTurnActive(opts: {
51
58
  * - An interrupting `concern`/`blocker` is normally steered into the agent: into
52
59
  * the live turn while one is streaming, or (when idle) a triggered turn so the
53
60
  * advice is acted on immediately.
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.
54
64
  * - After a deliberate user interrupt (`autoResumeSuppressed`) the advisor must
55
65
  * not auto-resume the stopped run. While the agent is idle — or still tearing
56
66
  * the interrupted turn down (`aborting`) — the note is preserved as a visible
@@ -60,13 +70,14 @@ export declare function isAdvisorInterruptImmuneTurnActive(opts: {
60
70
  * run instead strands it (it never reaches the running agent) and the withheld
61
71
  * notes dump as one burst at the next user prompt — the bug this guards.
62
72
  * - During the post-interrupt immune-turn window, further `concern`/`blocker`
63
- * notes are downgraded to asides; suppression preservation still wins.
73
+ * notes are downgraded to asides; preservation still wins.
64
74
  */
65
75
  export declare function resolveAdvisorDeliveryChannel(opts: {
66
76
  severity: AdvisorSeverity | undefined;
67
77
  autoResumeSuppressed: boolean;
68
78
  streaming: boolean;
69
79
  aborting: boolean;
80
+ terminalAnswerNoQueuedWork?: boolean;
70
81
  interruptImmuneTurnActive?: boolean;
71
82
  }): AdvisorDeliveryChannel;
72
83
  /**
@@ -1,4 +1,5 @@
1
1
  import type { AgentMessage } from "@oh-my-pi/pi-agent-core";
2
+ import type { AssistantMessage } from "@oh-my-pi/pi-ai";
2
3
  import { type SecretObfuscator } from "../secrets/obfuscator.js";
3
4
  /**
4
5
  * Minimal slice of `Agent` the runtime drives — satisfied by pi-agent-core
@@ -59,6 +60,24 @@ export interface AdvisorRuntimeHost {
59
60
  /** Surface a non-recovering advisor failure to the host UI without adding model-visible context. */
60
61
  notifyFailure?(error: unknown): void;
61
62
  }
63
+ /** Signals that an advisor response was discarded before it could become model-visible context. */
64
+ export declare class AdvisorOutputQuarantinedError extends Error {
65
+ constructor(message: string);
66
+ }
67
+ /**
68
+ * Replaces an advisor assistant turn that requested unavailable tools or generated
69
+ * output-only destructive directives with a sanitized error before dispatch.
70
+ *
71
+ * The agent loop records assistant turns before dispatching tools. Without this
72
+ * pre-dispatch rewrite, an advisor hallucination can leave unrelated text in the
73
+ * advisor transcript even though the action itself never executes.
74
+ */
75
+ export declare function quarantineAdvisorUnsafeOutput(message: AssistantMessage, availableToolNames: ReadonlySet<string>, sourceText?: string): string | undefined;
76
+ /**
77
+ * Builds the provenance text used to decide whether hazardous advisor output was
78
+ * generated by the advisor or came from model-visible primary/tool context.
79
+ */
80
+ export declare function buildAdvisorQuarantineSourceText(currentInput: string, messages: readonly AgentMessage[]): string;
62
81
  export declare class AdvisorRuntime {
63
82
  #private;
64
83
  private readonly agent;
@@ -67,7 +86,28 @@ export declare class AdvisorRuntime {
67
86
  disposed: boolean;
68
87
  constructor(agent: AdvisorAgent, host: AdvisorRuntimeHost, retryDelayMs?: number);
69
88
  get backlog(): number;
70
- onTurnEnd(messages?: AgentMessage[]): void;
89
+ /**
90
+ * True when `#pending` is non-empty while the drain loop is busy — i.e., newer
91
+ * primary turns arrived after the current batch's transcript window was fixed
92
+ * but before the advisor model finished processing it. The delivery path uses
93
+ * this to annotate advice that was generated without seeing those newer turns.
94
+ * Can be true during `agent.prompt()`, a `maintainContext` await, or a retry
95
+ * sleep — any time `#drain` is busy and a concurrent `onTurnEnd` pushed.
96
+ */
97
+ get hasFreshBacklog(): boolean;
98
+ /**
99
+ * Called after each primary turn ends. Renders the incremental delta and
100
+ * queues it for the advisor model.
101
+ *
102
+ * @param messages - Live primary transcript snapshot (defaults to `snapshotMessages()`).
103
+ * @param opts.willContinue - When `true` the primary is mid-turn (more tool-call
104
+ * steps will follow). The rendered heading is tagged `[in progress]` so the
105
+ * advisor knows to withhold critique on partial work. The flag is carried on
106
+ * the delta and forwarded to the reprime path so it is never silently dropped.
107
+ */
108
+ onTurnEnd(messages?: AgentMessage[], opts?: {
109
+ willContinue?: boolean;
110
+ }): void;
71
111
  waitForCatchup(maxMs: number, threshold: number, signal?: AbortSignal): Promise<void>;
72
112
  dispose(): void;
73
113
  /**
@@ -79,5 +79,7 @@ export declare function parseArgs(inputArgs: string[], extensionFlags?: Map<stri
79
79
  * process (issue #2459).
80
80
  */
81
81
  export declare function reportUnrecognizedFlags(args: Pick<Args, "unrecognizedFlags">, write?: (text: string) => void): boolean;
82
+ /** Emit a clean CLI usage error without an internal stack trace. */
83
+ export declare function reportCliUsageError(error: unknown, write?: (text: string) => void): boolean;
82
84
  export declare function getExtraHelpText(): string;
83
85
  export declare function printHelp(): void;
@@ -21,11 +21,12 @@ export declare function parseUpdateArgs(args: string[]): {
21
21
  check: boolean;
22
22
  plugins: boolean;
23
23
  } | undefined;
24
- type UpdateMethod = "brew" | "mise" | "bun" | "binary";
24
+ type UpdateMethod = "brew" | "mise" | "bun" | "npm" | "binary";
25
25
  interface UpdateMethodResolutionOptions {
26
26
  homebrewPrefix?: string;
27
27
  miseBinDirs?: readonly string[];
28
28
  miseDataDir?: string;
29
+ npmBinDir?: string;
29
30
  }
30
31
  export declare function resolveUpdateMethodForTest(ompPath: string, bunBinDir: string | undefined, options?: UpdateMethodResolutionOptions): UpdateMethod;
31
32
  interface BunInstallCachePruneResult {
@@ -89,6 +90,8 @@ export declare function replaceBinaryForUpdate(options: BinaryReplacementOptions
89
90
  * See #1824.
90
91
  */
91
92
  export declare function buildBunInstallArgs(expectedVersion: string, nativeTag?: string): string[];
93
+ /** Build the npm argv used to update npm-managed global installs. */
94
+ export declare function buildNpmInstallArgs(expectedVersion: string, nativeTag?: string): string[];
92
95
  export declare function buildHomebrewUpdateArgs(force: boolean): string[];
93
96
  export declare function buildMiseUpgradeArgs(): string[];
94
97
  export declare function buildMiseForceInstallArgs(expectedVersion: string): string[];
@@ -26,6 +26,9 @@ export interface UsageAccountIdentity {
26
26
  accountId?: string;
27
27
  projectId?: string;
28
28
  enterpriseUrl?: string;
29
+ /** Organization/workspace the credential is scoped to (Anthropic multi-subscription). */
30
+ orgId?: string;
31
+ orgName?: string;
29
32
  }
30
33
  /**
31
34
  * Minimal-reveal masks for identity strings (`--redact`).
@@ -0,0 +1,4 @@
1
+ /** Command-line input error that should be rendered without a stack trace. */
2
+ export declare class CliUsageError extends Error {
3
+ constructor(message: string);
4
+ }
@@ -1,4 +1,4 @@
1
- import type { Api, ApiKeyResolver, AuthStorage, Model } from "@oh-my-pi/pi-ai";
1
+ import { type Api, type ApiKeyResolver, type AuthStorage, type Model } from "@oh-my-pi/pi-ai";
2
2
  /** Model slice accepted by the model-form `resolver(model, sessionId)` overload. */
3
3
  export type ApiKeyResolverModel = Pick<Model<Api>, "provider" | "baseUrl" | "id">;
4
4
  export interface ApiKeyResolverOptions {
@@ -25,7 +25,7 @@ export interface ApiKeyResolverRegistry {
25
25
  /**
26
26
  * Build an {@link ApiKeyResolver} implementing the central a/b/c auth-retry
27
27
  * policy: initial → resolve; step (b) → force-refresh same account; step (c)
28
- * → rotate to a sibling credential, then re-resolve.
28
+ * → rotate to a sibling and re-resolve, unless quota exhaustion has no sibling.
29
29
  *
30
30
  * Two call forms: `resolver(provider, options?)` for provider-scoped keys,
31
31
  * and `resolver(model, sessionId?)` which derives `baseUrl`/`modelId` from
@@ -74,7 +74,7 @@ export declare class ModelRegistry {
74
74
  fetch?: FetchImpl;
75
75
  });
76
76
  /**
77
- * Reload models from disk (built-in + custom from models.json).
77
+ * Reload models from disk (built-in + custom config).
78
78
  */
79
79
  refresh(strategy?: ModelRefreshStrategy): Promise<void>;
80
80
  refreshInBackground(strategy?: ModelRefreshStrategy): void;
@@ -94,12 +94,12 @@ export declare class ModelRegistry {
94
94
  */
95
95
  refreshRuntimeProviders(strategy?: ModelRefreshStrategy): Promise<void>;
96
96
  /**
97
- * Get any error from loading models.json (undefined if no error).
97
+ * Get any error from loading custom models config (undefined if no error).
98
98
  */
99
99
  getError(): ConfigError | undefined;
100
100
  /**
101
101
  * Get all models (built-in + custom).
102
- * If models.json had errors, returns only built-in models.
102
+ * If custom config had errors, returns only built-in models.
103
103
  */
104
104
  getAll(): Model<Api>[];
105
105
  /**
@@ -144,6 +144,7 @@ export declare function resolveModelOverride(modelPatterns: string[], modelRegis
144
144
  model?: Model<Api>;
145
145
  thinkingLevel?: ConfiguredThinkingLevel;
146
146
  explicitThinkingLevel: boolean;
147
+ warning?: string;
147
148
  };
148
149
  /**
149
150
  * Resolve a list of override patterns to the first matching model, with an
@@ -156,6 +157,11 @@ export declare function resolveModelOverride(modelPatterns: string[], modelRegis
156
157
  * `modelRoles.task` pointing at an unqualified id whose only available
157
158
  * provider variant has no configured credentials — see #985).
158
159
  *
160
+ * `sessionId` is forwarded to `getApiKey` so that session-sticky OAuth
161
+ * credentials resolve correctly during the pre-flight auth check. Without it,
162
+ * providers with multiple OAuth accounts may return `undefined` even though
163
+ * the credential is usable once the subagent session starts — see #5325.
164
+ *
159
165
  * Keyless-by-design providers (llama.cpp, ollama, lm-studio) advertise the
160
166
  * `kNoAuth` sentinel from `getApiKey` to signal that they do not require
161
167
  * credentials. Those are treated as authenticated here so an explicitly
@@ -166,11 +172,12 @@ export declare function resolveModelOverride(modelPatterns: string[], modelRegis
166
172
  * primary resolution unchanged so the existing error path still surfaces
167
173
  * a meaningful failure downstream.
168
174
  */
169
- export declare function resolveModelOverrideWithAuthFallback(modelPatterns: string[], parentActiveModelPattern: string | undefined, modelRegistry: ModelLookupRegistry & Pick<ModelRegistry, "getApiKey">, settings?: Settings): Promise<{
175
+ export declare function resolveModelOverrideWithAuthFallback(modelPatterns: string[], parentActiveModelPattern: string | undefined, modelRegistry: ModelLookupRegistry & Pick<ModelRegistry, "getApiKey">, settings?: Settings, sessionId?: string): Promise<{
170
176
  model?: Model<Api>;
171
177
  thinkingLevel?: ConfiguredThinkingLevel;
172
178
  explicitThinkingLevel: boolean;
173
179
  authFallbackUsed: boolean;
180
+ warning?: string;
174
181
  }>;
175
182
  /**
176
183
  * Resolve a list of role patterns to the first matching model.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * models.json config file handle and provider configuration validation.
2
+ * Custom model/provider config file handle and validation.
3
3
  */
4
4
  import type { Api, ModelSpec } from "@oh-my-pi/pi-ai/types";
5
5
  import { ConfigFile } from "./config-file.js";
@@ -3699,6 +3699,16 @@ export declare const SETTINGS_SCHEMA: {
3699
3699
  readonly description: "Enable the tts tool for on-device (Kokoro) or xAI Grok Voice speech-file synthesis";
3700
3700
  };
3701
3701
  };
3702
+ readonly "generate_image.enabled": {
3703
+ readonly type: "boolean";
3704
+ readonly default: true;
3705
+ readonly ui: {
3706
+ readonly tab: "tools";
3707
+ readonly group: "Available Tools";
3708
+ readonly label: "Generate Image";
3709
+ readonly description: "Enable the generate_image tool for text-to-image generation and editing";
3710
+ };
3711
+ };
3702
3712
  readonly "inspect_image.enabled": {
3703
3713
  readonly type: "boolean";
3704
3714
  readonly default: false;
@@ -1 +1,23 @@
1
1
  export declare function substitutePluginRoot<T>(value: T, rootPath: string): T;
2
+ /**
3
+ * Rebase relative filesystem values in a discovered plugin stdio config against
4
+ * the directory of the `.mcp.json` that declared them.
5
+ *
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
9
+ * `command: "./bin/server"`, `cwd: "."` launches from the wrong directory and
10
+ * fails with ENOENT. This resolves those against `configDir` instead:
11
+ *
12
+ * - relative `cwd` → resolved against `configDir`;
13
+ * - path-like `command` (`./`, `../`, or the Windows `.\`/`..\` forms) →
14
+ * resolved against `configDir`;
15
+ * - bare executables (`npx`, `uvx`, …) and absolute paths are left untouched.
16
+ */
17
+ export declare function resolvePluginStdioPaths(config: {
18
+ command?: string;
19
+ cwd?: string;
20
+ }, configDir: string): {
21
+ command?: string;
22
+ cwd?: string;
23
+ };
@@ -13,10 +13,10 @@ export interface ExecutorBackendExecOptions {
13
13
  * driven entirely by `signal`, which the eval tool arms as a watchdog that
14
14
  * pauses on bridge timeout-control status events and fires a `TimeoutError`
15
15
  * reason only while the Python/JS runtime owns control. Backends use this
16
- * value only for timeout-annotation text and as cold-start headroom; they MUST
17
- * NOT derive a competing wall-clock timer from it.
16
+ * value only for timeout-annotation text and as cold-start headroom; undefined
17
+ * disables the cell timeout. Backends MUST NOT derive a competing wall-clock timer from it.
18
18
  */
19
- idleTimeoutMs: number;
19
+ idleTimeoutMs?: number;
20
20
  reset: boolean;
21
21
  onChunk: (chunk: string) => void;
22
22
  /**
@@ -20,8 +20,16 @@ export declare const EVAL_TIMEOUT_PAUSE_OP = "timeout-pause";
20
20
  export declare const EVAL_TIMEOUT_RESUME_OP = "timeout-resume";
21
21
  /** Whether a status event is pure eval-timeout control and should not render. */
22
22
  export declare function isEvalTimeoutControlEvent(event: JsStatusEvent): boolean;
23
+ /** Optional behavior for a timeout pause around a host bridge call. */
24
+ export interface BridgeTimeoutPauseOptions {
25
+ /**
26
+ * Marks the pause as an `agent()` call whose already-started work must finish
27
+ * before an external eval abort reaches the kernel.
28
+ */
29
+ deferExternalAbort?: boolean;
30
+ }
23
31
  /**
24
32
  * Run {@link operation} while suspending the eval watchdog through
25
33
  * {@link emitStatus}. A no-op wrapper when no status sink is wired.
26
34
  */
27
- export declare function withBridgeTimeoutPause<T>(emitStatus: ((event: JsStatusEvent) => void) | undefined, operation: () => Promise<T>): Promise<T>;
35
+ export declare function withBridgeTimeoutPause<T>(emitStatus: ((event: JsStatusEvent) => void) | undefined, operation: () => Promise<T>, options?: BridgeTimeoutPauseOptions): Promise<T>;
@@ -13,6 +13,8 @@ export interface VmRunState {
13
13
  * {@link WORKER_CLOSE_TIMEOUT_MS}; never call this outside tests.
14
14
  */
15
15
  export declare function setWorkerCloseTimeoutMsForTests(ms: number): number;
16
+ /** Test-only seam for the legacy Worker lifecycle mocks. */
17
+ export declare function setJsEvalWorkerThreadForTests(enabled: boolean): boolean;
16
18
  export declare function executeInVmContext(options: {
17
19
  sessionKey: string;
18
20
  sessionId: string;
@@ -30,9 +32,9 @@ export declare function executeInVmContext(options: {
30
32
  export declare function resetVmContext(sessionKey: string): Promise<void>;
31
33
  export declare function disposeAllVmContexts(): Promise<void>;
32
34
  /**
33
- * Smoke probe: spawn the JS eval worker through the worker-host entry and prove
34
- * it answers the `init` handshake on a real worker thread (not the inline
35
- * fallback). Catches the silent worker-load and init-message-drop regressions
35
+ * Smoke probe: spawn the JS evaluator through the worker-host entry and prove
36
+ * it answers the `init` handshake in a real isolated subprocess (not the inline
37
+ * fallback). Catches silent process-load and init-message regressions
36
38
  * that otherwise strand every cell on the init timeout in a distribution build —
37
39
  * the failure mode that motivated `installWorkerInbox`. Wired into
38
40
  * `omp --smoke-test` so binary / source / tarball installs all exercise it.
@@ -0,0 +1,6 @@
1
+ import type { WorkerInbound, WorkerOutbound } from "./worker-protocol.js";
2
+ /** Start the JavaScript evaluator inside a subprocess IPC transport. */
3
+ export declare function startJsEvalProcess(transport: {
4
+ send(message: WorkerOutbound): void;
5
+ onMessage(handler: (message: WorkerInbound) => void): () => void;
6
+ }): void;
@@ -1,6 +1,20 @@
1
1
  import type { Transport } from "./worker-protocol.js";
2
+ export type WorkerCoreOptions = {
3
+ mode: "isolated";
4
+ /**
5
+ * Mirror the session cwd onto the real process cwd so cell code using
6
+ * `process.cwd()`, relative paths, or child processes without an explicit
7
+ * `cwd` resolves against the project. Only the dedicated subprocess may
8
+ * pass this: `process.chdir` is unavailable in Worker threads and would
9
+ * mutate the host's own cwd on the inline fallback.
10
+ */
11
+ chdir?: (cwd: string) => void;
12
+ } | {
13
+ mode: "inline";
14
+ interceptUnhandledRejections(handler: (reason: unknown) => boolean): () => void;
15
+ };
2
16
  export declare class WorkerCore {
3
17
  #private;
4
- constructor(transport: Transport);
18
+ constructor(transport: Transport, options: WorkerCoreOptions);
5
19
  dispose(): void;
6
20
  }
@@ -26,6 +26,16 @@ export declare function shouldHideKernelWindow(opts: {
26
26
  platform: NodeJS.Platform;
27
27
  hostHasInheritableConsole: boolean;
28
28
  }): boolean;
29
+ /**
30
+ * Keep eval kernels outside the host's POSIX terminal session.
31
+ *
32
+ * User code can start an interactive shell which calls `tcsetpgrp(3)`. If the
33
+ * kernel shares OMP's session, that shell can replace OMP as the controlling
34
+ * terminal's foreground process group and the host is then stopped by SIGTTIN
35
+ * on its next stdin read. Bun implements `detached: true` with `setsid(2)` on
36
+ * POSIX, making the kernel a session leader with no controlling terminal.
37
+ */
38
+ export declare function shouldDetachKernel(platform: NodeJS.Platform): boolean;
29
39
  /**
30
40
  * TTY-based fallback used when the Win32 console probe is unavailable.
31
41
  *
@@ -4,6 +4,7 @@ export interface PyToolBridgeEntry {
4
4
  toolSession: ToolSession;
5
5
  signal?: AbortSignal;
6
6
  emitStatus?: (event: JsStatusEvent) => void;
7
+ abortRequested?: () => boolean;
7
8
  }
8
9
  export interface PyToolBridgeInfo {
9
10
  url: string;
@@ -17,6 +17,7 @@ import type { Settings } from "../../config/settings.js";
17
17
  import type { ExecOptions, ExecResult } from "../../exec/exec.js";
18
18
  import type { HookUIContext } from "../../extensibility/hooks/types.js";
19
19
  import type * as PiCodingAgent from "../../index.js";
20
+ import type { LocalProtocolOptions } from "../../internal-urls/local-protocol.js";
20
21
  import type { Theme } from "../../modes/theme/theme.js";
21
22
  import type { ReadonlySessionManager } from "../../session/session-manager.js";
22
23
  import type { TodoItem } from "../../tools/todo.js";
@@ -84,6 +85,8 @@ export interface CustomToolContext {
84
85
  settings?: Settings;
85
86
  /** Fetch implementation for outbound HTTP; defaults to global fetch when omitted. */
86
87
  fetch?: FetchImpl;
88
+ /** Calling session's `local://` root mapping for tools that bridge out of the OMP process. */
89
+ localProtocolOptions?: LocalProtocolOptions;
87
90
  /** Whether to auto-approve all destructive tool operations (--auto-approve CLI flag) */
88
91
  autoApprove?: boolean;
89
92
  }
@@ -6,6 +6,7 @@ import type { CredentialDisabledEvent, ImageContent, Model, ProviderResponseMeta
6
6
  import type { KeyId } from "@oh-my-pi/pi-tui";
7
7
  import type { ModelRegistry } from "../../config/model-registry.js";
8
8
  import type { Settings } from "../../config/settings.js";
9
+ import type { LocalProtocolOptions } from "../../internal-urls/local-protocol.js";
9
10
  import type { MemoryRuntimeContext } from "../../memory-backend/index.js";
10
11
  import type { SessionManager } from "../../session/session-manager.js";
11
12
  import type { BranchHandler, NavigateTreeHandler, NewSessionHandler } from "../session-handler-types.js";
@@ -65,7 +66,8 @@ export declare class ExtensionRunner {
65
66
  private readonly sessionManager;
66
67
  private readonly modelRegistry;
67
68
  private readonly settings?;
68
- constructor(extensions: Extension[], runtime: ExtensionRuntime, cwd: string, sessionManager: SessionManager, modelRegistry: ModelRegistry, getMemory?: () => MemoryRuntimeContext | undefined, settings?: Settings | undefined);
69
+ private readonly localProtocolOptions?;
70
+ constructor(extensions: Extension[], runtime: ExtensionRuntime, cwd: string, sessionManager: SessionManager, modelRegistry: ModelRegistry, getMemory?: () => MemoryRuntimeContext | undefined, settings?: Settings | undefined, localProtocolOptions?: LocalProtocolOptions | undefined);
69
71
  initialize(actions: ExtensionActions, contextActions: ExtensionContextActions, commandContextActions?: ExtensionCommandContextActions, uiContext?: ExtensionUIContext): void;
70
72
  /**
71
73
  * Forward a `credential_disabled` event from `AuthStorage` to extension handlers.
@@ -22,6 +22,7 @@ import type { PythonResult } from "../../eval/py/executor.js";
22
22
  import type { BashResult } from "../../exec/bash-executor.js";
23
23
  import type { ExecOptions, ExecResult } from "../../exec/exec.js";
24
24
  import type * as PiCodingAgent from "../../index.js";
25
+ import type { LocalProtocolOptions } from "../../internal-urls/local-protocol.js";
25
26
  import type { MemoryRuntimeContext } from "../../memory-backend/index.js";
26
27
  import type { CustomEditor } from "../../modes/components/custom-editor.js";
27
28
  import type { Theme } from "../../modes/theme/theme.js";
@@ -285,6 +286,8 @@ export interface ExtensionContext {
285
286
  sessionManager: ReadonlySessionManager;
286
287
  /** Model registry for API key resolution */
287
288
  modelRegistry: ModelRegistry;
289
+ /** Calling session's `local://` root mapping for external tool bridges. */
290
+ localProtocolOptions?: LocalProtocolOptions;
288
291
  /** Current model (may be undefined) */
289
292
  model: Model | undefined;
290
293
  /** Read-only model query facade: list / current / resolve / family. */
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Tool wrappers for extensions.
3
3
  */
4
- import type { AgentTool, AgentToolContext, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
4
+ import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
5
5
  import type { Static, TSchema } from "@oh-my-pi/pi-ai";
6
6
  import type { ExtensionRunner } from "./runner.js";
7
7
  import type { RegisteredTool } from "./types.js";
@@ -19,7 +19,7 @@ export declare class RegisteredToolAdapter implements AgentTool<any, any, any> {
19
19
  renderCall?: (args: any, options: any, theme: any) => any;
20
20
  renderResult?: (result: any, options: any, theme: any, args?: any) => any;
21
21
  constructor(registeredTool: RegisteredTool, runner: ExtensionRunner);
22
- execute(toolCallId: string, params: any, signal?: AbortSignal, onUpdate?: AgentToolUpdateCallback<any>, _context?: AgentToolContext): Promise<import("@oh-my-pi/pi-agent-core").AgentToolResult<unknown, unknown>>;
22
+ execute(toolCallId: string, params: any, signal?: AbortSignal, onUpdate?: AgentToolUpdateCallback<any>, _context?: AgentToolContext): Promise<AgentToolResult<unknown, unknown>>;
23
23
  }
24
24
  /**
25
25
  * Backward-compatible factory function wrapper.
@@ -47,8 +47,5 @@ export declare class ExtensionToolWrapper<TParameters extends TSchema = TSchema,
47
47
  * Forward browser mode changes when available.
48
48
  */
49
49
  restartForModeChange(): Promise<void>;
50
- execute(toolCallId: string, params: Static<TParameters>, signal?: AbortSignal, onUpdate?: AgentToolUpdateCallback<TDetails, TParameters>, context?: AgentToolContext): Promise<{
51
- content: any;
52
- details?: TDetails;
53
- }>;
50
+ execute(toolCallId: string, params: Static<TParameters>, signal?: AbortSignal, onUpdate?: AgentToolUpdateCallback<TDetails, TParameters>, context?: AgentToolContext): Promise<AgentToolResult<TDetails, TParameters>>;
54
51
  }
@@ -0,0 +1,3 @@
1
+ import type { GitSource } from "./git-url.js";
2
+ /** Fetches current heads and tags into Bun's matching cached bare clone before a plugin update. */
3
+ export declare function refreshBunGitCache(source: GitSource, cwd: string): Promise<void>;
@@ -14,5 +14,17 @@ export type GuidedGoalTurnResult = {
14
14
  export interface GuidedGoalTurnOptions {
15
15
  messages: readonly GuidedGoalMessage[];
16
16
  signal?: AbortSignal;
17
+ /**
18
+ * Stable Codex transport session id reused across every turn of one
19
+ * interview. `handleGuidedGoalCommand` runs up to six turns; minting a fresh
20
+ * id per turn opens a new websocket-only Codex socket each time (kept in
21
+ * `providerSessionState` until session dispose), which can trip
22
+ * `websocket_connection_limit_reached` and drop back to the SSE path this
23
+ * fix avoids. Callers pass one id for the whole interview; omitted for
24
+ * one-shot callers, which mint a unique id per call.
25
+ */
26
+ sideSessionId?: string;
17
27
  }
28
+ /** Mint a guided-goal Codex side-session id keyed off the main session id. */
29
+ export declare function newGuidedGoalSessionId(session: AgentSession): string;
18
30
  export declare function runGuidedGoalTurn(session: AgentSession, options: GuidedGoalTurnOptions): Promise<GuidedGoalTurnResult>;
@@ -2,8 +2,9 @@ import type { InternalResource, InternalUrl, ProtocolHandler, UrlCompletion } fr
2
2
  /**
3
3
  * Handler for history:// URLs.
4
4
  *
5
- * Resolves agent ids against the global AgentRegistry, serving transcripts
6
- * for both live and parked agents.
5
+ * Resolves agent ids against the global AgentRegistry, then falls back to
6
+ * on-disk `.jsonl` transcripts, serving read-only history for live, parked,
7
+ * and unregistered agents alike.
7
8
  */
8
9
  export declare class HistoryProtocolHandler implements ProtocolHandler {
9
10
  #private;
@@ -1,4 +1,4 @@
1
- import type { InternalResource, InternalUrl, ProtocolHandler, UrlCompletion } from "./types.js";
1
+ import type { InternalResource, InternalUrl, ProtocolHandler, ResolveContext, UrlCompletion } from "./types.js";
2
2
  /**
3
3
  * Snapshot of memory roots for every registered session, deduped.
4
4
  * Each session has its own cwd (possibly a worktree), so subagents and main
@@ -11,14 +11,13 @@ export declare function memoryRootsFromRegistry(): string[];
11
11
  export declare function resolveMemoryUrlToPath(url: InternalUrl, memoryRoot: string): string;
12
12
  /**
13
13
  * Protocol handler for memory:// URLs.
14
- *
15
- * Walks every active session's memory root. Worktree-based subagents have
16
- * their own root; first one containing the file wins. Parent and subagent
17
- * sharing a cwd see the same file regardless of order.
14
+ * Resolves file-backed roots against the calling session cwd when provided.
15
+ * Contextless callers fall back to the live-session registry for legacy
16
+ * cross-session lookups.
18
17
  */
19
18
  export declare class MemoryProtocolHandler implements ProtocolHandler {
20
19
  readonly scheme = "memory";
21
20
  readonly immutable = true;
22
- resolve(url: InternalUrl): Promise<InternalResource>;
23
- complete(): Promise<UrlCompletion[]>;
21
+ resolve(url: InternalUrl, context?: ResolveContext): Promise<InternalResource>;
22
+ complete(_query?: string, context?: ResolveContext): Promise<UrlCompletion[]>;
24
23
  }
@@ -1,3 +1,7 @@
1
+ /**
2
+ * Shared helpers for internal-url protocol handlers that resolve IDs against
3
+ * registered agent sessions.
4
+ */
1
5
  export declare function registerArtifactsDir(dir: string): () => void;
2
6
  export declare function resetRegisteredArtifactDirsForTests(): void;
3
7
  /**
@@ -12,3 +16,18 @@ export declare function resetRegisteredArtifactDirsForTests(): void;
12
16
  * single entry.
13
17
  */
14
18
  export declare function artifactsDirsFromRegistry(): string[];
19
+ /**
20
+ * Recursively scan artifacts dirs for agent session transcripts, keyed by
21
+ * agent id (the `.jsonl` basename). Used by `history://` so transcripts of
22
+ * agents no longer in the registry (unregistered one-shot helpers, released
23
+ * agents, or any agent after session resume) remain reachable — mirroring how
24
+ * `agent://` reads `.md` outputs straight off disk.
25
+ *
26
+ * Layout follows `task/index.ts`: a subagent's transcript is
27
+ * `<artifactsDir>/<AgentId>.jsonl`, and its own children nest one level deeper
28
+ * under `<artifactsDir>/<AgentId>/<AgentId>.<ChildId>.jsonl`. Advisor
29
+ * transcripts (`__advisor*.jsonl`) are observability-only and excluded;
30
+ * EPERM-rewrite backups (`.bak`) are skipped. When the same id appears in
31
+ * multiple dirs, the first hit wins (registry dirs are scanned first).
32
+ */
33
+ export declare function sessionFilesFromDisk(): Promise<Map<string, string>>;
@@ -53,6 +53,7 @@ export declare class SessionResolutionError extends Error {
53
53
  readonly hint?: string;
54
54
  constructor(message: string, hint?: string);
55
55
  }
56
+ export declare function normalizeContinueSessionArgs(parsed: Args, rawArgs?: readonly string[]): void;
56
57
  /** Resolves CLI session flags into an existing, forked, in-memory, or cancelled session manager. */
57
58
  export declare function createSessionManager(parsed: Args, cwd: string, activeSettings?: Settings, askToForkSession?: SessionPrompt, askToMoveSession?: SessionPrompt): Promise<SessionManager | undefined>;
58
59
  /** Apply resolved CLI/discovered prompt files without bypassing system prompt templates. */
@@ -3,6 +3,8 @@ export interface OAuthEndpoints {
3
3
  authorizationUrl: string;
4
4
  tokenUrl: string;
5
5
  clientId?: string;
6
+ /** Dynamic client registration endpoint advertised by the authorization server. */
7
+ registrationUrl?: string;
6
8
  scopes?: string;
7
9
  resource?: string;
8
10
  }
@@ -52,6 +52,8 @@ export interface MCPOAuthConfig {
52
52
  authorizationUrl: string;
53
53
  /** Token endpoint URL */
54
54
  tokenUrl: string;
55
+ /** Dynamic client registration endpoint advertised by the authorization server. */
56
+ registrationUrl?: string;
55
57
  /** Client ID (optional when already embedded in authorization URL) */
56
58
  clientId?: string;
57
59
  /** Client secret (optional for PKCE flows) */
@@ -69,6 +69,16 @@ export declare class AgentHubOverlayComponent extends Container {
69
69
  dispose(): void;
70
70
  render(width: number): readonly string[];
71
71
  handleInput(keyData: string): void;
72
+ /**
73
+ * Seed the table's left-left close detector with the current time so a single
74
+ * subsequent `←` (within {@link LEFT_TAP_WINDOW_MS}) dismisses the hub.
75
+ *
76
+ * The editor's own double-tap detector consumes the `←←` that opens the hub,
77
+ * leaving this detector at its fresh `0` — without this handoff the user would
78
+ * have to press `←←` a second time to escape. Called by the opener when the hub
79
+ * was raised by that gesture.
80
+ */
81
+ armCloseTap(): void;
72
82
  /**
73
83
  * Open the fullscreen transcript viewer for an agent id (public for table Enter
74
84
  * and tests). Mounts {@link AgentTranscriptViewer} as a `fullscreen` overlay so it