@oh-my-pi/pi-coding-agent 17.1.5 → 17.1.6

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 (207) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/dist/{CHANGELOG-qs3vd6xf.md → CHANGELOG-x9zt79k8.md} +31 -0
  3. package/dist/cli.js +2989 -2978
  4. package/dist/types/capability/index.d.ts +1 -1
  5. package/dist/types/capability/types.d.ts +23 -1
  6. package/dist/types/config/settings-schema.d.ts +23 -1
  7. package/dist/types/internal-urls/mcp-protocol.d.ts +3 -2
  8. package/dist/types/internal-urls/parse.d.ts +12 -0
  9. package/dist/types/internal-urls/router.d.ts +6 -0
  10. package/dist/types/internal-urls/types.d.ts +6 -0
  11. package/dist/types/lsp/config.d.ts +1 -0
  12. package/dist/types/lsp/types.d.ts +2 -0
  13. package/dist/types/mcp/manager.d.ts +5 -0
  14. package/dist/types/mcp/tool-bridge.d.ts +13 -0
  15. package/dist/types/modes/controllers/extension-ui-controller.d.ts +1 -1
  16. package/dist/types/modes/rpc/rpc-mode.d.ts +2 -0
  17. package/dist/types/sdk.d.ts +3 -1
  18. package/dist/types/session/agent-session-types.d.ts +3 -1
  19. package/dist/types/session/agent-session.d.ts +2 -0
  20. package/dist/types/session/model-controls.d.ts +3 -0
  21. package/dist/types/session/session-advisors.d.ts +7 -1
  22. package/dist/types/session/tool-choice-queue.d.ts +6 -4
  23. package/dist/types/session/turn-recovery.d.ts +4 -2
  24. package/dist/types/task/index.d.ts +1 -1
  25. package/dist/types/task/types.d.ts +3 -11
  26. package/dist/types/thinking.d.ts +21 -2
  27. package/dist/types/utils/title-generator.d.ts +17 -16
  28. package/package.json +12 -12
  29. package/src/capability/index.ts +43 -12
  30. package/src/capability/mcp.ts +21 -0
  31. package/src/capability/types.ts +20 -1
  32. package/src/cli/read-cli.ts +44 -2
  33. package/src/config/settings-schema.ts +27 -1
  34. package/src/eval/py/runner.py +16 -2
  35. package/src/extensibility/extensions/runner.ts +91 -5
  36. package/src/extensibility/extensions/types.ts +0 -1
  37. package/src/extensibility/hooks/types.ts +0 -1
  38. package/src/internal-urls/mcp-protocol.ts +17 -3
  39. package/src/internal-urls/parse.ts +31 -0
  40. package/src/internal-urls/router.ts +24 -4
  41. package/src/internal-urls/types.ts +6 -0
  42. package/src/live/transport.ts +2 -2
  43. package/src/lsp/client.ts +2 -2
  44. package/src/lsp/config.ts +4 -0
  45. package/src/lsp/types.ts +2 -0
  46. package/src/mcp/config.ts +26 -14
  47. package/src/mcp/manager.ts +26 -9
  48. package/src/mcp/tool-bridge.ts +52 -1
  49. package/src/memories/index.ts +25 -6
  50. package/src/modes/components/status-line/segments.ts +3 -1
  51. package/src/modes/controllers/command-controller.ts +10 -10
  52. package/src/modes/controllers/extension-ui-controller.ts +3 -3
  53. package/src/modes/rpc/rpc-mode.ts +60 -47
  54. package/src/prompts/steering/user-interjection.md +2 -5
  55. package/src/prompts/tools/task.md +4 -2
  56. package/src/sdk.ts +17 -8
  57. package/src/session/agent-session-types.ts +3 -0
  58. package/src/session/agent-session.ts +21 -4
  59. package/src/session/model-controls.ts +43 -7
  60. package/src/session/session-advisors.ts +30 -14
  61. package/src/session/session-tools.ts +4 -2
  62. package/src/session/tool-choice-queue.ts +19 -4
  63. package/src/session/turn-recovery.ts +21 -2
  64. package/src/task/executor.ts +11 -3
  65. package/src/task/index.ts +43 -32
  66. package/src/task/types.ts +12 -17
  67. package/src/thinking.ts +68 -5
  68. package/src/tools/read.ts +2 -2
  69. package/src/utils/title-generator.ts +88 -34
  70. package/dist/types/advisor/__tests__/advisor.test.d.ts +0 -1
  71. package/dist/types/advisor/__tests__/config.test.d.ts +0 -1
  72. package/dist/types/advisor/__tests__/emission-guard.test.d.ts +0 -1
  73. package/dist/types/cli/__tests__/auth-gateway-catalog.test.d.ts +0 -1
  74. package/dist/types/cli/update-cli.test.d.ts +0 -1
  75. package/dist/types/config/__tests__/model-registry.test.d.ts +0 -1
  76. package/dist/types/eval/__tests__/agent-bridge.test.d.ts +0 -1
  77. package/dist/types/eval/__tests__/bridge-timeout.test.d.ts +0 -1
  78. package/dist/types/eval/__tests__/budget-bridge.test.d.ts +0 -1
  79. package/dist/types/eval/__tests__/completion-bridge.test.d.ts +0 -1
  80. package/dist/types/eval/__tests__/helpers-local-roots.test.d.ts +0 -1
  81. package/dist/types/eval/__tests__/idle-timeout.test.d.ts +0 -1
  82. package/dist/types/eval/__tests__/js-context-manager.test.d.ts +0 -1
  83. package/dist/types/eval/__tests__/julia-prelude.test.d.ts +0 -1
  84. package/dist/types/eval/__tests__/kernel-spawn.test.d.ts +0 -1
  85. package/dist/types/eval/__tests__/prelude-agent.test.d.ts +0 -1
  86. package/dist/types/eval/__tests__/process-entry-import.test.d.ts +0 -1
  87. package/dist/types/eval/py/__tests__/prelude.test.d.ts +0 -1
  88. package/dist/types/eval/py/__tests__/runner-shell-output.test.d.ts +0 -1
  89. package/dist/types/hindsight/client.test.d.ts +0 -1
  90. package/dist/types/internal-urls/__tests__/agent-protocol-nested.test.d.ts +0 -1
  91. package/dist/types/internal-urls/__tests__/ssh-protocol.test.d.ts +0 -1
  92. package/dist/types/launch/broker-list-order.test.d.ts +0 -1
  93. package/dist/types/launch/broker-output-snapshot.test.d.ts +0 -1
  94. package/dist/types/launch/protocol.test.d.ts +0 -1
  95. package/dist/types/launch/spawn-options.test.d.ts +0 -1
  96. package/dist/types/launch/terminal-output.test.d.ts +0 -1
  97. package/dist/types/live/protocol.test.d.ts +0 -1
  98. package/dist/types/mcp/config-writer.test.d.ts +0 -1
  99. package/dist/types/mcp/smithery-auth.test.d.ts +0 -1
  100. package/dist/types/mcp/smithery-registry.test.d.ts +0 -1
  101. package/dist/types/mcp/transports/stdio.test.d.ts +0 -1
  102. package/dist/types/modes/components/__tests__/dynamic-border.test.d.ts +0 -1
  103. package/dist/types/modes/components/__tests__/move-overlay.test.d.ts +0 -1
  104. package/dist/types/modes/components/__tests__/pause-screen.test.d.ts +0 -1
  105. package/dist/types/modes/components/__tests__/skill-message.test.d.ts +0 -1
  106. package/dist/types/modes/components/custom-editor-plugin-ctor.test.d.ts +0 -1
  107. package/dist/types/modes/components/custom-editor.test.d.ts +0 -1
  108. package/dist/types/modes/components/login-dialog.test.d.ts +0 -1
  109. package/dist/types/modes/components/status-line/component.jj-cache.test.d.ts +0 -1
  110. package/dist/types/modes/components/status-line/component.test.d.ts +0 -1
  111. package/dist/types/modes/components/tool-execution.test.d.ts +0 -1
  112. package/dist/types/modes/controllers/extension-ui-controller.test.d.ts +0 -1
  113. package/dist/types/modes/noninteractive-dispose.test.d.ts +0 -1
  114. package/dist/types/modes/print-mode.test.d.ts +0 -1
  115. package/dist/types/modes/session-teardown.test.d.ts +0 -1
  116. package/dist/types/modes/theme/mermaid-rendering.test.d.ts +0 -1
  117. package/dist/types/modes/utils/transcript-render-helpers.test.d.ts +0 -1
  118. package/dist/types/modes/warp-events.test.d.ts +0 -1
  119. package/dist/types/plan-mode/approved-plan-prompt.test.d.ts +0 -1
  120. package/dist/types/plan-mode/model-transition.test.d.ts +0 -1
  121. package/dist/types/plan-mode/reentry-prompt.test.d.ts +0 -1
  122. package/dist/types/session/agent-session-error-log.test.d.ts +0 -1
  123. package/dist/types/session/blob-store.test.d.ts +0 -1
  124. package/dist/types/session/messages.test.d.ts +0 -1
  125. package/dist/types/session/session-context.test.d.ts +0 -1
  126. package/dist/types/ssh/__tests__/connection-manager-args.test.d.ts +0 -1
  127. package/dist/types/ssh/__tests__/connection-manager-timeout.test.d.ts +0 -1
  128. package/dist/types/ssh/__tests__/file-transfer-posix-guard.test.d.ts +0 -1
  129. package/dist/types/ssh/__tests__/sshfs-mount.test.d.ts +0 -1
  130. package/dist/types/system-prompt.test.d.ts +0 -1
  131. package/dist/types/task/render.test.d.ts +0 -1
  132. package/dist/types/task/spawn-policy.test.d.ts +0 -1
  133. package/dist/types/tools/__tests__/eval-description.test.d.ts +0 -1
  134. package/dist/types/tools/__tests__/glob.test.d.ts +0 -1
  135. package/dist/types/tools/__tests__/json-tree.test.d.ts +0 -1
  136. package/dist/types/tools/__tests__/vibe-render.test.d.ts +0 -1
  137. package/dist/types/tools/hub/launch-compat.test.d.ts +0 -1
  138. package/dist/types/vibe/__tests__/token-rate.test.d.ts +0 -1
  139. package/src/advisor/__tests__/advisor.test.ts +0 -4889
  140. package/src/advisor/__tests__/config.test.ts +0 -349
  141. package/src/advisor/__tests__/emission-guard.test.ts +0 -147
  142. package/src/cli/__tests__/auth-gateway-catalog.test.ts +0 -111
  143. package/src/cli/update-cli.test.ts +0 -28
  144. package/src/config/__tests__/model-registry.test.ts +0 -182
  145. package/src/eval/__tests__/agent-bridge.test.ts +0 -1509
  146. package/src/eval/__tests__/bridge-timeout.test.ts +0 -170
  147. package/src/eval/__tests__/budget-bridge.test.ts +0 -80
  148. package/src/eval/__tests__/completion-bridge.test.ts +0 -412
  149. package/src/eval/__tests__/helpers-local-roots.test.ts +0 -55
  150. package/src/eval/__tests__/idle-timeout.test.ts +0 -80
  151. package/src/eval/__tests__/js-context-manager.test.ts +0 -456
  152. package/src/eval/__tests__/julia-prelude.test.ts +0 -66
  153. package/src/eval/__tests__/kernel-spawn.test.ts +0 -115
  154. package/src/eval/__tests__/prelude-agent.test.ts +0 -156
  155. package/src/eval/__tests__/process-entry-import.test.ts +0 -137
  156. package/src/eval/py/__tests__/prelude.test.ts +0 -104
  157. package/src/eval/py/__tests__/runner-shell-output.test.ts +0 -157
  158. package/src/hindsight/client.test.ts +0 -75
  159. package/src/internal-urls/__tests__/agent-protocol-nested.test.ts +0 -141
  160. package/src/internal-urls/__tests__/ssh-protocol.test.ts +0 -331
  161. package/src/launch/broker-list-order.test.ts +0 -89
  162. package/src/launch/broker-output-snapshot.test.ts +0 -126
  163. package/src/launch/protocol.test.ts +0 -59
  164. package/src/launch/spawn-options.test.ts +0 -31
  165. package/src/launch/terminal-output.test.ts +0 -107
  166. package/src/live/protocol.test.ts +0 -140
  167. package/src/mcp/config-writer.test.ts +0 -43
  168. package/src/mcp/smithery-auth.test.ts +0 -29
  169. package/src/mcp/smithery-registry.test.ts +0 -51
  170. package/src/mcp/transports/stdio.test.ts +0 -427
  171. package/src/modes/components/__tests__/dynamic-border.test.ts +0 -55
  172. package/src/modes/components/__tests__/move-overlay.test.ts +0 -252
  173. package/src/modes/components/__tests__/pause-screen.test.ts +0 -143
  174. package/src/modes/components/__tests__/skill-message.test.ts +0 -94
  175. package/src/modes/components/custom-editor-plugin-ctor.test.ts +0 -36
  176. package/src/modes/components/custom-editor.test.ts +0 -510
  177. package/src/modes/components/login-dialog.test.ts +0 -56
  178. package/src/modes/components/status-line/component.jj-cache.test.ts +0 -229
  179. package/src/modes/components/status-line/component.test.ts +0 -84
  180. package/src/modes/components/tool-execution.test.ts +0 -162
  181. package/src/modes/controllers/extension-ui-controller.test.ts +0 -250
  182. package/src/modes/noninteractive-dispose.test.ts +0 -73
  183. package/src/modes/print-mode.test.ts +0 -71
  184. package/src/modes/session-teardown.test.ts +0 -219
  185. package/src/modes/theme/mermaid-rendering.test.ts +0 -53
  186. package/src/modes/utils/transcript-render-helpers.test.ts +0 -38
  187. package/src/modes/warp-events.test.ts +0 -794
  188. package/src/plan-mode/approved-plan-prompt.test.ts +0 -36
  189. package/src/plan-mode/model-transition.test.ts +0 -60
  190. package/src/plan-mode/reentry-prompt.test.ts +0 -41
  191. package/src/session/agent-session-error-log.test.ts +0 -59
  192. package/src/session/blob-store.test.ts +0 -56
  193. package/src/session/messages.test.ts +0 -282
  194. package/src/session/session-context.test.ts +0 -384
  195. package/src/ssh/__tests__/connection-manager-args.test.ts +0 -191
  196. package/src/ssh/__tests__/connection-manager-timeout.test.ts +0 -61
  197. package/src/ssh/__tests__/file-transfer-posix-guard.test.ts +0 -105
  198. package/src/ssh/__tests__/sshfs-mount.test.ts +0 -13
  199. package/src/system-prompt.test.ts +0 -236
  200. package/src/task/render.test.ts +0 -290
  201. package/src/task/spawn-policy.test.ts +0 -62
  202. package/src/tools/__tests__/eval-description.test.ts +0 -18
  203. package/src/tools/__tests__/glob.test.ts +0 -37
  204. package/src/tools/__tests__/json-tree.test.ts +0 -35
  205. package/src/tools/__tests__/vibe-render.test.ts +0 -210
  206. package/src/tools/hub/launch-compat.test.ts +0 -40
  207. package/src/vibe/__tests__/token-rate.test.ts +0 -96
@@ -11,7 +11,7 @@ export declare function registerProvider<T>(capabilityId: string, provider: Prov
11
11
  /**
12
12
  * Load a capability by ID.
13
13
  */
14
- export declare function loadCapability<T>(capabilityId: string, options?: LoadOptions): Promise<CapabilityResult<T>>;
14
+ export declare function loadCapability<T>(capabilityId: string, options?: LoadOptions<T>): Promise<CapabilityResult<T>>;
15
15
  /**
16
16
  * Initialize capability system with settings manager for persistence.
17
17
  * Call this once on startup to enable persistent provider state.
@@ -51,7 +51,7 @@ export interface Provider<T> {
51
51
  /**
52
52
  * Options for loading a capability.
53
53
  */
54
- export interface LoadOptions {
54
+ export interface LoadOptions<T = unknown> {
55
55
  /** Only use these providers (by ID). Default: all registered */
56
56
  providers?: string[];
57
57
  /** Exclude these providers (by ID). Default: none */
@@ -64,6 +64,26 @@ export interface LoadOptions {
64
64
  includeDisabled?: boolean;
65
65
  /** Explicit disabled extension IDs to apply instead of settings. */
66
66
  disabledExtensions?: string[];
67
+ /**
68
+ * Drop items before deduplication as if they never existed (e.g. scope
69
+ * exclusions). A dropped item neither survives nor claims its dedupe key,
70
+ * so it cannot shadow anything. Receives the item with its attached
71
+ * `_source`.
72
+ */
73
+ filter?(item: T & {
74
+ _source: SourceMeta;
75
+ }): boolean;
76
+ /**
77
+ * Exclude items from the results while letting them claim their dedupe key.
78
+ * A suppressed higher-priority item still shadows same-key lower-priority
79
+ * items (a disabled project server keeps the same-named user server off),
80
+ * but never equivalence-shadows a differently-keyed survivor — so a
81
+ * suppressed alias cannot starve an enabled equivalent connection.
82
+ * Return `true` to suppress. Receives the item with its attached `_source`.
83
+ */
84
+ suppress?(item: T & {
85
+ _source: SourceMeta;
86
+ }): boolean;
67
87
  }
68
88
  /**
69
89
  * Source metadata attached to every loaded item.
@@ -112,6 +132,8 @@ export interface Capability<T> {
112
132
  * Return undefined to never deduplicate (all items kept).
113
133
  */
114
134
  key(item: T): string | undefined;
135
+ /** Treat items with different keys as aliases; the first equivalent item wins. */
136
+ equivalent?(left: T, right: T): boolean;
115
137
  /**
116
138
  * Optional validation. Return error message if invalid, undefined if valid.
117
139
  */
@@ -846,7 +846,7 @@ export declare const SETTINGS_SCHEMA: {
846
846
  readonly tab: "appearance";
847
847
  readonly group: "Display";
848
848
  readonly label: "Terminal Title Run State";
849
- readonly description: "Show the agent run state in the terminal title's separator — an animated spinner while working, '>' when it's your turn, '!' when the agent is waiting on you";
849
+ readonly description: "Show the agent run state in the terminal title's separator — an animated spinner while working (a static ':' on Windows), '>' when it's your turn, '!' when the agent is waiting on you";
850
850
  };
851
851
  };
852
852
  readonly "tui.hyperlinks": {
@@ -4577,6 +4577,16 @@ export declare const SETTINGS_SCHEMA: {
4577
4577
  readonly description: "Switch the task tool to its batch shape: one call carries { context, tasks[] } — one subagent per item, with an optional per-item agent (defaulting to the session spawn-policy agent), per-item isolation, and a required shared context prepended to every assignment. With async.enabled=true, each spawn runs as an independent background agent with the normal idle/parked lifecycle; otherwise the call blocks for merged results. Disable to restore the flat single-spawn schema.";
4578
4578
  };
4579
4579
  };
4580
+ readonly "task.enableEffort": {
4581
+ readonly type: "boolean";
4582
+ readonly default: false;
4583
+ readonly ui: {
4584
+ readonly tab: "tasks";
4585
+ readonly group: "Subagents";
4586
+ readonly label: "Per-Task Effort";
4587
+ readonly description: "Expose the optional effort parameter on task spawns, allowing callers to override each subagent's thinking level";
4588
+ };
4589
+ };
4580
4590
  readonly "task.maxConcurrency": {
4581
4591
  readonly type: "number";
4582
4592
  readonly default: 32;
@@ -4719,6 +4729,18 @@ export declare const SETTINGS_SCHEMA: {
4719
4729
  readonly description: "Inject one steering notice when a subagent crosses its soft request budget, asking it to wrap up before the 1.5x forced-yield stop.";
4720
4730
  };
4721
4731
  };
4732
+ readonly "task.maxEffort": {
4733
+ readonly type: "enum";
4734
+ readonly values: readonly import("@oh-my-pi/pi-catalog").Effort[];
4735
+ readonly default: "max";
4736
+ readonly ui: {
4737
+ readonly tab: "tasks";
4738
+ readonly group: "Subagents";
4739
+ readonly label: "Maximum Per-Spawn Effort";
4740
+ readonly description: "Maximum reasoning effort allowed for the task tool's per-spawn effort hint. Lower values prevent callers from escalating subagents above this ceiling; the default preserves the model's full range.";
4741
+ readonly options: import("../thinking.js").ThinkingLevelMetadata[];
4742
+ };
4743
+ };
4722
4744
  readonly "task.disabledAgents": {
4723
4745
  readonly type: "array";
4724
4746
  readonly default: string[];
@@ -1,9 +1,10 @@
1
1
  import type { InternalResource, InternalUrl, ProtocolHandler } from "./types.js";
2
2
  /**
3
- * Protocol handler for mcp:// URLs.
3
+ * Protocol handler for MCP resources.
4
4
  *
5
- * URL form:
5
+ * URL forms:
6
6
  * - mcp://<resource-uri> (e.g. mcp://test://notes, mcp://ibkr://portfolio/positions)
7
+ * - A resource's native URI when its scheme has no OMP handler (e.g. ags://capabilities/current-host)
7
8
  */
8
9
  export declare class McpProtocolHandler implements ProtocolHandler {
9
10
  readonly scheme = "mcp";
@@ -10,6 +10,18 @@
10
10
  * MUST use this function instead of calling `new URL()` directly.
11
11
  */
12
12
  import type { InternalUrl } from "./types.js";
13
+ /**
14
+ * Extract the lowercased scheme from a URI-shaped input, or `undefined` when
15
+ * the input does not look like a URI.
16
+ *
17
+ * Accepts both hierarchical (`scheme://…`) and opaque (`scheme:rest`) forms —
18
+ * MCP resource URIs may be opaque (`urn:example:document`, `custom:item`).
19
+ * The opaque form is guarded against path-like false positives:
20
+ * - Windows drive paths (`C:\…`, `C:/…`, `C:foo`) — single-letter scheme.
21
+ * - Filenames with extensions (`foo.ts:50`) — dot in the scheme segment.
22
+ * - Read-tool selector tails (`Makefile:12`, `README:raw:1-20`).
23
+ */
24
+ export declare function extractUriScheme(input: string): string | undefined;
13
25
  /**
14
26
  * Parse an internal URL into an InternalUrl.
15
27
  *
@@ -10,6 +10,12 @@ export declare class InternalUrlRouter {
10
10
  unregister(scheme: string): boolean;
11
11
  getHandler(scheme: string): ProtocolHandler | undefined;
12
12
  canHandle(input: string): boolean;
13
+ /**
14
+ * Whether read can resolve this URL through either a native handler or the
15
+ * MCP resource fallback. MCP resources may use arbitrary custom schemes and
16
+ * may be opaque (`urn:example:document`) rather than hierarchical.
17
+ */
18
+ canResolve(input: string): boolean;
13
19
  /** Schemes whose handler supports host/path autocomplete. */
14
20
  completionSchemes(): string[];
15
21
  /**
@@ -66,6 +66,12 @@ export interface InternalUrl extends URL {
66
66
  * Raw pathname extracted from input, preserving traversal markers before URL normalization.
67
67
  */
68
68
  rawPathname?: string;
69
+ /**
70
+ * Exact input string this URL was parsed from, before any normalization.
71
+ * Set by `parseInternalUrl`; used where byte-exact URI matching matters
72
+ * (e.g. MCP resource URIs compared by string equality).
73
+ */
74
+ rawHref?: string;
69
75
  }
70
76
  /**
71
77
  * Caller-supplied context that the router threads into protocol handlers.
@@ -52,6 +52,7 @@ export declare function resolveCommand(command: string, cwd: string, options?: R
52
52
  * "command": "/path/to/server",
53
53
  * "args": ["--stdio"],
54
54
  * "fileTypes": [".xyz"],
55
+ * "languageId": "xyz",
55
56
  * "rootMarkers": [".xyz-project"]
56
57
  * }
57
58
  * }
@@ -200,6 +200,8 @@ export interface ServerConfig {
200
200
  command: string;
201
201
  args?: string[];
202
202
  fileTypes: string[];
203
+ /** LSP language identifier sent in didOpen; inferred from the file path when omitted. */
204
+ languageId?: string;
203
205
  rootMarkers: string[];
204
206
  initOptions?: Record<string, unknown>;
205
207
  settings?: Record<string, unknown>;
@@ -174,6 +174,11 @@ export declare class MCPManager {
174
174
  * Refresh resources from a specific server.
175
175
  */
176
176
  refreshServerResources(name: string): Promise<void>;
177
+ /**
178
+ * Wait until a connected server's resource catalog has been loaded.
179
+ * Coalesces with initial loading and notification-driven refreshes.
180
+ */
181
+ ensureServerResources(name: string): Promise<void>;
177
182
  /**
178
183
  * Refresh prompts from a specific server.
179
184
  */
@@ -35,6 +35,19 @@ export interface MCPToolDetails {
35
35
  meta?: OutputMeta;
36
36
  }
37
37
  export declare function createMCPToolName(serverName: string, toolName: string): string;
38
+ /**
39
+ * Keeps one MCP tool per minted name and logs collisions between distinct MCP
40
+ * origins. The winner is chosen by a stable origin key (server name + original
41
+ * tool name), NOT array order: MCPManager re-appends a reconnecting server's
42
+ * tools, so insertion order is mutable across reconnects and first-wins would
43
+ * silently flip ownership of the minted name. Non-MCP tools pass through
44
+ * unchanged.
45
+ */
46
+ export declare function deduplicateMCPToolsByName<T extends {
47
+ name: string;
48
+ mcpServerName?: unknown;
49
+ mcpToolName?: unknown;
50
+ }>(tools: readonly T[]): T[];
38
51
  /**
39
52
  * Parse an MCP tool name back to server and tool components.
40
53
  *
@@ -54,7 +54,7 @@ export declare class ExtensionUiController {
54
54
  /**
55
55
  * Show a confirmation dialog for hooks.
56
56
  */
57
- showHookConfirm(title: string, message: string): Promise<boolean>;
57
+ showHookConfirm(title: string, message: string, dialogOptions?: ExtensionUIDialogOptions): Promise<boolean>;
58
58
  /**
59
59
  * Show a text input for hooks.
60
60
  */
@@ -158,6 +158,8 @@ export declare function handleRpcSessionChange(session: RpcSessionChangeSession,
158
158
  export declare function requestRpcEditor(pendingRequests: Map<string, PendingExtensionRequest>, output: RpcOutput, title: string, prefill?: string, dialogOptions?: ExtensionUIDialogOptions, editorOptions?: {
159
159
  promptStyle?: boolean;
160
160
  }): Promise<string | undefined>;
161
+ /** Sends an RPC extension dialog and cancels the remote presentation when its signal aborts. */
162
+ export declare function requestRpcDialog<T>(pendingRequests: Map<string, PendingExtensionRequest>, output: RpcOutput, opts: ExtensionUIDialogOptions | undefined, defaultValue: T, request: Record<string, unknown>, parseResponse: (response: RpcExtensionUIResponse) => T): Promise<T>;
161
163
  /**
162
164
  * Run in RPC mode.
163
165
  * Listens for JSON commands on stdin, outputs events and responses on stdout.
@@ -1,5 +1,5 @@
1
1
  import { Agent, type AgentOptions, type AgentTelemetryConfig, type AgentTool, type ThinkingLevel } from "@oh-my-pi/pi-agent-core";
2
- import type { Model, SimpleStreamOptions } from "@oh-my-pi/pi-ai";
2
+ import type { Effort, Model, SimpleStreamOptions } from "@oh-my-pi/pi-ai";
3
3
  import type { Dialect } from "@oh-my-pi/pi-ai/dialect";
4
4
  import { type Rule } from "./capability/rule.js";
5
5
  import { ModelRegistry } from "./config/model-registry.js";
@@ -52,6 +52,8 @@ export interface CreateAgentSessionOptions {
52
52
  modelPatternDefaultFallbackChain?: string[];
53
53
  /** Thinking selector. Default: from settings, else unset */
54
54
  thinkingLevel?: ConfiguredThinkingLevel;
55
+ /** Hard ceiling on the session's thinking effort (e.g. a task spawn's `task.maxEffort`-capped hint); retry-fallback recovery re-clamps to it. */
56
+ thinkingLevelCeiling?: Effort;
55
57
  /** Models available for cycling (Ctrl+P in interactive mode) */
56
58
  scopedModels?: Array<{
57
59
  model: Model;
@@ -1,5 +1,5 @@
1
1
  import type { Agent, AgentMessage, AgentTool, StreamFn, ThinkingLevel } from "@oh-my-pi/pi-agent-core";
2
- import type { Context, ImageContent, Message, MessageAttribution, Model, OAuthAccountSummary, ServiceTierByFamily, SimpleStreamOptions, ToolChoice } from "@oh-my-pi/pi-ai";
2
+ import type { Context, Effort, ImageContent, Message, MessageAttribution, Model, OAuthAccountSummary, ServiceTierByFamily, SimpleStreamOptions, ToolChoice } from "@oh-my-pi/pi-ai";
3
3
  import type { postmortem } from "@oh-my-pi/pi-utils";
4
4
  import type { AdvisorConfig } from "../advisor/index.js";
5
5
  import type { AsyncJob, AsyncJobDeliveryState, AsyncJobManager } from "../async/index.js";
@@ -88,6 +88,8 @@ export interface AgentSessionConfig {
88
88
  }>;
89
89
  /** Initial session thinking selector. */
90
90
  thinkingLevel?: ConfiguredThinkingLevel;
91
+ /** Hard ceiling on the session's thinking effort (e.g. a task spawn's `task.maxEffort`-capped hint); every later change, including retry-fallback recovery, is re-clamped to it. */
92
+ thinkingLevelCeiling?: Effort;
91
93
  /** Retry chain ownership when startup selected one of its fallback entries. */
92
94
  initialRetryFallback?: InitialRetryFallbackState;
93
95
  /** Prewalk from the starting model to a fast/cheap target after implementation begins. */
@@ -1011,6 +1011,8 @@ export declare class AgentSession {
1011
1011
  status: AdvisorRuntimeStatus;
1012
1012
  }[];
1013
1013
  };
1014
+ /** Return cumulative cost recorded for the current session's advisor activity. */
1015
+ getAdvisorCost(): number;
1014
1016
  /**
1015
1017
  * Return structured advisor stats for the status command and TUI panel.
1016
1018
  */
@@ -38,10 +38,13 @@ export declare class ModelControls {
38
38
  thinkingLevel?: ThinkingLevel;
39
39
  }>;
40
40
  thinkingLevel?: ConfiguredThinkingLevel;
41
+ thinkingLevelCeiling?: Effort;
41
42
  serviceTierByFamily?: ServiceTierByFamily;
42
43
  });
43
44
  /** Effective metadata-clamped thinking level applied to the agent. */
44
45
  get thinkingLevel(): ThinkingLevel | undefined;
46
+ /** Hard per-session effort ceiling every thinking-level change is clamped to. */
47
+ get thinkingLevelCeiling(): Effort | undefined;
45
48
  /** Configured selector, preserving `auto` while classification is active. */
46
49
  configuredThinkingLevel(): ConfiguredThinkingLevel | undefined;
47
50
  /** Whether per-turn automatic thinking classification is enabled. */
@@ -121,7 +121,11 @@ export declare class SessionAdvisors {
121
121
  /** Detaches and drains recorder feeds before transcript artifacts are removed. */
122
122
  detachAndCloseRecorders(): Promise<void>;
123
123
  /** Re-primes advisor transcript views across a conversation boundary. */
124
- resetSessionState(): void;
124
+ resetSessionState(options?: {
125
+ preserveCost?: boolean;
126
+ }): void;
127
+ /** Drop the recorded spend once a conversation boundary has committed. */
128
+ clearCost(): void;
125
129
  /**
126
130
  * Rebind every live advisor to the active primary conversation's provider
127
131
  * identity (session id, prompt-cache key, credential + metadata resolvers,
@@ -216,6 +220,8 @@ export declare class SessionAdvisors {
216
220
  status: AdvisorRuntimeStatus;
217
221
  }[];
218
222
  };
223
+ /** Return cumulative advisor cost recorded for the current session. */
224
+ getAdvisorCost(): number;
219
225
  /**
220
226
  * Return structured advisor stats for the status command and TUI panel.
221
227
  */
@@ -8,14 +8,14 @@ export interface RejectInfo {
8
8
  choice: ToolChoice;
9
9
  reason: "aborted" | "error" | "cleared" | "removed" | "unavailable" | "not_invoked";
10
10
  }
11
- /** "requeue" replays the lost yield next turn; "drop" (or void/undefined) discards it. */
12
- export type RejectOutcome = "requeue" | "drop";
11
+ /** Controls whether rejection replays a yield, drops it, or drops its remaining sequence. */
12
+ export type RejectOutcome = "requeue" | "drop" | "drop_sequence";
13
13
  export interface DirectiveCallbacks {
14
14
  /** Fires when the yield completed; onInvoked directives require the requested tool to run first. */
15
15
  onResolved?: (info: ResolveInfo) => void;
16
16
  /**
17
- * Fires when the yield is being discarded. Return "requeue" to replay the
18
- * same value at the head of the queue for the next turn. Default: "drop".
17
+ * Return "requeue" to replay the same value, or "drop_sequence" to discard
18
+ * its directive including later yields. Default: drop the rejected yield.
19
19
  */
20
20
  onRejected?: (info: RejectInfo) => RejectOutcome | undefined;
21
21
  /**
@@ -30,6 +30,8 @@ export interface ToolChoiceDirective {
30
30
  /** Stable label for targeted removal and debugging (e.g. "user-force"). */
31
31
  label: string;
32
32
  callbacks: DirectiveCallbacks;
33
+ /** Original multi-yield directive retained across one-yield replays. */
34
+ sequenceRoot?: ToolChoiceDirective;
33
35
  }
34
36
  export interface PushOptions {
35
37
  /** Prepend to head instead of appending to tail. Default: false. */
@@ -1,8 +1,8 @@
1
1
  import { type Agent, type AgentMessage, type ThinkingLevel } from "@oh-my-pi/pi-agent-core";
2
- import type { AssistantMessage, CodexCompactionContext, Model, ToolChoice } from "@oh-my-pi/pi-ai";
2
+ import type { AssistantMessage, CodexCompactionContext, Effort, Model, ToolChoice } from "@oh-my-pi/pi-ai";
3
3
  import type { ModelRegistry } from "../config/model-registry.js";
4
4
  import type { Settings } from "../config/settings.js";
5
- import type { ConfiguredThinkingLevel } from "../thinking.js";
5
+ import { type ConfiguredThinkingLevel } from "../thinking.js";
6
6
  import type { AgentSessionEvent } from "./agent-session-events.js";
7
7
  import type { InitialRetryFallbackState } from "./agent-session-types.js";
8
8
  import { type RetryFallbackSelector } from "./retry-fallback-chains.js";
@@ -25,6 +25,8 @@ export interface TurnRecoveryHost {
25
25
  thinkingLevel(): ThinkingLevel | undefined;
26
26
  configuredThinkingLevel(): ConfiguredThinkingLevel | undefined;
27
27
  setThinkingLevel(level: ConfiguredThinkingLevel | undefined): void;
28
+ /** Hard per-session effort ceiling; fallback recovery must never raise thinking above it. */
29
+ thinkingLevelCeiling(): Effort | undefined;
28
30
  isDisposed(): boolean;
29
31
  isStreaming(): boolean;
30
32
  isCompacting(): boolean;
@@ -71,7 +71,7 @@ export declare class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskT
71
71
  readonly mergeCallAndResult = true;
72
72
  get parameters(): TaskToolSchemaInstance;
73
73
  renderCall(args: unknown, options: Parameters<typeof renderTaskCall>[1], theme: Theme): import("@oh-my-pi/pi-tui").Component;
74
- /** Dynamic description that reflects current disabled-agent settings */
74
+ /** Dynamic description that reflects current task settings. */
75
75
  get description(): string;
76
76
  private constructor();
77
77
  /**
@@ -83,7 +83,6 @@ export declare const taskItemSchema: import("arktype/internal/variants/object.ts
83
83
  name?: string | undefined;
84
84
  agent: import("arktype/internal/attributes.ts").Default<string, "task">;
85
85
  task: string;
86
- effort?: "hi" | "lo" | "med" | undefined;
87
86
  outputSchema?: string | boolean | object | null | undefined;
88
87
  schemaMode?: "permissive" | "strict" | undefined;
89
88
  }, {}>;
@@ -108,7 +107,6 @@ export declare const taskSchema: import("arktype/internal/variants/object.ts").O
108
107
  name?: string | undefined;
109
108
  agent: import("arktype/internal/attributes.ts").Default<string, "task">;
110
109
  task: string;
111
- effort?: "hi" | "lo" | "med" | undefined;
112
110
  outputSchema?: string | boolean | object | null | undefined;
113
111
  schemaMode?: "permissive" | "strict" | undefined;
114
112
  isolated?: boolean | undefined;
@@ -117,7 +115,6 @@ declare const ALL_TASK_SCHEMAS: readonly [import("arktype/internal/variants/obje
117
115
  name?: string | undefined;
118
116
  agent: import("arktype/internal/attributes.ts").Default<string, "task">;
119
117
  task: string;
120
- effort?: "hi" | "lo" | "med" | undefined;
121
118
  outputSchema?: string | boolean | object | null | undefined;
122
119
  schemaMode?: "permissive" | "strict" | undefined;
123
120
  isolated?: boolean | undefined;
@@ -125,7 +122,6 @@ declare const ALL_TASK_SCHEMAS: readonly [import("arktype/internal/variants/obje
125
122
  name?: string | undefined;
126
123
  agent: import("arktype/internal/attributes.ts").Default<string, "task">;
127
124
  task: string;
128
- effort?: "hi" | "lo" | "med" | undefined;
129
125
  outputSchema?: string | boolean | object | null | undefined;
130
126
  schemaMode?: "permissive" | "strict" | undefined;
131
127
  }, {}>, import("arktype/internal/variants/object.ts").ObjectType<{
@@ -134,7 +130,6 @@ declare const ALL_TASK_SCHEMAS: readonly [import("arktype/internal/variants/obje
134
130
  name?: string | undefined;
135
131
  agent: import("arktype/internal/attributes.ts").Default<string, "task">;
136
132
  task: string;
137
- effort?: "hi" | "lo" | "med" | undefined;
138
133
  outputSchema?: string | boolean | object | null | undefined;
139
134
  schemaMode?: "permissive" | "strict" | undefined;
140
135
  isolated?: boolean | undefined;
@@ -145,7 +140,6 @@ declare const ALL_TASK_SCHEMAS: readonly [import("arktype/internal/variants/obje
145
140
  name?: string | undefined;
146
141
  agent: import("arktype/internal/attributes.ts").Default<string, "task">;
147
142
  task: string;
148
- effort?: "hi" | "lo" | "med" | undefined;
149
143
  outputSchema?: string | boolean | object | null | undefined;
150
144
  schemaMode?: "permissive" | "strict" | undefined;
151
145
  }[];
@@ -154,14 +148,12 @@ type DynamicTaskSchema = (typeof ALL_TASK_SCHEMAS)[number];
154
148
  export type TaskSchema = typeof taskSchema;
155
149
  /** Active task tool parameter schema for the current isolation / batch flags */
156
150
  export type TaskToolSchemaInstance = DynamicTaskSchema | BaseType;
151
+ /** Build the task wire schema for the current settings and spawn policy. */
157
152
  export declare function getTaskSchema(options: {
158
153
  isolationEnabled: boolean;
159
154
  batchEnabled: boolean;
160
- }): DynamicTaskSchema;
161
- export declare function getTaskSchema(options: {
162
- isolationEnabled: boolean;
163
- batchEnabled: boolean;
164
- defaultAgent: string;
155
+ effortEnabled?: boolean;
156
+ defaultAgent?: string;
165
157
  }): TaskToolSchemaInstance;
166
158
  /**
167
159
  * Runtime params union over both wire shapes. The model sees exactly one shape
@@ -122,9 +122,28 @@ export type TaskEffort = (typeof TASK_EFFORTS)[number];
122
122
  * at — high, xhigh, or max), `med` = the middle (lower of the two middles for
123
123
  * an even-sized range). Without a model, maps over the full canonical range.
124
124
  * Returns `undefined` when the model has no controllable effort surface, so
125
- * callers fall back to their default selector (e.g. `auto`).
125
+ * callers fall back to their default selector (e.g. `auto`). Throws when the
126
+ * configured ceiling is below the model's lowest supported effort.
126
127
  */
127
- export declare function resolveTaskEffortLevel(model: Model | undefined, effort: TaskEffort): Effort | undefined;
128
+ export declare function resolveTaskEffortLevel(model: Model | undefined, effort: TaskEffort, maxEffort?: Effort): Effort | undefined;
129
+ /**
130
+ * Clamps a concrete thinking selector to a per-session effort ceiling (e.g. a
131
+ * task spawn's `task.maxEffort`-capped effort hint). `off`/`inherit`/
132
+ * `undefined` pass through, as do levels already at or below the ceiling.
133
+ * Levels above it snap to the highest model-supported effort at or below the
134
+ * ceiling. A model whose floor exceeds the ceiling has nothing valid to snap
135
+ * to; the requested level is returned unchanged and the caller is responsible
136
+ * for rejecting or skipping such models (see {@link modelSupportsEffortCeiling}).
137
+ */
138
+ export declare function clampThinkingLevelToCeiling(model: Model | undefined, level: Effort | undefined, ceiling: Effort | undefined): Effort | undefined;
139
+ export declare function clampThinkingLevelToCeiling(model: Model | undefined, level: ThinkingLevel | undefined, ceiling: Effort | undefined): ThinkingLevel | undefined;
140
+ /**
141
+ * True when `model` can honor a thinking-effort ceiling: it either has no
142
+ * controllable effort surface (nothing to cap) or supports at least one effort
143
+ * at or below the ceiling. Retry-fallback candidate filtering uses this to
144
+ * skip models whose floor would force the session above the ceiling.
145
+ */
146
+ export declare function modelSupportsEffortCeiling(model: Model, ceiling: Effort): boolean;
128
147
  /**
129
148
  * The provisional concrete level shown while `auto` is configured but before a
130
149
  * turn has been classified. Prefers the model's `defaultLevel`, otherwise High,
@@ -20,39 +20,40 @@ export declare function generateSessionTitle(firstMessage: string, registry: Mod
20
20
  export declare function generateTitleOnline(firstMessage: string, registry: ModelRegistry, settings: Settings, sessionId?: string, currentModel?: Model<Api>, metadataResolver?: (provider: string) => Record<string, unknown> | undefined, signal?: AbortSignal, customSystemPrompt?: string): Promise<string | null>;
21
21
  export declare function formatSessionTerminalTitle(sessionName: string | undefined, cwd?: string): string;
22
22
  /**
23
- * Set the terminal title using OSC 0 (sets both tab and window title). Unsupported terminals ignore it.
23
+ * Set the terminal title through the native Win32 API or OSC 0.
24
+ *
25
+ * Repeating the same sanitized title is a no-op on every platform.
24
26
  */
25
27
  export declare function setTerminalTitle(title: string): void;
26
28
  export declare function setSessionTerminalTitle(sessionName: string | undefined, cwd?: string): void;
27
29
  /**
28
30
  * Set a terminal title from an extension's `setTitle()`. Unlike the session base
29
- * title, this owns the terminal verbatim: the run-state separator will not rewrite
30
- * it on the next spinner tick or state change. Cleared when the app next sets an
31
- * authoritative session title via {@link setSessionTerminalTitle}.
31
+ * title, this owns the terminal verbatim: periodic and run-state updates will not
32
+ * rewrite it. Cleared when the app next sets an authoritative session title via
33
+ * {@link setSessionTerminalTitle}.
32
34
  */
33
35
  export declare function setExtensionTerminalTitle(title: string): void;
34
36
  export type TerminalTitleState = "idle" | "working" | "attention";
35
37
  /**
36
- * Compose the terminal title from the `π` brand, a state-carrying SEPARATOR, and
37
- * the session label. The brand never gains a prefix glyph the separator slot
38
- * expresses the run state instead. Pure (no I/O) so the state→separator contract
39
- * is unit-testable:
40
- * - `idle` (user's turn): > label` — reads like a prompt awaiting input;
41
- * - `working`: `π label` — spinner frames animate the separator;
42
- * - `attention`: `π ! label` — agent blocked on the user;
43
- * - disabled: `π: label` — the pre-state layout.
38
+ * Compose the terminal title from the `π` brand, a state-carrying separator, and
39
+ * the session label. Pure (no I/O) so the state→separator contract is testable:
40
+ * - `idle` (user's turn): `π > label`;
41
+ * - `working`: `π ⠋ label` (`π : label` on Windows);
42
+ * - `attention`: ! label`;
43
+ * - disabled: `π: label`.
44
44
  * Without a label the separator trails the brand (`π >`) so the state stays visible.
45
45
  */
46
- export declare function buildTerminalTitleWithState(label: string | undefined, state: TerminalTitleState, frame: number, enabled: boolean): string;
46
+ export declare function buildTerminalTitleWithState(label: string | undefined, state: TerminalTitleState, frame: number, enabled: boolean, platform?: NodeJS.Platform): string;
47
47
  /**
48
48
  * Reflect the agent run state in the terminal title's separator: `working`
49
- * animates spinner frames in the separator slot, `idle` shows `>` (your turn),
50
- * `attention` shows `!` (agent blocked on you). Gated off by `tui.titleState`.
49
+ * animates outside Windows and stays `:` on Windows, `idle` shows `>` (your
50
+ * turn), and `attention` shows `!` (agent blocked on you). Gated off by
51
+ * `tui.titleState`.
51
52
  */
52
53
  export declare function setTerminalTitleState(state: TerminalTitleState): void;
53
54
  /** Enable/disable the run-state separator (driven by the `tui.titleState` setting). */
54
55
  export declare function setTerminalTitleStateEnabled(enabled: boolean): void;
55
- /** Stop the spinner timer; call on session/UI teardown. */
56
+ /** Release terminal-title runtime resources. */
56
57
  export declare function disposeTerminalTitleState(): void;
57
58
  /**
58
59
  * Save the current terminal title on terminals that support xterm window ops.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@oh-my-pi/pi-coding-agent",
4
- "version": "17.1.5",
4
+ "version": "17.1.6",
5
5
  "description": "Coding agent CLI with read, bash, edit, write tools and session management",
6
6
  "homepage": "https://omp.sh",
7
7
  "author": "Can Boluk",
@@ -52,17 +52,17 @@
52
52
  "@agentclientprotocol/sdk": "1.2.1",
53
53
  "@babel/parser": "^7.29.7",
54
54
  "@mozilla/readability": "^0.6.0",
55
- "@oh-my-pi/hashline": "17.1.5",
56
- "@oh-my-pi/omp-stats": "17.1.5",
57
- "@oh-my-pi/pi-agent-core": "17.1.5",
58
- "@oh-my-pi/pi-ai": "17.1.5",
59
- "@oh-my-pi/pi-catalog": "17.1.5",
60
- "@oh-my-pi/pi-mnemopi": "17.1.5",
61
- "@oh-my-pi/pi-natives": "17.1.5",
62
- "@oh-my-pi/pi-tui": "17.1.5",
63
- "@oh-my-pi/pi-utils": "17.1.5",
64
- "@oh-my-pi/pi-wire": "17.1.5",
65
- "@oh-my-pi/snapcompact": "17.1.5",
55
+ "@oh-my-pi/hashline": "17.1.6",
56
+ "@oh-my-pi/omp-stats": "17.1.6",
57
+ "@oh-my-pi/pi-agent-core": "17.1.6",
58
+ "@oh-my-pi/pi-ai": "17.1.6",
59
+ "@oh-my-pi/pi-catalog": "17.1.6",
60
+ "@oh-my-pi/pi-mnemopi": "17.1.6",
61
+ "@oh-my-pi/pi-natives": "17.1.6",
62
+ "@oh-my-pi/pi-tui": "17.1.6",
63
+ "@oh-my-pi/pi-utils": "17.1.6",
64
+ "@oh-my-pi/pi-wire": "17.1.6",
65
+ "@oh-my-pi/snapcompact": "17.1.6",
66
66
  "@opentelemetry/api": "^1.9.1",
67
67
  "@opentelemetry/api-logs": "^0.220.0",
68
68
  "@opentelemetry/context-async-hooks": "^2.9.0",