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

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 (244) hide show
  1. package/CHANGELOG.md +54 -0
  2. package/dist/{CHANGELOG-qs3vd6xf.md → CHANGELOG-5k4dq4g6.md} +54 -0
  3. package/dist/cli.js +3342 -3274
  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 +39 -2
  7. package/dist/types/cursor.d.ts +2 -1
  8. package/dist/types/extensibility/extensions/runner.d.ts +4 -0
  9. package/dist/types/extensibility/shared-events.d.ts +18 -1
  10. package/dist/types/internal-urls/mcp-protocol.d.ts +3 -2
  11. package/dist/types/internal-urls/parse.d.ts +12 -0
  12. package/dist/types/internal-urls/router.d.ts +6 -0
  13. package/dist/types/internal-urls/types.d.ts +6 -0
  14. package/dist/types/lsp/config.d.ts +1 -0
  15. package/dist/types/lsp/types.d.ts +2 -0
  16. package/dist/types/mcp/manager.d.ts +5 -0
  17. package/dist/types/mcp/tool-bridge.d.ts +13 -0
  18. package/dist/types/modes/components/custom-editor.d.ts +5 -0
  19. package/dist/types/modes/controllers/extension-ui-controller.d.ts +1 -1
  20. package/dist/types/modes/rpc/rpc-mode.d.ts +2 -0
  21. package/dist/types/sdk.d.ts +3 -1
  22. package/dist/types/session/agent-session-types.d.ts +8 -6
  23. package/dist/types/session/agent-session.d.ts +28 -1
  24. package/dist/types/session/model-controls.d.ts +4 -1
  25. package/dist/types/session/session-advisors.d.ts +7 -1
  26. package/dist/types/session/session-tools.d.ts +44 -6
  27. package/dist/types/session/streaming-output.d.ts +7 -2
  28. package/dist/types/session/tool-choice-queue.d.ts +6 -4
  29. package/dist/types/session/turn-recovery.d.ts +5 -3
  30. package/dist/types/task/index.d.ts +1 -1
  31. package/dist/types/task/types.d.ts +3 -11
  32. package/dist/types/thinking.d.ts +21 -2
  33. package/dist/types/tools/index.d.ts +8 -3
  34. package/dist/types/tools/output-meta.d.ts +5 -0
  35. package/dist/types/tools/read.d.ts +9 -1
  36. package/dist/types/tools/xdev.d.ts +53 -67
  37. package/dist/types/utils/cpuprofile.d.ts +51 -0
  38. package/dist/types/utils/inspect-image-mode.d.ts +29 -0
  39. package/dist/types/utils/profile-tree.d.ts +47 -0
  40. package/dist/types/utils/sample-profile.d.ts +67 -0
  41. package/dist/types/utils/title-generator.d.ts +17 -16
  42. package/package.json +12 -12
  43. package/src/capability/index.ts +43 -12
  44. package/src/capability/mcp.ts +21 -0
  45. package/src/capability/types.ts +20 -1
  46. package/src/cli/read-cli.ts +44 -2
  47. package/src/config/settings-schema.ts +42 -2
  48. package/src/config/settings.ts +35 -0
  49. package/src/cursor.ts +4 -3
  50. package/src/discovery/builtin-rules/index.ts +2 -0
  51. package/src/discovery/builtin-rules/ts-no-local-is-record.md +48 -0
  52. package/src/eval/py/runner.py +16 -2
  53. package/src/extensibility/extensions/runner.ts +117 -5
  54. package/src/extensibility/extensions/types.ts +0 -1
  55. package/src/extensibility/extensions/wrapper.ts +74 -42
  56. package/src/extensibility/hooks/tool-wrapper.ts +11 -4
  57. package/src/extensibility/hooks/types.ts +0 -1
  58. package/src/extensibility/shared-events.ts +18 -1
  59. package/src/internal-urls/mcp-protocol.ts +17 -3
  60. package/src/internal-urls/parse.ts +31 -0
  61. package/src/internal-urls/router.ts +24 -4
  62. package/src/internal-urls/types.ts +6 -0
  63. package/src/live/transport.ts +2 -2
  64. package/src/lsp/client.ts +2 -2
  65. package/src/lsp/config.ts +4 -0
  66. package/src/lsp/types.ts +2 -0
  67. package/src/mcp/config.ts +26 -14
  68. package/src/mcp/manager.ts +26 -9
  69. package/src/mcp/tool-bridge.ts +52 -1
  70. package/src/memories/index.ts +25 -6
  71. package/src/modes/components/custom-editor.ts +39 -16
  72. package/src/modes/components/status-line/segments.ts +3 -1
  73. package/src/modes/components/tips.txt +2 -1
  74. package/src/modes/components/tool-execution.ts +8 -7
  75. package/src/modes/controllers/command-controller.ts +10 -10
  76. package/src/modes/controllers/extension-ui-controller.ts +7 -7
  77. package/src/modes/controllers/selector-controller.ts +7 -2
  78. package/src/modes/rpc/rpc-mode.ts +60 -47
  79. package/src/prompts/steering/user-interjection.md +2 -5
  80. package/src/prompts/tools/task.md +4 -2
  81. package/src/sdk.ts +64 -58
  82. package/src/session/agent-session-types.ts +8 -5
  83. package/src/session/agent-session.ts +144 -11
  84. package/src/session/model-controls.ts +48 -12
  85. package/src/session/session-advisors.ts +30 -14
  86. package/src/session/session-listing.ts +66 -4
  87. package/src/session/session-tools.ts +162 -54
  88. package/src/session/streaming-output.ts +18 -6
  89. package/src/session/tool-choice-queue.ts +19 -4
  90. package/src/session/turn-recovery.ts +25 -6
  91. package/src/slash-commands/builtin-registry.ts +69 -0
  92. package/src/task/executor.ts +11 -3
  93. package/src/task/index.ts +43 -32
  94. package/src/task/types.ts +12 -17
  95. package/src/thinking.ts +68 -5
  96. package/src/tools/bash.ts +16 -9
  97. package/src/tools/index.ts +36 -16
  98. package/src/tools/output-meta.ts +20 -0
  99. package/src/tools/read.ts +89 -15
  100. package/src/tools/write.ts +16 -7
  101. package/src/tools/xdev.ts +198 -210
  102. package/src/utils/cpuprofile.ts +235 -0
  103. package/src/utils/inspect-image-mode.ts +39 -0
  104. package/src/utils/profile-tree.ts +111 -0
  105. package/src/utils/sample-profile.ts +437 -0
  106. package/src/utils/title-generator.ts +88 -34
  107. package/dist/types/advisor/__tests__/advisor.test.d.ts +0 -1
  108. package/dist/types/advisor/__tests__/config.test.d.ts +0 -1
  109. package/dist/types/advisor/__tests__/emission-guard.test.d.ts +0 -1
  110. package/dist/types/cli/__tests__/auth-gateway-catalog.test.d.ts +0 -1
  111. package/dist/types/cli/update-cli.test.d.ts +0 -1
  112. package/dist/types/config/__tests__/model-registry.test.d.ts +0 -1
  113. package/dist/types/eval/__tests__/agent-bridge.test.d.ts +0 -1
  114. package/dist/types/eval/__tests__/bridge-timeout.test.d.ts +0 -1
  115. package/dist/types/eval/__tests__/budget-bridge.test.d.ts +0 -1
  116. package/dist/types/eval/__tests__/completion-bridge.test.d.ts +0 -1
  117. package/dist/types/eval/__tests__/helpers-local-roots.test.d.ts +0 -1
  118. package/dist/types/eval/__tests__/idle-timeout.test.d.ts +0 -1
  119. package/dist/types/eval/__tests__/js-context-manager.test.d.ts +0 -1
  120. package/dist/types/eval/__tests__/julia-prelude.test.d.ts +0 -1
  121. package/dist/types/eval/__tests__/kernel-spawn.test.d.ts +0 -1
  122. package/dist/types/eval/__tests__/prelude-agent.test.d.ts +0 -1
  123. package/dist/types/eval/__tests__/process-entry-import.test.d.ts +0 -1
  124. package/dist/types/eval/py/__tests__/prelude.test.d.ts +0 -1
  125. package/dist/types/eval/py/__tests__/runner-shell-output.test.d.ts +0 -1
  126. package/dist/types/hindsight/client.test.d.ts +0 -1
  127. package/dist/types/internal-urls/__tests__/agent-protocol-nested.test.d.ts +0 -1
  128. package/dist/types/internal-urls/__tests__/ssh-protocol.test.d.ts +0 -1
  129. package/dist/types/launch/broker-list-order.test.d.ts +0 -1
  130. package/dist/types/launch/broker-output-snapshot.test.d.ts +0 -1
  131. package/dist/types/launch/protocol.test.d.ts +0 -1
  132. package/dist/types/launch/spawn-options.test.d.ts +0 -1
  133. package/dist/types/launch/terminal-output.test.d.ts +0 -1
  134. package/dist/types/live/protocol.test.d.ts +0 -1
  135. package/dist/types/mcp/config-writer.test.d.ts +0 -1
  136. package/dist/types/mcp/smithery-auth.test.d.ts +0 -1
  137. package/dist/types/mcp/smithery-registry.test.d.ts +0 -1
  138. package/dist/types/mcp/transports/stdio.test.d.ts +0 -1
  139. package/dist/types/modes/components/__tests__/dynamic-border.test.d.ts +0 -1
  140. package/dist/types/modes/components/__tests__/move-overlay.test.d.ts +0 -1
  141. package/dist/types/modes/components/__tests__/pause-screen.test.d.ts +0 -1
  142. package/dist/types/modes/components/__tests__/skill-message.test.d.ts +0 -1
  143. package/dist/types/modes/components/custom-editor-plugin-ctor.test.d.ts +0 -1
  144. package/dist/types/modes/components/custom-editor.test.d.ts +0 -1
  145. package/dist/types/modes/components/login-dialog.test.d.ts +0 -1
  146. package/dist/types/modes/components/status-line/component.jj-cache.test.d.ts +0 -1
  147. package/dist/types/modes/components/status-line/component.test.d.ts +0 -1
  148. package/dist/types/modes/components/tool-execution.test.d.ts +0 -1
  149. package/dist/types/modes/controllers/extension-ui-controller.test.d.ts +0 -1
  150. package/dist/types/modes/noninteractive-dispose.test.d.ts +0 -1
  151. package/dist/types/modes/print-mode.test.d.ts +0 -1
  152. package/dist/types/modes/session-teardown.test.d.ts +0 -1
  153. package/dist/types/modes/theme/mermaid-rendering.test.d.ts +0 -1
  154. package/dist/types/modes/utils/transcript-render-helpers.test.d.ts +0 -1
  155. package/dist/types/modes/warp-events.test.d.ts +0 -1
  156. package/dist/types/plan-mode/approved-plan-prompt.test.d.ts +0 -1
  157. package/dist/types/plan-mode/model-transition.test.d.ts +0 -1
  158. package/dist/types/plan-mode/reentry-prompt.test.d.ts +0 -1
  159. package/dist/types/session/agent-session-error-log.test.d.ts +0 -1
  160. package/dist/types/session/blob-store.test.d.ts +0 -1
  161. package/dist/types/session/messages.test.d.ts +0 -1
  162. package/dist/types/session/session-context.test.d.ts +0 -1
  163. package/dist/types/ssh/__tests__/connection-manager-args.test.d.ts +0 -1
  164. package/dist/types/ssh/__tests__/connection-manager-timeout.test.d.ts +0 -1
  165. package/dist/types/ssh/__tests__/file-transfer-posix-guard.test.d.ts +0 -1
  166. package/dist/types/ssh/__tests__/sshfs-mount.test.d.ts +0 -1
  167. package/dist/types/system-prompt.test.d.ts +0 -1
  168. package/dist/types/task/render.test.d.ts +0 -1
  169. package/dist/types/task/spawn-policy.test.d.ts +0 -1
  170. package/dist/types/tools/__tests__/eval-description.test.d.ts +0 -1
  171. package/dist/types/tools/__tests__/glob.test.d.ts +0 -1
  172. package/dist/types/tools/__tests__/json-tree.test.d.ts +0 -1
  173. package/dist/types/tools/__tests__/vibe-render.test.d.ts +0 -1
  174. package/dist/types/tools/hub/launch-compat.test.d.ts +0 -1
  175. package/dist/types/vibe/__tests__/token-rate.test.d.ts +0 -1
  176. package/src/advisor/__tests__/advisor.test.ts +0 -4889
  177. package/src/advisor/__tests__/config.test.ts +0 -349
  178. package/src/advisor/__tests__/emission-guard.test.ts +0 -147
  179. package/src/cli/__tests__/auth-gateway-catalog.test.ts +0 -111
  180. package/src/cli/update-cli.test.ts +0 -28
  181. package/src/config/__tests__/model-registry.test.ts +0 -182
  182. package/src/eval/__tests__/agent-bridge.test.ts +0 -1509
  183. package/src/eval/__tests__/bridge-timeout.test.ts +0 -170
  184. package/src/eval/__tests__/budget-bridge.test.ts +0 -80
  185. package/src/eval/__tests__/completion-bridge.test.ts +0 -412
  186. package/src/eval/__tests__/helpers-local-roots.test.ts +0 -55
  187. package/src/eval/__tests__/idle-timeout.test.ts +0 -80
  188. package/src/eval/__tests__/js-context-manager.test.ts +0 -456
  189. package/src/eval/__tests__/julia-prelude.test.ts +0 -66
  190. package/src/eval/__tests__/kernel-spawn.test.ts +0 -115
  191. package/src/eval/__tests__/prelude-agent.test.ts +0 -156
  192. package/src/eval/__tests__/process-entry-import.test.ts +0 -137
  193. package/src/eval/py/__tests__/prelude.test.ts +0 -104
  194. package/src/eval/py/__tests__/runner-shell-output.test.ts +0 -157
  195. package/src/hindsight/client.test.ts +0 -75
  196. package/src/internal-urls/__tests__/agent-protocol-nested.test.ts +0 -141
  197. package/src/internal-urls/__tests__/ssh-protocol.test.ts +0 -331
  198. package/src/launch/broker-list-order.test.ts +0 -89
  199. package/src/launch/broker-output-snapshot.test.ts +0 -126
  200. package/src/launch/protocol.test.ts +0 -59
  201. package/src/launch/spawn-options.test.ts +0 -31
  202. package/src/launch/terminal-output.test.ts +0 -107
  203. package/src/live/protocol.test.ts +0 -140
  204. package/src/mcp/config-writer.test.ts +0 -43
  205. package/src/mcp/smithery-auth.test.ts +0 -29
  206. package/src/mcp/smithery-registry.test.ts +0 -51
  207. package/src/mcp/transports/stdio.test.ts +0 -427
  208. package/src/modes/components/__tests__/dynamic-border.test.ts +0 -55
  209. package/src/modes/components/__tests__/move-overlay.test.ts +0 -252
  210. package/src/modes/components/__tests__/pause-screen.test.ts +0 -143
  211. package/src/modes/components/__tests__/skill-message.test.ts +0 -94
  212. package/src/modes/components/custom-editor-plugin-ctor.test.ts +0 -36
  213. package/src/modes/components/custom-editor.test.ts +0 -510
  214. package/src/modes/components/login-dialog.test.ts +0 -56
  215. package/src/modes/components/status-line/component.jj-cache.test.ts +0 -229
  216. package/src/modes/components/status-line/component.test.ts +0 -84
  217. package/src/modes/components/tool-execution.test.ts +0 -162
  218. package/src/modes/controllers/extension-ui-controller.test.ts +0 -250
  219. package/src/modes/noninteractive-dispose.test.ts +0 -73
  220. package/src/modes/print-mode.test.ts +0 -71
  221. package/src/modes/session-teardown.test.ts +0 -219
  222. package/src/modes/theme/mermaid-rendering.test.ts +0 -53
  223. package/src/modes/utils/transcript-render-helpers.test.ts +0 -38
  224. package/src/modes/warp-events.test.ts +0 -794
  225. package/src/plan-mode/approved-plan-prompt.test.ts +0 -36
  226. package/src/plan-mode/model-transition.test.ts +0 -60
  227. package/src/plan-mode/reentry-prompt.test.ts +0 -41
  228. package/src/session/agent-session-error-log.test.ts +0 -59
  229. package/src/session/blob-store.test.ts +0 -56
  230. package/src/session/messages.test.ts +0 -282
  231. package/src/session/session-context.test.ts +0 -384
  232. package/src/ssh/__tests__/connection-manager-args.test.ts +0 -191
  233. package/src/ssh/__tests__/connection-manager-timeout.test.ts +0 -61
  234. package/src/ssh/__tests__/file-transfer-posix-guard.test.ts +0 -105
  235. package/src/ssh/__tests__/sshfs-mount.test.ts +0 -13
  236. package/src/system-prompt.test.ts +0 -236
  237. package/src/task/render.test.ts +0 -290
  238. package/src/task/spawn-policy.test.ts +0 -62
  239. package/src/tools/__tests__/eval-description.test.ts +0 -18
  240. package/src/tools/__tests__/glob.test.ts +0 -37
  241. package/src/tools/__tests__/json-tree.test.ts +0 -35
  242. package/src/tools/__tests__/vibe-render.test.ts +0 -210
  243. package/src/tools/hub/launch-compat.test.ts +0 -40
  244. package/src/vibe/__tests__/token-rate.test.ts +0 -96
@@ -603,6 +603,57 @@ export function requestRpcEditor(
603
603
  } as RpcExtensionUIRequest);
604
604
  return promise;
605
605
  }
606
+
607
+ /** Sends an RPC extension dialog and cancels the remote presentation when its signal aborts. */
608
+ export function requestRpcDialog<T>(
609
+ pendingRequests: Map<string, PendingExtensionRequest>,
610
+ output: RpcOutput,
611
+ opts: ExtensionUIDialogOptions | undefined,
612
+ defaultValue: T,
613
+ request: Record<string, unknown>,
614
+ parseResponse: (response: RpcExtensionUIResponse) => T,
615
+ ): Promise<T> {
616
+ if (opts?.signal?.aborted) return Promise.resolve(defaultValue);
617
+
618
+ const id = Snowflake.next() as string;
619
+ const { promise, resolve, reject } = Promise.withResolvers<T>();
620
+ let timeoutId: NodeJS.Timeout | undefined;
621
+
622
+ const cleanup = () => {
623
+ clearTimeout(timeoutId);
624
+ opts?.signal?.removeEventListener("abort", onAbort);
625
+ pendingRequests.delete(id);
626
+ };
627
+ const onAbort = () => {
628
+ output({
629
+ type: "extension_ui_request",
630
+ id: Snowflake.next() as string,
631
+ method: "cancel",
632
+ targetId: id,
633
+ } as RpcExtensionUIRequest);
634
+ cleanup();
635
+ resolve(defaultValue);
636
+ };
637
+ opts?.signal?.addEventListener("abort", onAbort, { once: true });
638
+
639
+ if (opts?.timeout !== undefined) {
640
+ timeoutId = setTimeout(() => {
641
+ opts.onTimeout?.();
642
+ cleanup();
643
+ resolve(defaultValue);
644
+ }, opts.timeout);
645
+ }
646
+
647
+ pendingRequests.set(id, {
648
+ resolve: response => {
649
+ cleanup();
650
+ resolve(parseResponse(response));
651
+ },
652
+ reject,
653
+ });
654
+ output({ type: "extension_ui_request", id, ...request } as RpcExtensionUIRequest);
655
+ return promise;
656
+ }
606
657
  /**
607
658
  * Run in RPC mode.
608
659
  * Listens for JSON commands on stdin, outputs events and responses on stdout.
@@ -685,56 +736,14 @@ export async function runRpcMode(
685
736
  private output: (obj: RpcResponse | RpcExtensionUIRequest | object) => void,
686
737
  ) {}
687
738
 
688
- /** Helper for dialog methods with signal/timeout support */
689
- #createDialogPromise<T>(
690
- opts: ExtensionUIDialogOptions | undefined,
691
- defaultValue: T,
692
- request: Record<string, unknown>,
693
- parseResponse: (response: RpcExtensionUIResponse) => T,
694
- ): Promise<T> {
695
- if (opts?.signal?.aborted) return Promise.resolve(defaultValue);
696
-
697
- const id = Snowflake.next() as string;
698
- const { promise, resolve, reject } = Promise.withResolvers<T>();
699
- let timeoutId: NodeJS.Timeout | undefined;
700
-
701
- const cleanup = () => {
702
- if (timeoutId) clearTimeout(timeoutId);
703
- opts?.signal?.removeEventListener("abort", onAbort);
704
- this.pendingRequests.delete(id);
705
- };
706
-
707
- const onAbort = () => {
708
- cleanup();
709
- resolve(defaultValue);
710
- };
711
- opts?.signal?.addEventListener("abort", onAbort, { once: true });
712
-
713
- if (opts?.timeout !== undefined) {
714
- timeoutId = setTimeout(() => {
715
- opts.onTimeout?.();
716
- cleanup();
717
- resolve(defaultValue);
718
- }, opts.timeout);
719
- }
720
-
721
- this.pendingRequests.set(id, {
722
- resolve: (response: RpcExtensionUIResponse) => {
723
- cleanup();
724
- resolve(parseResponse(response));
725
- },
726
- reject,
727
- });
728
- this.output({ type: "extension_ui_request", id, ...request } as RpcExtensionUIRequest);
729
- return promise;
730
- }
731
-
732
739
  select(
733
740
  title: string,
734
741
  options: ExtensionUISelectItem[],
735
742
  dialogOptions?: ExtensionUIDialogOptions,
736
743
  ): Promise<string | undefined> {
737
- return this.#createDialogPromise(
744
+ return requestRpcDialog(
745
+ this.pendingRequests,
746
+ this.output,
738
747
  dialogOptions,
739
748
  undefined,
740
749
  {
@@ -748,7 +757,9 @@ export async function runRpcMode(
748
757
  }
749
758
 
750
759
  confirm(title: string, message: string, dialogOptions?: ExtensionUIDialogOptions): Promise<boolean> {
751
- return this.#createDialogPromise(
760
+ return requestRpcDialog(
761
+ this.pendingRequests,
762
+ this.output,
752
763
  dialogOptions,
753
764
  false,
754
765
  { method: "confirm", title, message, timeout: dialogOptions?.timeout },
@@ -768,7 +779,9 @@ export async function runRpcMode(
768
779
  placeholder?: string,
769
780
  dialogOptions?: ExtensionUIDialogOptions,
770
781
  ): Promise<string | undefined> {
771
- return this.#createDialogPromise(
782
+ return requestRpcDialog(
783
+ this.pendingRequests,
784
+ this.output,
772
785
  dialogOptions,
773
786
  undefined,
774
787
  { method: "input", title, placeholder, timeout: dialogOptions?.timeout },
@@ -1,9 +1,6 @@
1
- <user_interjection>
1
+ <system-notice>
2
2
  The user sent this message as an interjection while you were working. It takes
3
3
  priority and supersedes earlier instructions wherever they conflict — re-read it
4
4
  and make sure your current work reflects their intent.
5
-
6
- <message>
5
+ </system-notice>
7
6
  {{message}}
8
- </message>
9
- </user_interjection>
@@ -25,7 +25,8 @@ Agents marked BLOCKING run inline — results return in this call; non-blocking
25
25
  - `name`: A stable CamelCase identifier (≤32 chars), used to address the agent (IRC, job ids). Generated automatically if omitted.
26
26
  - `agent`: The agent type running this item (e.g. `scout`, `reviewer`). Omitting it gives you the general-purpose worker (`{{defaultAgent}}`) — NEVER pass that name explicitly. Only omit it after checking the agent list below and finding no specialist that fits.{{#if allowedAgentsText}} Current spawn policy allows: {{allowedAgentsText}}.{{/if}}
27
27
  - `task`: Complete, self-contained instructions. One-liners or missing acceptance criteria are PROHIBITED.
28
- - `effort`: Scale w/ complexity of this task: `"lo"`|`"med"`|`"hi"`
28
+ {{#if effortEnabled}} - `effort`: Scale w/ complexity of this task: `"lo"`|`"med"`|`"hi"`
29
+ {{/if}}
29
30
  - `outputSchema`: Invocation-specific JSON Schema. Overrides the selected agent and parent-session schemas.
30
31
  - `schemaMode`: `"permissive"` (default) accepts a retry-exhausted invalid result with a warning; `"strict"` fails it.
31
32
  {{#if isolationEnabled}}
@@ -39,7 +40,8 @@ Agents marked BLOCKING run inline — results return in this call; non-blocking
39
40
  - `name`: A stable CamelCase identifier (≤32 chars), used to address the agent (IRC, job ids). Generated automatically if omitted.
40
41
  - `agent`: The agent type to spawn (e.g. `scout`, `reviewer`). Omitting it gives you the general-purpose worker (`{{defaultAgent}}`) — NEVER pass that name explicitly. Only omit it after checking the agent list below and finding no specialist that fits.{{#if allowedAgentsText}} Current spawn policy allows: {{allowedAgentsText}}.{{/if}}
41
42
  - `task`: Complete, self-contained instructions. One-liners or missing acceptance criteria are PROHIBITED.
42
- - `effort`: Scale w/ complexity of this task: `"lo"`|`"med"`|`"hi"`
43
+ {{#if effortEnabled}}- `effort`: Scale w/ complexity of this task: `"lo"`|`"med"`|`"hi"`
44
+ {{/if}}
43
45
  - `outputSchema`: Invocation-specific JSON Schema. Overrides the selected agent and parent-session schemas.
44
46
  - `schemaMode`: `"permissive"` (default) accepts a retry-exhausted invalid result with a warning; `"strict"` fails it.
45
47
  {{#if isolationEnabled}}
package/src/sdk.ts CHANGED
@@ -12,6 +12,7 @@ import {
12
12
  import type {
13
13
  Context,
14
14
  CredentialDisabledEvent,
15
+ Effort,
15
16
  Message,
16
17
  Model,
17
18
  ModelUsageHealth,
@@ -98,6 +99,7 @@ import type { HindsightSessionState } from "./hindsight/state";
98
99
  import { LocalProtocolHandler, type LocalProtocolOptions } from "./internal-urls";
99
100
  import { LSP_STARTUP_EVENT_CHANNEL, type LspStartupEvent } from "./lsp/startup-events";
100
101
  import {
102
+ deduplicateMCPToolsByName,
101
103
  discoverAndLoadMCPTools,
102
104
  type MCPLoadResult,
103
105
  MCPManager,
@@ -188,13 +190,17 @@ import {
188
190
  HIDDEN_TOOLS,
189
191
  isMountableUnderXdev,
190
192
  type LspStartupServerInfo,
193
+ listXdevTools,
191
194
  ReadTool,
192
195
  releaseComputerSessionsForOwner,
196
+ resolveMountedXdevExecutable,
193
197
  type Tool,
194
198
  type ToolSession,
195
199
  WebSearchTool,
196
200
  WriteTool,
197
201
  warmupLspServers,
202
+ xdevDocsAll,
203
+ xdevEntries,
198
204
  } from "./tools";
199
205
  import { isMCPToolName, normalizeToolNames } from "./tools/builtin-names";
200
206
  import { ToolContextStore } from "./tools/context";
@@ -357,6 +363,8 @@ export interface CreateAgentSessionOptions {
357
363
  modelPatternDefaultFallbackChain?: string[];
358
364
  /** Thinking selector. Default: from settings, else unset */
359
365
  thinkingLevel?: ConfiguredThinkingLevel;
366
+ /** 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. */
367
+ thinkingLevelCeiling?: Effort;
360
368
  /** Models available for cycling (Ctrl+P in interactive mode) */
361
369
  scopedModels?: Array<{ model: Model; thinkingLevel?: ThinkingLevel }>;
362
370
  /** Prewalk from the starting model to a fast/cheap target at the first edit/write once the todo list exists. */
@@ -924,13 +932,14 @@ export function customToolToDefinition(tool: CustomTool): ToolDefinition {
924
932
  }
925
933
 
926
934
  function createCustomToolsExtension(tools: CustomTool[]): ExtensionFactory {
935
+ const uniqueTools = deduplicateMCPToolsByName(tools);
927
936
  return api => {
928
- for (const tool of tools) {
937
+ for (const tool of uniqueTools) {
929
938
  api.registerTool(customToolToDefinition(tool));
930
939
  }
931
940
 
932
941
  const runOnSession = async (event: CustomToolSessionEvent, ctx: ExtensionContext) => {
933
- for (const tool of tools) {
942
+ for (const tool of uniqueTools) {
934
943
  if (!tool.onSession) continue;
935
944
  try {
936
945
  await tool.onSession(event, createCustomToolContext(ctx));
@@ -1615,6 +1624,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
1615
1624
  // mutation (any tool) bumped it in the meantime.
1616
1625
  const fileMutationVersions = new Map<string, number>();
1617
1626
  const activeToolNames = new Set<string>();
1627
+ const toolRegistry = new Map<string, Tool>();
1618
1628
  const setActiveToolNames = (names: Iterable<string>): void => {
1619
1629
  activeToolNames.clear();
1620
1630
  for (const name of names) {
@@ -1627,6 +1637,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
1627
1637
  },
1628
1638
  isToolActive: name => activeToolNames.has(name),
1629
1639
  setActiveToolNames,
1640
+ toolRegistry,
1630
1641
  hasUI: options.hasUI ?? false,
1631
1642
  get additionalDirectories() {
1632
1643
  return sessionManager.getAdditionalDirectories();
@@ -1677,6 +1688,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
1677
1688
  getModelString: () => (hasExplicitModel && model ? formatModelString(model) : undefined),
1678
1689
  getActiveModelString,
1679
1690
  getActiveModel: () => agent?.state.model ?? model,
1691
+ getInspectImageModeOverride: () => session?.getInspectImageModeOverride(),
1680
1692
  getServiceTierByFamily: () => session?.serviceTierByFamily,
1681
1693
  getImageAttachments: () => session?.getImageAttachments() ?? [],
1682
1694
  getPlanModeState: () => session?.getPlanModeState(),
@@ -1771,7 +1783,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
1771
1783
  );
1772
1784
 
1773
1785
  // Create built-in tools (already wrapped with meta notice formatting)
1774
- const builtinTools = await logger.time("createAllTools", createTools, toolSession, options.toolNames);
1786
+ await logger.time("createAllTools", createTools, toolSession, options.toolNames);
1775
1787
 
1776
1788
  // Restricted sessions cannot inherit or discover MCP capabilities.
1777
1789
  const enableMCP = !restrictToolNames && (options.enableMCP ?? true);
@@ -1863,7 +1875,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
1863
1875
  // to mirror the AsyncJobManager ownership rule.
1864
1876
  if (mcpManager && !options.parentTaskPrefix) MCPManager.setInstance(mcpManager);
1865
1877
 
1866
- const builtInToolNames = builtinTools.map(t => t.name);
1878
+ const builtInToolNames = [...toolRegistry.keys()];
1867
1879
  let customToolPaths: ToolPathWithSource[] = [];
1868
1880
  const inlineExtensions: ExtensionFactory[] = [];
1869
1881
  if (!restrictToolNames) {
@@ -1985,10 +1997,12 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
1985
1997
  // Process provider registrations queued during extension loading.
1986
1998
  // This must happen before the runner is created so that models registered by
1987
1999
  // extensions are available for model selection on session resume / fallback.
1988
- const activeExtensionSources = extensionsResult.extensions.map(extension => extension.path);
1989
- modelRegistry.syncExtensionSources(activeExtensionSources);
1990
- for (const sourceId of new Set(activeExtensionSources)) {
1991
- modelRegistry.clearSourceRegistrations(sourceId);
2000
+ if (!restrictToolNames) {
2001
+ const activeExtensionSources = extensionsResult.extensions.map(extension => extension.path);
2002
+ modelRegistry.syncExtensionSources(activeExtensionSources);
2003
+ for (const sourceId of new Set(activeExtensionSources)) {
2004
+ modelRegistry.clearSourceRegistrations(sourceId);
2005
+ }
1992
2006
  }
1993
2007
  if (extensionsResult.runtime.pendingProviderRegistrations.length > 0) {
1994
2008
  for (const { name, config, sourceId } of extensionsResult.runtime.pendingProviderRegistrations) {
@@ -2537,17 +2551,12 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
2537
2551
  // Built-in tools get it in `createTools`; extension, SDK-custom, image-gen,
2538
2552
  // TTS, and startup (non-deferred) MCP tools all funnel through here, so apply
2539
2553
  // it once at this adapter boundary (idempotent — a no-op if already wrapped).
2540
- const wrappedExtensionTools: Tool[] = wrapRegisteredTools(allCustomTools, extensionRunner).map(
2541
- wrapToolWithMetaNotice,
2554
+ const wrappedExtensionTools: Tool[] = deduplicateMCPToolsByName(
2555
+ wrapRegisteredTools(allCustomTools, extensionRunner).map(wrapToolWithMetaNotice),
2542
2556
  );
2543
2557
 
2544
2558
  // All built-in tools are active (conditional tools like git/ask return null from factory if disabled)
2545
- const builtInRegistryToolNames = new Set<string>();
2546
- const toolRegistry = new Map<string, Tool>();
2547
- for (const tool of builtinTools) {
2548
- toolRegistry.set(tool.name, tool);
2549
- builtInRegistryToolNames.add(tool.name);
2550
- }
2559
+ const builtInRegistryToolNames = toolSession.xdev?.builtInNames ?? new Set(toolRegistry.keys());
2551
2560
  if (!restrictToolNames && !toolRegistry.has("goal") && settings.get("goal.enabled")) {
2552
2561
  const goalTool = await logger.time("createTools:goal:session", HIDDEN_TOOLS.goal, toolSession);
2553
2562
  if (goalTool) {
@@ -2599,31 +2608,26 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
2599
2608
  // Existing staged/device paths need write registered before active-set assembly.
2600
2609
  // Deferred MCP also registers it now, but refresh activates it only after a server connects.
2601
2610
  const hasDeferrableTools = Array.from(toolRegistry.values()).some(tool => tool.deferrable === true);
2602
- const hasXdevTools = (toolSession.xdevRegistry?.size ?? 0) > 0;
2611
+ const hasXdevTools = (toolSession.xdev?.mountedNames.size ?? 0) > 0;
2603
2612
  const planModeAvailable = settings.get("plan.enabled");
2604
2613
  if (!restrictToolNames && (hasDeferrableTools || hasXdevTools || planModeAvailable || deferMCPDiscoveryForUI)) {
2605
2614
  await ensureWriteRegistered();
2606
2615
  }
2607
2616
 
2608
2617
  let cursorEventEmitter: ((event: AgentEvent) => void) | undefined;
2609
- // Built-in xd:// devices (ast_edit, debug, browser, lsp, web_search) are
2610
- // mounted in createTools BEFORE this loop wraps registry entries in
2611
- // ExtensionToolWrapper, so the registry holds them unwrapped. The normal
2612
- // `write xd://<tool>` path runs approval through the wrapped `write` tool's
2613
- // tier gate, but Cursor invokes advertised devices via `tool.execute()`
2614
- // directly, and the agent loop's fallback resolver executes mounted
2615
- // devices the model called by their top-level name — so wrap unwrapped
2616
- // devices here to keep the approval/deny/prompt gate. Dynamic mounts
2617
- // (custom/MCP) already come from the wrapped registry.
2618
+ // Cursor and the agent loop may call a mounted device by its top-level
2619
+ // name. Resolve that name from the canonical map and apply the same
2620
+ // execution-only ACP decorator used by `write xd://<tool>`; docs and
2621
+ // renderer lookup continue to use the undecorated canonical instance.
2618
2622
  const resolveDeviceTool = (name: string): AgentTool | undefined => {
2619
- const device = toolSession.xdevRegistry?.get(name);
2620
- if (!device) return undefined;
2621
- return device instanceof ExtensionToolWrapper ? device : new ExtensionToolWrapper(device, extensionRunner);
2623
+ const state = toolSession.xdev;
2624
+ if (!state) return undefined;
2625
+ return resolveMountedXdevExecutable(state, name);
2622
2626
  };
2623
2627
  const cursorExecHandlers = new CursorExecHandlers({
2624
2628
  cwd,
2625
2629
  tools: toolRegistry,
2626
- getTool: resolveDeviceTool,
2630
+ getExecutableTool: resolveDeviceTool,
2627
2631
  getToolContext: () => toolContextStore.getContext(),
2628
2632
  emitEvent: event => cursorEventEmitter?.(event),
2629
2633
  getTodoPhases: () => session.getTodoPhases(),
@@ -2673,7 +2677,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
2673
2677
  if (memoryInstructions) appendParts.push(memoryInstructions);
2674
2678
  if (autoLearnInstructions) appendParts.push(autoLearnInstructions);
2675
2679
  const projection = projectMountedMCPXdevGuidance(
2676
- collectMountedMCPToolRoutes(toolSession.xdevRegistry?.list() ?? []),
2680
+ collectMountedMCPToolRoutes(toolSession.xdev ? listXdevTools(toolSession.xdev) : []),
2677
2681
  );
2678
2682
  if (projection.mappings.length > 0 || projection.hasOmittedMappings) {
2679
2683
  appendParts.push(
@@ -2716,13 +2720,10 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
2716
2720
  const defaultPrompt = await buildSystemPromptInternal({
2717
2721
  cwd,
2718
2722
  additionalWorkspaceRoots: sessionManager.getAdditionalDirectories(),
2719
- xdevTools: toolSession.xdevRegistry?.entries() ?? [],
2720
- xdevDocs:
2721
- toolSession.xdevRegistry?.docsAll(
2722
- settings.get("tools.xdevDocs"),
2723
- settings.get("tools.xdevInlineDevices"),
2724
- ) ?? "",
2725
- autoQaEnabled: !restrictToolNames && isAutoQaEnabled(settings),
2723
+ xdevTools: toolSession.xdev ? xdevEntries(toolSession.xdev) : [],
2724
+ xdevDocs: toolSession.xdev
2725
+ ? xdevDocsAll(toolSession.xdev, settings.get("tools.xdevDocs"), settings.get("tools.xdevInlineDevices"))
2726
+ : "",
2726
2727
  resolvedCustomPrompt: options.customSystemPrompt,
2727
2728
  skills: session?.skills ?? skills,
2728
2729
  contextFiles,
@@ -2740,6 +2741,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
2740
2741
  taskBatch: settings.get("task.batch"),
2741
2742
  taskMaxConcurrency: settings.get("task.maxConcurrency"),
2742
2743
  taskIrcEnabled: !restrictToolNames && isIrcEnabled(settings, options.taskDepth ?? 0),
2744
+ autoQaEnabled: !restrictToolNames && isAutoQaEnabled(settings),
2743
2745
  secretsEnabled,
2744
2746
  workspaceTree: workspaceTreePromise,
2745
2747
  includeWorkspaceTree,
@@ -2846,31 +2848,24 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
2846
2848
  // constructed and attached. Startup failure therefore leaves it revivable.
2847
2849
  hasRegistered = options.expectedAgentRef === undefined || options.expectedAgentRef === null;
2848
2850
 
2849
- // Partition the initial enabled set for the xd:// transport: ambient
2850
- // discoverable tools become mounted devices, while explicitly requested
2851
- // tools keep their top-level presentation. The registry already holds the
2852
- // default-set built-in devices from createTools; this reconciles dynamic
2853
- // mounts (image-gen, TTS, startup MCP, active extension tools).
2854
- let initialMountedXdevToolNames: string[] = [];
2855
- if (toolSession.xdevRegistry) {
2851
+ // Partition the initial enabled set for the xd:// transport. Tool instances
2852
+ // remain in the canonical map; only presentation names move between layers.
2853
+ if (toolSession.xdev) {
2856
2854
  const topLevelToolNames: string[] = [];
2857
- const mountedTools: Tool[] = [];
2855
+ const mountedNames: string[] = [];
2858
2856
  for (const name of initialToolNames) {
2859
2857
  const tool = toolRegistry.get(name);
2860
2858
  const explicitlyRequested = explicitlyRequestedToolNameSet?.has(name) === true;
2861
2859
  if (tool && xdevReadAvailable && !explicitlyRequested && isMountableUnderXdev(tool))
2862
- mountedTools.push(tool);
2860
+ mountedNames.push(name);
2863
2861
  else topLevelToolNames.push(name);
2864
2862
  }
2865
- const writeTransportAvailable = mountedTools.length === 0 || (await ensureWriteRegistered());
2863
+ const writeTransportAvailable = mountedNames.length === 0 || (await ensureWriteRegistered());
2864
+ toolSession.xdev.mountedNames.clear();
2866
2865
  if (writeTransportAvailable) {
2867
- toolSession.xdevRegistry.reconcile(mountedTools);
2868
- initialMountedXdevToolNames = mountedTools.map(tool => tool.name);
2866
+ for (const name of mountedNames) toolSession.xdev.mountedNames.add(name);
2869
2867
  initialToolNames = topLevelToolNames;
2870
- if (initialMountedXdevToolNames.length > 0 && !initialToolNames.includes("write"))
2871
- initialToolNames.push("write");
2872
- } else {
2873
- toolSession.xdevRegistry.reconcile([]);
2868
+ if (mountedNames.length > 0 && !initialToolNames.includes("write")) initialToolNames.push("write");
2874
2869
  }
2875
2870
  }
2876
2871
 
@@ -3048,7 +3043,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
3048
3043
  return settingsAwareStreamFn(streamModel, context, streamOptions);
3049
3044
  },
3050
3045
  cursorExecHandlers,
3051
- getCursorTools: () => [...(toolSession.xdevRegistry?.list() ?? [])],
3046
+ getCursorTools: () => (toolSession.xdev ? listXdevTools(toolSession.xdev) : []),
3052
3047
  transformToolCallArguments,
3053
3048
  resolveFallbackTool: resolveDeviceTool,
3054
3049
  intentTracing: !!intentField,
@@ -3056,6 +3051,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
3056
3051
  dialect: resolveDialect(settings.get("tools.format"), model),
3057
3052
  abortOnFabricatedToolResult: settings.get("tools.abortOnFabricatedResult"),
3058
3053
  getToolChoice: () => session?.nextToolChoiceDirective(),
3054
+ onToolChoiceUnavailable: () => session?.toolChoiceQueue.reject("unavailable"),
3059
3055
  telemetry: options.telemetry,
3060
3056
  appendOnlyContext: model
3061
3057
  ? shouldEnableAppendOnlyContext(settings.get("provider.appendOnlyContext"), model)
@@ -3103,6 +3099,13 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
3103
3099
  return id ? `${id}-advisor` : null;
3104
3100
  },
3105
3101
  getAgentId: () => "advisor",
3102
+ // The primary's availability signals are wrong for advisors: their tool
3103
+ // slate is filtered separately at runtime (default read/grep/glob, no
3104
+ // write transport), so xd:// devices are unreachable and read must never
3105
+ // advertise inspect_image — images are inlined, and the provider
3106
+ // boundary handles text-only advisor models.
3107
+ xdev: undefined,
3108
+ isToolActive: name => name !== "inspect_image" && toolSession.isToolActive?.(name) === true,
3106
3109
  };
3107
3110
  const advisorToolBuilds: Array<Tool | null | Promise<Tool | null>> = [];
3108
3111
  for (const name in BUILTIN_TOOLS) {
@@ -3131,6 +3134,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
3131
3134
  agent,
3132
3135
  pruneToolDescriptions: inlineToolDescriptors,
3133
3136
  thinkingLevel: autoThinking ? AUTO_THINKING : effectiveThinkingLevel,
3137
+ thinkingLevelCeiling: options.thinkingLevelCeiling,
3134
3138
  initialRetryFallback,
3135
3139
  prewalk: options.prewalk,
3136
3140
  planYolo: options.planYolo,
@@ -3169,6 +3173,9 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
3169
3173
  createComputerTool: restrictToolNames
3170
3174
  ? undefined
3171
3175
  : async () => (await BUILTIN_TOOLS.computer(toolSession)) ?? null,
3176
+ createInspectImageTool: restrictToolNames
3177
+ ? undefined
3178
+ : async () => (await BUILTIN_TOOLS.inspect_image(toolSession)) ?? null,
3172
3179
  createVibeTools:
3173
3180
  (options.taskDepth ?? 0) === 0 && !options.parentTaskPrefix
3174
3181
  ? () => createVibeTools(toolSession)
@@ -3183,9 +3190,8 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
3183
3190
  preferWebsockets: preferOpenAICodexWebsockets,
3184
3191
  convertToLlm: convertToLlmFinal,
3185
3192
  rebuildSystemPrompt,
3186
- getXdevToolEntries: () => toolSession.xdevRegistry?.entries() ?? [],
3187
- xdevRegistry: toolSession.xdevRegistry,
3188
- initialMountedXdevToolNames,
3193
+ getXdevToolEntries: () => (toolSession.xdev ? xdevEntries(toolSession.xdev) : []),
3194
+ xdev: toolSession.xdev,
3189
3195
  presentationPinnedToolNames: explicitlyRequestedToolNameSet,
3190
3196
  setActiveToolNames,
3191
3197
  ensureWriteRegistered,
@@ -1,6 +1,7 @@
1
1
  import type { Agent, AgentMessage, AgentTool, StreamFn, ThinkingLevel } from "@oh-my-pi/pi-agent-core";
2
2
  import type {
3
3
  Context,
4
+ Effort,
4
5
  ImageContent,
5
6
  Message,
6
7
  MessageAttribution,
@@ -25,7 +26,7 @@ import type { Skill, SkillWarning } from "../extensibility/skills";
25
26
  import type { FileSlashCommand } from "../extensibility/slash-commands";
26
27
  import type { SecretObfuscator } from "../secrets/obfuscator";
27
28
  import type { ConfiguredThinkingLevel } from "../thinking";
28
- import type { XdevRegistry } from "../tools/xdev";
29
+ import type { XdevState } from "../tools/xdev";
29
30
  import type { SessionManager } from "./session-manager";
30
31
 
31
32
  /** Maximum time the interactive shutdown path waits for Mnemopi consolidation. */
@@ -105,6 +106,8 @@ export interface AgentSessionConfig {
105
106
  scopedModels?: Array<{ model: Model; thinkingLevel?: ThinkingLevel }>;
106
107
  /** Initial session thinking selector. */
107
108
  thinkingLevel?: ConfiguredThinkingLevel;
109
+ /** 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. */
110
+ thinkingLevelCeiling?: Effort;
108
111
  /** Retry chain ownership when startup selected one of its fallback entries. */
109
112
  initialRetryFallback?: InitialRetryFallbackState;
110
113
  /** Prewalk from the starting model to a fast/cheap target after implementation begins. */
@@ -136,6 +139,8 @@ export interface AgentSessionConfig {
136
139
  createMemoryTools?: () => Promise<AgentTool[]>;
137
140
  /** Creates the built-in `computer` tool for session-scoped runtime enablement (see {@link AgentSession.setComputerToolEnabled}). */
138
141
  createComputerTool?: () => Promise<AgentTool | null>;
142
+ /** Creates the built-in `inspect_image` tool for session-scoped runtime enablement (see {@link AgentSession.setInspectImageMode}). */
143
+ createInspectImageTool?: () => Promise<AgentTool | null>;
139
144
  /** Model registry for API key resolution and model discovery. */
140
145
  modelRegistry: ModelRegistry;
141
146
  /** Tool registry for LSP and settings. */
@@ -174,10 +179,8 @@ export interface AgentSessionConfig {
174
179
  getLocalCalendarDate?: () => string;
175
180
  /** Tools mounted under `xd://`, for `/tools` display. */
176
181
  getXdevToolEntries?: () => Array<{ name: string; summary: string }>;
177
- /** Session-owned `xd://` registry. */
178
- xdevRegistry?: XdevRegistry;
179
- /** Discoverable tools mounted under `xd://` in the initial enabled set. */
180
- initialMountedXdevToolNames?: string[];
182
+ /** `xd://` presentation state backed by the canonical tool map. */
183
+ xdev?: XdevState;
181
184
  /** Names pinned top-level during runtime repartitioning. */
182
185
  presentationPinnedToolNames?: ReadonlySet<string>;
183
186
  /** Accessor for live MCP server instructions. */