@herbertgao/pi-extensions 2026.8.2 → 2026.8.3

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 (272) hide show
  1. package/README.md +9 -2
  2. package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +6 -8
  3. package/node_modules/@herbertgao/pi-cc-extensions/README.md +5 -7
  4. package/node_modules/@herbertgao/pi-cc-extensions/assets/readme/hero.en.svg +101 -0
  5. package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/config.ts +1 -17
  6. package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/panel.ts +5 -3
  7. package/node_modules/@herbertgao/pi-cc-extensions/extensions/{utils/agent-summary.ts → feature/agent-summary/core.ts} +37 -35
  8. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/{agent-summary.ts → agent-summary/index.ts} +2 -6
  9. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/{session-reference.ts → reference/index.ts} +1 -1
  10. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/{agent-autocomplete.ts → reference/subagent.ts} +19 -9
  11. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/{pi-startup-header.ts → shell/startup-header.ts} +1 -1
  12. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/{working-message.ts → shell/working-message.ts} +5 -2
  13. package/node_modules/@herbertgao/pi-cc-extensions/extensions/index.ts +32 -28
  14. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +379 -85
  15. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/default-mode.ts +727 -0
  16. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/index.ts +65 -775
  17. package/node_modules/@herbertgao/pi-cc-extensions/extensions/{feature → renderer}/markdown-enhance.ts +35 -31
  18. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{mouse-hover.ts → mouse/hover.ts} +5 -5
  19. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{mouse-interaction.ts → mouse/interaction.ts} +34 -35
  20. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{mouse-layout.ts → mouse/layout.ts} +5 -21
  21. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{mouse-packets.ts → mouse/packets.ts} +1 -1
  22. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{mouse-scroll.ts → mouse/scroll.ts} +48 -37
  23. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{tool-diff → tool/diff}/ansi-utils.ts +56 -1
  24. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{tool-diff → tool/diff}/diff-renderer.ts +2 -2
  25. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{tool-diff → tool/diff}/line-width-safety.ts +1 -1
  26. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/write-display-utils.ts +12 -0
  27. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{tool-diff → tool/diff}/write-execution.ts +1 -2
  28. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{tool-grouping.ts → tool/grouping.ts} +18 -8
  29. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{tool-result.ts → tool/result.ts} +4 -13
  30. package/node_modules/@herbertgao/pi-cc-extensions/extensions/utils/fullscreen-detect.ts +0 -27
  31. package/node_modules/@herbertgao/pi-cc-extensions/package.json +3 -3
  32. package/node_modules/@herbertgao/pi-subagents/CHANGELOG.md +6 -0
  33. package/node_modules/@herbertgao/pi-subagents/package.json +2 -2
  34. package/node_modules/@herbertgao/pi-subagents/src/agent-manager.ts +1 -0
  35. package/node_modules/@herbertgao/pi-subagents/src/agent-runner.ts +3 -1
  36. package/node_modules/@herbertgao/pi-subagents/src/index.ts +33 -35
  37. package/node_modules/@herbertgao/pi-subagents/src/nested-tools.ts +26 -35
  38. package/node_modules/@herbertgao/pi-subagents/src/prompts.ts +15 -1
  39. package/node_modules/pi-mcp-adapter/CHANGELOG.md +19 -0
  40. package/node_modules/pi-mcp-adapter/README.md +19 -4
  41. package/node_modules/pi-mcp-adapter/agent-dir.ts +40 -0
  42. package/node_modules/pi-mcp-adapter/commands.ts +12 -2
  43. package/node_modules/pi-mcp-adapter/direct-tools.ts +6 -8
  44. package/node_modules/pi-mcp-adapter/index.ts +15 -3
  45. package/node_modules/pi-mcp-adapter/mcp-auth-flow.ts +87 -4
  46. package/node_modules/pi-mcp-adapter/mcp-callback-server.ts +138 -61
  47. package/node_modules/pi-mcp-adapter/mcp-oauth-provider.ts +43 -4
  48. package/node_modules/pi-mcp-adapter/oauth.ts +48 -0
  49. package/node_modules/pi-mcp-adapter/package.json +8 -2
  50. package/node_modules/pi-mcp-adapter/proxy-modes.ts +8 -10
  51. package/node_modules/pi-mcp-adapter/tool-registrar.ts +187 -3
  52. package/node_modules/pi-mcp-adapter/types.ts +2 -0
  53. package/node_modules/pi-web-access/CHANGELOG.md +45 -0
  54. package/node_modules/pi-web-access/README.md +104 -29
  55. package/node_modules/pi-web-access/bocha.ts +221 -0
  56. package/node_modules/pi-web-access/curator-page.ts +113 -12
  57. package/node_modules/pi-web-access/curator-server.ts +56 -20
  58. package/node_modules/pi-web-access/datalab-pdf-extract.ts +568 -0
  59. package/node_modules/pi-web-access/duckduckgo.ts +123 -0
  60. package/node_modules/pi-web-access/extract.ts +288 -143
  61. package/node_modules/pi-web-access/feature-config.ts +29 -0
  62. package/node_modules/pi-web-access/gemini-api.ts +4 -0
  63. package/node_modules/pi-web-access/gemini-search.ts +45 -12
  64. package/node_modules/pi-web-access/gemini-web.ts +68 -3
  65. package/node_modules/pi-web-access/index.ts +160 -71
  66. package/node_modules/pi-web-access/jina-search.ts +284 -0
  67. package/node_modules/pi-web-access/kagi.ts +12 -12
  68. package/node_modules/pi-web-access/openai-search.ts +12 -2
  69. package/node_modules/pi-web-access/package.json +4 -3
  70. package/node_modules/pi-web-access/pdf-extract.ts +327 -228
  71. package/node_modules/pi-web-access/storage.ts +440 -2
  72. package/node_modules/pi-web-access/summary-model-scope.ts +1 -1
  73. package/node_modules/pi-web-access/summary-review.ts +4 -2
  74. package/node_modules/pi-web-access/video-extract.ts +10 -8
  75. package/node_modules/pi-web-access/xai-search.ts +12 -2
  76. package/node_modules/pi-web-access/youtube-extract.ts +2 -1
  77. package/node_modules/remote-pi/LICENSE +21 -0
  78. package/node_modules/remote-pi/README.md +675 -0
  79. package/node_modules/remote-pi/dist/actions/handlers.d.ts +122 -0
  80. package/node_modules/remote-pi/dist/actions/handlers.js +160 -0
  81. package/node_modules/remote-pi/dist/actions/handlers.js.map +1 -0
  82. package/node_modules/remote-pi/dist/actions/registry.d.ts +39 -0
  83. package/node_modules/remote-pi/dist/actions/registry.js +58 -0
  84. package/node_modules/remote-pi/dist/actions/registry.js.map +1 -0
  85. package/node_modules/remote-pi/dist/bin/supervisord.d.ts +2 -0
  86. package/node_modules/remote-pi/dist/bin/supervisord.js +86 -0
  87. package/node_modules/remote-pi/dist/bin/supervisord.js.map +1 -0
  88. package/node_modules/remote-pi/dist/commands/builtin_mirror.d.ts +58 -0
  89. package/node_modules/remote-pi/dist/commands/builtin_mirror.js +71 -0
  90. package/node_modules/remote-pi/dist/commands/builtin_mirror.js.map +1 -0
  91. package/node_modules/remote-pi/dist/commands/list_commands.d.ts +60 -0
  92. package/node_modules/remote-pi/dist/commands/list_commands.js +73 -0
  93. package/node_modules/remote-pi/dist/commands/list_commands.js.map +1 -0
  94. package/node_modules/remote-pi/dist/config.d.ts +62 -0
  95. package/node_modules/remote-pi/dist/config.js +115 -0
  96. package/node_modules/remote-pi/dist/config.js.map +1 -0
  97. package/node_modules/remote-pi/dist/daemon/client.d.ts +20 -0
  98. package/node_modules/remote-pi/dist/daemon/client.js +131 -0
  99. package/node_modules/remote-pi/dist/daemon/client.js.map +1 -0
  100. package/node_modules/remote-pi/dist/daemon/control_protocol.d.ts +176 -0
  101. package/node_modules/remote-pi/dist/daemon/control_protocol.js +63 -0
  102. package/node_modules/remote-pi/dist/daemon/control_protocol.js.map +1 -0
  103. package/node_modules/remote-pi/dist/daemon/cron_log.d.ts +45 -0
  104. package/node_modules/remote-pi/dist/daemon/cron_log.js +72 -0
  105. package/node_modules/remote-pi/dist/daemon/cron_log.js.map +1 -0
  106. package/node_modules/remote-pi/dist/daemon/cron_registry.d.ts +80 -0
  107. package/node_modules/remote-pi/dist/daemon/cron_registry.js +194 -0
  108. package/node_modules/remote-pi/dist/daemon/cron_registry.js.map +1 -0
  109. package/node_modules/remote-pi/dist/daemon/id.d.ts +24 -0
  110. package/node_modules/remote-pi/dist/daemon/id.js +36 -0
  111. package/node_modules/remote-pi/dist/daemon/id.js.map +1 -0
  112. package/node_modules/remote-pi/dist/daemon/install.d.ts +170 -0
  113. package/node_modules/remote-pi/dist/daemon/install.js +547 -0
  114. package/node_modules/remote-pi/dist/daemon/install.js.map +1 -0
  115. package/node_modules/remote-pi/dist/daemon/registry.d.ts +63 -0
  116. package/node_modules/remote-pi/dist/daemon/registry.js +153 -0
  117. package/node_modules/remote-pi/dist/daemon/registry.js.map +1 -0
  118. package/node_modules/remote-pi/dist/daemon/rpc_child.d.ts +194 -0
  119. package/node_modules/remote-pi/dist/daemon/rpc_child.js +389 -0
  120. package/node_modules/remote-pi/dist/daemon/rpc_child.js.map +1 -0
  121. package/node_modules/remote-pi/dist/daemon/supervisor.d.ts +93 -0
  122. package/node_modules/remote-pi/dist/daemon/supervisor.js +596 -0
  123. package/node_modules/remote-pi/dist/daemon/supervisor.js.map +1 -0
  124. package/node_modules/remote-pi/dist/extension_ui_bridge.d.ts +26 -0
  125. package/node_modules/remote-pi/dist/extension_ui_bridge.js +341 -0
  126. package/node_modules/remote-pi/dist/extension_ui_bridge.js.map +1 -0
  127. package/node_modules/remote-pi/dist/index.d.ts +213 -0
  128. package/node_modules/remote-pi/dist/index.js +4996 -0
  129. package/node_modules/remote-pi/dist/index.js.map +1 -0
  130. package/node_modules/remote-pi/dist/mcp/mesh_result.d.ts +10 -0
  131. package/node_modules/remote-pi/dist/mcp/mesh_result.js +42 -0
  132. package/node_modules/remote-pi/dist/mcp/mesh_result.js.map +1 -0
  133. package/node_modules/remote-pi/dist/mcp/mesh_server.d.ts +16 -0
  134. package/node_modules/remote-pi/dist/mcp/mesh_server.js +327 -0
  135. package/node_modules/remote-pi/dist/mcp/mesh_server.js.map +1 -0
  136. package/node_modules/remote-pi/dist/mesh/canonical.d.ts +30 -0
  137. package/node_modules/remote-pi/dist/mesh/canonical.js +61 -0
  138. package/node_modules/remote-pi/dist/mesh/canonical.js.map +1 -0
  139. package/node_modules/remote-pi/dist/mesh/client.d.ts +18 -0
  140. package/node_modules/remote-pi/dist/mesh/client.js +125 -0
  141. package/node_modules/remote-pi/dist/mesh/client.js.map +1 -0
  142. package/node_modules/remote-pi/dist/mesh/encoding.d.ts +38 -0
  143. package/node_modules/remote-pi/dist/mesh/encoding.js +216 -0
  144. package/node_modules/remote-pi/dist/mesh/encoding.js.map +1 -0
  145. package/node_modules/remote-pi/dist/mesh/self_revoke.d.ts +73 -0
  146. package/node_modules/remote-pi/dist/mesh/self_revoke.js +401 -0
  147. package/node_modules/remote-pi/dist/mesh/self_revoke.js.map +1 -0
  148. package/node_modules/remote-pi/dist/mesh/siblings.d.ts +49 -0
  149. package/node_modules/remote-pi/dist/mesh/siblings.js +159 -0
  150. package/node_modules/remote-pi/dist/mesh/siblings.js.map +1 -0
  151. package/node_modules/remote-pi/dist/mesh/types.d.ts +34 -0
  152. package/node_modules/remote-pi/dist/mesh/types.js +11 -0
  153. package/node_modules/remote-pi/dist/mesh/types.js.map +1 -0
  154. package/node_modules/remote-pi/dist/mesh/verify.d.ts +17 -0
  155. package/node_modules/remote-pi/dist/mesh/verify.js +86 -0
  156. package/node_modules/remote-pi/dist/mesh/verify.js.map +1 -0
  157. package/node_modules/remote-pi/dist/pairing/crypto.d.ts +8 -0
  158. package/node_modules/remote-pi/dist/pairing/crypto.js +22 -0
  159. package/node_modules/remote-pi/dist/pairing/crypto.js.map +1 -0
  160. package/node_modules/remote-pi/dist/pairing/handshake.d.ts +28 -0
  161. package/node_modules/remote-pi/dist/pairing/handshake.js +113 -0
  162. package/node_modules/remote-pi/dist/pairing/handshake.js.map +1 -0
  163. package/node_modules/remote-pi/dist/pairing/noise-sha256.d.ts +16 -0
  164. package/node_modules/remote-pi/dist/pairing/noise-sha256.js +103 -0
  165. package/node_modules/remote-pi/dist/pairing/noise-sha256.js.map +1 -0
  166. package/node_modules/remote-pi/dist/pairing/qr.d.ts +59 -0
  167. package/node_modules/remote-pi/dist/pairing/qr.js +125 -0
  168. package/node_modules/remote-pi/dist/pairing/qr.js.map +1 -0
  169. package/node_modules/remote-pi/dist/pairing/storage.d.ts +120 -0
  170. package/node_modules/remote-pi/dist/pairing/storage.js +604 -0
  171. package/node_modules/remote-pi/dist/pairing/storage.js.map +1 -0
  172. package/node_modules/remote-pi/dist/protocol/codec.d.ts +7 -0
  173. package/node_modules/remote-pi/dist/protocol/codec.js +49 -0
  174. package/node_modules/remote-pi/dist/protocol/codec.js.map +1 -0
  175. package/node_modules/remote-pi/dist/protocol/types.d.ts +393 -0
  176. package/node_modules/remote-pi/dist/protocol/types.js +2 -0
  177. package/node_modules/remote-pi/dist/protocol/types.js.map +1 -0
  178. package/node_modules/remote-pi/dist/rooms.d.ts +29 -0
  179. package/node_modules/remote-pi/dist/rooms.js +57 -0
  180. package/node_modules/remote-pi/dist/rooms.js.map +1 -0
  181. package/node_modules/remote-pi/dist/session/address.d.ts +49 -0
  182. package/node_modules/remote-pi/dist/session/address.js +58 -0
  183. package/node_modules/remote-pi/dist/session/address.js.map +1 -0
  184. package/node_modules/remote-pi/dist/session/agent_bridge.d.ts +55 -0
  185. package/node_modules/remote-pi/dist/session/agent_bridge.js +146 -0
  186. package/node_modules/remote-pi/dist/session/agent_bridge.js.map +1 -0
  187. package/node_modules/remote-pi/dist/session/bridge.d.ts +37 -0
  188. package/node_modules/remote-pi/dist/session/bridge.js +130 -0
  189. package/node_modules/remote-pi/dist/session/bridge.js.map +1 -0
  190. package/node_modules/remote-pi/dist/session/broker.d.ts +189 -0
  191. package/node_modules/remote-pi/dist/session/broker.js +507 -0
  192. package/node_modules/remote-pi/dist/session/broker.js.map +1 -0
  193. package/node_modules/remote-pi/dist/session/broker_remote.d.ts +74 -0
  194. package/node_modules/remote-pi/dist/session/broker_remote.js +583 -0
  195. package/node_modules/remote-pi/dist/session/broker_remote.js.map +1 -0
  196. package/node_modules/remote-pi/dist/session/cwd_lock.d.ts +33 -0
  197. package/node_modules/remote-pi/dist/session/cwd_lock.js +126 -0
  198. package/node_modules/remote-pi/dist/session/cwd_lock.js.map +1 -0
  199. package/node_modules/remote-pi/dist/session/envelope.d.ts +33 -0
  200. package/node_modules/remote-pi/dist/session/envelope.js +117 -0
  201. package/node_modules/remote-pi/dist/session/envelope.js.map +1 -0
  202. package/node_modules/remote-pi/dist/session/global_config.d.ts +33 -0
  203. package/node_modules/remote-pi/dist/session/global_config.js +73 -0
  204. package/node_modules/remote-pi/dist/session/global_config.js.map +1 -0
  205. package/node_modules/remote-pi/dist/session/ipc.d.ts +27 -0
  206. package/node_modules/remote-pi/dist/session/ipc.js +22 -0
  207. package/node_modules/remote-pi/dist/session/ipc.js.map +1 -0
  208. package/node_modules/remote-pi/dist/session/leader_election.d.ts +32 -0
  209. package/node_modules/remote-pi/dist/session/leader_election.js +106 -0
  210. package/node_modules/remote-pi/dist/session/leader_election.js.map +1 -0
  211. package/node_modules/remote-pi/dist/session/local_config.d.ts +55 -0
  212. package/node_modules/remote-pi/dist/session/local_config.js +157 -0
  213. package/node_modules/remote-pi/dist/session/local_config.js.map +1 -0
  214. package/node_modules/remote-pi/dist/session/mesh_message.d.ts +20 -0
  215. package/node_modules/remote-pi/dist/session/mesh_message.js +28 -0
  216. package/node_modules/remote-pi/dist/session/mesh_message.js.map +1 -0
  217. package/node_modules/remote-pi/dist/session/mesh_node.d.ts +116 -0
  218. package/node_modules/remote-pi/dist/session/mesh_node.js +573 -0
  219. package/node_modules/remote-pi/dist/session/mesh_node.js.map +1 -0
  220. package/node_modules/remote-pi/dist/session/peer.d.ts +139 -0
  221. package/node_modules/remote-pi/dist/session/peer.js +451 -0
  222. package/node_modules/remote-pi/dist/session/peer.js.map +1 -0
  223. package/node_modules/remote-pi/dist/session/peer_inventory.d.ts +13 -0
  224. package/node_modules/remote-pi/dist/session/peer_inventory.js +48 -0
  225. package/node_modules/remote-pi/dist/session/peer_inventory.js.map +1 -0
  226. package/node_modules/remote-pi/dist/session/peer_limits.d.ts +9 -0
  227. package/node_modules/remote-pi/dist/session/peer_limits.js +21 -0
  228. package/node_modules/remote-pi/dist/session/peer_limits.js.map +1 -0
  229. package/node_modules/remote-pi/dist/session/setup_wizard.d.ts +39 -0
  230. package/node_modules/remote-pi/dist/session/setup_wizard.js +63 -0
  231. package/node_modules/remote-pi/dist/session/setup_wizard.js.map +1 -0
  232. package/node_modules/remote-pi/dist/session/tool_gate.d.ts +5 -0
  233. package/node_modules/remote-pi/dist/session/tool_gate.js +11 -0
  234. package/node_modules/remote-pi/dist/session/tool_gate.js.map +1 -0
  235. package/node_modules/remote-pi/dist/session/tools.d.ts +24 -0
  236. package/node_modules/remote-pi/dist/session/tools.js +252 -0
  237. package/node_modules/remote-pi/dist/session/tools.js.map +1 -0
  238. package/node_modules/remote-pi/dist/session/wizard.d.ts +13 -0
  239. package/node_modules/remote-pi/dist/session/wizard.js +20 -0
  240. package/node_modules/remote-pi/dist/session/wizard.js.map +1 -0
  241. package/node_modules/remote-pi/dist/settings.d.ts +15 -0
  242. package/node_modules/remote-pi/dist/settings.js +52 -0
  243. package/node_modules/remote-pi/dist/settings.js.map +1 -0
  244. package/node_modules/remote-pi/dist/transport/peer_channel.d.ts +37 -0
  245. package/node_modules/remote-pi/dist/transport/peer_channel.js +98 -0
  246. package/node_modules/remote-pi/dist/transport/peer_channel.js.map +1 -0
  247. package/node_modules/remote-pi/dist/transport/pi_forward_client.d.ts +29 -0
  248. package/node_modules/remote-pi/dist/transport/pi_forward_client.js +62 -0
  249. package/node_modules/remote-pi/dist/transport/pi_forward_client.js.map +1 -0
  250. package/node_modules/remote-pi/dist/transport/relay_client.d.ts +91 -0
  251. package/node_modules/remote-pi/dist/transport/relay_client.js +206 -0
  252. package/node_modules/remote-pi/dist/transport/relay_client.js.map +1 -0
  253. package/node_modules/remote-pi/dist/ui/footer.d.ts +32 -0
  254. package/node_modules/remote-pi/dist/ui/footer.js +34 -0
  255. package/node_modules/remote-pi/dist/ui/footer.js.map +1 -0
  256. package/node_modules/remote-pi/docs/daemon.md +289 -0
  257. package/node_modules/remote-pi/package.json +88 -0
  258. package/node_modules/remote-pi/service-templates/launchd.plist.template +35 -0
  259. package/node_modules/remote-pi/service-templates/systemd.service.template +19 -0
  260. package/node_modules/remote-pi/service-templates/task-launcher.vbs.template +10 -0
  261. package/node_modules/remote-pi/service-templates/task-scheduler.xml.template +38 -0
  262. package/node_modules/remote-pi/skills/agent-network/SKILL.md +310 -0
  263. package/package.json +19 -9
  264. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool-diff/write-display-utils.ts +0 -29
  265. /package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/{session-reference-core.ts → reference/session.ts} +0 -0
  266. /package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/{pi-aliases.ts → shell/aliases.ts} +0 -0
  267. /package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{tool-diff → tool/diff}/ATTRIBUTION.md +0 -0
  268. /package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{tool-diff → tool/diff}/diff-presentation.ts +0 -0
  269. /package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{tool-diff → tool/diff}/index.ts +0 -0
  270. /package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{tool-diff → tool/diff}/render-utils.ts +0 -0
  271. /package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{tool-diff → tool/diff}/shiki-highlight.ts +0 -0
  272. /package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{tool-diff → tool/diff}/types.ts +0 -0
@@ -0,0 +1,727 @@
1
+ /**
2
+ * default mode(config.mode === "on"):Claude Code 风格工具卡渲染。
3
+ *
4
+ * 经 ToolExecutionComponent 原型补丁接管 call/result;edit/write 走 rich diff。
5
+ * 生命周期对齐 compact-mode:installDefaultMode → hooks.shutdown。
6
+ */
7
+ import { ToolExecutionComponent } from "@earendil-works/pi-coding-agent";
8
+ import { Text, truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
9
+ import { config, getToolDisplayConfig, type CompactStyleMode } from "../config/config.ts";
10
+ import { isToolCallHovered } from "./mouse/interaction.ts";
11
+ import {
12
+ countLines,
13
+ hasExpandableDetail,
14
+ headTruncateToWidth,
15
+ insetComponent,
16
+ isToolExpanded,
17
+ oneLine,
18
+ outputLineCount,
19
+ pendingIcon,
20
+ renderCollapsedToolResultToWidth,
21
+ renderExpandedToolResult,
22
+ resolveToolVisualState,
23
+ scheduleAnimation,
24
+ settledIcon,
25
+ setToolVisualState,
26
+ textFromResult,
27
+ toolIconColor,
28
+ toolViewportWidth,
29
+ } from "./tool/result.ts";
30
+ import { showMoreHintText } from "./show-more-hint.ts";
31
+ import { renderRichToolResult, type WriteExecutionMetadataStore } from "./tool/diff/index.ts";
32
+ import { getMessageDisplayTheme } from "./message-display.ts";
33
+
34
+ // 成功勾:亮绿 truecolor(与 message-display 一致)
35
+ const BRIGHT_GREEN = "\x1b[38;2;80;220;100m";
36
+ const ANSI_FG_RESET = "\x1b[39m";
37
+
38
+ const GLOBAL_TOOL_RENDER_PATCH = Symbol.for("pi.ccstyle.global-tool-render-patch");
39
+ const COMPONENT_TOOL_RENDER_MODE = Symbol.for("pi.ccstyle.component-tool-render-mode");
40
+ const COMPONENT_TOOL_SELF_SHELL_MODE = Symbol.for("pi.ccstyle.component-tool-self-shell-mode");
41
+ const TOOL_EXPANDED_BACKGROUND_PATCH = Symbol.for("pi.ccstyle.tool-expanded-background-patch");
42
+
43
+ const AGENT_FAMILY_TOOL_NAMES = new Set([
44
+ "Agent",
45
+ "Agents",
46
+ "get_subagent_result",
47
+ "steer_subagent",
48
+ ]);
49
+ // pi-subagents 等扩展为 Agent 提供专用渲染器,ccstyle 必须保留。
50
+ const DEDICATED_RENDERER_TOOLS = new Set(["Agent"]);
51
+
52
+ export type DefaultModeHooks = {
53
+ /** 本安装是否仍持有全局工具渲染补丁。 */
54
+ isOwner(): boolean;
55
+ shutdown(): void;
56
+ };
57
+
58
+ type ToolRenderMethods = {
59
+ hasRendererDefinition: (...args: any[]) => boolean;
60
+ getRenderShell: (...args: any[]) => "default" | "self";
61
+ getCallRenderer: (...args: any[]) => any;
62
+ getResultRenderer: (...args: any[]) => any;
63
+ };
64
+
65
+ type GlobalToolRenderPatch = {
66
+ version: 2;
67
+ prototype: any;
68
+ owner: object;
69
+ active: boolean;
70
+ enabled: () => boolean;
71
+ mode: () => CompactStyleMode;
72
+ wrap: (tool: any) => any;
73
+ byDefinition: WeakMap<object, any>;
74
+ byName: Map<string, any>;
75
+ downstream: ToolRenderMethods;
76
+ installed: ToolRenderMethods;
77
+ // 兼容旧扩展读取 Symbol 上的 legacy 字段。
78
+ originalHasRendererDefinition: ToolRenderMethods["hasRendererDefinition"];
79
+ originalGetRenderShell: ToolRenderMethods["getRenderShell"];
80
+ originalGetCallRenderer: ToolRenderMethods["getCallRenderer"];
81
+ originalGetResultRenderer: ToolRenderMethods["getResultRenderer"];
82
+ };
83
+
84
+ type ToolExpandedBackgroundPatch = {
85
+ active: boolean;
86
+ prototype: any;
87
+ installed: (...args: any[]) => void;
88
+ original: (...args: any[]) => void;
89
+ dispose: () => void;
90
+ };
91
+
92
+ export function shouldRenderRichDiff(
93
+ mode: CompactStyleMode,
94
+ toolName: string,
95
+ isError: boolean,
96
+ ): boolean {
97
+ return mode === "on" && !isError && (toolName === "edit" || toolName === "write");
98
+ }
99
+
100
+ export function isMcpToolDefinition(definition: any, toolName: string): boolean {
101
+ const label = typeof definition?.label === "string" ? definition.label.trim() : "";
102
+ if (/^MCP(?::|$)/i.test(label)) return true;
103
+ if (toolName === "mcp" || /^mcp[_:-]|[_:-]mcp[_:-]/i.test(toolName)) return true;
104
+ if (label) return false;
105
+ const description = typeof definition?.description === "string" ? definition.description : "";
106
+ return /\bModel Context Protocol\b/i.test(description);
107
+ }
108
+
109
+ export function humanizeMcpToolName(toolName: string): string {
110
+ const words = toolName
111
+ .replace(/^mcp(?:[_:-]+)+/i, "")
112
+ .split(/[_:-]+/)
113
+ .filter(Boolean);
114
+ return words.length
115
+ ? words.map((word) => word[0]!.toUpperCase() + word.slice(1)).join(" ")
116
+ : "MCP";
117
+ }
118
+
119
+ /** 排除名单内且自带 renderer 的工具保留原渲染。 */
120
+ export function preservesOriginalRenderer(
121
+ extensionDefinition: any,
122
+ toolName: string,
123
+ builtInToolDefinition?: any,
124
+ excludeRenderers: readonly string[] = config.excludeRenderers,
125
+ ): boolean {
126
+ if (!excludeRenderers.includes(toolName)) return false;
127
+ return [extensionDefinition, builtInToolDefinition].some(
128
+ (definition) =>
129
+ definition?.renderShell === "self" ||
130
+ typeof definition?.renderCall === "function" ||
131
+ typeof definition?.renderResult === "function",
132
+ );
133
+ }
134
+
135
+ function renderDefault(tool: any, slot: "renderCall" | "renderResult", args: any[], fallback = "") {
136
+ try {
137
+ if (typeof tool?.[slot] === "function") return tool[slot](...args);
138
+ } catch {
139
+ // Fall through to raw fallback.
140
+ }
141
+ return new Text(fallback, 0, 0);
142
+ }
143
+
144
+ function humanizeToolLabel(label: string): string {
145
+ return label
146
+ .replace(/([a-z0-9])([A-Z])/g, "$1 $2")
147
+ .replace(/[_-]+/g, " ")
148
+ .replace(/\b\w/g, (char) => char.toUpperCase());
149
+ }
150
+
151
+ function singleToolCallSummary(
152
+ toolName: string,
153
+ label: string,
154
+ args: any,
155
+ ): { main: string; detail: string } {
156
+ const title = label === toolName ? humanizeToolLabel(label) : label;
157
+ if (!args || typeof args !== "object") return { main: title, detail: "" };
158
+ const name = toolName.toLowerCase();
159
+ const value = (fallback: string, ...keys: string[]) => {
160
+ const found = keys.map((key) => args[key]).find((item) => typeof item === "string" && item);
161
+ // 与多 tool 摘要对齐:从头截断,上限 96 字符(tool-grouping oneLine 默认值)。
162
+ return `${title} ${oneLine(found || fallback, 96)}`;
163
+ };
164
+ if (AGENT_FAMILY_TOOL_NAMES.has(toolName) && args.agent_id) {
165
+ return { main: `${title} ${oneLine(args.agent_id, 96)}`, detail: "" };
166
+ }
167
+ // Agents 走 ccstyle wrapper;Agent 保留专用渲染器。
168
+ if (name === "agents") {
169
+ return {
170
+ main: value("launch agents", "description", "prompt"),
171
+ detail: "",
172
+ };
173
+ }
174
+ if (name === "skill") return { main: value("run skill", "name"), detail: "" };
175
+ if (name === "enterplanmode" || name === "enter_plan_mode") {
176
+ return { main: `${title} enable read-only planning`, detail: "" };
177
+ }
178
+ if (name === "exitplanmode" || name === "exit_plan_mode") {
179
+ return { main: `${title} present plan`, detail: "" };
180
+ }
181
+ if (name === "taskcreate") return { main: value("create task", "subject"), detail: "" };
182
+ if (name === "tasklist") return { main: `${title} task list`, detail: "" };
183
+ if (name === "taskget" || name === "taskupdate") {
184
+ return { main: value("task", "taskId", "task_id"), detail: "" };
185
+ }
186
+ if (name === "taskoutput" || name === "taskstop") {
187
+ return { main: value("background task", "task_id", "taskId"), detail: "" };
188
+ }
189
+ if (name === "taskexecute") {
190
+ const ids = Array.isArray(args.task_ids)
191
+ ? args.task_ids
192
+ : Array.isArray(args.taskIds)
193
+ ? args.taskIds
194
+ : [];
195
+ const summary = ids.length
196
+ ? `${ids[0]}${ids.length > 1 ? ` (+${ids.length - 1} tasks)` : ""}`
197
+ : "start tasks";
198
+ return { main: `${title} ${summary}`, detail: "" };
199
+ }
200
+ if (toolName === "read") {
201
+ const details = [
202
+ args.offset !== undefined ? `offset=${args.offset}` : "",
203
+ args.limit !== undefined ? `limit=${args.limit}` : "",
204
+ ].filter(Boolean);
205
+ return {
206
+ main: `${title}${args.path ? ` ${oneLine(args.path, 96)}` : ""}`,
207
+ detail: details.length ? ` (${details.join(", ")})` : "",
208
+ };
209
+ }
210
+ const preferred =
211
+ args.path ??
212
+ args.file_path ??
213
+ args.command ??
214
+ args.query ??
215
+ args.question ??
216
+ args.pattern ??
217
+ args.url ??
218
+ args.name ??
219
+ args.tool_use_id ??
220
+ args.toolCallId ??
221
+ args.id ??
222
+ args.message;
223
+ return {
224
+ main:
225
+ preferred !== undefined && preferred !== null && typeof preferred !== "object"
226
+ ? `${title} ${oneLine(preferred, 96)}`
227
+ : title,
228
+ detail: "",
229
+ };
230
+ }
231
+
232
+ type ParsedTask = { id: string; status: string; subject: string };
233
+
234
+ function parseTaskList(text: string): ParsedTask[] {
235
+ return text
236
+ .split("\n")
237
+ .map((line) => line.match(/^#(\d+) \[([^\]]+)] (.+)$/))
238
+ .filter((match): match is RegExpMatchArray => Boolean(match))
239
+ .map((match) => ({ id: match[1]!, status: match[2]!, subject: match[3]! }));
240
+ }
241
+
242
+ function taskListSummary(tasks: ParsedTask[]): string {
243
+ const counts = { pending: 0, in_progress: 0, completed: 0 };
244
+ for (const task of tasks) {
245
+ if (task.status in counts) counts[task.status as keyof typeof counts]++;
246
+ }
247
+ return [
248
+ `${tasks.length} tasks`,
249
+ counts.in_progress ? `${counts.in_progress} in progress` : "",
250
+ counts.pending ? `${counts.pending} pending` : "",
251
+ counts.completed ? `${counts.completed} completed` : "",
252
+ ]
253
+ .filter(Boolean)
254
+ .join(" • ");
255
+ }
256
+
257
+ function renderExpandedTaskResult(
258
+ toolName: string,
259
+ text: string,
260
+ theme: any,
261
+ isError: boolean,
262
+ ): any | undefined {
263
+ if (isError) return undefined;
264
+ if (toolName === "TaskList") {
265
+ const tasks = parseTaskList(text);
266
+ if (!tasks.length) return undefined;
267
+ const limit = Math.max(1, config.expandedPreviewMaxLines);
268
+ const rows = tasks.slice(0, limit).map((task) => {
269
+ const color =
270
+ task.status === "completed"
271
+ ? "success"
272
+ : task.status === "in_progress"
273
+ ? "warning"
274
+ : "muted";
275
+ return ` ${theme.fg("accent", `#${task.id}`)} ${theme.fg(color, task.status)} ${theme.fg("dim", task.subject)}`;
276
+ });
277
+ if (tasks.length > rows.length)
278
+ rows.push(theme.fg("muted", ` … ${tasks.length - rows.length} more tasks`));
279
+ return new Text(` ↳ ${theme.fg("muted", taskListSummary(tasks))}\n${rows.join("\n")}`, 0, 0);
280
+ }
281
+ const line = text.trim();
282
+ if (!line || line.includes("\n")) return undefined;
283
+ let formatted: string | undefined;
284
+ let match: RegExpMatchArray | null;
285
+ if (
286
+ toolName === "TaskCreate" &&
287
+ (match = line.match(/^Task #(\d+) created successfully: (.+)$/))
288
+ ) {
289
+ formatted = `${theme.fg("success", "Created task")} ${theme.fg("accent", `#${match[1]}`)} ${theme.fg("muted", match[2])}`;
290
+ } else if (toolName === "TaskUpdate" && (match = line.match(/^Updated task #(\d+) (.+)$/))) {
291
+ formatted = `${theme.fg("success", "Updated task")} ${theme.fg("accent", `#${match[1]}`)} ${theme.fg("muted", match[2])}`;
292
+ } else if (toolName === "TaskExecute") {
293
+ formatted = `${theme.fg("success", "Started")} ${theme.fg("muted", line)}`;
294
+ } else if (toolName === "TaskStop") {
295
+ formatted = `${theme.fg("success", "Stopped")} ${theme.fg("muted", line)}`;
296
+ }
297
+ return formatted ? new Text(` ↳ ${formatted}`, 0, 0) : undefined;
298
+ }
299
+
300
+ /** 用 ccstyle call/result 包装任意工具定义。 */
301
+ function createCcstyleTool(
302
+ originalTool: any,
303
+ writeExecutionMetadata: WriteExecutionMetadataStore,
304
+ ): any {
305
+ const toolName = originalTool.name;
306
+ const label = isMcpToolDefinition(originalTool, toolName)
307
+ ? humanizeMcpToolName(toolName)
308
+ : originalTool.label || toolName;
309
+
310
+ return {
311
+ ...originalTool,
312
+ renderShell: "self",
313
+ renderCall(args: any, theme: any, context: any) {
314
+ if (config.mode !== "on") {
315
+ return renderDefault(originalTool, "renderCall", [args, theme, context], String(toolName));
316
+ }
317
+
318
+ const visualState = resolveToolVisualState(context);
319
+ const isPending =
320
+ visualState === "pending" ||
321
+ (!visualState && (context?.isPartial || context?.executionStarted));
322
+ if (isPending) scheduleAnimation(context);
323
+ const rawIcon = isPending ? pendingIcon(toolName) : settledIcon(toolName, visualState);
324
+ const icon =
325
+ visualState === "success"
326
+ ? `${BRIGHT_GREEN}${rawIcon}${ANSI_FG_RESET}`
327
+ : theme.fg(toolIconColor(context), rawIcon);
328
+ const summary = singleToolCallSummary(toolName, label, args);
329
+ let cachedWidth: number | undefined;
330
+ let cachedLine: string | undefined;
331
+ return {
332
+ render(width: number) {
333
+ if (cachedLine !== undefined && cachedWidth === width) return [cachedLine];
334
+ const viewportWidth = toolViewportWidth(width);
335
+ const callWidth = Math.max(0, viewportWidth - visibleWidth(icon) - 2);
336
+ const mainWidth = Math.max(0, callWidth - visibleWidth(summary.detail));
337
+ cachedWidth = width;
338
+ // 纯文本先截断再着色(省略号不带 ANSI);从头截断,与多 tool 一致
339
+ const line = ` ${icon} ${theme.fg("toolTitle", headTruncateToWidth(summary.main, mainWidth))}${theme.fg("dim", summary.detail)}`;
340
+ cachedLine = truncateToWidth(line, viewportWidth, "");
341
+ return [cachedLine];
342
+ },
343
+ invalidate() {},
344
+ };
345
+ },
346
+ renderResult(result: any, options: any, theme: any, context: any) {
347
+ if (config.mode !== "on") {
348
+ return renderDefault(
349
+ originalTool,
350
+ "renderResult",
351
+ [result, options, theme, context],
352
+ textFromResult(result),
353
+ );
354
+ }
355
+
356
+ if (options?.isPartial) {
357
+ return new Text(theme.fg("muted", " ↳ Pending…"), 0, 0);
358
+ }
359
+
360
+ const isError = options?.isError || context?.isError;
361
+ setToolVisualState(context, isError ? "error" : "success");
362
+ const expanded = isToolExpanded(options, context);
363
+ const toolCallId = context?.toolCallId;
364
+ if (shouldRenderRichDiff(config.mode, toolName, Boolean(isError))) {
365
+ // getter 保证 Diff indicator / wrap / limits 下次绘制即更新
366
+ const richResult = renderRichToolResult(
367
+ toolName,
368
+ result,
369
+ {
370
+ ...options,
371
+ expanded,
372
+ // 全局共享状态避免 /reload 后旧 result renderer 闭包失联
373
+ isHovered: () => isToolCallHovered(toolCallId),
374
+ },
375
+ theme,
376
+ context,
377
+ writeExecutionMetadata,
378
+ getToolDisplayConfig,
379
+ );
380
+ if (richResult) return insetComponent(richResult);
381
+ }
382
+
383
+ const text = textFromResult(result, expanded);
384
+ const args = context?.args;
385
+ if (expanded) {
386
+ const taskResult = renderExpandedTaskResult(toolName, text, theme, Boolean(isError));
387
+ if (taskResult) return taskResult;
388
+ }
389
+ const tasks = !isError && toolName === "TaskList" ? parseTaskList(text) : [];
390
+ const outputLines = outputLineCount(result) || countLines(text);
391
+ const lineWord = outputLines === 1 ? "line" : "lines";
392
+ const action = toolName === "read" ? "loaded" : "returned";
393
+ const rendered = tasks.length
394
+ ? taskListSummary(tasks)
395
+ : isError
396
+ ? text
397
+ ? oneLine(text)
398
+ : "Failed"
399
+ : outputLines
400
+ ? `${outputLines} ${lineWord} ${action}`
401
+ : "Done";
402
+ const expandable = !expanded && (tasks.length > 0 || hasExpandableDetail(text, args));
403
+ const hintText = showMoreHintText();
404
+ const hintPrefix = expandable ? theme.fg("dim", " • ") : "";
405
+ const hint = expandable ? hintPrefix + theme.fg("dim", hintText) : "";
406
+ const hoveredHint = expandable ? hintPrefix + theme.fg("text", hintText) : "";
407
+ if (expanded) {
408
+ return renderExpandedToolResult(
409
+ text || "",
410
+ theme,
411
+ Boolean(isError),
412
+ context?.lastComponent,
413
+ args,
414
+ context,
415
+ );
416
+ }
417
+ if (context?.state) context.state.ccstyleIoView = undefined;
418
+ let cachedWidth: number | undefined;
419
+ let cachedLine: string | undefined;
420
+ let cachedHoveredLine: string | undefined;
421
+ return {
422
+ render(width: number) {
423
+ if (cachedLine === undefined || cachedWidth !== width) {
424
+ cachedWidth = width;
425
+ cachedLine = theme.fg(
426
+ isError ? "error" : "muted",
427
+ renderCollapsedToolResultToWidth(rendered, hint, width),
428
+ );
429
+ cachedHoveredLine = theme.fg(
430
+ isError ? "error" : "muted",
431
+ renderCollapsedToolResultToWidth(rendered, hoveredHint, width),
432
+ );
433
+ }
434
+ return [isToolCallHovered(toolCallId) ? cachedHoveredLine! : cachedLine];
435
+ },
436
+ invalidate() {},
437
+ };
438
+ },
439
+ };
440
+ }
441
+
442
+ function syncToolShell(component: any, shell: "default" | "self"): void {
443
+ const target = shell === "self" ? component.selfRenderContainer : component.contentBox;
444
+ if (!target || !Array.isArray(component.children)) return;
445
+ const candidates = new Set(
446
+ [component.contentText, component.contentBox, component.selfRenderContainer].filter(Boolean),
447
+ );
448
+ const indexes = component.children
449
+ .map((child: any, index: number) => (candidates.has(child) ? index : -1))
450
+ .filter((index: number) => index >= 0);
451
+ const targetIndex = indexes[0];
452
+ // 构造期 getRenderShell 先于 Pi 挂载 shell;此处勿挂载,否则构造器会二次添加。
453
+ if (targetIndex === undefined) return;
454
+ component.children[targetIndex] = target;
455
+ for (const index of indexes.sort((left: number, right: number) => right - left)) {
456
+ if (index !== targetIndex) component.children.splice(index, 1);
457
+ }
458
+ }
459
+
460
+ function shouldGloballyStyleTool(component: any, patch: GlobalToolRenderPatch): boolean {
461
+ const extensionDefinition = component.toolDefinition;
462
+ const builtInDefinition = component.builtInToolDefinition;
463
+ const definition = extensionDefinition ?? builtInDefinition;
464
+ const toolName = String(component.toolName || definition?.name || "");
465
+ const useCcstyle =
466
+ patch.mode() === "on" &&
467
+ !DEDICATED_RENDERER_TOOLS.has(toolName) &&
468
+ !preservesOriginalRenderer(extensionDefinition, toolName, builtInDefinition);
469
+ component[COMPONENT_TOOL_RENDER_MODE] = useCcstyle;
470
+ return useCcstyle;
471
+ }
472
+
473
+ function shouldUseSelfShell(component: any, _patch: GlobalToolRenderPatch): boolean {
474
+ component[COMPONENT_TOOL_SELF_SHELL_MODE] = false;
475
+ return false;
476
+ }
477
+
478
+ function getGloballyStyledTool(component: any, patch: GlobalToolRenderPatch): any {
479
+ const definition = component.toolDefinition ?? component.builtInToolDefinition;
480
+ if (definition && typeof definition === "object") {
481
+ let wrapped = patch.byDefinition.get(definition);
482
+ if (!wrapped) {
483
+ wrapped = patch.wrap(definition);
484
+ patch.byDefinition.set(definition, wrapped);
485
+ }
486
+ return wrapped;
487
+ }
488
+
489
+ const name = String(component.toolName || "tool");
490
+ let wrapped = patch.byName.get(name);
491
+ if (!wrapped) {
492
+ wrapped = patch.wrap({ name, label: name });
493
+ patch.byName.set(name, wrapped);
494
+ }
495
+ return wrapped;
496
+ }
497
+
498
+ function prototypeToolRenderMethods(prototype: any): ToolRenderMethods {
499
+ return {
500
+ hasRendererDefinition: prototype.hasRendererDefinition,
501
+ getRenderShell: prototype.getRenderShell,
502
+ getCallRenderer: prototype.getCallRenderer,
503
+ getResultRenderer: prototype.getResultRenderer,
504
+ };
505
+ }
506
+
507
+ function isOwnershipAwarePatch(value: any): value is GlobalToolRenderPatch {
508
+ if (!value || value.version !== 2 || !value.installed || !value.downstream) return false;
509
+ return ["hasRendererDefinition", "getRenderShell", "getCallRenderer", "getResultRenderer"].every(
510
+ (name) =>
511
+ typeof value.installed[name] === "function" && typeof value.downstream[name] === "function",
512
+ );
513
+ }
514
+
515
+ function isLegacyInstalledWrapper(method: unknown, downstreamField: string): boolean {
516
+ if (typeof method !== "function") return false;
517
+ try {
518
+ const source = Function.prototype.toString.call(method);
519
+ return (
520
+ source.includes(downstreamField) &&
521
+ (source.includes("shouldGloballyStyleTool") ||
522
+ source.includes("shouldUseSelfShell") ||
523
+ source.includes("getGloballyStyledTool"))
524
+ );
525
+ } catch {
526
+ return false;
527
+ }
528
+ }
529
+
530
+ function downstreamForGlobalToolInstall(prototype: any, previous: any): ToolRenderMethods {
531
+ const current = prototypeToolRenderMethods(prototype);
532
+ if (!previous || previous.prototype !== prototype) return current;
533
+ if (isOwnershipAwarePatch(previous)) {
534
+ return {
535
+ hasRendererDefinition:
536
+ current.hasRendererDefinition === previous.installed.hasRendererDefinition
537
+ ? previous.downstream.hasRendererDefinition
538
+ : current.hasRendererDefinition,
539
+ getRenderShell:
540
+ current.getRenderShell === previous.installed.getRenderShell
541
+ ? previous.downstream.getRenderShell
542
+ : current.getRenderShell,
543
+ getCallRenderer:
544
+ current.getCallRenderer === previous.installed.getCallRenderer
545
+ ? previous.downstream.getCallRenderer
546
+ : current.getCallRenderer,
547
+ getResultRenderer:
548
+ current.getResultRenderer === previous.installed.getResultRenderer
549
+ ? previous.downstream.getResultRenderer
550
+ : current.getResultRenderer,
551
+ };
552
+ }
553
+
554
+ // pre-v2 Symbol 无 wrapper 引用;能识别则回退,否则保留当前方法为 external。
555
+ const legacyDownstream = (method: Function, field: string): Function => {
556
+ const saved = previous[field];
557
+ return typeof saved === "function" && isLegacyInstalledWrapper(method, field) ? saved : method;
558
+ };
559
+ return {
560
+ hasRendererDefinition: legacyDownstream(
561
+ current.hasRendererDefinition,
562
+ "originalHasRendererDefinition",
563
+ ) as ToolRenderMethods["hasRendererDefinition"],
564
+ getRenderShell: legacyDownstream(
565
+ current.getRenderShell,
566
+ "originalGetRenderShell",
567
+ ) as ToolRenderMethods["getRenderShell"],
568
+ getCallRenderer: legacyDownstream(
569
+ current.getCallRenderer,
570
+ "originalGetCallRenderer",
571
+ ) as ToolRenderMethods["getCallRenderer"],
572
+ getResultRenderer: legacyDownstream(
573
+ current.getResultRenderer,
574
+ "originalGetResultRenderer",
575
+ ) as ToolRenderMethods["getResultRenderer"],
576
+ };
577
+ }
578
+
579
+ function disconnectGlobalToolRenderPatch(patch: any): void {
580
+ if (!patch || typeof patch !== "object") return;
581
+ patch.active = false;
582
+ patch.enabled = () => false;
583
+ patch.mode = () => "off";
584
+ patch.wrap = (tool: any) => tool;
585
+ patch.byDefinition = new WeakMap();
586
+ if (patch.byName && typeof patch.byName.clear === "function") patch.byName.clear();
587
+ else patch.byName = new Map();
588
+ }
589
+
590
+ function installGlobalToolRendering(
591
+ writeExecutionMetadata: WriteExecutionMetadataStore,
592
+ ): GlobalToolRenderPatch {
593
+ const prototype = (ToolExecutionComponent as any).prototype;
594
+ const host = globalThis as any;
595
+ const previous = host[GLOBAL_TOOL_RENDER_PATCH];
596
+ const downstream = downstreamForGlobalToolInstall(prototype, previous);
597
+ // 外部仍持有的旧 wrapper 先变为无回调 pass-through,再挂新安装。
598
+ disconnectGlobalToolRenderPatch(previous);
599
+
600
+ const patch: GlobalToolRenderPatch = {
601
+ version: 2,
602
+ prototype,
603
+ owner: {},
604
+ active: true,
605
+ enabled: () => config.mode === "on",
606
+ mode: () => config.mode,
607
+ wrap: (tool: any) => createCcstyleTool(tool, writeExecutionMetadata),
608
+ byDefinition: new WeakMap(),
609
+ byName: new Map(),
610
+ downstream,
611
+ installed: undefined as any,
612
+ originalHasRendererDefinition: downstream.hasRendererDefinition,
613
+ originalGetRenderShell: downstream.getRenderShell,
614
+ originalGetCallRenderer: downstream.getCallRenderer,
615
+ originalGetResultRenderer: downstream.getResultRenderer,
616
+ };
617
+
618
+ patch.installed = {
619
+ hasRendererDefinition: function (this: any, ...args: any[]) {
620
+ if (patch.active && shouldGloballyStyleTool(this, patch)) return true;
621
+ return patch.downstream.hasRendererDefinition.apply(this, args);
622
+ },
623
+ getRenderShell: function (this: any, ...args: any[]) {
624
+ if (!patch.active) return patch.downstream.getRenderShell.apply(this, args);
625
+ const useSelfShell = shouldUseSelfShell(this, patch);
626
+ const useCcstyle = shouldGloballyStyleTool(this, patch);
627
+ const shell =
628
+ useSelfShell || (useCcstyle && !this.expanded)
629
+ ? "self"
630
+ : useCcstyle
631
+ ? "default"
632
+ : patch.downstream.getRenderShell.apply(this, args);
633
+ syncToolShell(this, shell);
634
+ return shell;
635
+ },
636
+ getCallRenderer: function (this: any, ...args: any[]) {
637
+ if (patch.active && shouldGloballyStyleTool(this, patch)) {
638
+ return getGloballyStyledTool(this, patch).renderCall;
639
+ }
640
+ return patch.downstream.getCallRenderer.apply(this, args);
641
+ },
642
+ getResultRenderer: function (this: any, ...args: any[]) {
643
+ if (patch.active && shouldGloballyStyleTool(this, patch)) {
644
+ return getGloballyStyledTool(this, patch).renderResult;
645
+ }
646
+ return patch.downstream.getResultRenderer.apply(this, args);
647
+ },
648
+ };
649
+
650
+ prototype.hasRendererDefinition = patch.installed.hasRendererDefinition;
651
+ prototype.getRenderShell = patch.installed.getRenderShell;
652
+ prototype.getCallRenderer = patch.installed.getCallRenderer;
653
+ prototype.getResultRenderer = patch.installed.getResultRenderer;
654
+ host[GLOBAL_TOOL_RENDER_PATCH] = patch;
655
+ return patch;
656
+ }
657
+
658
+ function deactivateGlobalToolRendering(patch: GlobalToolRenderPatch): void {
659
+ if (!patch.active) return;
660
+ disconnectGlobalToolRenderPatch(patch);
661
+ const prototype = patch.prototype;
662
+ if (prototype.hasRendererDefinition === patch.installed.hasRendererDefinition) {
663
+ prototype.hasRendererDefinition = patch.downstream.hasRendererDefinition;
664
+ }
665
+ if (prototype.getRenderShell === patch.installed.getRenderShell) {
666
+ prototype.getRenderShell = patch.downstream.getRenderShell;
667
+ }
668
+ if (prototype.getCallRenderer === patch.installed.getCallRenderer) {
669
+ prototype.getCallRenderer = patch.downstream.getCallRenderer;
670
+ }
671
+ if (prototype.getResultRenderer === patch.installed.getResultRenderer) {
672
+ prototype.getResultRenderer = patch.downstream.getResultRenderer;
673
+ }
674
+ }
675
+
676
+ /** 展开面板背景统一为 user message 背景色;折叠行保持原生状态色。
677
+ * 必须在 compact-mode 之后安装,shutdown 时先于 compact-mode 释放。 */
678
+ export function installToolExpandedBackground(): () => void {
679
+ const host = globalThis as any;
680
+ const previous = host[TOOL_EXPANDED_BACKGROUND_PATCH] as ToolExpandedBackgroundPatch | undefined;
681
+ if (previous) previous.dispose();
682
+ const prototype = ToolExecutionComponent.prototype as unknown as { updateDisplay: () => void };
683
+ const original = prototype.updateDisplay;
684
+ const patch: ToolExpandedBackgroundPatch = {
685
+ active: true,
686
+ prototype,
687
+ installed: function (this: any) {
688
+ original.call(this);
689
+ if (!patch.active || config.mode !== "on" || !this.expanded) return;
690
+ const theme = getMessageDisplayTheme();
691
+ if (!theme?.bg) return;
692
+ const box = this.contentBox;
693
+ if (box?.setBgFn) box.setBgFn((text: string) => theme.bg("userMessageBg", text));
694
+ },
695
+ original,
696
+ dispose: () => {
697
+ patch.active = false;
698
+ if (prototype.updateDisplay === patch.installed) {
699
+ prototype.updateDisplay = original;
700
+ }
701
+ if (host[TOOL_EXPANDED_BACKGROUND_PATCH] === patch) {
702
+ delete host[TOOL_EXPANDED_BACKGROUND_PATCH];
703
+ }
704
+ },
705
+ };
706
+ prototype.updateDisplay = patch.installed;
707
+ host[TOOL_EXPANDED_BACKGROUND_PATCH] = patch;
708
+ return patch.dispose;
709
+ }
710
+
711
+ /** 安装 default mode 全局工具渲染补丁(不含展开背景,见 installToolExpandedBackground)。 */
712
+ export function installDefaultMode(
713
+ writeExecutionMetadata: WriteExecutionMetadataStore,
714
+ ): DefaultModeHooks {
715
+ const globalToolRendering = installGlobalToolRendering(writeExecutionMetadata);
716
+ return {
717
+ isOwner() {
718
+ return (
719
+ (globalThis as any)[GLOBAL_TOOL_RENDER_PATCH] === globalToolRendering &&
720
+ globalToolRendering.active
721
+ );
722
+ },
723
+ shutdown() {
724
+ deactivateGlobalToolRendering(globalToolRendering);
725
+ },
726
+ };
727
+ }