@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
@@ -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
@@ -13,7 +13,21 @@ export interface AdvisorConfig {
13
13
  model?: string;
14
14
  tools?: string[];
15
15
  instructions?: string;
16
+ /** Per-advisor on/off toggle (default `true`). When `false`, the advisor
17
+ * stays in the roster but its runtime is never built — it shows `○` in
18
+ * the status line and `/advisor status` rather than disappearing. */
19
+ enabled?: boolean;
16
20
  }
21
+ /**
22
+ * Runtime health of a single advisor, surfaced in stats and the status line.
23
+ * - `running` — actively processing primary turns
24
+ * - `paused` — user-toggled off via per-advisor switch (runtime disposed)
25
+ * - `quota_exhausted` — provider returned a quota/rate-limit error; the
26
+ * runtime auto-retries after a cooldown so it can resume without user action
27
+ * - `error` — repeated transient failures; backlog dropped to prevent stall
28
+ * - `no_model` — no model resolved for this advisor's role/explicit model
29
+ */
30
+ export type AdvisorRuntimeStatus = "running" | "paused" | "quota_exhausted" | "error" | "no_model";
17
31
  /**
18
32
  * The result of walking the `WATCHDOG.yml`/`WATCHDOG.yaml` search path: the
19
33
  * deduped advisor roster plus the concatenated top-level `instructions` baseline
@@ -83,12 +97,6 @@ export declare function resolveAdvisorConfigEditPath(scope: AdvisorConfigScope,
83
97
  * editor opens cleanly on a fresh or broken file.
84
98
  */
85
99
  export declare function loadWatchdogConfigFile(filePath: string): Promise<WatchdogConfigDoc>;
86
- /**
87
- * Serialize an editable doc back to block-style `WATCHDOG.yml` text via Bun's
88
- * `YAML.stringify` (the same API the repo uses for other hand-editable config),
89
- * omitting empty fields. Round-trips through {@link loadWatchdogConfigFile}.
90
- * Returns `""` for an empty doc.
91
- */
92
100
  export declare function serializeWatchdogConfig(doc: WatchdogConfigDoc): string;
93
101
  /**
94
102
  * Write an editable doc to `WATCHDOG.yml`. An empty doc removes the file so
@@ -33,10 +33,10 @@ export interface AdvisorRuntimeHost {
33
33
  * Pre-prompt context maintenance for the advisor's own append-only context.
34
34
  * Promotes the advisor model to a larger sibling when its context nears the
35
35
  * window (mirroring the primary's promote-first policy) and resolves `true`
36
- * when the advisor should re-prime reset and replay the current
37
- * primary-bounded transcript because promotion did not free enough room.
38
- * Optional: hosts that omit it get no maintenance (context only shrinks when
39
- * the primary's next compaction triggers {@link AdvisorRuntime.reset}).
36
+ * when the advisor must clear its own context before sending the current
37
+ * incremental update. The cursor stays at the current primary position: this
38
+ * recovery path must never replay the full primary transcript.
39
+ * Optional: hosts that omit it get no proactive maintenance.
40
40
  */
41
41
  maintainContext?(incomingTokens: number): Promise<boolean>;
42
42
  /**
@@ -49,16 +49,21 @@ export interface AdvisorRuntimeHost {
49
49
  /**
50
50
  * Called with the error of every failed advisor turn, before the retry sleep
51
51
  * or the dropped-after-3 path. Lets the host apply credential-level remedies
52
- * the advisor loop lacks: the in-stream a/b/c auth retry rotates through
53
- * sibling credentials within one request but never blocks the LAST failing
54
- * one the primary agent's retry pipeline does that via
55
- * `markUsageLimitReached`, so without this hook the advisor re-picks the
56
- * same usage-limited account on every retry. Errors thrown here are logged
57
- * and swallowed.
52
+ * and configured model fallback that the advisor loop cannot perform itself.
53
+ * Return `true` after switching models so the same clean batch is retried
54
+ * immediately with a fresh failure budget. `failedMessages` contains the
55
+ * failed prompt's appended turns before rollback. Errors thrown here are
56
+ * logged and swallowed.
58
57
  */
59
- onTurnError?(error: unknown): Promise<void> | void;
58
+ onTurnError?(error: unknown, failedMessages: readonly AgentMessage[]): Promise<boolean | undefined> | boolean | undefined;
59
+ /** Called after a successful advisor turn so the host can finish fallback lifecycle reporting. */
60
+ onTurnSuccess?(): Promise<void> | void;
60
61
  /** Surface a non-recovering advisor failure to the host UI without adding model-visible context. */
61
62
  notifyFailure?(error: unknown): void;
63
+ /** Signal that the advisor paused on a quota/rate-limit after host-level
64
+ * recovery (credential switch, fallback chain) declined. Cleared only by
65
+ * an explicit reset (`/new`, config rebuild, session restart). */
66
+ notifyQuotaExhausted?(): void;
62
67
  }
63
68
  /** Signals that an advisor response was discarded before it could become model-visible context. */
64
69
  export declare class AdvisorOutputQuarantinedError extends Error {
@@ -86,6 +91,10 @@ export declare class AdvisorRuntime {
86
91
  disposed: boolean;
87
92
  constructor(agent: AdvisorAgent, host: AdvisorRuntimeHost, retryDelayMs?: number);
88
93
  get backlog(): number;
94
+ get quotaExhausted(): boolean;
95
+ get failureNotified(): boolean;
96
+ /** True after the runtime hard-stopped on repeated or permanent failures. */
97
+ get halted(): boolean;
89
98
  /**
90
99
  * True when `#pending` is non-empty while the drain loop is busy — i.e., newer
91
100
  * primary turns arrived after the current batch's transcript window was fixed
@@ -18,6 +18,7 @@ export declare function buildAutoLearnInstructions(available: {
18
18
  export interface AutoLearnControllerOptions {
19
19
  session: AgentSession;
20
20
  settings: Settings;
21
+ capture: (content: string) => Promise<void>;
21
22
  }
22
23
  export declare class AutoLearnController {
23
24
  #private;
@@ -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
  *
@@ -44,6 +44,23 @@ type LlamaCppDiscoveredModelRuntimeMetadata = {
44
44
  };
45
45
  export declare function discoverModelsByProviderType(providerConfig: DiscoveryProviderConfig, ctx: DiscoveryContext): Promise<Model<Api>[]>;
46
46
  export declare function discoverOllamaModels(providerConfig: DiscoveryProviderConfig, ctx: DiscoveryContext): Promise<Model<Api>[]>;
47
+ /**
48
+ * applyLlamaCppQwenThinking rewrites a discovered or cached llama.cpp model so a
49
+ * Qwen-family chat template (which defaults `enable_thinking: true`) can be
50
+ * turned off. Qwen ids and the Qwen3.6-based PrismLM Ternary Bonsai GGUFs are
51
+ * routed through chat-completions (the implicit llama.cpp provider defaults to
52
+ * `openai-responses`, whose disable path has no Qwen encoding) with the
53
+ * `qwen-template-false` dialect; omp emits `preserve_thinking` inside
54
+ * `chat_template_kwargs` for Qwen, so the toggle rides there too and history
55
+ * `<think>` blocks survive (`qwenPreserveThinking`). The runtime base URL gets a
56
+ * `/v1` suffix because the chat-completions request would otherwise POST to the
57
+ * native root, which does not serve it. A model with a custom transport (e.g.
58
+ * `pi-native`, whose client appends `/v1/pi/stream`) keeps its base URL so the
59
+ * suffix is not doubled. Non-Qwen models pass through unchanged. Applied on both
60
+ * fresh discovery and cache load, so an upgraded cache is corrected without
61
+ * waiting for re-discovery.
62
+ */
63
+ export declare function applyLlamaCppQwenThinking(model: Model<Api>): Model<Api>;
47
64
  export declare function discoverLlamaCppModels(providerConfig: DiscoveryProviderConfig, ctx: DiscoveryContext): Promise<Model<Api>[]>;
48
65
  export declare function discoverLlamaCppModelRuntimeMetadata(model: Pick<Model<Api>, "provider" | "id" | "baseUrl" | "headers">, ctx: DiscoveryContext): Promise<LlamaCppDiscoveredModelRuntimeMetadata | undefined>;
49
66
  export declare function discoverOpenAIModelsList(providerConfig: DiscoveryProviderConfig, ctx: DiscoveryContext): Promise<Model<Api>[]>;
@@ -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
  */
@@ -94,11 +94,14 @@ export interface ParsedModelResult {
94
94
  export declare function parseModelPattern(pattern: string, availableModels: Model<Api>[], preferences?: ModelMatchPreferences, options?: {
95
95
  allowInvalidThinkingSelectorFallback?: boolean;
96
96
  }): ParsedModelResult;
97
+ export interface ModelRoleLookup {
98
+ getModelRole(role: ModelRole | string): string | undefined;
99
+ }
97
100
  /**
98
101
  * Expand a role alias like "@smol" to the configured model string.
99
102
  */
100
- export declare function expandRoleAlias(value: string, settings?: Settings): string;
101
- export declare function resolveConfiguredModelPatterns(value: string | string[] | undefined, settings?: Settings): string[];
103
+ export declare function expandRoleAlias(value: string, settings?: ModelRoleLookup): string;
104
+ export declare function resolveConfiguredModelPatterns(value: string | string[] | undefined, settings?: ModelRoleLookup): string[];
102
105
  export interface AgentModelPatternResolutionOptions {
103
106
  settingsOverride?: string | string[];
104
107
  agentModel?: string | string[];
@@ -135,6 +138,7 @@ export interface ResolvedModelRoleValue {
135
138
  }
136
139
  export declare function resolveModelRoleValue(roleValue: string | undefined, availableModels: Model<Api>[], options?: {
137
140
  settings?: Settings;
141
+ roleLookup?: ModelRoleLookup;
138
142
  matchPreferences?: ModelMatchPreferences;
139
143
  }): ResolvedModelRoleValue;
140
144
  interface ExplicitThinkingSelectorOptions {
@@ -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;
@@ -14,6 +14,7 @@ import { type SearchProviderId } from "../web/search/types.js";
14
14
  * settings.get("compaction.enabled") // => boolean
15
15
  * settings.set("theme.dark", "titanium") // sync, saves in background
16
16
  */
17
+ export type ModelRoleStorage = "global" | "project";
17
18
  export type SettingTab = "appearance" | "model" | "interaction" | "context" | "memory" | "files" | "shell" | "tools" | "tasks" | "providers";
18
19
  /** Tab display metadata - icon is resolved via theme.symbol() */
19
20
  export type TabMetadata = {
@@ -281,6 +282,26 @@ export declare const SETTINGS_SCHEMA: {
281
282
  readonly type: "array";
282
283
  readonly default: string[];
283
284
  };
285
+ readonly modelRoleStorage: {
286
+ readonly type: "enum";
287
+ readonly values: readonly ["global", "project"];
288
+ readonly default: "global";
289
+ readonly ui: {
290
+ readonly tab: "model";
291
+ readonly group: "Prompt";
292
+ readonly label: "Model Role Storage";
293
+ readonly description: "Where model selector role assignments are saved";
294
+ readonly options: readonly [{
295
+ readonly value: "global";
296
+ readonly label: "Global";
297
+ readonly description: "Save role models in the active profile config (current behavior)";
298
+ }, {
299
+ readonly value: "project";
300
+ readonly label: "Per-project";
301
+ readonly description: "Save project role models in .omp/config.yml; missing project roles use global defaults";
302
+ }];
303
+ };
304
+ };
284
305
  readonly modelRoles: {
285
306
  readonly type: "record";
286
307
  readonly default: Record<string, string>;
@@ -1424,7 +1445,7 @@ export declare const SETTINGS_SCHEMA: {
1424
1445
  readonly tab: "model";
1425
1446
  readonly group: "Retry & Fallback";
1426
1447
  readonly label: "Retry Fallback Chains";
1427
- readonly description: 'JSON object mapping model roles, model selectors ("provider/model-id"), or provider wildcards ("provider/*") to ordered fallback selectors, e.g. {"default":["openai/gpt-4o-mini"],"google-antigravity/*":["google/*","google-vertex/*"]}. Model-oriented keys apply whenever that model/provider is active, regardless of role; a "provider/*" entry keeps the failing model\'s id and swaps the provider.';
1448
+ readonly description: 'JSON object mapping model roles, model selectors ("provider/model-id"), or provider wildcards ("provider/*") to ordered fallback selectors, e.g. {"default":["openai/gpt-4o-mini"],"google-antigravity/*":["google/*","google-vertex/*"]}. Model-oriented keys apply whenever that model/provider is active, regardless of role; a "provider/*" entry keeps the failing model\'s id and swaps the provider. An id-prefixed wildcard ("openrouter/google/*") re-prefixes the failing model\'s bare id (google-antigravity/gemini-x -> openrouter/google/gemini-x) and, used as a key, matches only that provider\'s ids under the prefix.';
1428
1449
  };
1429
1450
  };
1430
1451
  readonly "retry.fallbackRevertPolicy": {
@@ -2547,7 +2568,7 @@ export declare const SETTINGS_SCHEMA: {
2547
2568
  readonly tab: "memory";
2548
2569
  readonly group: "Auto-Learn";
2549
2570
  readonly label: "Auto-run capture at stop";
2550
- readonly description: "When on, auto-run one capture turn at stop (uses extra tokens). Off = passive reminder on your next turn.";
2571
+ readonly description: "When on, auto-run one private capture turn at stop (uses extra tokens). When off, only standing auto-learn guidance remains.";
2551
2572
  readonly condition: "autolearnActive";
2552
2573
  };
2553
2574
  };
@@ -3721,7 +3742,7 @@ export declare const SETTINGS_SCHEMA: {
3721
3742
  };
3722
3743
  readonly "generate_image.enabled": {
3723
3744
  readonly type: "boolean";
3724
- readonly default: true;
3745
+ readonly default: false;
3725
3746
  readonly ui: {
3726
3747
  readonly tab: "tools";
3727
3748
  readonly group: "Available Tools";
@@ -4619,7 +4640,7 @@ export declare const SETTINGS_SCHEMA: {
4619
4640
  }, {
4620
4641
  readonly value: "kimi";
4621
4642
  readonly label: "Kimi";
4622
- readonly description: "Requires MOONSHOT_SEARCH_API_KEY or MOONSHOT_API_KEY";
4643
+ readonly description: "Kimi Code search (requires a Kimi Code Console key via KIMI_SEARCH_API_KEY/MOONSHOT_SEARCH_API_KEY or /login kimi-code; not MOONSHOT_API_KEY)";
4623
4644
  }, {
4624
4645
  readonly value: "parallel";
4625
4646
  readonly label: "Parallel";
@@ -4705,7 +4726,7 @@ export declare const SETTINGS_SCHEMA: {
4705
4726
  };
4706
4727
  readonly "providers.image": {
4707
4728
  readonly type: "enum";
4708
- readonly values: readonly ["auto", "openai", "antigravity", "xai", "gemini", "openrouter"];
4729
+ readonly values: readonly ["auto", "openai", "openai-codex", "antigravity", "xai", "gemini", "openrouter"];
4709
4730
  readonly default: "auto";
4710
4731
  readonly ui: {
4711
4732
  readonly tab: "providers";
@@ -4715,11 +4736,15 @@ export declare const SETTINGS_SCHEMA: {
4715
4736
  readonly options: readonly [{
4716
4737
  readonly value: "auto";
4717
4738
  readonly label: "Auto";
4718
- readonly description: "Priority: GPT model image tool > Antigravity > xAI > OpenRouter > Gemini";
4739
+ readonly description: "Priority: per-request provider > configured provider > active session provider > GPT model image tool > Codex subscription > Antigravity > xAI > OpenRouter > Gemini";
4719
4740
  }, {
4720
4741
  readonly value: "openai";
4721
4742
  readonly label: "OpenAI";
4722
- readonly description: "Uses the active GPT Responses/Codex model";
4743
+ readonly description: "OPENAI_API_KEY (gpt-image-2) or active GPT model; falls back to a connected Codex subscription";
4744
+ }, {
4745
+ readonly value: "openai-codex";
4746
+ readonly label: "OpenAI Codex (ChatGPT)";
4747
+ readonly description: "Uses a connected Codex / ChatGPT subscription — no OPENAI_API_KEY needed";
4723
4748
  }, {
4724
4749
  readonly value: "antigravity";
4725
4750
  readonly label: "Antigravity";
@@ -131,12 +131,62 @@ export declare class Settings {
131
131
  /**
132
132
  * Set a model role (helper for modelRoles record). Passing `undefined`
133
133
  * clears the role from the persisted record and any runtime override.
134
+ *
135
+ * In project storage mode, when a project edit has temporarily replaced
136
+ * the process-wide runtime override for `role` and that override is still
137
+ * active (the runtime slot currently matches the project value), the
138
+ * global-layer write must not rewrite that runtime slot — otherwise the
139
+ * global fallback would immediately shadow the still-configured project
140
+ * role. The global layer is still persisted; only the runtime override is
141
+ * left untouched. The guard is precise so that a later clear, a late
142
+ * `overrideModelRoles`, or a storage-mode transition does not leave a
143
+ * stale skip in place.
134
144
  */
135
145
  setModelRole(role: ModelRole | string, modelId: string | undefined): void;
146
+ /**
147
+ * Whether `role`'s runtime override slot currently holds the temporary
148
+ * project-scoped value installed by a prior `setProjectModelRole`. Returns
149
+ * `false` when storage is not project-mode, no capture exists, or the
150
+ * project role was cleared. With explicit provenance invalidation, a
151
+ * surviving capture implies no external supersession occurred.
152
+ */
153
+ isProjectModelRoleRuntimeOverrideActive(role: ModelRole | string): boolean;
154
+ /**
155
+ * Set a model role in the current project's settings layer.
156
+ */
157
+ setProjectModelRole(role: ModelRole | string, modelId: string): void;
158
+ /**
159
+ * Clear a model role from the current project's settings layer.
160
+ */
161
+ clearProjectModelRole(role: ModelRole | string): void;
136
162
  /**
137
163
  * Get a model role (helper for modelRoles record).
138
164
  */
139
165
  getModelRole(role: ModelRole | string): string | undefined;
166
+ /**
167
+ * Get a model role from only the global settings layer.
168
+ */
169
+ getGlobalModelRole(role: ModelRole | string): string | undefined;
170
+ /**
171
+ * Get a model role from only the current project settings layer.
172
+ */
173
+ getProjectModelRole(role: ModelRole | string): string | undefined;
174
+ /**
175
+ * Report which layer actually supplies the effective model role across
176
+ * full merge precedence (runtime override → config overlay → project →
177
+ * global → default). Unlike {@link getModelRoleSource}, this accounts
178
+ * for runtime and config-overlay layers and detects ownership by key
179
+ * presence rather than normalized value, so a `null` tombstone in the
180
+ * overlay or runtime layer correctly blocks lower layers. The project
181
+ * layer is checked through {@link #projectSettingsForMerge} because a
182
+ * project null is a cleared value (falls back to global), not a
183
+ * tombstone.
184
+ */
185
+ getModelRoleProvenance(role: ModelRole | string): "runtime" | "overlay" | "project" | "global" | "default";
186
+ /**
187
+ * Get the persisted layer supplying a model role (project/global/default only).
188
+ */
189
+ getModelRoleSource(role: ModelRole | string): "project" | "global" | "default";
140
190
  /**
141
191
  * Get all model roles (helper for modelRoles record).
142
192
  */
@@ -2,9 +2,20 @@ import type { AgentEvent, AgentTool, AgentToolContext } from "@oh-my-pi/pi-agent
2
2
  import type { CursorMcpCall, CursorShellStreamCallbacks, CursorExecHandlers as ICursorExecHandlers, ToolResultMessage } from "@oh-my-pi/pi-ai";
3
3
  interface CursorExecBridgeOptions {
4
4
  cwd: string;
5
+ getCwd?: () => string;
5
6
  tools: Map<string, AgentTool>;
7
+ getTool?: (name: string) => AgentTool | undefined;
6
8
  getToolContext?: () => AgentToolContext | undefined;
7
9
  emitEvent?: (event: AgentEvent) => void;
10
+ /**
11
+ * Whether the Cursor native `delete` frame may remove files. Unlike every
12
+ * other exec handler, `executeDelete` mutates the filesystem directly instead
13
+ * of consulting {@link tools}, so a background read-only advisor could delete
14
+ * workspace files it was never granted a mutating tool for (issue #5680
15
+ * review). Defaults to allowed to preserve the primary agent's behavior;
16
+ * callers with a restricted tool set (advisors) opt out.
17
+ */
18
+ allowNativeDelete?: boolean;
8
19
  }
9
20
  export declare class CursorExecHandlers implements ICursorExecHandlers {
10
21
  private options;
@@ -185,13 +185,16 @@ export declare function buildExtensionModuleItems(providerId: string, userPaths:
185
185
  * Entry for an installed Claude Code plugin.
186
186
  */
187
187
  export interface ClaudePluginEntry {
188
- scope: "user" | "project";
188
+ /** Claude registry scope; local entries are restricted to their project path. */
189
+ scope?: "user" | "project" | "local";
189
190
  installPath: string;
190
191
  version: string;
191
192
  installedAt: string;
192
193
  lastUpdated: string;
193
194
  gitCommitSha?: string;
194
195
  enabled?: boolean;
196
+ /** Project root recorded by Claude for a local installation. */
197
+ projectPath?: string;
195
198
  }
196
199
  /**
197
200
  * Claude Code installed_plugins.json registry format.
@@ -254,7 +257,7 @@ export declare function registerPluginCacheInvalidator(invalidator: () => void):
254
257
  * Reads ~/.claude/plugins/installed_plugins.json and ~/.omp/plugins/installed_plugins.json,
255
258
  * and optionally the nearest project-scoped registry resolved from `cwd`.
256
259
  *
257
- * Results are cached per `home:resolvedProjectPath` key to avoid repeated parsing.
260
+ * Results are cached per home, project registry, and canonical active project.
258
261
  */
259
262
  export declare function listClaudePluginRoots(home: string, cwd?: string): Promise<{
260
263
  roots: ClaudePluginRoot[];
@@ -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
  };
@@ -33,6 +33,8 @@ export interface BashResult {
33
33
  output: string;
34
34
  exitCode: number | undefined;
35
35
  cancelled: boolean;
36
+ /** True when the command was killed by its timeout deadline (not a user abort). */
37
+ timedOut?: boolean;
36
38
  truncated: boolean;
37
39
  totalLines: number;
38
40
  totalBytes: number;
@@ -0,0 +1,15 @@
1
+ /** Callback invoked when a managed timer's callback throws or rejects. */
2
+ export type ManagedTimerErrorHandler = (event: string, error: string, stack?: string) => void;
3
+ export declare class ManagedTimers {
4
+ #private;
5
+ private readonly onError;
6
+ constructor(onError: ManagedTimerErrorHandler);
7
+ /** Schedule a repeating callback whose throws are contained. */
8
+ setInterval(callback: (...args: unknown[]) => void, ms?: number, ...args: unknown[]): Timer;
9
+ /** Schedule a one-shot callback whose throws are contained. Deregisters after it fires. */
10
+ setTimeout(callback: (...args: unknown[]) => void, ms?: number, ...args: unknown[]): Timer;
11
+ /** Clear one managed timer. Accepts an interval or timeout handle. */
12
+ clear(timer: Timer): void;
13
+ /** Clear every outstanding managed timer. Called on session teardown. */
14
+ clearAll(): void;
15
+ }
@@ -118,6 +118,13 @@ export declare class ExtensionRunner {
118
118
  * Request a graceful shutdown. Called by extension tools and event handlers.
119
119
  */
120
120
  shutdown(): void;
121
+ /**
122
+ * Clear every timer scheduled through `ctx.setInterval` / `ctx.setTimeout`.
123
+ * Called during session teardown so extension background work does not
124
+ * outlive the session (a self-scheduling interval would otherwise keep
125
+ * firing against a disposed session).
126
+ */
127
+ clearManagedTimers(): void;
121
128
  createCommandContext(): ExtensionCommandContext;
122
129
  emit<TEvent extends RunnerEmitEvent>(event: TEvent): Promise<RunnerEmitResult<TEvent>>;
123
130
  emitToolResult(event: ToolResultEvent): Promise<ToolResultEventResult | undefined>;